@@ -131,7 +131,8 @@ func sortByID(arr []interface{}) {
131131 })
132132}
133133
134- // sortByRuleID sorts an array of results by their "ruleId" field
134+ // sortByRuleID sorts an array of results by their "ruleId" field,
135+ // with artifact URI as a tiebreaker for stable ordering.
135136func sortByRuleID (arr []interface {}) {
136137 sort .Slice (arr , func (i , j int ) bool {
137138 iMap , iOk := arr [i ].(map [string ]interface {})
@@ -141,10 +142,27 @@ func sortByRuleID(arr []interface{}) {
141142 }
142143 iID , _ := iMap ["ruleId" ].(string ) //nolint:errcheck // test helper, ok to ignore
143144 jID , _ := jMap ["ruleId" ].(string ) //nolint:errcheck // test helper, ok to ignore
144- return iID < jID
145+ if iID != jID {
146+ return iID < jID
147+ }
148+ // Multiple results can share the same ruleId (e.g. duplicate secrets findings),
149+ // so we use artifact URI as a tiebreaker to avoid flaky ordering from Go map iteration.
150+ return extractArtifactURI (iMap ) < extractArtifactURI (jMap )
145151 })
146152}
147153
154+ func extractArtifactURI (result map [string ]interface {}) string {
155+ locations , _ := result ["locations" ].([]interface {})
156+ if len (locations ) == 0 {
157+ return ""
158+ }
159+ loc , _ := locations [0 ].(map [string ]interface {})
160+ physLoc , _ := loc ["physicalLocation" ].(map [string ]interface {})
161+ artLoc , _ := physLoc ["artifactLocation" ].(map [string ]interface {})
162+ uri , _ := artLoc ["uri" ].(string )
163+ return uri
164+ }
165+
148166// normalizeHelpContent removes help.markdown content to avoid comparing test data descriptions
149167func normalizeHelpContent (run map [string ]interface {}) {
150168 normalizeRuleHelp (run )
0 commit comments