Skip to content

Fix malformed version: crash for gh --repo in DIFC proxy steps#35293

Merged
pelikhan merged 4 commits into
mainfrom
copilot/fix-gh-cli-malformed-version
May 27, 2026
Merged

Fix malformed version: crash for gh --repo in DIFC proxy steps#35293
pelikhan merged 4 commits into
mainfrom
copilot/fix-gh-cli-malformed-version

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 27, 2026

When the DIFC proxy is active, every custom step received GH_HOST=localhost:18443 as step-level env. The gh CLI treats any non-github.com/non-*.ghe.com host as GHES and performs a /api/v3/meta version check before --repo calls. The proxy forwards this to github.com, which omits installed_version, so gh aborts with malformed version: .

Changes

  • proxyEnvVars() — change GH_HOST from localhost:18443 to ${{ env.GH_HOST || 'github.com' }}, picking up the identity host written by the preceding configure_gh_for_ghe.sh step:

    • github.com / GHEC (*.ghe.com): resolves to github.com or tenant.ghe.comgh skips the GHES version check; API traffic still routes through the proxy via GITHUB_API_URL
    • GHES: resolves to the real GHES hostname → gh performs the version check via GITHUB_API_URL (proxy → real GHES /meta) which returns installed_version and passes
  • CommentsproxyEnvVars() and injectProxyEnvIntoCustomSteps() now document why GH_HOST must differ between GHES and non-GHES environments

  • Tests — updated to assert the new expression; changeset updated to accurately describe the fix

# Before (broken): gh treats localhost:18443 as GHES, version check fails
GH_HOST: localhost:18443

# After: uses the correct identity host for each deployment type
GH_HOST: ${{ env.GH_HOST || 'github.com' }}

Copilot AI and others added 2 commits May 27, 2026 20:23
…Vars()

The DIFC proxy was injecting GH_HOST=localhost:18443 as step-level env on
custom steps. The gh CLI treats any non-github.com/non-*.ghe.com host as
GHES and performs a /meta version check before --repo calls. The proxy
forwards the check to github.com, which omits installed_version, causing
gh to fail with "malformed version: ".

Fix: use ${{ env.GH_HOST || 'github.com' }} instead of localhost:18443.
This picks up the identity host set by configure_gh_for_ghe.sh:
- github.com/GHEC: gh skips the GHES version check entirely
- GHES: gh does the version check via GITHUB_API_URL (proxy -> real GHES)

All API traffic continues to flow through the proxy via GITHUB_API_URL.

Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix 'malformed version' error for gh commands with --repo Fix malformed version: crash for gh --repo in DIFC proxy steps May 27, 2026
Copilot finished work on behalf of lpcox May 27, 2026 20:25
Copilot AI requested a review from lpcox May 27, 2026 20:25
@lpcox lpcox marked this pull request as ready for review May 27, 2026 20:31
Copilot AI review requested due to automatic review settings May 27, 2026 20:31
@lpcox lpcox added the smoke label May 27, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 27, 2026

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

No ADR enforcement needed for PR #35293: PR does not have the 'implementation' label and has only 54 new lines (≤100 threshold) in business logic directories.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 27, 2026

🧪 Test Quality Sentinel completed test quality analysis.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 27, 2026

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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 27, 2026

PR Code Quality Reviewer completed the code quality review.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 27, 2026

🚀 Smoke Pi MISSION COMPLETE! Pi delivered. 🥧

@github-actions
Copy link
Copy Markdown
Contributor

📰 BREAKING: Smoke Copilot is now investigating this pull request. Sources say the story is developing...

@github-actions github-actions Bot removed the smoke label May 27, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 27, 2026

✨ The prophecy is fulfilled... Smoke Codex has completed its mystical journey. The stars align. 🌟

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 27, 2026

🚀 Smoke Antigravity MISSION COMPLETE! Antigravity has spoken. ✨

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 27, 2026

🚀 Smoke Gemini MISSION COMPLETE! Gemini has spoken. ✨

Testing safeoutputs CLI

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 27, 2026

💫 TO BE CONTINUED... Smoke Claude failed! Our hero faces unexpected challenges...

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

Fixes a malformed version: crash in gh --repo calls within DIFC proxy-protected custom steps by switching the injected GH_HOST from the proxy address (localhost:18443) to the identity host expression ${{ env.GH_HOST || 'github.com' }}, which is supplied by the preceding configure_gh_for_ghe.sh step.

Changes:

  • Replace hardcoded GH_HOST: localhost:18443 in proxyEnvVars() with ${{ env.GH_HOST || 'github.com' }} so gh doesn't misclassify the proxy as GHES.
  • Expand function-level and call-site comments documenting the rationale across github.com / GHEC / GHES deployments.
  • Update tests and the changeset to reflect the new value and root-cause analysis.
Show a summary per file
File Description
pkg/workflow/compiler_difc_proxy.go Change injected GH_HOST value and document deployment-type rationale.
pkg/workflow/compiler_difc_proxy_test.go Update assertions for new GH_HOST expression.
.changeset/patch-fix-difc-proxy-gh-host-mismatch.md Rewrite changeset to describe the actual fix and root cause.

Copilot's findings

Tip

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

  • Files reviewed: 3/3 changed files
  • Comments generated: 0

@github-actions
Copy link
Copy Markdown
Contributor

Agent Container Tool Check

Tool Status Version
bash 5.2.21
sh available
git 2.54.0
jq 1.7
yq v4.53.2
curl 8.5.0
gh 2.92.0
node v22.22.3
python3 3.14.5
go 1.24.13
java openjdk 21.0.11
dotnet 10.0.300

Result: 12/12 tools available ✅

Overall Status: PASS

🔧 Tool validation by Agent Container Smoke Test · sonnet46 504.1K ·

@github-actions github-actions Bot mentioned this pull request May 27, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Smoke test results: GitHub-MCP:✅, Web-Fetch:✅, File-Write:✅, Bash:✅, Build:❌. Overall: FAIL

Warning

Firewall blocked 1 domain

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

  • localhost

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

network:
  allowed:
    - defaults
    - "localhost"

See Network Configuration for more information.

Smoke Gemini — Powered by Gemini ·

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 · sonnet46 1.2M


require.NotEmpty(t, vars, "proxyEnvVars should return a non-empty map")
assert.Equal(t, "localhost:18443", vars["GH_HOST"], "GH_HOST should be the proxy address")
// GH_HOST should use the identity host expression, not the proxy address.
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 unit test for proxyEnvVars verifies the expression string is correct, but there's no test case explicitly covering the GHES deployment path (where env.GH_HOST holds a real enterprise hostname like ghes.example.com). Since the expression is evaluated at GitHub Actions runtime rather than compile time, a companion test with a table-driven case or a descriptive comment would make the intent of each deployment scenario explicit as a living spec.

💡 Example: add a table-driven scenario to TestInjectProxyEnvIntoCustomSteps
// Add to TestInjectProxyEnvIntoCustomSteps test table to document the GHES scenario
{
    name: "GHES: expression selects real GHES hostname at runtime",
    customSteps: "steps:\n- name: gh call\n  run: gh issue list --repo owner/repo\n",
    expectedContains: []string{
        // The injected expression picks up the hostname set by configure_gh_for_ghe.sh;
        // on GHES this resolves to the real GHES host, not the proxy address.
        "GH_HOST: ${{ env.GH_HOST || 'github.com' }}",
        "GITHUB_API_URL: (localhost/redacted),
    },
    desc: "GHES path: identity host expression injected; API traffic still routes via proxy",
},

The test already exists as a string assertion, so this is low-effort to add and documents intent clearly.

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.

Smoke test reply: noted, and the existing assertion line is a good anchor for the GH_HOST identity-host behavior.

Warning

Firewall blocked 6 domains

The following domains were blocked by the firewall during workflow execution:

  • accounts.google.com
  • android.clients.google.com
  • clients2.google.com
  • contentautofill.googleapis.com
  • safebrowsingohttpgateway.googleapis.com
  • www.google.com

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

network:
  allowed:
    - defaults
    - "accounts.google.com"
    - "android.clients.google.com"
    - "clients2.google.com"
    - "contentautofill.googleapis.com"
    - "safebrowsingohttpgateway.googleapis.com"
    - "www.google.com"

See Network Configuration for more information.

📰 BREAKING: Report filed by Smoke Copilot · gpt55 3.3M

@github-actions
Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 97/100 — Excellent

Analyzed 3 modified test functions (no new Test* functions added): all are behavioral design tests verifying the corrected GH_HOST value; no guideline violations detected.

📊 Metrics & Test Classification (3 tests analyzed)
Metric Value
New/modified tests analyzed 3 (modified only; no new Test* functions added)
✅ Design tests (behavioral contracts) 3 (100%)
⚠️ Implementation tests (low value) 0 (0%)
Tests with error/edge cases 2 (67%) — table-driven tests include multi-scenario coverage
Duplicate test clusters 0
Test inflation detected No (11 test lines / 43 production lines = 0.26:1 ratio)
🚨 Coding-guideline violations 0

Test Classification Details

Test File Classification Notes
TestProxyEnvVars pkg/workflow/compiler_difc_proxy_test.go:659 ✅ Design Directly asserts proxyEnvVars() map output; all assertions have descriptive messages
TestInjectProxyEnvIntoCustomSteps pkg/workflow/compiler_difc_proxy_test.go:687 ✅ Design Table-driven (6+ rows); covers steps with/without env, uses: steps, multiline runs, artifact uploads
Integration assertion (~line 456) pkg/workflow/compiler_difc_proxy_test.go:456 ✅ Design Asserts compiled workflow YAML contains the corrected GH_HOST expression

Language Support

Tests analyzed:

  • 🐹 Go (*_test.go): 3 tests — unit (//go:build !integration)
  • 🟨 JavaScript (*.test.cjs, *.test.js): 0 tests

Verdict

Check passed. 0% of modified tests are implementation tests (threshold: 30%). All changes are direct behavioral-contract assertions on observable outputs (proxyEnvVars() return values and compiled workflow YAML content), with proper assertion messages and no mock usage.

📖 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.

🧪 Test quality analysis by Test Quality Sentinel · sonnet46 1.3M ·

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: 97/100. Test quality is excellent — 0% of modified tests are implementation tests (threshold: 30%). All 3 modified test assertions are behavioral contract verifications with proper assertion messages and no mock usage.

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.

LGTM — focused, correct fix

The GH_HOST=localhost:18443 root cause is clearly understood and well-documented. The expression ${{ env.GH_HOST || 'github.com' }} correctly resolves to the right identity host for all three deployment types (github.com, GHEC, GHES) without breaking proxy routing through GITHUB_API_URL.

Analysis details

What I checked:

  1. Self-referential env — step-level env: expressions are evaluated before the step executes, so env.GH_HOST reads the job-level value (written by configure_gh_for_ghe.sh via GITHUB_ENV) without any circular reference.

  2. YAML single-quote serialization — the value contains single quotes. Regardless of whether the YAML serializer emits them as a plain scalar or single-quoted scalar (doubling the internal quotes), the post-YAML-parse value is identical and GitHub Actions evaluates the expression correctly.

  3. Ordering dependency — the fix implicitly requires configure_gh_for_ghe.sh to have run before any custom step receives the injected env. Based on the compiler flow described in the file header (proxy starts after "Configure gh CLI"), this ordering is architecturally guaranteed — not a new risk introduced by this PR.

  4. GHES proxy forwarding — the claim that the proxy forwards /api/v3/meta to the real GHES upstream (returning installed_version) is an assumption about proxy behavior not verifiable from this diff, but it is the same assumption the existing GHES proxy support relies on and is clearly documented.

  5. Test coverage — tests verify the correct expression string is emitted in compiled output. Runtime expression resolution is GitHub Actions behavior and not testable at the Go unit test level. Coverage is appropriate.

Warning

Firewall blocked 1 domain

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

  • proxy.golang.org

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

network:
  allowed:
    - defaults
    - "proxy.golang.org"

See Network Configuration for more information.

🔎 Code quality review by PR Code Quality Reviewer · sonnet46 2M

@github-actions
Copy link
Copy Markdown
Contributor

Smoke test run 26537099294

Merged PRs: #35275 "Widen review_path_unresolved_422 safe-output fallback to match 'Path could not be resolved'"; #35274 "refactor(cli): consolidate local tokenClassWeights into types.TokenClassWeights"

Result: FAIL

  • GitHub PR samples: ✅
  • Serena: ✅
  • Playwright: ✅
  • Web fetch: ❌
  • Build: ✅

Warning

Firewall blocked 6 domains

The following domains were blocked by the firewall during workflow execution:

  • accounts.google.com
  • android.clients.google.com
  • clients2.google.com
  • contentautofill.googleapis.com
  • safebrowsingohttpgateway.googleapis.com
  • www.google.com

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

network:
  allowed:
    - defaults
    - "accounts.google.com"
    - "android.clients.google.com"
    - "clients2.google.com"
    - "contentautofill.googleapis.com"
    - "safebrowsingohttpgateway.googleapis.com"
    - "www.google.com"

See Network Configuration for more information.

🔮 The oracle has spoken through Smoke Codex · gpt54 11.2M ·

@github-actions
Copy link
Copy Markdown
Contributor

Comment Memory

Code wakes at sunrise
Silent checks hum through the wires
Smoke drifts, green and light

Note

This comment is managed by comment memory.

It stores persistent context for this thread in the code block at the top of this comment.
Edit only the text inside the backtick fences; workflow metadata and the footer are regenerated automatically.

Learn more about comment memory

Warning

Firewall blocked 6 domains

The following domains were blocked by the firewall during workflow execution:

  • accounts.google.com
  • android.clients.google.com
  • clients2.google.com
  • contentautofill.googleapis.com
  • safebrowsingohttpgateway.googleapis.com
  • www.google.com

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

network:
  allowed:
    - defaults
    - "accounts.google.com"
    - "android.clients.google.com"
    - "clients2.google.com"
    - "contentautofill.googleapis.com"
    - "safebrowsingohttpgateway.googleapis.com"
    - "www.google.com"

See Network Configuration for more information.

🔮 The oracle has spoken through Smoke Codex · gpt54 11.2M ·

@github-actions
Copy link
Copy Markdown
Contributor

PRs: Refactor docs landing-page guardrails section into visual security overview; Add cost management guidance to the docs home page; Fix malformed version: crash for gh --repo in DIFC proxy steps
Tests: ✅1 ❌2 ✅3 ✅4 ❌5 ✅6 ✅7 ✅8 ✅9 ✅10 ✅11 ✅12 ✅13 ❌14 ✅15 ✅16
Overall: FAIL
Author: app/copilot-swe-agent; Assignees: lpcox, Copilot

Warning

Firewall blocked 6 domains

The following domains were blocked by the firewall during workflow execution:

  • accounts.google.com
  • android.clients.google.com
  • clients2.google.com
  • contentautofill.googleapis.com
  • safebrowsingohttpgateway.googleapis.com
  • www.google.com

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

network:
  allowed:
    - defaults
    - "accounts.google.com"
    - "android.clients.google.com"
    - "clients2.google.com"
    - "contentautofill.googleapis.com"
    - "safebrowsingohttpgateway.googleapis.com"
    - "www.google.com"

See Network Configuration for more information.

📰 BREAKING: Report filed by Smoke Copilot · gpt55 3.3M ·

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.

Smoke review complete: checked the DIFC proxy GH_HOST changes and regression assertions.

Warning

Firewall blocked 6 domains

The following domains were blocked by the firewall during workflow execution:

  • accounts.google.com
  • android.clients.google.com
  • clients2.google.com
  • contentautofill.googleapis.com
  • safebrowsingohttpgateway.googleapis.com
  • www.google.com

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

network:
  allowed:
    - defaults
    - "accounts.google.com"
    - "android.clients.google.com"
    - "clients2.google.com"
    - "contentautofill.googleapis.com"
    - "safebrowsingohttpgateway.googleapis.com"
    - "www.google.com"

See Network Configuration for more information.

📰 BREAKING: Report filed by Smoke Copilot · gpt55 3.3M

"GH_HOST": "localhost:18443",
// Identity host from configure_gh_for_ghe.sh, not the proxy address.
// See function-level comment for full rationale.
"GH_HOST": "${{ env.GH_HOST || 'github.com' }}",
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.

Smoke review: this is the core behavior change, keeping GH_HOST as the identity host while proxying API URLs.

require.NotEmpty(t, vars, "proxyEnvVars should return a non-empty map")
assert.Equal(t, "localhost:18443", vars["GH_HOST"], "GH_HOST should be the proxy address")
// GH_HOST should use the identity host expression, not the proxy address.
assert.Equal(t, "${{ env.GH_HOST || 'github.com' }}", vars["GH_HOST"], "GH_HOST should use the identity host from configure_gh_for_ghe.sh, not the proxy address")
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.

Smoke review: this assertion directly captures the regression guard for the gh --repo crash scenario.

@github-actions
Copy link
Copy Markdown
Contributor

📰 VERDICT: Smoke Copilot has concluded. All systems operational. This is a developing story. 🎤

@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot investigate why the playwright cli skills is failing to install

https://github.com/github/gh-aw/actions/runs/26537099387/job/78168949897

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
@pelikhan pelikhan merged commit 9a95605 into main May 27, 2026
@pelikhan pelikhan deleted the copilot/fix-gh-cli-malformed-version branch May 27, 2026 21:19
Copilot stopped work on behalf of pelikhan due to an error May 27, 2026 21:19
Copilot AI requested a review from pelikhan May 27, 2026 21:19
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.

'malformed version' for all gh commands in user steps using explicit --repo

4 participants