@@ -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,39 @@ 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 , ok := result ["locations" ].([]interface {})
156+ if ! ok || len (locations ) == 0 {
157+ return ""
158+ }
159+ loc , ok := locations [0 ].(map [string ]interface {})
160+ if ! ok {
161+ return ""
162+ }
163+ physLoc , ok := loc ["physicalLocation" ].(map [string ]interface {})
164+ if ! ok {
165+ return ""
166+ }
167+ artLoc , ok := physLoc ["artifactLocation" ].(map [string ]interface {})
168+ if ! ok {
169+ return ""
170+ }
171+ uri , ok := artLoc ["uri" ].(string )
172+ if ! ok {
173+ return ""
174+ }
175+ return uri
176+ }
177+
148178// normalizeHelpContent removes help.markdown content to avoid comparing test data descriptions
149179func normalizeHelpContent (run map [string ]interface {}) {
150180 normalizeRuleHelp (run )
0 commit comments