Skip to content

Auto-detect ARC/DinD and emit AWF --docker-host-path-prefix in generated workflows#31614

Merged
pelikhan merged 9 commits into
mainfrom
copilot/arc-dind-first-class-support
May 12, 2026
Merged

Auto-detect ARC/DinD and emit AWF --docker-host-path-prefix in generated workflows#31614
pelikhan merged 9 commits into
mainfrom
copilot/arc-dind-first-class-support

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 12, 2026

  • Review new PR comment and confirm required action
  • Merge origin/main into current branch
  • Recompile workflows
  • Run targeted validation
  • Reply on PR comment with result

Copilot AI and others added 3 commits May 12, 2026 02:12
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Add first-class ARC runner support for AWF-backed workflows Auto-detect ARC/DinD and emit AWF --docker-host-path-prefix in generated workflows May 12, 2026
Copilot AI requested a review from pelikhan May 12, 2026 02:16
@pelikhan pelikhan marked this pull request as ready for review May 12, 2026 02:18
Copilot AI review requested due to automatic review settings May 12, 2026 02:18
@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot merge main and recompile

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · ● 5.3M

}

// Build the expandable args string for args that need shell variable expansion.
// These MUST be appended as raw (unescaped) strings because single-quoting would
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.

[/zoom-out] The arcDindPrefixProbe injection is copy-pasted into all four fmt.Sprintf branches (lines ~193, ~212, ~229, ~245). These branches already differ only in which of pathSetup / preCreateLog / configFileSetup they include — this change makes each branch one line longer in two places, amplifying the existing duplication.

Consider extracting the command assembly into a small helper that accepts the optional preamble lines as a slice and joins them, so the ARC/DinD probe (and any future injections) only needs to be added once:

func assemblePipefailCommand(preambles []string, probe, awfCmd, expandableArgs, arcDindRef, awfArgs, wrapped, logFile string) string {
    body := strings.Join(append(preambles, probe), "\n")
    return fmt.Sprintf("set -o pipefail\n%s\n# shellcheck disable=SC1003\n%s %s %s %s \\\n  -- %s 2>&1 | tee -a %s", body, awfCmd, expandableArgs, arcDindRef, awfArgs, wrapped, logFile)
}

This would make future version-gated injections trivial and keep the logic in one place.

if awfSupportsDockerHostPathPrefix(firewallConfig) {
arcDindPrefixProbe = fmt.Sprintf(`%s=""
if [[ "${DOCKER_HOST:-}" =~ %s ]]; then
%s="%s"
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] When awfSupportsDockerHostPathPrefix returns false, arcDindPrefixProbe is set to "" and arcDindPrefixArgsRef is also "". Each format string has %s\n%s\n — two consecutive %s slots that will both expand to empty strings, producing a stray blank line in the generated script on older AWF versions.

A test that captures the full command output for the old-version path and asserts there are no consecutive blank lines (or that the probe variable name does not appear at all) would pin this behavior explicitly and catch any future regression.

}

initSnippet := `GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS=""`
conditionSnippet := `if [[ "${DOCKER_HOST:-}" =~ ^tcp://(localhost|127\.0\.0\.1)(:[0-9]+)?$ ]]; then`
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 conditionSnippet string duplicates the regex literal from the awfArcDindDockerHostRegex package-level constant in awf_helpers.go. If the regex ever changes (e.g., to add IPv6 support), this test will pass with the old string while the real probe uses the new one.

Reference the constant directly so the test always stays in sync:

conditionSnippet := fmt.Sprintf(`if [[ "${DOCKER_HOST:-}" =~ %s ]]; then`, awfArcDindDockerHostRegex)

Comment thread pkg/workflow/firewall_args_test.go Outdated
stepContent := requireCopilotExecutionStep(t, steps)

if strings.Contains(stepContent, "--docker-host-path-prefix /tmp/gh-aw") {
t.Error("Expected command to skip --docker-host-path-prefix for unsupported AWF versions")
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 "skips docker-host-path-prefix probe" test only asserts that --docker-host-path-prefix is absent from the generated command. It doesn't assert that the probe variable initialisation (GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="") is also absent.

On an old AWF version the probe block should be entirely omitted — not just the flag value. Adding:

if strings.Contains(stepContent, awfArcDindPrefixArgsVarName) {
    t.Error("Expected no probe variable for unsupported AWF versions")
}

would give the test full coverage of the negative path and guard against accidental partial injection.

Draft ADR generated by the Design Decision Gate covering the runtime
DOCKER_HOST probe and version-gated --docker-host-path-prefix emission
introduced by this PR.
@github-actions
Copy link
Copy Markdown
Contributor

Commit pushed: 79fba3c

🏗️ ADR gate enforced by Design Decision Gate 🏗️

@github-actions
Copy link
Copy Markdown
Contributor

🏗️ Design Decision Gate — ADR Required

This PR makes significant changes to core business logic (142 new lines across pkg/constants/ and pkg/workflow/) but does not have a linked Architecture Decision Record (ADR).

AI has analyzed the PR diff and generated a draft ADR to help you get started:

📄 Draft ADR: docs/adr/31614-auto-detect-arc-dind-docker-host-path-prefix.md

The draft covers:

  • The split-filesystem problem on ARC DinD that motivated the change
  • The runtime DOCKER_HOST probe and why it was preferred over compile-time or YAML opt-in detection
  • The version gate (AWFDockerHostPathPrefixMinVersion = v0.25.43) and its consequences
  • A normative (RFC 2119) specification of the probe shape, version gating, and test coverage requirements

What to do next

  1. Review the draft ADR committed to your branch — it was generated from the PR diff and may have gaps the AI couldn't infer (e.g. prior incidents, internal discussions, stakeholder decisions).
  2. Refine the narrative — confirm the alternatives section reflects options you actually considered; add/remove as needed.
  3. Tighten the normative spec — adjust any MUST/SHOULD that doesn't match the team's intent.
  4. Reference the ADR in this PR body by adding:

    ADR: ADR-31614: Auto-Detect ARC/DinD and Emit AWF --docker-host-path-prefix at Runtime

  5. Change the ADR's Status: from Draft to Proposed (or Accepted after team review).

Once an ADR is linked in the PR body, this gate will re-run and verify the implementation matches the decision.

Why ADRs Matter

"AI made me procrastinate on key design decisions. Because refactoring was cheap, I could always say 'I'll deal with this later.' Deferring decisions corroded my ability to think clearly."

The runtime DinD probe is exactly the kind of decision worth capturing: it's a load-bearing piece of generated shell that future contributors will need to understand before touching BuildAWFCommand. An ADR turns "why is this regex hardcoded?" into a 30-second read instead of a git blame archaeology session.

📋 Michael Nygard ADR Format Reference

An ADR must contain these four sections to be considered complete:

  • Context — What is the problem? What forces are at play?
  • Decision — What did you decide? Why?
  • Alternatives Considered — What else could have been done?
  • Consequences — What are the trade-offs (positive and negative)?

All ADRs in this repo live in docs/adr/ as Markdown files numbered by PR number (e.g., 31614-...md for PR #31614).

🔒 This PR cannot merge until an ADR is linked in the PR body.

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · ● 5.8M ·

@github-actions
Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 90/100

Excellent test quality

Metric Value
New/modified tests analyzed 3
✅ Design tests (behavioral contracts) 3 (100%)
⚠️ Implementation tests (low value) 0 (0%)
Tests with error/edge cases 3 (100%)
Duplicate test clusters 0
Test inflation detected No
🚨 Coding-guideline violations 0

Test Classification Details

View All Tests
Test File Classification Issues Detected
TestAWFSupportsDockerHostPathPrefix (5 table rows) pkg/workflow/awf_helpers_test.go ✅ Design None — covers nil, empty, "latest", exact minimum, and below-minimum versions
Inline ARC/DinD probe ordering check (in TestFirewallArgsInCopilotEngine) pkg/workflow/firewall_args_test.go:44-56 ✅ Design Minor: verifies exact snippet strings; refactoring variable names would break it without changing behavior
t.Run("skips docker-host-path-prefix probe when AWF version is too old") pkg/workflow/firewall_args_test.go:222-250 ✅ Design None — verifies version-gate behavioral contract

Analysis Notes

TestAWFSupportsDockerHostPathPrefix

Classification: Design test
Excellent table-driven test with 5 rows covering the full version-gate contract: nil firewall config, empty version string, "latest", the exact minimum version (v0.25.43), and the one-below-minimum boundary (v0.25.42). Assertion message is present. This would catch any regression in the awfSupportsDockerHostPathPrefix version comparison logic.

✅ Inline probe ordering check (in TestFirewallArgsInCopilotEngine)

Classification: Design test (with a minor note)
Verifies that the generated shell step initializes the variable, then evaluates the DOCKER_HOST regex condition, then assigns the flag — in the correct order. The observable contract here is the generated code, so checking snippet ordering is appropriate. The score deduction of 10 points reflects that exact snippet string matching is somewhat fragile to legitimate refactoring (e.g., variable renaming) without behavioral change.

t.Run("skips docker-host-path-prefix probe when AWF version is too old")

Classification: Design test
Verifies the negative case of the version gate: when v0.25.42 is specified, the flag must not appear in the generated command. This is a clear behavioral contract test.


Build Tags & Guidelines

  • ✅ Both files have //go:build !integration on line 1
  • ✅ No mock libraries (gomock, testify/mock, .EXPECT(), .On()) detected
  • ✅ Assertion messages present in all assert.* calls
  • ✅ No test inflation (production added ~70 lines; tests added ~76 lines across both files; within 2:1 ratio)

Language Support

Tests analyzed:

  • 🐹 Go (*_test.go): 3 test additions — unit (//go:build !integration)

Verdict

Check passed. 0% of new tests are implementation tests (threshold: 30%). The tests cover version-gate boundary conditions and generated-output behavioral contracts with solid table-driven structure.


📖 Understanding Test Classifications

Design Tests (High Value) verify what the system does:

  • Assert on observable outputs, return values, or state changes
  • Cover error paths and boundary conditions
  • Would catch a behavioral regression if deleted
  • Remain valid even after internal refactoring

Implementation Tests (Low Value) verify how the system does it:

  • Assert on internal function calls (mocking internals)
  • Only test the happy path with typical inputs
  • Break during legitimate refactoring even when behavior is correct
  • Give false assurance: they pass even when the system is wrong

Goal: Shift toward tests that describe the system's behavioral contract — the promises it makes to its users and collaborators.

References: §25709268968

🧪 Test quality analysis by Test Quality Sentinel · ● 8.8M ·

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds automatic ARC/DinD topology detection to generated AWF-backed workflow commands so users no longer need to manually author --docker-host-path-prefix workarounds, while safely gating emission based on the pinned AWF version.

Changes:

  • Emit a runtime Bash probe (based on DOCKER_HOST localhost TCP patterns) and conditionally append --docker-host-path-prefix /tmp/gh-aw to the AWF invocation.
  • Add a minimum-version constant (AWFDockerHostPathPrefixMinVersion = v0.25.43) plus a helper gate (awfSupportsDockerHostPathPrefix).
  • Extend unit tests to validate probe presence/order by default and omission for older pinned AWF versions.
Show a summary per file
File Description
pkg/workflow/firewall_args_test.go Adds assertions around the new ARC/DinD probe and version-gated skipping behavior.
pkg/workflow/awf_helpers.go Implements runtime ARC/DinD detection and conditionally injects --docker-host-path-prefix into AWF command generation.
pkg/workflow/awf_helpers_test.go Adds unit coverage for the new version gate helper.
pkg/constants/version_constants.go Introduces the minimum supported AWF version constant for --docker-host-path-prefix.

Copilot's findings

Tip

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

  • Files reviewed: 5/5 changed files
  • Comments generated: 1

Comment on lines +115 to +117
awfArcDindHostPathPrefixFlag)
arcDindPrefixArgsRef = fmt.Sprintf("${%s}", awfArcDindPrefixArgsVarName)
}
Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

✅ Test Quality Sentinel: 90/100. Test quality is excellent — 0% of new tests are implementation tests (threshold: 30%). All 3 new test additions cover behavioral contracts with good edge-case coverage including version-gate boundary conditions.

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot review all comments

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 12, 2026

@copilot merge main and recompile

Done. I synced with origin/main (already up to date on merge) and recompiled/pushed the lock workflows in commit 92ef155.

@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot merge main and recompile

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 12, 2026

@copilot review all comments

Reviewed all comments and addressed the outstanding test coverage feedback in ba3ecc9.

Copilot AI and others added 2 commits May 12, 2026 02:45
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 12, 2026

@copilot merge main and recompile

Done. I merged origin/main and recompiled; updated lock workflows are pushed in 8378b3d.

@pelikhan pelikhan merged commit 373a469 into main May 12, 2026
@pelikhan pelikhan deleted the copilot/arc-dind-first-class-support branch May 12, 2026 03:24
github-actions Bot added a commit that referenced this pull request May 12, 2026
Document the runtime probe added in #31614 that detects ARC with
Docker-in-Docker sidecar topology via DOCKER_HOST and appends
--docker-host-path-prefix /tmp/gh-aw to AWF invocations.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ARC-DinD] GAW should provide first-class ARC runner support for AWF-backed workflows

3 participants