77 "context"
88 "errors"
99 "fmt"
10+ "strings"
1011
12+ "github.com/aws/aws-sdk-go-v2/aws"
1113 "github.com/aws/aws-sdk-go-v2/service/securityhub"
1214 "github.com/aws/aws-sdk-go-v2/service/securityhub/types"
1315 "github.com/rs/zerolog/log"
@@ -132,8 +134,7 @@ func (a *mqlAwsSecurityhubHub) standardSubscriptions() ([]any, error) {
132134 return nil , err
133135 }
134136 for _ , std := range page .StandardsSubscriptions {
135- // Extract a readable name from the standard ARN
136- name := convert .ToValue (std .StandardsArn )
137+ name := standardNameFromArn (convert .ToValue (std .StandardsArn ))
137138
138139 mqlStd , err := CreateResource (a .MqlRuntime , "aws.securityhub.standardSubscription" ,
139140 map [string ]* llx.RawData {
@@ -219,17 +220,17 @@ func (a *mqlAwsSecurityhubHub) findings() ([]any, error) {
219220 RecordState : []types.StringFilter {
220221 {
221222 Comparison : types .StringFilterComparisonEquals ,
222- Value : strPtr ("ACTIVE" ),
223+ Value : aws . String ("ACTIVE" ),
223224 },
224225 },
225226 WorkflowStatus : []types.StringFilter {
226227 {
227228 Comparison : types .StringFilterComparisonNotEquals ,
228- Value : strPtr ("SUPPRESSED" ),
229+ Value : aws . String ("SUPPRESSED" ),
229230 },
230231 },
231232 },
232- MaxResults : int32Ptr (100 ),
233+ MaxResults : aws . Int32 (100 ),
233234 })
234235
235236 // Limit to 1000 findings to avoid unbounded API calls
@@ -242,8 +243,11 @@ func (a *mqlAwsSecurityhubHub) findings() ([]any, error) {
242243 }
243244 return nil , err
244245 }
245- for _ , finding := range page .Findings {
246- mqlFinding , err := newMqlSecurityHubFinding (a .MqlRuntime , finding , region )
246+ for i := range page .Findings {
247+ if len (res ) >= maxFindings {
248+ break
249+ }
250+ mqlFinding , err := newMqlSecurityHubFinding (a .MqlRuntime , & page .Findings [i ], region )
247251 if err != nil {
248252 return nil , err
249253 }
@@ -253,7 +257,7 @@ func (a *mqlAwsSecurityhubHub) findings() ([]any, error) {
253257 return res , nil
254258}
255259
256- func newMqlSecurityHubFinding (runtime * plugin.Runtime , finding types.AwsSecurityFinding , region string ) (* mqlAwsSecurityhubFinding , error ) {
260+ func newMqlSecurityHubFinding (runtime * plugin.Runtime , finding * types.AwsSecurityFinding , region string ) (* mqlAwsSecurityhubFinding , error ) {
257261 var severity string
258262 var severityScore float64
259263 if finding .Severity != nil {
@@ -273,6 +277,8 @@ func newMqlSecurityHubFinding(runtime *plugin.Runtime, finding types.AwsSecurity
273277 workflowStatus = string (finding .Workflow .Status )
274278 }
275279
280+ // A finding can reference multiple resources, but we expose only the first
281+ // (primary) one. Most findings have exactly one resource.
276282 var resourceType , resourceId , resourceRegion string
277283 if len (finding .Resources ) > 0 {
278284 resourceType = convert .ToValue (finding .Resources [0 ].Type )
@@ -295,7 +301,6 @@ func newMqlSecurityHubFinding(runtime *plugin.Runtime, finding types.AwsSecurity
295301 map [string ]* llx.RawData {
296302 "__id" : llx .StringData (fmt .Sprintf ("securityhub/finding/%s/%s" , region , convert .ToValue (finding .Id ))),
297303 "id" : llx .StringDataPtr (finding .Id ),
298- "arn" : llx .StringDataPtr (finding .ProductArn ),
299304 "title" : llx .StringDataPtr (finding .Title ),
300305 "description" : llx .StringDataPtr (finding .Description ),
301306 "severity" : llx .StringData (severity ),
@@ -396,7 +401,10 @@ func (a *mqlAwsSecurityhubHub) insights() ([]any, error) {
396401 return nil , err
397402 }
398403 for _ , insight := range page .Insights {
399- filters , _ := convert .JsonToDict (insight .Filters )
404+ filters , err := convert .JsonToDict (insight .Filters )
405+ if err != nil {
406+ return nil , err
407+ }
400408
401409 mqlInsight , err := CreateResource (a .MqlRuntime , "aws.securityhub.insight" ,
402410 map [string ]* llx.RawData {
@@ -466,11 +474,18 @@ func (a *mqlAwsSecurityhubInsightResult) id() (string, error) {
466474 return a .__id , nil
467475}
468476
469- // Helper functions
470- func strPtr (s string ) * string {
471- return & s
472- }
473-
474- func int32Ptr (i int32 ) * int32 {
475- return & i
477+ // standardNameFromArn extracts a human-readable name from a Security Hub standard ARN.
478+ // e.g. "arn:aws:securityhub:::standards/aws-foundational-security-best-practices/v/1.0.0"
479+ // becomes "aws-foundational-security-best-practices".
480+ func standardNameFromArn (arn string ) string {
481+ const prefix = "standards/"
482+ idx := strings .Index (arn , prefix )
483+ if idx == - 1 {
484+ return arn
485+ }
486+ name := arn [idx + len (prefix ):]
487+ if slash := strings .Index (name , "/" ); slash != - 1 {
488+ name = name [:slash ]
489+ }
490+ return name
476491}
0 commit comments