Skip to content

Commit 1f2277d

Browse files
tas50claude
andcommitted
🐛 Fix foundation model duplicates and privateca tags N+1
Foundation models: query once from default region instead of all regions, since ListFoundationModels returns a global catalog. Private CA tags: lazy-load via computed method to avoid N+1 ListTags calls during listing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e8bb750 commit 1f2277d

5 files changed

Lines changed: 66 additions & 95 deletions

File tree

.github/actions/spelling/expect.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ cname
5252
compressratio
5353
cooldown
5454
cpe
55+
crowdstrike
5556
cryptokey
5657
ctx
5758
customresources

providers/aws/resources/aws.lr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10692,7 +10692,7 @@ private aws.privateca.certificateAuthority @defaults("arn status type") {
1069210692
// Failure reason if the CA is in a failed state
1069310693
failureReason string
1069410694
// Tags for the certificate authority
10695-
tags map[string]string
10695+
tags() map[string]string
1069610696
// PEM-encoded CA certificate
1069710697
certificate() string
1069810698
// PEM-encoded CA certificate chain

providers/aws/resources/aws.lr.go

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

providers/aws/resources/aws_bedrock.go

Lines changed: 30 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -26,78 +26,43 @@ func (a *mqlAwsBedrock) id() (string, error) {
2626

2727
func (a *mqlAwsBedrock) foundationModels() ([]any, error) {
2828
conn := a.MqlRuntime.Connection.(*connection.AwsConnection)
29-
res := []any{}
30-
poolOfJobs := jobpool.CreatePool(a.getFoundationModels(conn), 5)
31-
poolOfJobs.Run()
32-
33-
if poolOfJobs.HasErrors() {
34-
return nil, poolOfJobs.GetErrors()
35-
}
36-
for i := range poolOfJobs.Jobs {
37-
if poolOfJobs.Jobs[i].Result != nil {
38-
res = append(res, poolOfJobs.Jobs[i].Result.([]any)...)
39-
}
40-
}
41-
return res, nil
42-
}
29+
// ListFoundationModels returns a global catalog, identical across all regions.
30+
// Query once from the default region to avoid duplicates.
31+
svc := conn.Bedrock("")
32+
ctx := context.Background()
4333

44-
func (a *mqlAwsBedrock) getFoundationModels(conn *connection.AwsConnection) []*jobpool.Job {
45-
tasks := make([]*jobpool.Job, 0)
46-
regions, err := conn.Regions()
34+
resp, err := svc.ListFoundationModels(ctx, &bedrock.ListFoundationModelsInput{})
4735
if err != nil {
48-
return []*jobpool.Job{{Err: err}}
36+
return nil, err
4937
}
5038

51-
for _, region := range regions {
52-
f := func() (jobpool.JobResult, error) {
53-
svc := conn.Bedrock(region)
54-
ctx := context.Background()
55-
res := []any{}
56-
57-
// ListFoundationModels is not paginated
58-
resp, err := svc.ListFoundationModels(ctx, &bedrock.ListFoundationModelsInput{})
59-
if err != nil {
60-
if Is400AccessDeniedError(err) {
61-
log.Warn().Str("region", region).Msg("error accessing region for AWS API")
62-
return res, nil
63-
}
64-
if IsServiceNotAvailableInRegionError(err) {
65-
log.Debug().Str("region", region).Msg("bedrock is not available in region")
66-
return res, nil
67-
}
68-
return nil, err
69-
}
70-
71-
for _, fm := range resp.ModelSummaries {
72-
var lifecycleStatus string
73-
if fm.ModelLifecycle != nil {
74-
lifecycleStatus = string(fm.ModelLifecycle.Status)
75-
}
39+
res := []any{}
40+
for _, fm := range resp.ModelSummaries {
41+
var lifecycleStatus string
42+
if fm.ModelLifecycle != nil {
43+
lifecycleStatus = string(fm.ModelLifecycle.Status)
44+
}
7645

77-
mqlFM, err := CreateResource(a.MqlRuntime, "aws.bedrock.foundationModel",
78-
map[string]*llx.RawData{
79-
"__id": llx.StringDataPtr(fm.ModelArn),
80-
"modelArn": llx.StringDataPtr(fm.ModelArn),
81-
"modelId": llx.StringDataPtr(fm.ModelId),
82-
"modelName": llx.StringDataPtr(fm.ModelName),
83-
"providerName": llx.StringDataPtr(fm.ProviderName),
84-
"inputModalities": llx.ArrayData(enumSliceToAny(fm.InputModalities), types.String),
85-
"outputModalities": llx.ArrayData(enumSliceToAny(fm.OutputModalities), types.String),
86-
"customizationsSupported": llx.ArrayData(enumSliceToAny(fm.CustomizationsSupported), types.String),
87-
"inferenceTypesSupported": llx.ArrayData(enumSliceToAny(fm.InferenceTypesSupported), types.String),
88-
"responseStreamingSupported": llx.BoolDataPtr(fm.ResponseStreamingSupported),
89-
"modelLifecycleStatus": llx.StringData(lifecycleStatus),
90-
})
91-
if err != nil {
92-
return nil, err
93-
}
94-
res = append(res, mqlFM)
95-
}
96-
return jobpool.JobResult(res), nil
46+
mqlFM, err := CreateResource(a.MqlRuntime, "aws.bedrock.foundationModel",
47+
map[string]*llx.RawData{
48+
"__id": llx.StringDataPtr(fm.ModelArn),
49+
"modelArn": llx.StringDataPtr(fm.ModelArn),
50+
"modelId": llx.StringDataPtr(fm.ModelId),
51+
"modelName": llx.StringDataPtr(fm.ModelName),
52+
"providerName": llx.StringDataPtr(fm.ProviderName),
53+
"inputModalities": llx.ArrayData(enumSliceToAny(fm.InputModalities), types.String),
54+
"outputModalities": llx.ArrayData(enumSliceToAny(fm.OutputModalities), types.String),
55+
"customizationsSupported": llx.ArrayData(enumSliceToAny(fm.CustomizationsSupported), types.String),
56+
"inferenceTypesSupported": llx.ArrayData(enumSliceToAny(fm.InferenceTypesSupported), types.String),
57+
"responseStreamingSupported": llx.BoolDataPtr(fm.ResponseStreamingSupported),
58+
"modelLifecycleStatus": llx.StringData(lifecycleStatus),
59+
})
60+
if err != nil {
61+
return nil, err
9762
}
98-
tasks = append(tasks, jobpool.NewJob(f))
63+
res = append(res, mqlFM)
9964
}
100-
return tasks
65+
return res, nil
10166
}
10267

10368
func (a *mqlAwsBedrockFoundationModel) id() (string, error) {

providers/aws/resources/aws_privateca.go

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import (
1616
"go.mondoo.com/mql/v13/providers-sdk/v1/util/convert"
1717
"go.mondoo.com/mql/v13/providers-sdk/v1/util/jobpool"
1818
"go.mondoo.com/mql/v13/providers/aws/connection"
19-
"go.mondoo.com/mql/v13/types"
2019
)
2120

2221
func (a *mqlAwsPrivateca) id() (string, error) {
@@ -69,7 +68,7 @@ func (a *mqlAwsPrivateca) getCertificateAuthorities(conn *connection.AwsConnecti
6968
}
7069

7170
for _, ca := range page.CertificateAuthorities {
72-
mqlCA, err := newMqlPrivatecaCertificateAuthority(a.MqlRuntime, ca, region, svc)
71+
mqlCA, err := newMqlPrivatecaCertificateAuthority(a.MqlRuntime, ca, region)
7372
if err != nil {
7473
return nil, err
7574
}
@@ -83,7 +82,7 @@ func (a *mqlAwsPrivateca) getCertificateAuthorities(conn *connection.AwsConnecti
8382
return tasks
8483
}
8584

86-
func newMqlPrivatecaCertificateAuthority(runtime *plugin.Runtime, ca acmpcatypes.CertificateAuthority, region string, svc *acmpca.Client) (*mqlAwsPrivatecaCertificateAuthority, error) {
85+
func newMqlPrivatecaCertificateAuthority(runtime *plugin.Runtime, ca acmpcatypes.CertificateAuthority, region string) (*mqlAwsPrivatecaCertificateAuthority, error) {
8786
var subject any
8887
if ca.CertificateAuthorityConfiguration != nil {
8988
subject, _ = convert.JsonToDict(ca.CertificateAuthorityConfiguration.Subject)
@@ -99,30 +98,6 @@ func newMqlPrivatecaCertificateAuthority(runtime *plugin.Runtime, ca acmpcatypes
9998
signingAlgorithm = string(ca.CertificateAuthorityConfiguration.SigningAlgorithm)
10099
}
101100

102-
tags := make(map[string]any)
103-
if ca.Arn != nil {
104-
ctx := context.Background()
105-
var nextToken *string
106-
for {
107-
tagsResp, err := svc.ListTags(ctx, &acmpca.ListTagsInput{
108-
CertificateAuthorityArn: ca.Arn,
109-
NextToken: nextToken,
110-
})
111-
if err != nil {
112-
break
113-
}
114-
for _, tag := range tagsResp.Tags {
115-
if tag.Key != nil && tag.Value != nil {
116-
tags[*tag.Key] = *tag.Value
117-
}
118-
}
119-
if tagsResp.NextToken == nil {
120-
break
121-
}
122-
nextToken = tagsResp.NextToken
123-
}
124-
}
125-
126101
res, err := CreateResource(runtime, "aws.privateca.certificateAuthority",
127102
map[string]*llx.RawData{
128103
"__id": llx.StringDataPtr(ca.Arn),
@@ -143,7 +118,6 @@ func newMqlPrivatecaCertificateAuthority(runtime *plugin.Runtime, ca acmpcatypes
143118
"createdAt": llx.TimeDataPtr(ca.CreatedAt),
144119
"lastStateChangeAt": llx.TimeDataPtr(ca.LastStateChangeAt),
145120
"failureReason": llx.StringData(string(ca.FailureReason)),
146-
"tags": llx.MapData(tags, types.String),
147121
})
148122
if err != nil {
149123
return nil, err
@@ -217,6 +191,35 @@ func (a *mqlAwsPrivatecaCertificateAuthority) certificateChain() (string, error)
217191
return a.certChainData, nil
218192
}
219193

194+
func (a *mqlAwsPrivatecaCertificateAuthority) tags() (map[string]any, error) {
195+
conn := a.MqlRuntime.Connection.(*connection.AwsConnection)
196+
svc := conn.Acmpca(a.cacheRegion)
197+
ctx := context.Background()
198+
199+
arn := a.Arn.Data
200+
res := map[string]any{}
201+
var nextToken *string
202+
for {
203+
resp, err := svc.ListTags(ctx, &acmpca.ListTagsInput{
204+
CertificateAuthorityArn: &arn,
205+
NextToken: nextToken,
206+
})
207+
if err != nil {
208+
return nil, err
209+
}
210+
for _, tag := range resp.Tags {
211+
if tag.Key != nil && tag.Value != nil {
212+
res[*tag.Key] = *tag.Value
213+
}
214+
}
215+
if resp.NextToken == nil {
216+
break
217+
}
218+
nextToken = resp.NextToken
219+
}
220+
return res, nil
221+
}
222+
220223
func (a *mqlAwsPrivatecaCertificateAuthority) policy() (string, error) {
221224
conn := a.MqlRuntime.Connection.(*connection.AwsConnection)
222225
svc := conn.Acmpca(a.cacheRegion)

0 commit comments

Comments
 (0)