Skip to content

refactor(cli-proxy): decompose handleExec into buildExecEnv and runGhCommand#5126

Merged
lpcox merged 3 commits into
mainfrom
copilot/refactor-handleexec-function
Jun 16, 2026
Merged

refactor(cli-proxy): decompose handleExec into buildExecEnv and runGhCommand#5126
lpcox merged 3 commits into
mainfrom
copilot/refactor-handleexec-function

Conversation

Copilot AI commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

handleExec in containers/cli-proxy/server.js was a 107-line monolith mixing env construction, subprocess execution, and HTTP response — making the security-critical env-filtering logic untestable in isolation.

Changes

  • buildExecEnv(extraEnv) — extracts the env-merge step; enforces PROTECTED_ENV_KEYS filtering without requiring an HTTP context
  • runGhCommand(args, childEnv, stdin) — extracts the execFile Promise wrapper; handles stdin, timeout/signal errors, and output capture
  • handleExec — reduced from 107 → ~35 lines; now a pure orchestrator delegating to the two sub-functions
  • Both new functions exported and covered by unit tests
// Before: all inlined in handleExec
// After:
const childEnv = buildExecEnv(extraEnv);           // security boundary, now unit-testable
const { stdout, stderr, exitCode } = await runGhCommand(args, childEnv, stdin);

New tests (16 added, 52 total passing)

  • buildExecEnv: verifies all 6 PROTECTED_ENV_KEYS are blocked, safe vars pass through, non-string values and null/undefined extraEnv are handled gracefully
  • runGhCommand: success path, non-zero exit on invalid subcommand, behavior when binary is missing

Copilot AI changed the title [WIP] Refactor handleExec by decomposing into sub-functions refactor(cli-proxy): decompose handleExec into buildExecEnv and runGhCommand Jun 16, 2026
Copilot finished work on behalf of lpcox June 16, 2026 18:44
Copilot AI requested a review from lpcox June 16, 2026 18:44
@lpcox lpcox marked this pull request as ready for review June 16, 2026 19:55
Copilot AI review requested due to automatic review settings June 16, 2026 19:55
@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

✅ Coverage Check Passed

Overall Coverage

Metric Base PR Delta
Lines 97.27% 97.31% 📈 +0.04%
Statements 97.15% 97.19% 📈 +0.04%
Functions 98.81% 98.81% ➡️ +0.00%
Branches 91.95% 91.98% 📈 +0.03%
📁 Per-file Coverage Changes (1 files)
File Lines (Before → After) Statements (Before → After)
src/workdir-setup.ts 92.6% → 94.4% (+1.85%) 92.6% → 94.4% (+1.85%)

Coverage comparison generated by scripts/ci/compare-coverage.ts

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

This PR refactors the cli-proxy’s /exec handler (containers/cli-proxy/server.js) by extracting subprocess environment construction and gh execution into separate exported helpers, aiming to make the security-sensitive env filtering logic unit-testable and reduce handleExec complexity.

Changes:

  • Extracts buildExecEnv(extraEnv) to centralize env merging while filtering PROTECTED_ENV_KEYS.
  • Extracts runGhCommand(args, childEnv, stdin) to wrap execFile('gh', ...) execution and output capture.
  • Adds Jest coverage for both new helpers and updates exports; includes incidental package-lock.json changes.
Show a summary per file
File Description
containers/cli-proxy/server.js Decomposes handleExec into buildExecEnv + runGhCommand and exports both helpers.
containers/cli-proxy/server.test.js Adds unit tests for buildExecEnv and runGhCommand; updates imports accordingly.
containers/cli-proxy/package-lock.json Removes libc constraints from several optional native binding entries (platform selection behavior may change).

Copilot's findings

Tip

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

Files not reviewed (1)
  • containers/cli-proxy/package-lock.json: Generated file
Comments suppressed due to low confidence (1)

containers/cli-proxy/server.js:217

  • buildExecEnv builds childEnv as a normal object (Object.assign({}, process.env)). If extraEnv includes a JSON key like "proto", the assignment childEnv[key] = value can throw (or mutate the prototype) because __proto__ is a magic accessor on Object.prototype. Since extraEnv comes from untrusted JSON, this is a security/robustness bug and can be used to force 500s on /exec.

Use a null-prototype env object and explicitly skip dangerous keys (e.g. proto/constructor/prototype) before assignment.

  // Inherit server environment (includes GH_HOST, NODE_EXTRA_CA_CERTS, GH_REPO, etc.)
  const childEnv = Object.assign({}, process.env);
  if (extraEnv && typeof extraEnv === 'object') {
    // Only allow safe string env overrides; never allow overriding keys in PROTECTED_ENV_KEYS.
    for (const [key, value] of Object.entries(extraEnv)) {
  • Files reviewed: 2/3 changed files
  • Comments generated: 4

Comment thread containers/cli-proxy/server.test.js Outdated
Comment on lines +241 to +245
it('should silently skip non-string keys', () => {
// Object.entries coerces, but we guard typeof key === 'string'
const env = buildExecEnv({ MY_VAR: 'ok' });
expect(env.MY_VAR).toBe('ok');
});
Comment on lines +322 to +323
const childEnv = buildExecEnv(extraEnv);
const { stdout, stderr, exitCode } = await runGhCommand(args, childEnv, stdin);
Comment thread containers/cli-proxy/server.test.js Outdated
process.env.PATH = '';
try {
const result = await runGhCommand(['--version'], process.env, null);
// When the binary is not found, exitCode is the ENOENT error code (truthy, non-zero)
Comment on lines 1268 to 1276
"node_modules/@unrs/resolver-binding-linux-arm64-gnu": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz",
"integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==",
"cpu": [
"arm64"
],
"dev": true,
"libc": [
"glibc"
],
"license": "MIT",
@lpcox

lpcox commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

@copilot address review feedback

@github-actions

Copy link
Copy Markdown
Contributor

⏳ Copilot review left inline comments.

@copilot To proceed:

  1. Ask @copilot to address the review feedback (reply to this comment or the review thread)
  2. Once the fix is pushed, add the ready-for-aw label to trigger agentic CI smoke tests

Copilot AI commented Jun 16, 2026

Copy link
Copy Markdown
Contributor Author

@copilot address review feedback

Addressed in commit aae9d72.

  • Normalized runGhCommand exit codes to always return numbers (including spawn/system errors like ENOENT).
  • Replaced the ineffective env-key test with a regression test for dangerous prototype keys from JSON payloads.
  • Updated the ENOENT test expectation/comment to match numeric exitCode behavior.
  • Restored containers/cli-proxy/package-lock.json libc constraints to remove the incidental lockfile drift.

Validation run:

  • cd /home/runner/work/gh-aw-firewall/gh-aw-firewall/containers/cli-proxy && npm test
  • cd /home/runner/work/gh-aw-firewall/gh-aw-firewall && npm run lint && npm run build && npm test
  • CodeQL check: 0 alerts

@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

🔌 Smoke Services — All services reachable! ✅

@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Smoke Copilot BYOK completed. Copilot BYOK mode operational. 🔓

@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

📡 Smoke OTel Tracing completed. All tracing scenarios validated. ✅

@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

🔑 Smoke Copilot PAT PAT auth validated. All systems operational. ✅

@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Smoke Copilot BYOK AOAI (api-key) completed. Copilot AOAI BYOK (api-key) mode operational. 🔓

@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Build Test Suite completed successfully!

@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Smoke Copilot BYOK AOAI (Entra) completed. Copilot AOAI BYOK (Entra) mode operational. 🔓

@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Contribution Check failed. Please review the logs for details.

@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Smoke Claude failed

No user request was provided in this turn — only system reminders listing available skills, project context (CLAUDE.md), and safety policies were present. No GitHub action, code change, or analysis was requested, so no action was taken.

@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

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

@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Chroot tests passed! Smoke Chroot - All security and functionality tests succeeded.

@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Security Guard failed. Please review the logs for details.

@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

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

@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Smoke Gemini completed. All facets verified. 💎

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Smoke Test: Copilot BYOK (Direct)

All tests passed

  • ✅ GitHub MCP: Retrieved 2 recent PRs
  • ✅ GitHub.com connectivity: HTTP 200
  • ✅ File write/read: Working
  • ✅ BYOK inference: Running via api-proxy → api.githubcopilot.com

Status: PASS | Running in direct BYOK mode (COPILOT_PROVIDER_API_KEY)

🔑 BYOK report filed by Smoke Copilot BYOK

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Smoke Test Results — PASS

Test Result
GitHub MCP connectivity
GitHub.com HTTP connectivity
File write/read

PR: refactor(cli-proxy): decompose handleExec into buildExecEnv and runGhCommand
Author: @Copilot | Assignees: @lpcox @Copilot

Overall: PASS

📰 BREAKING: Report filed by Smoke Copilot

@github-actions

Copy link
Copy Markdown
Contributor

🔬 Smoke Test Results — PAT Auth

Test Status
GitHub MCP connectivity
GitHub.com HTTP ✅ 200
File write/read

Overall: PASS

Auth mode: PAT (COPILOT_GITHUB_TOKEN)
PR: refactor(cli-proxy): decompose handleExec into buildExecEnv and runGhCommand
Author: @Copilot · Assignees: @lpcox @Copilot

🔑 PAT report filed by Smoke Copilot PAT

@github-actions

Copy link
Copy Markdown
Contributor

🔍 Smoke Test: API Proxy OpenTelemetry Tracing

Scenario Result Detail
✅ Module Loading Pass otel.js loads; exports: startRequestSpan, setTokenAttributes, setBudgetAttributes, endSpan, endSpanError, shutdown, isEnabled + private helpers
✅ Test Suite Pass 59 tests passed, 0 failed across otel.test.js + otel-fanout.test.js
✅ Env Var Forwarding Pass api-proxy-service-config.ts forwards OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_HEADERS, GITHUB_AW_OTEL_TRACE_ID, GITHUB_AW_OTEL_PARENT_SPAN_ID, OTEL_SERVICE_NAME
✅ Token Tracker Integration Pass onUsage callback present in token-tracker-http.js (lines 283/324/326); serves as OTEL hook for setTokenAttributes
✅ Graceful Degradation Pass No OTLP endpoint → spans written to FileSpanExporter (/var/log/api-proxy/otel.jsonl); no errors

All 5 scenarios pass. OTEL tracing integration is fully functional on this PR's branch.

📡 OTel tracing validated by Smoke OTel Tracing

@github-actions

Copy link
Copy Markdown
Contributor

@lpcox @Copilot

GitHub MCP Testing: ✅
GitHub.com Connectivity: ✅
File Write/Read Test: ✅
BYOK Inference Test: ✅

Running in direct BYOK mode (AWF_AUTH_TYPE=github-oidc + AWF_AUTH_AZURE_* + COPILOT_PROVIDER_BASE_URL) via api-proxy → Azure OpenAI (Foundry, o4-mini-aw) authenticated via Microsoft Entra

Overall: PASS

🪪 BYOK (AOAI Entra) report filed by Smoke Copilot BYOK AOAI (Entra)

@github-actions

Copy link
Copy Markdown
Contributor

Merged PRs reviewed: docs: sync schemas and specs with source changes; [Test Coverage] Improve test coverage for network-options, environment-builder, log-parser, workspace-mounts
GitHub query: ❌
GitHub page title: ✅
File write/read: ✅
Discussion lookup/comment: ✅
Build: ❌ (node missing during npm ci && npm run build)
Overall: FAIL

🔮 The oracle has spoken through Smoke Codex

@github-actions

Copy link
Copy Markdown
Contributor

Chroot Smoke Test Results

Runtime Host Version Chroot Version Match?
Python Python 3.12.13 Python 3.12.3
Node.js v24.16.0 v22.22.3
Go go1.22.12 go1.22.12

Overall: ❌ Not all tests passed — Python and Node.js versions differ between host and chroot environments.

Tested by Smoke Chroot

@github-actions

Copy link
Copy Markdown
Contributor

@lpcox @Copilot

  • refactor(cli-proxy): decompose handleExec into buildExecEnv and runGhCommand ✅
  • GitHub MCP connectivity: ✅
  • GitHub.com connectivity: ✅
  • File I/O in sandbox: ✅
  • Running in direct BYOK mode (COPILOT_PROVIDER_API_KEY + COPILOT_PROVIDER_BASE_URL) via api-proxy → Azure OpenAI (Foundry, o4-mini-aw) ✅

Overall: PASS

🔑 BYOK (AOAI api-key) report filed by Smoke Copilot BYOK AOAI (api-key)

@github-actions

Copy link
Copy Markdown
Contributor

🏗️ Build Test Suite Results

Ecosystem Project Build/Install Tests Status
Bun elysia 1/1 passed ✅ PASS
Bun hono 1/1 passed ✅ PASS
C++ fmt N/A ✅ PASS
C++ json N/A ✅ PASS
Deno oak N/A 1/1 passed ✅ PASS
Deno std N/A 1/1 passed ✅ PASS
.NET hello-world N/A ✅ PASS
.NET json-parse N/A ✅ PASS
Go color 1/1 passed ✅ PASS
Go env 1/1 passed ✅ PASS
Go uuid 1/1 passed ✅ PASS
Java gson 1/1 passed ✅ PASS
Java caffeine 1/1 passed ✅ PASS
Node.js clsx passed ✅ PASS
Node.js execa passed ✅ PASS
Node.js p-limit passed ✅ PASS
Rust fd 1/1 passed ✅ PASS
Rust zoxide 1/1 passed ✅ PASS

Overall: 8/8 ecosystems passed — ✅ PASS

Generated by Build Test Suite for issue #5126 ·

@github-actions

Copy link
Copy Markdown
Contributor

Smoke Test: GitHub Actions Services Connectivity

Check Result
Redis PING ❌ (timeout)
PostgreSQL pg_isready ❌ (no response)
PostgreSQL SELECT 1 ❌ (timeout)

Overall: FAILhost.docker.internal resolves to 172.17.0.1 but no service responded on ports 6379 or 5432.

🔌 Service connectivity validated by Smoke Services

@github-actions

Copy link
Copy Markdown
Contributor

Gemini Smoke Test Results:

Overall status: PASS

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.

💎 Faceted by Smoke Gemini

@lpcox lpcox merged commit 827140d into main Jun 16, 2026
81 of 85 checks passed
@lpcox lpcox deleted the copilot/refactor-handleexec-function branch June 16, 2026 22:57
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.

3 participants