🔍 Duplicate Code Detected: Divergent runs-on Normalization Across Config Parsers
Analysis of commit 5e03fe022755ab7af5fcc3cf36899b4003a5544a
Assignee: @copilot
Summary
The head commit introduced another dedicated runs-on parsing path in pkg/workflow/repo_config.go and pkg/workflow/safe_jobs.go, but the codebase already has multiple independent implementations that normalize or render runs-on values.
This now spans repo config JSON, safe-jobs YAML, safe-outputs JSON, threat-detection config, evals config, and custom jobs. The duplication is no longer just cosmetic: each path supports a slightly different shape set and rendering strategy, which raises the risk of inconsistent behavior when runner syntax evolves.
Duplication Details
Pattern: repeated runs-on shape parsing and rendering logic
- Severity: Medium
- Occurrences: 6
- Locations:
pkg/workflow/repo_config.go (lines 73-125, 473-489)
pkg/workflow/safe_jobs.go (lines 71-76, 241-250)
pkg/workflow/runs_on_unmarshal.go (lines 13-29, 35-50)
pkg/workflow/evals_config.go (lines 98-100)
pkg/workflow/threat_detection_config.go (lines 141-143)
pkg/workflow/compiler_custom_jobs.go (lines 245-260)
- Code Sample:
func (r *RunsOnValue) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err == nil {
*r = RunsOnValue{s}
return nil
}
var ss []string
if err := json.Unmarshal(data, &ss); err != nil {
return fmt.Errorf("runs_on value is not recognized: %w", err)
}
*r = RunsOnValue(ss)
return nil
}
if runsOn, exists := jobConfig["runs-on"]; exists {
safeJob.RunsOn = toRunsOnValue(runsOn)
safeJob.runsOnArray = isRunsOnArrayValue(runsOn)
}
if runsOnRaw, ok := v["runs-on"]; ok {
cfg.RunsOn = renderRunsOnSnippet(runsOnRaw)
}
The same concern shows up in multiple forms:
- some call sites preserve list-vs-string shape (
safe_jobs.go)
- some normalize directly to a YAML snippet (
runs_on_unmarshal.go, evals_config.go, threat_detection_config.go)
- some special-case strings and marshal everything else (
compiler_custom_jobs.go)
- the new repo-config path only supports string and string-array forms (
repo_config.go)
Impact Analysis
- Maintainability: adding support for new runner forms or changing normalization rules now requires touching several unrelated parsers.
- Bug Risk: fixes can land in one parser and miss the others, leaving
runs-on behavior inconsistent across config surfaces.
- Code Bloat: the new commit increased the number of specialized helpers instead of consolidating the existing runner-shape handling.
Refactoring Recommendations
-
Introduce a shared runs-on normalization package-level helper
Extract common parsing/rendering into one API that can accept the supported raw shapes and return both normalized labels and rendered YAML when needed.
Estimated effort: medium.
Benefits: one behavior definition, one validation surface, lower regression risk.
-
Separate parsing from rendering
Keep a single normalized internal representation for runs-on, then render YAML only at emission sites.
Estimated effort: medium.
Benefits: avoids mixing config decoding rules with workflow serialization details.
-
Add one compatibility matrix for all supported runs-on surfaces
Cover repo config, safe-jobs, safe-outputs, threat detection, evals, and custom jobs with the same fixture set.
Estimated effort: low to medium.
Benefits: makes behavior drift visible before more parsers diverge.
Implementation Checklist
Analysis Metadata
- Analyzed Files: 2 changed production files (
pkg/workflow/repo_config.go, pkg/workflow/safe_jobs.go)
- Detection Method: Serena activation attempted; fallback to targeted code/pattern analysis because the runner lacks a working Go language server (
go not installed)
- Commit:
5e03fe022755ab7af5fcc3cf36899b4003a5544a
- Analysis Date:
2026-08-15T21:55:35Z
Generated by 🔍 Duplicate Code Detector · gpt54 · 55.3 AIC · ⊞ 13K · ◷
🔍 Duplicate Code Detected: Divergent
runs-onNormalization Across Config ParsersAnalysis of commit
5e03fe022755ab7af5fcc3cf36899b4003a5544aAssignee:
@copilotSummary
The head commit introduced another dedicated
runs-onparsing path inpkg/workflow/repo_config.goandpkg/workflow/safe_jobs.go, but the codebase already has multiple independent implementations that normalize or renderruns-onvalues.This now spans repo config JSON, safe-jobs YAML, safe-outputs JSON, threat-detection config, evals config, and custom jobs. The duplication is no longer just cosmetic: each path supports a slightly different shape set and rendering strategy, which raises the risk of inconsistent behavior when runner syntax evolves.
Duplication Details
Pattern: repeated
runs-onshape parsing and rendering logicpkg/workflow/repo_config.go(lines 73-125, 473-489)pkg/workflow/safe_jobs.go(lines 71-76, 241-250)pkg/workflow/runs_on_unmarshal.go(lines 13-29, 35-50)pkg/workflow/evals_config.go(lines 98-100)pkg/workflow/threat_detection_config.go(lines 141-143)pkg/workflow/compiler_custom_jobs.go(lines 245-260)The same concern shows up in multiple forms:
safe_jobs.go)runs_on_unmarshal.go,evals_config.go,threat_detection_config.go)compiler_custom_jobs.go)repo_config.go)Impact Analysis
runs-onbehavior inconsistent across config surfaces.Refactoring Recommendations
Introduce a shared
runs-onnormalization package-level helperExtract common parsing/rendering into one API that can accept the supported raw shapes and return both normalized labels and rendered YAML when needed.
Estimated effort: medium.
Benefits: one behavior definition, one validation surface, lower regression risk.
Separate parsing from rendering
Keep a single normalized internal representation for
runs-on, then render YAML only at emission sites.Estimated effort: medium.
Benefits: avoids mixing config decoding rules with workflow serialization details.
Add one compatibility matrix for all supported
runs-onsurfacesCover repo config, safe-jobs, safe-outputs, threat detection, evals, and custom jobs with the same fixture set.
Estimated effort: low to medium.
Benefits: makes behavior drift visible before more parsers diverge.
Implementation Checklist
Analysis Metadata
pkg/workflow/repo_config.go,pkg/workflow/safe_jobs.go)gonot installed)5e03fe022755ab7af5fcc3cf36899b4003a5544a2026-08-15T21:55:35Z