Skip to content

Deduplicate runtime override cloning in applyRuntimeOverrides#43134

Merged
pelikhan merged 6 commits into
mainfrom
copilot/duplicate-code-fix-runtime-cloning
Jul 3, 2026
Merged

Deduplicate runtime override cloning in applyRuntimeOverrides#43134
pelikhan merged 6 commits into
mainfrom
copilot/duplicate-code-fix-runtime-cloning

Conversation

Copilot AI commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

applyRuntimeOverrides duplicated the same Runtime clone-and-override logic in both the existing-requirement and known-runtime paths. That made action override behavior easy to drift as Runtime evolves.

  • Refactor runtime cloning

    • Extract cloneRuntimeWithActionOverrides(base, actionRepo, actionVersion) to centralize Runtime copying plus action-repo / action-version overrides.
    • Reuse the helper in both override branches inside applyRuntimeOverrides.
  • Preserve override behavior

    • Keep the existing semantics for:
      • overriding ActionRepo only
      • overriding ActionVersion only
      • cloning before mutation so shared known runtime definitions are not modified
  • Add focused coverage

    • Add a test for the known-runtime override path to verify:
      • a customized runtime is cloned rather than reused
      • action overrides are applied to the clone
      • the global known runtime remains unchanged
existing.Runtime = cloneRuntimeWithActionOverrides(existing.Runtime, actionRepo, actionVersion)
runtime = cloneRuntimeWithActionOverrides(knownRuntime, actionRepo, actionVersion)

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix duplicate code in applyRuntimeOverrides for cloning Runtime Deduplicate runtime override cloning in applyRuntimeOverrides Jul 3, 2026
Copilot AI requested a review from pelikhan July 3, 2026 06:42
@pelikhan
pelikhan marked this pull request as ready for review July 3, 2026 06:42
Copilot AI review requested due to automatic review settings July 3, 2026 06:42
@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check.

No ADR enforcement needed: PR #43134 does not have the 'implementation' label and has only 67 new lines of code in business logic directories (threshold is 100).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Refactors applyRuntimeOverrides to deduplicate the “clone runtime + apply action-repo/action-version overrides” logic, and adds a focused regression test for the known-runtime override path to ensure overrides don’t mutate the global knownRuntimes.

Changes:

  • Introduces cloneRuntimeWithActionOverrides to centralize runtime cloning plus action overrides.
  • Reuses the helper for both “existing requirement” and “known runtime” override paths.
  • Adds a test covering the known-runtime action override cloning behavior.
Show a summary per file
File Description
pkg/workflow/runtime_overrides.go Adds a helper for cloning runtimes with action overrides and uses it in both override branches.
pkg/workflow/runtime_override_test.go Adds a test asserting the known-runtime override path clones and applies action overrides without mutating the global runtime definition.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 2/2 changed files
  • Comments generated: 2
  • Review effort level: Low

Comment on lines +8 to +28
func cloneRuntimeWithActionOverrides(base *Runtime, actionRepo, actionVersion string) *Runtime {
customRuntime := &Runtime{
ID: base.ID,
Name: base.Name,
ActionRepo: base.ActionRepo,
ActionVersion: base.ActionVersion,
VersionField: base.VersionField,
DefaultVersion: base.DefaultVersion,
Commands: base.Commands,
ExtraWithFields: base.ExtraWithFields,
}

if actionRepo != "" {
customRuntime.ActionRepo = actionRepo
}
if actionVersion != "" {
customRuntime.ActionVersion = actionVersion
}

return customRuntime
}
Comment thread pkg/workflow/runtime_override_test.go Outdated
Comment on lines +271 to +273
if knownNode.ActionRepo == "custom/setup-node" {
t.Fatal("expected known runtime to remain unchanged")
}
@github-actions github-actions Bot mentioned this pull request Jul 3, 2026
@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 100/100 — Excellent

Analyzed 1 test(s): 1 design, 0 implementation, 0 violation(s).

📊 Metrics (1 test)
Metric Value
Analyzed 1 (Go: 1, JS: 0)
✅ Design 1 (100%)
⚠️ Implementation 0 (0%)
Edge/error coverage 1 (100%)
Duplicate clusters 0
Inflation No (1.79:1, threshold 2:1)
🚨 Violations 0
Test File Classification Issues
TestApplyRuntimeOverrides_KnownRuntimeActionOverrides pkg/workflow/runtime_override_test.go:233 design_test / behavioral_contract / high_value None

Verdict

Passed. 0% implementation tests (threshold: 30%). The new test directly enforces the clone-isolation invariant: it verifies that applying action-repo/action-version overrides to a known runtime produces a clone (pointer inequality) while leaving the original knownRuntimes entry unchanged. Build tag (//go:build !integration) is present, no mock libraries are used, and all assertions carry descriptive failure messages.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • awmgmcpg

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "awmgmcpg"

See Network Configuration for more information.

🧪 Test quality analysis by Test Quality Sentinel · 27.7 AIC · ⌖ 11.7 AIC · ⊞ 6.8K ·
Comment /review to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Test Quality Sentinel: 100/100. 0% implementation tests (threshold: 30%). The new test TestApplyRuntimeOverrides_KnownRuntimeActionOverrides is a high-value design test that enforces the clone-isolation invariant introduced by the refactoring. No violations found.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: Deduplicate runtime override cloning in applyRuntimeOverrides

The refactor is clean and well-motivated. One issue requires attention before merge.

Blocking issue — incomplete field copy in cloneRuntimeWithActionOverrides

The Runtime struct has 9 fields; the new clone helper copies only 8. The ManifestFiles []string field is absent from the struct literal (line 17). This means any cloned runtime (created when action-repo or action-version is overridden) will have a nil ManifestFiles.

Today this is latent: ManifestFiles is only read via knownRuntimes directly (in buildBaseManifestFiles), not via req.Runtime.ManifestFiles. But it is a regression hidden by the current access pattern — adding one line files = append(files, req.Runtime.ManifestFiles...) anywhere would silently break runtime manifest detection for customised runtimes.

The simplest fix uses a value-copy:

func cloneRuntimeWithActionOverrides(base *Runtime, actionRepo, actionVersion string) *Runtime {
    r := *base  // copies all 9 fields
    if actionRepo != "" {
        r.ActionRepo = actionRepo
    }
    if actionVersion != "" {
        r.ActionVersion = actionVersion
    }
    return &r
}

This also keeps the helper correct automatically when new fields are added to Runtime.

Non-blocking observations

  • Commands and ExtraWithFields are slice/map fields that will be shared (shallow-copy) between the original and the clone. This is safe now because neither is mutated after construction, but worth a comment or a future deep-copy if mutation is ever added.
  • The new test TestApplyRuntimeOverrides_KnownRuntimeActionOverrides correctly validates the clone-vs-pointer check and that the global known runtime is unmodified. It does not cover the missing-field case; a ManifestFiles assertion on nodeReq.Runtime would catch the regression.

Verdict: REQUEST_CHANGES on the missing field; everything else is an improvement.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · 46 AIC · ⌖ 6.26 AIC · ⊞ 4.8K

Comment thread pkg/workflow/runtime_overrides.go Outdated
VersionField: base.VersionField,
DefaultVersion: base.DefaultVersion,
Commands: base.Commands,
ExtraWithFields: base.ExtraWithFields,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing ManifestFiles field in clone — the Runtime struct has 9 fields but cloneRuntimeWithActionOverrides only copies 8. ManifestFiles is not included in the struct literal.

While today ManifestFiles is only read via the global knownRuntimes slice (not through req.Runtime.ManifestFiles), any future code that accesses req.Runtime.ManifestFiles on an action-overridden runtime will silently get nil. A shallow copy guards against this:

customRuntime := *base // shallow copy all fields
if actionRepo != "" {
    customRuntime.ActionRepo = actionRepo
}
if actionVersion != "" {
    customRuntime.ActionVersion = actionVersion
}
return &customRuntime

Note: Commands and ExtraWithFields are slice/map references shared between the clone and the original — currently safe since neither is mutated, but worth documenting or deep-copying if that changes.

@copilot please address this.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skills-Based Review 🧠

Applied /codebase-design and /tdd — requesting changes on two correctness issues and one test-coverage gap.

📋 Key Themes & Highlights

Issues Found

  1. Missing field in cloneManifestFiles is not copied in cloneRuntimeWithActionOverrides, making cloned runtimes silently lossy (correctness bug).
  2. Shallow copy of reference typesCommands (slice) and ExtraWithFields (map) are copied by reference; mutations to the clone would corrupt the original runtime.
  3. Incomplete test coverage — The new test only exercises the both-fields-overridden path; a single-field-only case (e.g. only action-repo) would fully spec the || branch condition.

Positive Highlights

  • ✅ Clean extraction of cloneRuntimeWithActionOverrides — the deduplication is correct and well-motivated
  • ✅ New test verifies pointer inequality (clone isolation) and global-runtime immutability — exactly the right assertions
  • ✅ PR description is clear and the code change is minimal and focused

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · 51.1 AIC · ⌖ 6.5 AIC · ⊞ 6.6K
Comment /matt to run again

Comment thread pkg/workflow/runtime_overrides.go Outdated
VersionField: base.VersionField,
DefaultVersion: base.DefaultVersion,
Commands: base.Commands,
ExtraWithFields: base.ExtraWithFields,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/codebase-design] ManifestFiles is missing from the clone — this field exists on Runtime but is not copied, so any cloned runtime silently loses its manifest-file detection hints.

💡 Fix

Add the missing field to the struct literal in cloneRuntimeWithActionOverrides:

ManifestFiles:   base.ManifestFiles,

Without this, a runtime cloned for action overrides will behave differently from the original when manifest-file detection is evaluated (e.g. triggering the Go runtime from go.mod).

@copilot please address this.

Comment thread pkg/workflow/runtime_overrides.go Outdated
ActionVersion: base.ActionVersion,
VersionField: base.VersionField,
DefaultVersion: base.DefaultVersion,
Commands: base.Commands,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/codebase-design] Commands and ExtraWithFields are shallow-copied — both are reference types (slice and map). Mutations to the clone's slice or map would affect the original Runtime, undermining the mutation-safety goal of this helper.

💡 Safer deep copy

For the Commands slice:

Commands: slices.Clone(base.Commands),

For the ExtraWithFields map:

ExtraWithFields: maps.Clone(base.ExtraWithFields),

The current call sites only mutate ActionRepo and ActionVersion (scalars), so there is no active bug today — but the helper's contract implies full isolation. Callers that later mutate the map or slice would silently corrupt shared runtime state.

@copilot please address this.

if nodeReq.Version != "22" {
t.Fatalf("expected version 22, got %s", nodeReq.Version)
}
if nodeReq.Runtime == knownNode {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] The identity check nodeReq.Runtime == knownNode tests the pointer, which is good — but the test only covers the case where both action-repo and action-version are specified. The known-runtime path branches on actionRepo != "" || actionVersion != ""; a test for the single-field case (e.g., only action-repo, no action-version) would fully specify the behaviour of the OR condition.

💡 Suggested additional test
func TestApplyRuntimeOverrides_KnownRuntimeActionRepoOnly(t *testing.T) {
    // ... look up knownNode as before ...
    requirements := map[string]*RuntimeRequirement{}
    applyRuntimeOverrides(map[string]any{
        "node": map[string]any{
            "action-repo": "custom/setup-node",
            // no action-version
        },
    }, requirements)
    nodeReq := requirements["node"]
    if nodeReq.Runtime == knownNode {
        t.Fatal("expected clone even when only action-repo is overridden")
    }
    if nodeReq.Runtime.ActionVersion != knownNode.ActionVersion {
        t.Fatalf("expected ActionVersion to be inherited, got %s", nodeReq.Runtime.ActionVersion)
    }
}

@copilot please address this.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST_CHANGES — shallow-copy bugs undermine the clone's safety guarantee

The refactor's correctness hinges on cloneRuntimeWithActionOverrides producing a fully independent copy, but the new helper performs a shallow copy for two reference-type fields:

  • ExtraWithFields (map) — the map pointer is shared with the original knownRuntimes entry. Any future write to the clone's map will mutate the global definition. Elixir's entry has a non-empty ExtraWithFields, so this is immediately exploitable.
  • Commands (slice) — the slice header is copied but the backing array is shared. Direct index writes or in-capacity appends on the clone corrupt the original.

Both issues exist in the same function that was introduced specifically to centralize safe cloning — if anything, that makes them worse than the duplicate code they replaced.

Additionally, the new test covers only the known-runtime branch; the existing-requirement branch at line 95 goes untested.

Findings summary
Severity Issue
High ExtraWithFields shallow copy shares map with global knownRuntimes
Medium Commands shallow copy shares slice backing array
Medium Missing test for existing-requirement branch (line 95 call site)
(Pre-existing, flagged elsewhere) ManifestFiles field not copied at all

🔎 Code quality review by PR Code Quality Reviewer · 82.9 AIC · ⌖ 5.42 AIC · ⊞ 5.4K
Comment /review to run again

Comment thread pkg/workflow/runtime_overrides.go Outdated
VersionField: base.VersionField,
DefaultVersion: base.DefaultVersion,
Commands: base.Commands,
ExtraWithFields: base.ExtraWithFields,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shallow copy of ExtraWithFields defeats the purpose of cloning — any write to customRuntime.ExtraWithFields will mutate the shared global knownRuntimes entry.

💡 Suggested fix

The assignment ExtraWithFields: base.ExtraWithFields copies the map header (a pointer), not the map contents. Because knownRuntimes entries are package-level globals, a caller that later adds an entry to the cloned runtime's ExtraWithFields will silently corrupt the original global definition — exactly the side-effect the clone was introduced to prevent.

Elixir's global entry carries "otp-version": "27" in ExtraWithFields, so the risk is not theoretical.

Deep-copy the map:

var extraWithFields map[string]string
if len(base.ExtraWithFields) > 0 {
    extraWithFields = make(map[string]string, len(base.ExtraWithFields))
    for k, v := range base.ExtraWithFields {
        extraWithFields[k] = v
    }
}
customRuntime := &Runtime{
    // ... other fields ...
    ExtraWithFields: extraWithFields,
}

Comment thread pkg/workflow/runtime_overrides.go Outdated
ActionVersion: base.ActionVersion,
VersionField: base.VersionField,
DefaultVersion: base.DefaultVersion,
Commands: base.Commands,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shallow copy of Commands slice shares the backing array with the global runtime definition.

💡 Suggested fix

Commands: base.Commands copies the slice header (pointer, length, capacity) but both slices share the same underlying array. Any in-capacity append or direct index write (customRuntime.Commands[i] = "x") on the clone will silently corrupt the original knownRuntimes entry.

Use a defensive copy:

commands := append([]string(nil), base.Commands...)

then assign Commands: commands in the struct literal. The same pattern applies to ManifestFiles once it is added to the clone.


func TestDetectRuntimeRequirementsWithOverrides(t *testing.T) {
tests := []struct {
name string

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New test only covers one of the two call sites of cloneRuntimeWithActionOverrides — the existing-requirement branch (line 95 in runtime_overrides.go) has zero coverage in this diff.

💡 Suggested fix

The test exercises the path where runtimeID is not yet in requirements (known-runtime branch, runtime_overrides.go:106). The other call site at line 95, where action overrides are applied to an already-existing RuntimeRequirement, is untested. A shallow-copy bug or nil-Runtime bug in that branch would be invisible.

Add a test that pre-populates requirements with a node entry (including a non-nil Runtime and a non-empty ExtraWithFields), then calls applyRuntimeOverrides with an action-repo override, and asserts:

  • the returned Runtime pointer is different from the pre-populated one (clone happened)
  • the overridden fields are applied
  • the original Runtime is not mutated

@pelikhan

pelikhan commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

@copilot run pr-finisher skill

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address unresolved review comments, and rerun checks once the branch is up to date.
Open review feedback to address:

  • copilot-pull-request-reviewer:

Run: https://github.com/github/gh-aw/actions/runs/28645166299

Generated by 👨‍🍳 PR Sous Chef · 4.8 AIC · ⌖ 4.46 AIC · ⊞ 3.1K ·
Comment /souschef to run again

@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

🤖 PR Triage

Field Value
Category refactor
Risk 🟡 Medium
Score 55 / 100
Action fast_track
Batch pr-batch:runtime-refactor (with #43135)

Score Breakdown: Impact 28 + Urgency 14 + Quality 13

Rationale: Deduplicates runtime override cloning logic (67+/39−, 2 files). Has 6 comments indicating active review discussion. Clean scope targeting applyRuntimeOverrides. Paired with #43135.

Recommended Action: Review together with #43135 as a runtime-refactor batch. Address open review comments first.

Generated by 🔧 PR Triage Agent · 86.3 AIC · ⌖ 6.42 AIC · ⊞ 5.5K ·

Copilot AI and others added 2 commits July 3, 2026 07:32
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

@copilot run pr-finisher skill

Implemented a PR-finisher pass and pushed b3b5056 (plus 302f9be) with the review-driven fixes. Local make fmt, make lint, make test-unit, make test, and make recompile all pass. CI on this new head is stale until a maintainer re-triggers workflows.

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address unresolved review comments, and rerun checks once the branch is up to date.
Open review feedback to address:

  • copilot-pull-request-reviewer: ...

Addressed remaining in-scope review feedback in 82c5526 by adding coverage for the unresolved clone paths (known-runtime action-repo-only and existing-requirement action-repo-only) and asserting originals remain unchanged. Re-ran local checks: make fmt, make lint, make test-unit, make test, and make recompile all pass. CI on this new head is stale and needs a maintainer-triggered rerun.

Copilot AI requested a review from gh-aw-bot July 3, 2026 07:56
@pelikhan
pelikhan merged commit 3ea90c7 into main Jul 3, 2026
24 of 25 checks passed
@pelikhan
pelikhan deleted the copilot/duplicate-code-fix-runtime-cloning branch July 3, 2026 08:54
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.82.3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[duplicate-code] Duplicate Code: Runtime Override Cloning in applyRuntimeOverrides

4 participants