Skip to content

Default sandbox.agent.sudo to false (network isolation) - #42354

Merged
pelikhan merged 5 commits into
mainfrom
copilot/set-sandbox-agent-sudo-default-false
Jun 29, 2026
Merged

Default sandbox.agent.sudo to false (network isolation)#42354
pelikhan merged 5 commits into
mainfrom
copilot/set-sandbox-agent-sudo-default-false

Conversation

Copilot AI commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Changes the global default for sandbox.agent.sudo from true (sudo/host-access mode) to false (network isolation/rootless mode). No .md workflow files changed — Go default behavior only.

Behavior

Scenario Before After
sudo omitted sudo -E awf rootless awf
sudo: false rootless awf rootless awf (no change)
sudo: true sudo -E awf sudo -E awf + error (strict) / warning (non-strict)

Implementation

  • AgentSandboxConfig — adds SudoExplicitlyEnabled bool (not serialized) to distinguish sudo: true in frontmatter from the default
  • frontmatter_extraction_security.goextractAgentSandboxConfig defaults NetworkIsolation=true when sudo is absent; sets SudoExplicitlyEnabled=true only on explicit sudo: true
  • sandbox.goapplySandboxDefaults applies NetworkIsolation: true to all freshly-created AgentSandboxConfig instances (covers code paths that bypass frontmatter extraction)
  • strict_mode_sandbox_validation.govalidateStrictSandboxCustomization gates on SudoExplicitlyEnabled: hard error in strict mode, stderr warning + counter increment in non-strict mode

Test changes

  • Updated TestNetworkIsolationRootless "sudo omitted" case to assert rootless behavior
  • Added TestValidateStrictSandboxCustomizationSudoTrue for both strict error and non-strict warning paths
  • Extended TestExtractAgentSandboxConfigSudo with omitted-sudo default and SudoExplicitlyEnabled assertions
  • Updated compiler_permissions_test.go, sandbox_custom_agent_test.go, and Wasm golden files that asserted sudo -E awf as the default

…ict mode, warning in non-strict

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI requested a review from pelikhan June 29, 2026 22:02
@pelikhan
pelikhan marked this pull request as ready for review June 29, 2026 22:03
Copilot AI review requested due to automatic review settings June 29, 2026 22:03
@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

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

@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

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

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 pull request changes the default sandbox behavior so sandbox.agent.sudo now defaults to false, making network-isolation/rootless the default execution mode for the firewall (AWF). It adds an explicit-tracking flag to distinguish “explicit sudo: true” from “unset”, and updates strict-mode validation and golden/test expectations accordingly.

Changes:

  • Default AgentSandboxConfig to NetworkIsolation=true when sudo is omitted (and in default-initialization paths).
  • Add SudoExplicitlyEnabled (non-serialized) to detect explicit sudo: true and emit strict-mode errors / non-strict warnings.
  • Update unit tests and Wasm golden outputs to reflect rootless AWF invocation and bridge-network MCP gateway wiring.
Show a summary per file
File Description
pkg/workflow/sandbox.go Adds SudoExplicitlyEnabled and applies network-isolation defaults in applySandboxDefaults.
pkg/workflow/frontmatter_extraction_security.go Defaults NetworkIsolation=true when sudo is omitted; records explicit sudo: true.
pkg/workflow/strict_mode_sandbox_validation.go Emits strict error / non-strict warning when sudo: true was explicitly set.
pkg/workflow/strict_mode_sandbox_validation_test.go Adds coverage for strict error + non-strict warning behavior for sudo: true.
pkg/workflow/frontmatter_extraction_security_test.go Extends extraction tests for omitted sudo default + explicit sudo tracking.
pkg/workflow/sandbox_network_isolation_rootless_test.go Updates the “sudo omitted” scenario assertions to expect rootless/network-isolated defaults.
pkg/workflow/sandbox_custom_agent_test.go Updates expectations to assert rootless awf --config rather than sudo -E awf.
pkg/workflow/compiler_permissions_test.go Updates expectations for default AWF invocation under the new rootless default.
pkg/workflow/testdata/TestWasmGolden_CompileFixtures/with-imports.golden Updates compiled workflow golden output for rootless install/invocation and isolated MCP gateway topology.
pkg/workflow/testdata/TestWasmGolden_CompileFixtures/smoke-copilot.golden Same as above for smoke-copilot fixture.
pkg/workflow/testdata/TestWasmGolden_CompileFixtures/playwright-cli-mode.golden Same as above for Playwright CLI mode fixture.
pkg/workflow/testdata/TestWasmGolden_CompileFixtures/basic-copilot.golden Same as above for basic-copilot fixture.
pkg/workflow/testdata/TestWasmGolden_AllEngines/pi.golden Updates all-engines Pi golden to reflect isolated/rootless defaults and topology attach.
pkg/workflow/testdata/TestWasmGolden_AllEngines/gemini.golden Updates all-engines Gemini golden for rootless defaults and MCP gateway bridge wiring.
pkg/workflow/testdata/TestWasmGolden_AllEngines/copilot.golden Updates all-engines Copilot golden for rootless defaults and MCP gateway bridge wiring.
pkg/workflow/testdata/TestWasmGolden_AllEngines/codex.golden Updates all-engines Codex golden for rootless defaults and MCP gateway bridge wiring.
pkg/workflow/testdata/TestWasmGolden_AllEngines/claude.golden Updates all-engines Claude golden for rootless defaults and MCP gateway bridge wiring.

Review details

Tip

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

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

Comment thread pkg/workflow/sandbox_network_isolation_rootless_test.go Outdated
…alse

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Design Decision Gate - ADR Required

This PR makes significant changes to core sandbox security logic (231 new lines in business logic directories) but does not have a linked Architecture Decision Record (ADR).

Draft ADR committed: docs/adr/42354-default-sandbox-agent-sudo-to-false-network-isolation.md - review and complete it before merging.

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

What to do next
  1. Review the draft ADR committed to your branch - it was generated from the PR diff
  2. Complete the missing sections - add context the AI could not infer, refine the decision rationale, and list real alternatives you considered
  3. Commit the finalized ADR to docs/adr/ on your branch
  4. Reference the ADR in this PR body by adding a line such as:

    ADR: ADR-42354: Default sandbox.agent.sudo to False (Network Isolation)

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

Why ADRs Matter

ADRs create a searchable, permanent record of why the codebase looks the way it does. Future contributors (and your future self) will thank you.

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 are stored in docs/adr/ as Markdown files numbered by PR number (e.g., 0042-use-postgresql.md for PR #42).

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · 38.8 AIC · ⌖ 12.6 AIC · ⊞ 8.4K ·
Comment /review to run again

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel — Score: 83/100 ✅ Excellent

This PR ("Default sandbox.agent.sudo to false") adds well-structured behavioral tests covering the sudo:false network-isolation default across extraction, compilation, and strict-mode validation layers, with strong error-case coverage and no guideline violations.

📊 Metrics & Scoring
Metric Value
Test files analyzed 5 Go (*_test.go)
Test functions / groups 8
Design tests (behavioral contract) 8 / 8 (100%)
Implementation tests (low-value) 0 / 8 (0%)
Tests with error/edge-case coverage 6 / 8 (75%)
Duplicate clusters 0
Coding-guideline violations None
Mock libraries detected None
Missing //go:build tags None

Score breakdown

Component Points
Behavioral coverage (8/8 design tests) 40 / 40
Error/edge case coverage (6/8 tests) 22.5 / 30
Low duplication (0 clusters) 20 / 20
Proportional growth (strict_mode_sandbox_validation_test.go 60 additions vs strict_mode_sandbox_validation.go 28 additions = 2.14:1 ratio) 0 / 10
Total 82.5 → 83 / 100
🔍 Test Classification Table
Test function File Table-driven Error/edge cases Q3 Classification Value if deleted
TestExtractAgentSandboxConfigSudo frontmatter_extraction_security_test.go No (3 inline runs) ✅ Yes (sudo:false, sudo:true, omitted) Design test High — detects regression of the new sudo:false default in extraction
TestNetworkIsolationRootless sandbox_network_isolation_rootless_test.go No (2 inline runs) ✅ Yes (explicit false + omitted default) Design test High — detects if sudo -E awf reappears or --rootless is dropped from install
TestValidateStrictSandboxCustomization strict_mode_sandbox_validation_test.go ✅ Yes (13 rows) ✅ Yes (8 error rows) Design test High — any loosening of strict-mode enforcement goes undetected
TestValidateStrictSandboxCustomizationNonStrictMode strict_mode_sandbox_validation_test.go No ❌ Happy-path only Design test Medium — validates non-strict mode does not reject valid fields
TestValidateStrictSandboxCustomizationSetsAWFDefault strict_mode_sandbox_validation_test.go ✅ Yes (2 rows) ❌ Success-only Design test Medium — ensures AWF default assignment runs in strict mode
TestValidateStrictSandboxCustomizationSudoTrue strict_mode_sandbox_validation_test.go No (3 inline runs) ✅ Yes (error case + warning case) Design test High — detects if strict-mode rejection of sudo:true regresses
TestCustomAWFConfiguration additions sandbox_custom_agent_test.go No ✅ Yes (boundary: isolation vs non-isolation) Design test High — detects if --rootless install flag is dropped or incorrectly applied
TestNetworkPermissionsDefaultBehavior modifications compiler_permissions_test.go ✅ Yes (5 rows) ✅ Yes (negative assertion on sudo -E awf) Design test High — detects if sudo invocation leaks back into default network-permissions paths

⚠️ Minor note — test inflation flag: strict_mode_sandbox_validation_test.go added 60 lines against 28 production lines (2.14:1 ratio). This is expected for a security-validation test file covering many rejection paths and is not a quality concern here.


Verdict: ✅ PASS — 0% implementation tests (threshold: 30%). No coding-guideline violations. All new tests enforce behavioral contracts and the security invariant is well-covered end-to-end.

🧪 Test quality analysis by Test Quality Sentinel · 79.8 AIC · ⌖ 21.3 AIC · ⊞ 8.1K ·
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: 83/100. Test quality is excellent — 0% of new tests are implementation tests (threshold: 30%). All 8 test functions/groups enforce behavioral contracts with no coding-guideline violations detected.

@github-actions

Copy link
Copy Markdown
Contributor

Skills-Based Review Summary 🧠

Applied /improve-codebase-architecture, /tdd, and /zoom-out. Requesting changes on 10 issues — 3 blocking, 7 improvements.

🔴 Blocking issues (3)
  1. sandbox.go:213 — Silent API footgun [/improve-codebase-architecture]: The post-construction !SudoExplicitlyEnabled block silently overrides NetworkIsolation=false for any caller that builds a config programmatically without knowing about SudoExplicitlyEnabled. The existing sandbox_test.go table fixtures hit this path with no assertions — add NetworkIsolation assertions to detect the silent flip.

  2. sandbox_network_isolation_rootless_test.go:64,126 — Brittle whitespace assertions [/tdd]: "\n awf --config " hardcodes 10-space YAML indentation. If the lock-file format ever changes, these silently fail/pass incorrectly. Strip the whitespace.

  3. compiler_permissions_test.go:149 — Missing positive assertion for sudo: true [/tdd]: All four test cases assert sudo -E awf is absent. There's no integration test that compiles a workflow with explicit sudo: true and asserts sudo -E awf is present.

🟡 Improvements (7)
  1. strict_mode_sandbox_validation_test.go:252 — Shared fixture pointer [/tdd]: sudoTrueSandbox is shared across three subtests. Future mutations could cause cross-contamination.

  2. strict_mode_sandbox_validation_test.go:281 — Warning message content not tested [/tdd]: Only GetWarningCount() is checked; stderr message content isn't captured. Pattern from action_pins_test.go should be followed.

  3. strict_mode_sandbox_validation.go:62 — Misleading log message [/zoom-out]: "Skipping sandbox customization validation" fires after the sudo deprecation warning was emitted.

  4. sandbox.go:174 — Missing comment on multi-site initialization [/improve-codebase-architecture]: The fresh-path NetworkIsolation: true inits and the post-construction block at line 213 should cross-reference each other.

  5. sandbox.go:54SudoExplicitlyEnabled doc incomplete [/improve-codebase-architecture]: Field doc only mentions compile-time validation, not its role in applySandboxDefaults runtime defaults.

  6. frontmatter_extraction_security.go:216sudo: false not tracked, not explained [/zoom-out]: One-line comment explaining why only sudo: true sets SudoExplicitlyEnabled would pre-empt future confusion.

  7. strict_mode_sandbox_validation.go:46 — Undocumented cross-mode behaviour [/zoom-out]: The sudo check fires regardless of c.strictMode, but the comment structure implies it might not. The updated function doc at line 27–28 covers this, but a short inline comment at the block itself would reinforce the intent.

@copilot please address the review comments above.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · 137.1 AIC · ⌖ 8.58 AIC · ⊞ 6.6K ·
Comment /matt 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.

Skills-Based Review 🧠

Applied /improve-codebase-architecture, /tdd, and /zoom-out — requesting changes on test coverage gaps and a documentation/API-contract issue.

📋 Key Themes & Highlights

Key Themes

  • Silent API footgun (sandbox.go:213): SudoExplicitlyEnabled drives both compile-time validation and runtime defaults in applySandboxDefaults, but the field doc only mentions the former. Any caller that sets NetworkIsolation: false without also setting SudoExplicitlyEnabled: true will be silently overridden. The existing sandbox_test.go fixtures already hit this path with zero assertions.
  • Brittle test assertions (sandbox_network_isolation_rootless_test.go): Two assertions hardcode 10-space YAML indentation ("\n awf --config "). These are silent false-negatives if the emitter indentation ever shifts.
  • Test isolation (strict_mode_sandbox_validation_test.go): Shared sudoTrueSandbox pointer across subtests; fragile if validation ever mutates the struct before the early-return.
  • Missing integration test: No test verifies that sudo: true in frontmatter generates sudo -E awf in the compiled output — all four updated cases only assert the negative.
  • Misleading log message (strict_mode_sandbox_validation.go:62): "Skipping sandbox customization validation" fires after the sudo deprecation warning already emitted.

Positive Highlights

  • ✅ Clean three-layer default strategy covers nil-config, nil-agent, and pre-existing-agent paths
  • SudoExplicitlyEnabled neatly separates tracking from semantics — right field for the job
  • ✅ Comprehensive golden-file and test updates throughout; no existing assertions left unaddressed
  • ✅ Deprecation UX is excellent: strict-mode error + non-strict warning with a documentation URL

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

Comments that could not be inline-anchored

pkg/workflow/sandbox.go:213

[/improve-codebase-architecture] Post-construction block silently overrides NetworkIsolation=false for any caller that builds AgentSandboxConfig{NetworkIsolation: false} without also setting SudoExplicitlyEnabled: true. Since SudoExplicitlyEnabled is yaml:&quot;-&quot; and only set by extractAgentSandboxConfig, any programmatic caller of applySandboxDefaults passing a pre-built config will have its setting stomped silently.

<details>
<summary>💡 Suggested fix / documentation</summary>

pkg/workflow/sandbox_network_isolation_rootless_test.go:64

[/tdd] Brittle whitespace assertion: &quot;\n awf --config &quot; hardcodes 10 spaces of YAML indentation. If the YAML emitter or run-block indentation ever changes, this check silently fails with a misleading error message ("Expected rootless 'awf --config'...") even though the AWF invocation is present.

<details>
<summary>💡 Suggested fix</summary>

Drop the newline and leading spaces — strings.Contains is already specific enough to distinguish this from the awf logs summary line:

pkg/workflow/sandbox_network_isolation_rootless_test.go:126

[/tdd] Same brittle whitespace issue as line 64 — &quot;\n awf --config &quot; hardcodes YAML indentation. Silently breaks if the lock-file indentation changes.

<details>
<summary>💡 Suggested fix</summary>

if !strings.Contains(lockStr, &quot;awf --config&quot;) {
    t.Error(&quot;Expected rootless &#39;awf --config&#39; invocation in lock file&quot;)
}

</details>

@copilot please address this.

pkg/workflow/strict_mode_sandbox_validation_test.go:252

[/tdd] sudoTrueSandbox is a shared pointer used across three subtests. While safe today (strict-mode path returns before mutating agent.Type), the strict-mode path in validateStrictSandboxCustomization does contain a struct mutation (agent.Type = SandboxTypeAWF) lower in the function. If future validation logic runs before the sudo early-return, the shared struct would cause cross-test contamination.

<details>
<summary>💡 Suggested fix</summary>

Construct a fresh fixture per subte…

pkg/workflow/strict_mode_sandbox_validation_test.go:281

[/tdd] The non-strict warning test only verifies that GetWarningCount() incremented — it doesn't capture or assert the actual stderr warning message. A refactor that swapped out the message (or broke formatting) would pass this test silently. Other warning tests in this codebase (e.g., action_pins_test.go) capture stderr to check content.

<details>
<summary>💡 Suggested addition</summary>

Capture stderr and assert the message contains the key details:

// Capture stderr
oldStder</details>

<details><summary>pkg/workflow/strict_mode_sandbox_validation.go:62</summary>

**[/zoom-out]** Misleading log message: `&quot;Strict mode disabled, skipping sandbox customization validation&quot;` fires *after* the sudo check has already run and potentially emitted a deprecation warning. A reader of this log line would incorrectly conclude that nothing happened for this invocation.

&lt;details&gt;
&lt;summary&gt;💡 Suggested fix&lt;/summary&gt;

Update the message to reflect partial execution:

```go
strictModeValidationLog.Printf(&quot;Strict mode disabled, skipping remaining strict-only sandbox checks…

</details>

<details><summary>pkg/workflow/sandbox.go:174</summary>

**[/improve-codebase-architecture]** The fresh-construction paths here (lines 174, 194) set `NetworkIsolation: true` inline, but the post-construction block at line 213 also unconditionally sets `NetworkIsolation = true` for any existing agent with `!SudoExplicitlyEnabled`. Both the fresh and existing paths end up at the same result, but via different mechanisms with no comment explaining the relationship. This makes it hard to reason about invariants.

&lt;details&gt;
&lt;summary&gt;💡 Suggestion&lt;/summary…

</details>

<details><summary>pkg/workflow/frontmatter_extraction_security.go:216</summary>

**[/zoom-out]** The `SudoExplicitlyEnabled` flag is only set for `sudo: true`, not for `sudo: false`. This is correct — the flag tracks the *dangerous* explicit opt-in. However, a future reader might wonder why `sudo: false` doesn&#39;t also set a flag. A one-line comment would pre-empt this confusion.

&lt;details&gt;
&lt;summary&gt;💡 Suggested clarification&lt;/summary&gt;

```go
if sudoBool {
    // Only track explicit sudo: true (host-access opt-in), not sudo: false
    // (which is the safe default and require…

</details>

<details><summary>pkg/workflow/compiler_permissions_test.go:149</summary>

**[/tdd]** The four test cases here all assert that `sudo -E awf` is absent (the new default). There&#39;s no integration test in this file that compiles a workflow with `sudo: true` explicitly set and verifies that `sudo -E awf` IS generated. Without such a test, a regression that drops `sudo -E awf` from the explicit-sudo path would go undetected.

&lt;details&gt;
&lt;summary&gt;💡 Suggested addition&lt;/summary&gt;

Add a test case (or a subtest) that sets `sudo: true` in the workflow frontmatter and verifies:

`</details>

<details><summary>pkg/workflow/sandbox.go:54</summary>

**[/improve-codebase-architecture]** The `SudoExplicitlyEnabled` field doc says it&#39;s used to emit errors/warnings at compile time, but it also drives runtime behaviour in `applySandboxDefaults` (line 213). The doc comment should mention both uses so that readers understand the full scope of impact:

&lt;details&gt;
&lt;summary&gt;💡 Suggested doc update&lt;/summary&gt;

```go
// True when sudo: true was explicitly set in frontmatter.
// Used in two places:
//   1. validateStrictSandboxCustomization — emits an er…

</details>

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

Non-blocking observations on two code paths

The core logic is sound: the three-pronged approach (frontmatter default, two early-creation defaults in applySandboxDefaults, and the late safety net at line 213) correctly enforces network isolation for all standard-format workflows. Test coverage is thorough. Two medium concerns are worth addressing before or shortly after merge.

### Issues found (2 medium)

1. Legacy sandbox.type format silently bypasses the new default (sandbox.go line 183–186)

When sandboxConfig.Type != "" the function exits before line 213, so any workflow still using the old top-level sandbox: {type: awf} format remains in sudo mode with no warning. isAWFNetworkIsolationEnabled returns false for those configs because Agent stays nil. If operators believe this change covers all workflows, they are wrong for legacy-format configs. See inline comment.

2. Strict-mode sudo: true error short-circuits all other strict-mode checks (strict_mode_sandbox_validation.go line 54)

Before this PR, strict mode reported command/args/env/MCP violations in a single compilation pass. Now, a workflow that combines sudo: true with other forbidden fields will only reveal the sudo: true error; subsequent violations surface only after each fix-compile cycle. See inline comment.

🔎 Code quality review by PR Code Quality Reviewer · 146 AIC · ⌖ 6.99 AIC · ⊞ 5.2K
Comment /review to run again

Comment thread pkg/workflow/sandbox.go
// Apply the default sudo: false (network isolation) when sudo was not explicitly
// set to true in frontmatter. This ensures network isolation is the default.
if !sandboxConfig.Agent.SudoExplicitlyEnabled {
sandboxConfig.Agent.NetworkIsolation = true

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.

The legacy sandbox.type code path above silently keeps sudo mode, inconsistent with the new default.

When sandboxConfig.Type != "" (line 183), the function returns early before reaching this block, so any workflow still using the old top-level sandbox.type: awf format never gets NetworkIsolation = true applied. The security policy change does not cover that format — there is no warning, no migration, and isAWFNetworkIsolationEnabled returns false for those configs because Agent remains nil.

💡 Suggested fix

Either apply the new default inside the legacy early-return path, or emit a deprecation warning so operators know their config is outside the new policy:

if sandboxConfig.Type != "" {
    sandboxLog.Printf("Sandbox config uses legacy Type field: %s, preserving it", sandboxConfig.Type)
    // Apply network isolation default to Agent if present.
    if sandboxConfig.Agent != nil && !sandboxConfig.Agent.SudoExplicitlyEnabled {
        sandboxConfig.Agent.NetworkIsolation = true
    }
    ensureDefaultAgentWritePath(sandboxConfig)
    return sandboxConfig
}

If the legacy path is intentionally excluded, document that explicitly in the function comment so reviewers and operators can audit their workflow inventory.

"Remove 'sudo: true' to use the secure default. " +
"See: https://github.github.com/gh-aw/reference/sandbox/"
if c.strictMode {
return fmt.Errorf("strict mode: %s", sudoTrueMsg)

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.

Returning here in strict mode short-circuits all remaining strict-mode checks, making error discovery order-dependent.

A workflow with sudo: true plus command: "custom-wrapper" plus a forbidden MCP field in strict mode will only surface the sudo: true error on first compile. The user must fix-compile-fix to find each subsequent violation, whereas before this change strict mode reported command/args/env/MCP violations in a single pass.

💡 Suggested fix

Collect the sudo-true error rather than returning immediately, so all strict-mode violations are visible together:

var errs []string
if agent.SudoExplicitlyEnabled {
    if c.strictMode {
        errs = append(errs, sudoTrueMsg)
    } else {
        fmt.Fprintln(os.Stderr, console.FormatWarningMessage(sudoTrueMsg))
        c.IncrementWarningCount()
    }
}
// ... remaining checks append to errs ...
if len(errs) > 0 {
    return fmt.Errorf("strict mode: %s", strings.Join(errs, "; "))
}

Alternatively, keep the early return but document the ordering contract explicitly, since the behaviour is now observable to users.

@github-actions

Copy link
Copy Markdown
Contributor

Review: Default sandbox.agent.sudo to false (network isolation)

Security posture: ✅ positive. Defaulting to network-isolation mode is the right call — no blocking issues found.

What was reviewed
  • frontmatter_extraction_security.go — new NetworkIsolation = true default in extractAgentSandboxConfig (object format)
  • sandbox.goAgentSandboxConfig.SudoExplicitlyEnabled field; applySandboxDefaults applies the network-isolation default for all programmatic code paths
  • strict_mode_sandbox_validation.gosudo: true → strict error / non-strict warning; nil-guard reordering
  • All 17 changed files including golden files and tests

Non-blocking suggestions (4 inline comments posted)

  1. String-format agent (agent: awf shorthand) does not eagerly set NetworkIsolation = true in extractAgentSandboxConfig; the default is applied later by applySandboxDefaults. Correct today, but a latent footgun if new code reads NetworkIsolation between extraction and applySandboxDefaults.
  2. Legacy sandboxConfig.Type != "" early-return in applySandboxDefaults bypasses the new !SudoExplicitlyEnabled guard. Safe for frontmatter paths (already defaulted by extractAgentSandboxConfig), but a clarifying comment would protect future maintainers.
  3. Fragile whitespace-sensitive test assertion "\n awf --config " — will fail silently if YAML indentation changes.
  4. Warning URL https://github.github.com/gh-aw/reference/sandbox/ — verify it is live before merge.

Verdict: COMMENT — all suggestions are non-blocking. The implementation is correct, the security improvement is real, and test coverage is thorough.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · 158 AIC · ⌖ 7.12 AIC · ⊞ 4.9K ·

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

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · 158 AIC · ⌖ 7.12 AIC · ⊞ 4.9K

// (omitted) → sudo enabled = normal mode → NetworkIsolation=false (zero value)
// sudo: true → sudo enabled = normal mode → NetworkIsolation=false (deprecated; error in strict mode, warning otherwise)
// (omitted) → default = network isolation mode → NetworkIsolation=true (same as sudo: false)
agentConfig.NetworkIsolation = true // Default: sudo: false (network isolation enabled)

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.

The object-format branch now correctly defaults NetworkIsolation = true here, but the string-format branch (line ~164, unchanged) still returns &AgentSandboxConfig{Type: agentType} with NetworkIsolation = false.

The default is fixed up later by applySandboxDefaults via the !SudoExplicitlyEnabled guard, so current behavior is correct. However, any future code reading agentConfig.NetworkIsolation from the pre-defaults sandboxConfig (e.g., inside runPostEngineValidations) would see false for string-format agents, which contradicts the stated default.

Consider making the default eager and consistent:

return &AgentSandboxConfig{
    Type:             agentType,
    NetworkIsolation: true, // Default: sudo: false (network isolation)
}

@copilot please address this.

Comment thread pkg/workflow/sandbox.go
// Apply the default sudo: false (network isolation) when sudo was not explicitly
// set to true in frontmatter. This ensures network isolation is the default.
if !sandboxConfig.Agent.SudoExplicitlyEnabled {
sandboxConfig.Agent.NetworkIsolation = true

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.

The !SudoExplicitlyEnabled → NetworkIsolation = true guard correctly applies the new default for configs that reach this point.

However, the early-return path at line 183–186 (when sandboxConfig.Type != "") bypasses this block:

if sandboxConfig.Type != "" {
    ensureDefaultAgentWritePath(sandboxConfig)
    return sandboxConfig  // ← bypasses the NetworkIsolation default below
}

For frontmatter-sourced configs this is safe because extractAgentSandboxConfig already sets NetworkIsolation = true as the default (line 212 of frontmatter_extraction_security.go). But programmatically-created configs with sandboxConfig.Type != "" and sandboxConfig.Agent != nil will silently skip the new default.

A defensive fix or a comment explaining the invariant would prevent future regressions:

if sandboxConfig.Type != "" {
    // NetworkIsolation is already set by extractAgentSandboxConfig; skip re-defaulting.
    ensureDefaultAgentWritePath(sandboxConfig)\n    return sandboxConfig\n}\n```\n\n@copilot please address this.

if strings.Contains(lockStr, "--rootless") {
t.Error("Expected no '--rootless' flag in install step when sudo is not set")
// AWF must still be invoked (without sudo). Check for the main AWF invocation pattern.
if !strings.Contains(lockStr, "\n awf --config ") {

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.

The "\n awf --config " assertion relies on the exact indentation of the generated YAML run block. If the YAML renderer ever changes indentation (e.g., moving from 10 to 8 spaces), this test would fail with a confusing message rather than a useful one.

The first test case (line 64) uses the same pattern with a comment explaining the rationale. Consider extracting this into a helper or using a slightly looser match:

// Checks that AWF is invoked directly (not via sudo) as the main execution step.
if !strings.Contains(lockStr, "awf --config ") || strings.Contains(lockStr, "sudo -E awf") {
    t.Error("Expected rootless 'awf --config' invocation without sudo")
}\n```

@copilot please address this.

const sudoTrueMsg = "sandbox.agent.sudo: true re-enables host-access (sudo) mode. " +
"The default is now sudo: false (network isolation). " +
"Remove 'sudo: true' to use the secure default. " +
"See: https://github.github.com/gh-aw/reference/sandbox/"

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.

Please verify that https://github.github.com/gh-aw/reference/sandbox/ is a live URL before this PR merges. If the docs page doesn't exist yet, consider using a placeholder or the repo URL (https://github.com/github/gh-aw) until it is published — a broken link in a user-facing warning message is confusing.

@copilot please address this.

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot run pr-finisher skill

Copilot AI and others added 2 commits June 29, 2026 22:31
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Jun 29, 2026

Copy link
Copy Markdown
Contributor Author

@copilot run pr-finisher skill

Done. I ran a pr-finisher pass, applied a minimal follow-up fix for the fragile rootless assertion, and pushed commit 489d02a.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill to move this PR toward merge.

The following review threads are unresolved and need attention:

  • github-actions[bot] (Matt Pocock Skills Reviewer): review thread

Please address the unresolved review feedback, ensure all checks pass, and run pr-finisher to complete the process.

Generated by 👨‍🍳 PR Sous Chef · 91.4 AIC · ⌖ 9.62 AIC · ⊞ 6.7K ·

@pelikhan
pelikhan merged commit 73c496b into main Jun 29, 2026
19 of 20 checks passed
@pelikhan
pelikhan deleted the copilot/set-sandbox-agent-sudo-default-false branch June 29, 2026 22:53
Copilot stopped work on behalf of gh-aw-bot due to an error June 29, 2026 22:54
Copilot AI requested a review from gh-aw-bot June 29, 2026 22:54
github-actions Bot added a commit that referenced this pull request Jun 30, 2026
Added sandbox.agent.sudo glossary entry documenting the field's behavior
and new default (false = network isolation mode), introduced by PR #42354
which changed the default from sudo mode to rootless/network-isolation mode.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.82.1

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.

4 participants