Skip to content

ci(test): enforce hermetic deterministic Reborn suite - #6883

Merged
serrrfirat merged 22 commits into
mainfrom
codex/ws1-hermetic-suite
Jul 30, 2026
Merged

serrrfirat merged 22 commits into
mainfrom
codex/ws1-hermetic-suite

Conversation

@serrrfirat

@serrrfirat serrrfirat commented Jul 29, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • Define scripts/ci/run-hermetic-deterministic-suite.sh all as the canonical local composition of the deterministic Reborn merge gates, and route the corresponding CI jobs through the same checked-in stages.
  • Use one checked-in package-discovery helper for the local suite, local coverage ratchet, and CI crate matrix so the complete Reborn package set cannot drift between lanes.
  • Default-deny the inherited environment, isolate Cargo/Rustup homes from credentials and agent sockets, and guard sendfile alongside the existing socket-write paths.
  • Put every test process behind one boundary that scrubs provider credentials and ambient behavior, creates unique temporary mutable roots, pins deterministic Python hash iteration while retaining typed Rust clock seams and zero-jitter test configuration, disables the OS keychain, and rejects non-loopback IP traffic while preserving localhost fakes.
  • Add fail-loud mutation coverage for environment scrubbing, temporary roots, Python hash-seed injection, TCP/UDP egress, repeat/parallel root isolation, and minimal-env E2E child propagation.
  • Document setup, CI parity, and deliberate exclusions for live/nightly/stress/tool-download lanes.

Change Type

  • Bug fix
  • New feature
  • Refactor
  • Documentation
  • CI/Infrastructure
  • Security
  • Dependencies

Linked Issue

Related #6524 (WS1)

Overlap reconciliation:

  • test: isolate Trace Commons coverage from local state #6714 remains open at 41f0c9284c88b5bd6614542ca060075226952fb5. It isolates direct execution of the Trace Commons coverage test in its own child process. This PR does not copy that test-specific harness; the canonical suite instead supplies an isolated process root to all registered lanes. The changes are complementary and neither PR depends on the other.
  • ci: pin TZ/locale for tests and reject orphan-history branches #6721 already landed TZ/locale pinning in CI. This PR preserves those values at the shared local/CI process boundary but does not recreate its workflow/history work.
  • Completed WS3 provider reset/order coverage is not duplicated. Repeat/parallel checks here cover only process-local mutable roots and guard state.

Validation

  • cargo fmt --all -- --check
  • cargo clippy -p ironclaw_skills -p ironclaw_host_runtime --all-targets --all-features -- -D warnings and cargo clippy -p ironclaw_llm --all-targets --all-features -- -D warnings; the new C guard is compiled with -Wall -Wextra -Werror by the self-test.
  • cargo build — not run as a standalone command; the representative Rust E2E substrate lane compiled every exercised target through the canonical runner.
  • Relevant tests pass:
    • scripts/ci/test-hermetic-test-process.sh
    • scripts/ci/run-hermetic-deterministic-suite.sh rust-e2e substrates (262 passed)
    • scripts/ci/run-hermetic-deterministic-suite.sh frontend after rebasing onto current main (111 files, 914 tests passed)
    • final-head CI Reborn WebUI v2 smoke (43 guarded browser tests, 403 harvested QA/provider tests, and 21 Responses API tests passed)
    • guarded ironclaw_skills::catalog::test_search_returns_error_on_network_failure (1 passed)
    • guarded ironclaw_host_runtime::connect_override_proceeds_past_trust_boundary_with_opt_in (1 passed)
    • guarded cargo test -p ironclaw_llm --lib (995 passed; Copilot refresh-failure tests verified through loopback-only proxy)
    • scripts/ci/run-hermetic-deterministic-suite.sh command cargo test -p ironclaw_common env_helpers::tests::runtime_override_round_trip -- --exact --nocapture (1 passed)
    • scripts/ci/test-classify-test-scope.sh
    • scripts/ci/test-check-hermetic-env.sh (8/8)
    • scripts/pre-commit-safety.sh
    • YAML parse of all three changed workflows
    • explicit PLAYWRIGHT_BROWSERS_PATH propagation through the hermetic self-test
    • guarded current-main product/provider evidence contracts (108 passed)
    • Rust-less guarded command path (passed)
    • final rebased-head CI: 59 passed, 0 failed, 5 intentionally skipped
  • cargo test --features integration — not applicable: no database-backed product behavior or schema changed.
  • Manual testing: ran all four sabotage modes and confirmed env=31, temp=32, python-seed=34, and network=1 with the intended diagnostics; confirmed loopback remains allowed, route-only UDP association emits no packet, and TCP plus connected UDP send/sendmmsg/write/writev paths are rejected.
  • If a coding agent was used and supports it, review-pr or pr-shepherd --fix was run before requesting review — pr-shepherd plus the IronClaw maintainer review lens found two blocking gaps; both were fixed in a59a3ab3a and revalidated locally.

Test Strategy

User behavior:

Local deterministic Reborn testing now uses one documented command whose stages and configuration are also invoked by CI. Tests cannot silently inherit real provider credentials, developer homes/databases/workspaces, or external network access.

Risk areas:

  • Model behavior
  • Browser
  • Side effect
  • Persistence
  • Security or permissions
  • External provider
  • Cross-component behavior

Tests added or updated:

  • Unit or contract: scripts/ci/test-hermetic-test-process.sh compiles/probes the guard, validates the default-deny environment allowlist (including unlisted providers, multiline values, token files, credential-agent sockets, and shell startup state), sanitized toolchain homes, unique and parallel roots, fixed inputs, workflow/stage parity, loopback allowance, nested minimal-env E2E propagation, and all four mutation modes.
  • Reborn integration: scripts/ci/run-hermetic-deterministic-suite.sh rust-e2e substrates passed 262 filesystem, event, projection, network, secret, resource, approval, and authorization contract tests through the new boundary.
  • Recorded fixture: scripts/ci/check-reborn-qa-fixtures.sh passed for all 61 fixtures through the guarded qa stage. The replay target rebuilt through the guarded WebUI/Corepack path and passed: 41 passed, 12 intentionally ignored, 0 failed.
  • Browser E2E: Final-head CI passed the complete Reborn WebUI v2 smoke job: 43 guarded browser tests, 403 harvested QA/provider tests, and 21 Responses API tests. CI installs and caches Chromium at an explicit runner-temporary PLAYWRIGHT_BROWSERS_PATH that the guard preserves as immutable tooling input. The product-surface evidence contracts and all merge-gating launchers use the hermetic boundary, and the canonical local Python stage includes the SSO smoke.
  • Backend or runtime: ironclaw_common::env_helpers::tests::runtime_override_round_trip passed through the command stage; the complete substrate group passed through rust-e2e.
  • Live canary: Not applicable: live providers are deliberately excluded from a credential-free, non-loopback hermetic lane.

What the tests prove:

  • Ambient provider and generic secret variables do not cross the process boundary.
  • Homes, IronClaw bases, Reborn homes, workspaces, XDG state, and temp directories are unique per invocation and safe under four-way parallel execution.
  • Python hash iteration is pinned and deleting that real interpreter input fails loudly. Rust domain time uses existing typed FakeClock/FixedClock seams, configured deterministic jitter is zero, and security/identity randomness remains OS-backed rather than being weakened by a process-global seed.
  • Unexpected TCP and UDP non-loopback attempts fail the lane even if the child handles the syscall error; IPv4 localhost fakes continue to work.
  • Default-deny environment construction removes unknown credentials, token files, agent sockets, multiline injection-like values, ambient target overrides, and host Cargo/Rustup configuration while retaining named deterministic fixture inputs.
  • Network controls survive the intentionally minimal Python E2E child environments, including macOS loader-variable stripping.
  • The canonical suite retains every required deterministic CI stage.

Commands run:

bash scripts/codebase-graph.sh status                         # MISSING; used required live-code rg fallback
scripts/ci/test-hermetic-test-process.sh                     # PASS
IRONCLAW_HERMETIC_SELF_TEST_SABOTAGE=env ...                 # FAIL 31 as expected
IRONCLAW_HERMETIC_SELF_TEST_SABOTAGE=temp ...                # FAIL 32 as expected
IRONCLAW_HERMETIC_SELF_TEST_SABOTAGE=python-seed ...         # FAIL 34 as expected
IRONCLAW_HERMETIC_SELF_TEST_SABOTAGE=network ...             # FAIL 1 as expected
scripts/ci/run-hermetic-deterministic-suite.sh rust-e2e substrates
scripts/ci/run-hermetic-deterministic-suite.sh frontend        # PASS: 111 files, 914 tests
scripts/ci/run-hermetic-deterministic-suite.sh qa              # PASS: fixture scrub + 41 passed, 12 ignored
cargo clippy -p ironclaw_skills -p ironclaw_host_runtime --all-targets --all-features -- -D warnings
cargo clippy -p ironclaw_llm --all-targets --all-features -- -D warnings
scripts/ci/run-hermetic-deterministic-suite.sh command cargo test -p ironclaw_common env_helpers::tests::runtime_override_round_trip -- --exact --nocapture
scripts/ci/test-classify-test-scope.sh
scripts/ci/test-check-hermetic-env.sh
scripts/pre-commit-safety.sh
cargo fmt --all -- --check
git diff --check origin/main...HEAD
pytest tests/e2e/scenarios/test_product_surface_coverage.py tests/e2e/scenarios/test_provider_capability_inventory.py tests/e2e/scenarios/test_journey_coverage.py -q  # PASS: 108

Checkbox-to-test/PR map:

  • Canonical complete suite/runbook → deterministic-suite script, workflow parity assertions, internal runbook (this PR)
  • Credential/ambient scrub → self-test plus env sabotage (this PR)
  • Temporary isolated mutable state → repeat/four-way-parallel root assertions (this PR); direct Trace Commons defense-in-depth remains test: isolate Trace Commons coverage from local state #6714
  • Deterministic inputs → real PYTHONHASHSEED consumer plus python-seed sabotage; live-code audit confirmed Rust time-sensitive behavior already uses typed clock seams and deterministic Reborn jitter defaults to zero, while cryptographic/identity randomness must remain OS-backed
  • Non-loopback guard/localhost allowance → TCP, UDP, localhost, and nested-child probes plus network sabotage (this PR)
  • WS1-owned repeat/parallel safety → unique process-root checks (this PR); provider reset/order remains completed WS3

Security Impact

Test-only security boundary added. It removes provider credentials and unrelated behavioral environment, disables OS keychain access, isolates file-backed mutable state, and interposes test-binary/Python/Node IP syscalls to deny and record non-loopback egress. Unix sockets and loopback fakes remain allowed. Product authorization, provider mediation, runtime policy, and production networking are unchanged.

Reborn Trust-Boundary Checklist

  • Public policy/evidence/trust-bearing types: N/A — no product types or constructors changed.
  • Untrusted content enters prompts only through an envelope/escaping primitive: N/A — no prompt path changed.
  • Hashes declare purpose; trust/binding/authenticity uses SHA-256/BLAKE3 or separate authenticity check: N/A — no hashing changed.
  • New/changed status, exit, policy, runtime, or error variants: downstream match sites audited. Command/output: N/A — no product variants changed; the test runner reserves exit 86 only for its shell boundary.
  • Security/durability serde(default) fields fail closed or have migration tests: N/A — no serialization changed.
  • Queues/maps/buffers/counters have bounds and overflow-safe arithmetic: N/A — no product queue/counter changed; the guard writes one bounded diagnostic per denied syscall.
  • Driver/operator-visible errors have stable class semantics (Transient, Permanent, Misconfigured, PolicyDenied or equivalent): N/A — no driver errors changed.
  • Sandbox/native/host names accurately describe trust boundary: the new scripts and variables consistently use hermetic-network-guard / hermetic-test-process and are test-only.

Database Impact

None. No migration, schema, or backend implementation changed. Test database paths are redirected into per-invocation temporary roots.

Blast Radius

Merge-gating Reborn CI jobs and developers using the canonical local suite. The main risks are over-scrubbing a required test variable, blocking a test that intentionally reaches a non-loopback service, or platform loader differences. The allowlist, explicit live-lane exclusions, Linux/macOS guard implementations, localhost probes, nested-child probe, and draft CI run constrain those risks.

Compatibility: existing individual test commands still work; the canonical path adds stronger environment/process controls. CI matrix sharding and existing test discovery scripts remain authoritative.

Rollback Plan

Revert this twenty-two-commit focused stack to restore the previous direct workflow commands. No persistent data or schema rollback is required. If one lane proves intentionally non-hermetic, it can temporarily return to its previous direct command while a narrow, documented exemption is reviewed.

Review Follow-Through

Reviewer judgment is requested on the generic secret scrub suffixes and the deliberate boundary between guarded test execution and unguarded dependency-download/compiler-cache setup. CI validates the Linux LD_PRELOAD path; local mutation testing validated the macOS interposer plus SIP-resistant process-sandbox fallback. The guard now wraps arbitrary launchers, forces Cargo offline after a checked locked fetch, and disables remote compiler wrappers inside the boundary.

The maintainer self-review found no remaining correctness or security issue after the arbitrary-launcher, Linux fortified-build, unsupported-clock-claim, Corepack isolation, interposer race, intentional TEST-NET and Copilot refresh-failure fixture fixes, isolated Playwright browser-toolchain path, one-time CI dependency preparation, preload-chain preservation, packet-free UDP route-probe handling, IPv4-mapped loopback allowance, connected-UDP write/writev/sendmmsg/sendfile bypass closure, shared local/CI package discovery, default-deny environment construction, credential-agent removal, sanitized Cargo/Rustup state, Rust-less execution, SSO/product-evidence parity, forced macOS loader mode, and fail-closed empty nested-guard validation. All readiness-triggered review threads and outside-diff findings were verified, fixed where valid, and resolved. No proven WS1 item is left unimplemented in this PR's process/CI boundary. #6714 is a complementary direct-test defense, not a blocker or copied dependency.


Review track: C (security/runtime/DB/CI)

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@railway-app

railway-app Bot commented Jul 29, 2026 •

Copy link
Copy Markdown

🚅 Deployed to the ironclaw-pr-6883 environment in ironclaw-ci-preview

Service Status Web Updated (UTC)
ironclaw ✅ Success (View Logs) Web Jul 30, 2026 at 4:36 pm

@coderabbitai

coderabbitai Bot commented Jul 29, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • Documentation
    • Added internal documentation for the deterministic, hermetic Reborn test suite, including canonical local/CI commands and supported stages.
  • Tests / CI
    • Updated Reborn E2E and test lanes to execute via the deterministic hermetic wrapper, with expanded change-path detection and standardized stage composition.
    • Improved deterministic crate/coverage selection and added stronger CI hermetic self-tests.
  • Reliability
    • Hardened hermetic networking by blocking outbound non-loopback traffic (while allowing localhost) and made network-failure tests use deterministic unreachable loopback endpoints.

Walkthrough

Adds hermetic process isolation, native network enforcement, deterministic Reborn suite orchestration, CI integration, E2E environment forwarding, centralized package discovery, and deterministic loopback-based network-failure tests.

Changes

Hermetic deterministic Reborn testing

Layer / File(s) Summary
Hermetic process and network boundary
scripts/ci/run-hermetic-test-process.sh, scripts/ci/hermetic-network-*, scripts/ci/test-hermetic-test-process.sh
Creates isolated roots, sanitizes environments, enforces deterministic settings, blocks non-loopback traffic across socket APIs, and validates platform-specific behavior.
Deterministic suite orchestration and CI wiring
scripts/ci/run-hermetic-deterministic-suite.sh, scripts/ci/discover-reborn-package-crates.sh, .github/workflows/*, docs/internal/*, scripts/ci/reborn-local-coverage-ratchet.sh
Composes Rust, integration, frontend, QA, and E2E stages; centralizes crate discovery; and routes CI lanes through the shared runner.
E2E forwarding and deterministic failure tests
tests/e2e/*, crates/ironclaw_host_runtime/..., crates/ironclaw_llm/..., crates/ironclaw_skills/...
Forwards hermetic loader controls to child processes and replaces external test endpoints with unreachable loopback targets.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related issues

Suggested reviewers: think-in-universe

Sequence Diagram(s)

sequenceDiagram
  participant CI
  participant SuiteRunner as run-hermetic-deterministic-suite.sh
  participant ProcessRunner as run-hermetic-test-process.sh
  participant TestCommand
  participant NetworkGuard as hermetic-network-guard.c
  CI->>SuiteRunner: invoke deterministic stage
  SuiteRunner->>ProcessRunner: run stage command
  ProcessRunner->>TestCommand: provide isolated environment
  TestCommand->>NetworkGuard: attempt outbound network operation
  NetworkGuard-->>TestCommand: allow loopback or reject non-loopback
  TestCommand-->>CI: return test result
Loading
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title follows Conventional Commits style and accurately summarizes the hermetic deterministic CI/test suite changes.
Description check ✅ Passed The description matches the required template and includes summary, change type, linked issue, validation, test strategy, and risk sections.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-6883 July 29, 2026 22:42 Destroyed
@github-actions github-actions Bot added scope: ci CI/CD workflows scope: docs Documentation size: XL 500+ changed lines risk: medium Business logic, config, or moderate-risk modules contributor: core 20+ merged PRs labels Jul 29, 2026
@ironloopai

ironloopai Bot commented Jul 29, 2026 •

Copy link
Copy Markdown
Contributor

🔎 Review · PR #6883

🟢 Completed · Review submitted

2 actionable findings →

The new hermetic suite has two blocking gaps in its core guarantees: non-loopback enforcement is skipped for many supported command launchers, and the advertised Rust clock/random controls have no consumers. Other changed workflow, documentation, environment-forwarding, and test areas were reviewed without additional material findings.

Automatic · PR opened + CI failed · attempt 1 of 3 · completed in 2m 5s

Run details
  • Repository: nearai/ironclaw
  • Base: main at bed3f68
  • Head: codex/ws1-hermetic-suite at ffd67b7
  • Created: Jul 29, 2026, 10:47 PM UTC
  • Updated: Jul 29, 2026, 10:49 PM UTC
  • Run: 21b7a2e7-77a9-4490-b474-49173c96fb9e
  • Latest attempt: 1 · Completed · 8e76c7be-abed-490b-9b0a-73836d555530

@ironloopai ironloopai 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 complete · PR #6883

⚠️ 2 findings · 2 blocking

The new hermetic suite has two blocking gaps in its core guarantees: non-loopback enforcement is skipped for many supported command launchers, and the advertised Rust clock/random controls have no consumers. Other changed workflow, documentation, environment-forwarding, and test areas were reviewed without additional material findings.

Findings

  1. 🔴 High · Network guard is bypassed for unrecognized command launchers — scripts/ci/run-hermetic-test-process.sh:140-148
    Details are attached to the relevant diff.
  2. 🟠 Medium · Injected Rust clock and random seed variables are unused — scripts/ci/run-hermetic-test-process.sh:118-124
    Details are attached to the relevant diff.
Validation and technical details
  • Reviewed the complete refs/ironloop/base (bed3f68) to refs/ironloop/head (ffd67b7) comparison across all 15 changed files.
  • Ran git diff --check; it passed.
  • Ran Bash syntax checks for scripts/ci/*.sh; they passed.
  • Compiled the four changed/added Python modules with python3 -m py_compile; they passed.
  • Repository-wide search confirmed IRONCLAW_TEST_RANDOM_SEED and IRONCLAW_TEST_CLOCK occur only in the new runner and its self-test.
  • Attempted scripts/ci/test-hermetic-test-process.sh; this sandbox lacks a mounted /proc/self/fd, so Bash process substitution failed at runner line 69 before the behavioral probes could execute.
  • Base: main
  • Head: codex/ws1-hermetic-suite at ffd67b7
  • Run: 21b7a2e7-77a9-4490-b474-49173c96fb9e

Comment thread scripts/ci/run-hermetic-test-process.sh Outdated
Comment thread scripts/ci/run-hermetic-test-process.sh Outdated
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-6883 July 30, 2026 08:16 Destroyed
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-6883 July 30, 2026 08:19 Destroyed
@serrrfirat
serrrfirat force-pushed the codex/ws1-hermetic-suite branch from e91f5b4 to 1614044 Compare July 30, 2026 08:20
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-6883 July 30, 2026 08:20 Destroyed
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-6883 July 30, 2026 08:25 Destroyed
@serrrfirat
serrrfirat force-pushed the codex/ws1-hermetic-suite branch from b301d15 to 35a7982 Compare July 30, 2026 08:25
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-6883 July 30, 2026 08:25 Destroyed
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-6883 July 30, 2026 08:26 Destroyed
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-6883 July 30, 2026 08:35 Destroyed
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-6883 July 30, 2026 08:53 Destroyed
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-6883 July 30, 2026 09:01 Destroyed
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-6883 July 30, 2026 09:09 Destroyed
@serrrfirat
serrrfirat force-pushed the codex/ws1-hermetic-suite branch from 6674927 to bb0e867 Compare July 30, 2026 09:10
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-6883 July 30, 2026 09:10 Destroyed
@serrrfirat
serrrfirat force-pushed the codex/ws1-hermetic-suite branch from bb0e867 to 38ab508 Compare July 30, 2026 09:21
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-6883 July 30, 2026 09:21 Destroyed
@serrrfirat
serrrfirat force-pushed the codex/ws1-hermetic-suite branch from 38ab508 to d3251d3 Compare July 30, 2026 09:32
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-6883 July 30, 2026 09:32 Destroyed
@serrrfirat
serrrfirat force-pushed the codex/ws1-hermetic-suite branch from d3251d3 to 608f8cf Compare July 30, 2026 09:33
@serrrfirat
serrrfirat force-pushed the codex/ws1-hermetic-suite branch from 546eb1b to 62b6375 Compare July 30, 2026 14:43
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-6883 July 30, 2026 14:43 Destroyed
@serrrfirat
serrrfirat marked this pull request as ready for review July 30, 2026 14:45
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@ironloopai

ironloopai Bot commented Jul 30, 2026 •

Copy link
Copy Markdown
Contributor

🔎 Review · PR #6883

🟢 Completed · Review submitted

1 actionable findings →

Reviewed the complete trusted base-to-head comparison across all 20 changed files. The hermetic suite has one credential-isolation gap: agent sockets remain available inside guarded test processes. No other material correctness, CI-wiring, or test-fixture defects were identified.

Automatic · PR opened · attempt 1 of 3 · completed in 1m 56s

Run details
  • Repository: nearai/ironclaw
  • Base: main at a643292
  • Head: codex/ws1-hermetic-suite at 62b6375
  • Created: Jul 30, 2026, 2:50 PM UTC
  • Updated: Jul 30, 2026, 2:52 PM UTC
  • Run: 3e7e864a-09fd-444f-a2e9-c783695dafe6
  • Latest attempt: 1 · Completed · 5b91db19-a914-43a4-a7c8-09d514485030

@ironloopai ironloopai 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 complete · PR #6883

💬 1 finding

Reviewed the complete trusted base-to-head comparison across all 20 changed files. The hermetic suite has one credential-isolation gap: agent sockets remain available inside guarded test processes. No other material correctness, CI-wiring, or test-fixture defects were identified.

Findings

  1. 🟠 Medium · Hermetic tests retain access to ambient credential-agent sockets — scripts/ci/run-hermetic-test-process.sh:52-68
    Details are attached to the relevant diff.
Validation and technical details
  • Inspected the complete refs/ironloop/base..refs/ironloop/head diff and surrounding workflow, runner, network-interposer, Rust-test, and Python E2E code.
  • Shell syntax checks passed for all changed CI scripts.
  • Python compilation passed for all changed E2E modules.
  • git diff --check passed for the trusted comparison.
  • The hermetic self-test could not execute in this review environment because rustc is unavailable; it exited at guard setup before running assertions.
  • Base: main
  • Head: codex/ws1-hermetic-suite at 62b6375
  • Run: 3e7e864a-09fd-444f-a2e9-c783695dafe6

Comment thread scripts/ci/run-hermetic-test-process.sh Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/reborn-tests.yml (1)

286-293: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Close the unguarded E2E test bypass.

webui-v2-smoke still runs pytest directly at lines 254-260. Only the later E2E stages are wrapped here, leaving a merge-gating test outside the scrubbed environment and network boundary. Route that validation invocation through run-hermetic-deterministic-suite.sh command too. As per coding guidelines, guardrails must enforce their stated guarantees; the suite documentation says every test stage runs through the hermetic process boundary.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/reborn-tests.yml around lines 286 - 293, Update the
webui-v2-smoke validation step to invoke pytest through
run-hermetic-deterministic-suite.sh command, matching the guarded E2E stages.
Ensure every test stage uses this hermetic process boundary and no direct pytest
invocation remains in that workflow path.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/ci/hermetic-network-guard.c`:
- Around line 297-339: Update guarded_write and guarded_writev to avoid calling
non_loopback_destination for regular files, pipes, stdout, and stderr; first
determine whether fd is a socket using a cached descriptor classification or
equivalent socket check, invalidating cached entries when descriptors close.
Only perform the peer lookup and violation handling for socket descriptors,
while preserving the existing platform-specific write/writev dispatch.

In `@scripts/ci/run-hermetic-test-process.sh`:
- Around line 50-69: Replace the denylist-based environment filtering in the
env_args construction loop with an explicit allowlist of variables required by
the hermetic toolchain, including PATH, CC, CARGO_*, RUSTUP_*, RUNNER_*, CI,
TERM, and LD_LIBRARY_PATH. Unset every other inherited variable by default,
while preserving the existing sabotage=env bypass and explicitly retaining only
the documented test-control variables needed by the script.
- Around line 125-136: The hermetic runner must not require Rust for non-Rust
stages. In scripts/ci/run-hermetic-test-process.sh lines 125-136, always add
IRONCLAW_HERMETIC_NETWORK_GUARD_LIBRARY to env_args, but derive and add the
CARGO_TARGET_*_RUNNER entry only when command -v rustc succeeds; in
.github/workflows/code_style.yml line 236, make no direct change if this guarded
runner removes the dependency, otherwise add an explicit Rust toolchain setup
for the static-checks job.

In `@tests/e2e/hermetic_process.py`:
- Around line 32-36: Update the macOS branch in the preload environment setup to
unconditionally assign DYLD_FORCE_FLAT_NAMESPACE the required value of "1"
instead of preserving an existing value via setdefault. Keep the existing
_prepend_preload behavior and Linux handling unchanged.

---

Outside diff comments:
In @.github/workflows/reborn-tests.yml:
- Around line 286-293: Update the webui-v2-smoke validation step to invoke
pytest through run-hermetic-deterministic-suite.sh command, matching the guarded
E2E stages. Ensure every test stage uses this hermetic process boundary and no
direct pytest invocation remains in that workflow path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: dc9009dd-5e80-4d51-933b-ac48bcf129dc

📥 Commits

Reviewing files that changed from the base of the PR and between 3cd9c73 and 62b6375.

📒 Files selected for processing (20)
  • .github/workflows/README.md
  • .github/workflows/code_style.yml
  • .github/workflows/reborn-e2e.yml
  • .github/workflows/reborn-tests.yml
  • crates/ironclaw_host_runtime/src/sandbox_process/connect.rs
  • crates/ironclaw_llm/src/github_copilot_auth.rs
  • crates/ironclaw_skills/src/catalog.rs
  • docs/internal/hermetic-deterministic-suite.md
  • scripts/ci/discover-reborn-package-crates.sh
  • scripts/ci/hermetic-network-guard.c
  • scripts/ci/hermetic-network-probe.c
  • scripts/ci/hermetic-network-runner.sh
  • scripts/ci/reborn-local-coverage-ratchet.sh
  • scripts/ci/run-hermetic-deterministic-suite.sh
  • scripts/ci/run-hermetic-test-process.sh
  • scripts/ci/test-hermetic-test-process.sh
  • tests/e2e/conftest.py
  • tests/e2e/hermetic_process.py
  • tests/e2e/reborn_webui_harness.py
  • tests/e2e/scenarios/test_reborn_responses_api.py

Comment thread scripts/ci/hermetic-network-guard.c
Comment thread scripts/ci/run-hermetic-test-process.sh
Comment thread scripts/ci/run-hermetic-test-process.sh
Comment thread tests/e2e/hermetic_process.py
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-6883 July 30, 2026 14:59 Destroyed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
scripts/ci/run-hermetic-test-process.sh (2)

72-86: 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Don’t propagate host Cargo/Rustup directories into the hermetic shell.

Lines 72-86 derive CARGO_HOME and RUSTUP_HOME from ambient values or the original $HOME, then re-export them after HOME/XDG roots move under hermetic_root. Wrapped tests can read/write host toolchain/install and registry cache files, including ~/.cargo/credentials.toml. Reuse dependency state outside this boundary or provide sanitized/read-only copies and test that contract explicitly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/ci/run-hermetic-test-process.sh` around lines 72 - 86, The hermetic
test setup must not derive or re-export host Cargo and Rustup directories.
Update the environment initialization around original_home, cargo_home, and
rustup_home so CARGO_HOME and RUSTUP_HOME point only to sanitized hermetic
locations or are omitted, while preserving any intentional dependency reuse
through explicit read-only copies outside the host paths.

52-69: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Make environment enumeration multiline-safe.

Lines 52-69 parse env output with line-delimited reads, so a value containing \nPATH=... is seen as a variable name and can be -ued. Use exported names/NUL-delimited input and add a self-test case with ambient env containing a multiline value.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/ci/run-hermetic-test-process.sh` around lines 52 - 69, Update the
environment enumeration loop to consume exported variable names using a
NUL-delimited, multiline-safe source instead of parsing line-delimited env
output, while preserving the existing case-based allowlist and unset rules. Add
a self-test covering an ambient exported variable whose value contains a newline
and text resembling another variable assignment, verifying that only the
intended variable is unset.

Source: Coding guidelines

♻️ Duplicate comments (2)
scripts/ci/run-hermetic-test-process.sh (2)

57-69: 🔒 Security & Privacy | 🟠 Major

Replace the denylist with an allowlist.

PERPLEXITY_KEY, DEEPSEEK_APIKEY, HF_TOKEN_FILE, SSH_AUTH_SOCK, GPG_AGENT_INFO, BASH_ENV, and mutable-path overrides such as CARGO_TARGET_DIR do not match these cases and remain available to the guarded process. That permits ambient credential/agent access, inherited shell startup code, and writes outside the hermetic root. Build the child environment from the minimal toolchain/test-control allowlist and add fixtures for unlisted providers and agent variables.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/ci/run-hermetic-test-process.sh` around lines 57 - 69, Replace the
environment-variable denylist in the shell script’s case statement with an
explicit allowlist containing only the minimal toolchain and test-control
variables required by the guarded process. Ensure variables such as
PERPLEXITY_KEY, DEEPSEEK_APIKEY, HF_TOKEN_FILE, SSH_AUTH_SOCK, GPG_AGENT_INFO,
BASH_ENV, and CARGO_TARGET_DIR are excluded by default, and add fixtures
covering unlisted providers, agent variables, startup hooks, and mutable-path
overrides.

126-137: 🩺 Stability & Availability | 🟠 Major

Make Rust runner wiring conditional on Rust availability.

The suite routes Python, frontend, QA, and E2E stages through this wrapper, but every normal invocation executes rustc -vV first. On a runner without Rust, non-Rust commands fail before they start. Export the native guard library unconditionally and derive CARGO_TARGET_*_RUNNER only when command -v rustc succeeds.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/ci/run-hermetic-test-process.sh` around lines 126 - 137, Update the
environment setup around cargo_runner_key so
IRONCLAW_HERMETIC_NETWORK_GUARD_LIBRARY is added unconditionally, while rustc
host-triple detection and CARGO_TARGET_*_RUNNER wiring occur only when command
-v rustc succeeds. Preserve the existing sabotage network condition and failure
handling for available Rust installations, but allow non-Rust stages to run
without rustc.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@scripts/ci/run-hermetic-test-process.sh`:
- Around line 72-86: The hermetic test setup must not derive or re-export host
Cargo and Rustup directories. Update the environment initialization around
original_home, cargo_home, and rustup_home so CARGO_HOME and RUSTUP_HOME point
only to sanitized hermetic locations or are omitted, while preserving any
intentional dependency reuse through explicit read-only copies outside the host
paths.
- Around line 52-69: Update the environment enumeration loop to consume exported
variable names using a NUL-delimited, multiline-safe source instead of parsing
line-delimited env output, while preserving the existing case-based allowlist
and unset rules. Add a self-test covering an ambient exported variable whose
value contains a newline and text resembling another variable assignment,
verifying that only the intended variable is unset.

---

Duplicate comments:
In `@scripts/ci/run-hermetic-test-process.sh`:
- Around line 57-69: Replace the environment-variable denylist in the shell
script’s case statement with an explicit allowlist containing only the minimal
toolchain and test-control variables required by the guarded process. Ensure
variables such as PERPLEXITY_KEY, DEEPSEEK_APIKEY, HF_TOKEN_FILE, SSH_AUTH_SOCK,
GPG_AGENT_INFO, BASH_ENV, and CARGO_TARGET_DIR are excluded by default, and add
fixtures covering unlisted providers, agent variables, startup hooks, and
mutable-path overrides.
- Around line 126-137: Update the environment setup around cargo_runner_key so
IRONCLAW_HERMETIC_NETWORK_GUARD_LIBRARY is added unconditionally, while rustc
host-triple detection and CARGO_TARGET_*_RUNNER wiring occur only when command
-v rustc succeeds. Preserve the existing sabotage network condition and failure
handling for available Rust installations, but allow non-Rust stages to run
without rustc.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0b00804b-4700-4bc3-8c35-21959523a157

📥 Commits

Reviewing files that changed from the base of the PR and between 62b6375 and f0b3c40.

📒 Files selected for processing (2)
  • scripts/ci/run-hermetic-test-process.sh
  • scripts/ci/test-hermetic-test-process.sh

@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-6883 July 30, 2026 15:36 Destroyed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/e2e/hermetic_process.py (1)

29-34: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Fail closed when the guard library is empty.

An empty IRONCLAW_HERMETIC_NETWORK_GUARD_LIBRARY passes this check, then _prepend_preload() writes an empty loader value; nested E2E processes run without network enforcement. Reject whitespace/empty configuration instead of silently proceeding.

Proposed fix
     guard_library = source_env.get("IRONCLAW_HERMETIC_NETWORK_GUARD_LIBRARY")
     if guard_library is None:
         return
+    if not guard_library.strip():
+        raise ValueError("Hermetic network guard library must be non-empty")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/hermetic_process.py` around lines 29 - 34, Update the guard_library
validation in the hermetic process setup to treat empty or whitespace-only
IRONCLAW_HERMETIC_NETWORK_GUARD_LIBRARY values as invalid and fail closed before
calling _prepend_preload(). Preserve the existing behavior for a valid library
path and the non-macOS flow.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@tests/e2e/hermetic_process.py`:
- Around line 29-34: Update the guard_library validation in the hermetic process
setup to treat empty or whitespace-only IRONCLAW_HERMETIC_NETWORK_GUARD_LIBRARY
values as invalid and fail closed before calling _prepend_preload(). Preserve
the existing behavior for a valid library path and the non-macOS flow.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1e2f0a01-c394-4e4f-9aac-b21ab7084ad7

📥 Commits

Reviewing files that changed from the base of the PR and between f0b3c40 and 701f093.

📒 Files selected for processing (9)
  • .github/workflows/reborn-e2e.yml
  • docs/internal/hermetic-deterministic-suite.md
  • scripts/ci/hermetic-network-guard.c
  • scripts/ci/hermetic-network-probe.c
  • scripts/ci/hermetic-network-runner.sh
  • scripts/ci/run-hermetic-deterministic-suite.sh
  • scripts/ci/run-hermetic-test-process.sh
  • scripts/ci/test-hermetic-test-process.sh
  • tests/e2e/hermetic_process.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
scripts/ci/test-hermetic-test-process.sh (1)

70-73: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Assert CARGO_TARGET_DIR is inside the hermetic root.

Lines [70]-[73] reject only the seeded /developer/target value and otherwise accept any path ending in /target; /tmp/target or /developer/other/target would pass. This can let a regression leak Cargo state outside the isolated root without failing the self-test.

As per path instructions, CI guardrail behavior requires regression coverage that validates the enforced boundary.

Suggested fix
-      if [[ "${CARGO_TARGET_DIR}" != */target || "${CARGO_TARGET_DIR}" == "/developer/target" ]]; then
-        echo "ambient CARGO_TARGET_DIR leaked into the hermetic process" >&2
-        exit 40
-      fi
+      case "${CARGO_TARGET_DIR}" in
+        "${IRONCLAW_HERMETIC_ROOT}"/*) ;;
+        *)
+          echo "CARGO_TARGET_DIR is outside the hermetic root: ${CARGO_TARGET_DIR}" >&2
+          exit 40
+          ;;
+      esac
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/ci/test-hermetic-test-process.sh` around lines 70 - 73, Update the
CARGO_TARGET_DIR validation in the hermetic process self-test to require the
resolved path to be within the hermetic root, rather than merely ending in
/target or excluding /developer/target. Preserve rejection of external paths
such as /tmp/target and /developer/other/target, and add regression coverage
exercising both an in-root value and representative out-of-root values.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@scripts/ci/test-hermetic-test-process.sh`:
- Around line 70-73: Update the CARGO_TARGET_DIR validation in the hermetic
process self-test to require the resolved path to be within the hermetic root,
rather than merely ending in /target or excluding /developer/target. Preserve
rejection of external paths such as /tmp/target and /developer/other/target, and
add regression coverage exercising both an in-root value and representative
out-of-root values.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 2e499f87-37f4-4643-8c40-90912e831167

📥 Commits

Reviewing files that changed from the base of the PR and between 701f093 and a82720d.

📒 Files selected for processing (2)
  • scripts/ci/test-hermetic-test-process.sh
  • tests/e2e/hermetic_process.py

@serrrfirat

Copy link
Copy Markdown
Collaborator Author

Final maintainer readiness audit — head a82720d26

  • Ready/non-draft, mergeable, 0 behind / 22 ahead of current origin/main; clean worktree and git diff --check clean.
  • Exact-head CI: 59 passed, 0 failed, 5 intentionally skipped (including complete Reborn WebUI/provider replay and Railway preview).
  • Local closeout: hermetic self-test; sabotage exits env=31, temp=32, python-seed=34, network=1; frontend 111 files / 914 tests; current provider evidence 108 tests; representative guarded Rust; Rust-less guarded command; fmt, YAML, workflow contracts, safety scans.
  • Review follow-through: all inline and outside-diff findings verified; valid issues fixed; 0 unresolved review threads.
  • Test Strategy card is complete with compatibility, rollback, blast radius, exact commands, and checkbox-to-test mapping.

@serrrfirat
serrrfirat merged commit 9698704 into main Jul 30, 2026
64 checks passed
@serrrfirat
serrrfirat deleted the codex/ws1-hermetic-suite branch July 30, 2026 18:57
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-6883 July 30, 2026 18:57 Destroyed
@ironclaw-ci ironclaw-ci Bot mentioned this pull request Jul 30, 2026
l3ocifer pushed a commit to l3ocifer/frick-ironclaw that referenced this pull request Sep 3, 2026
* ci(test): enforce hermetic deterministic suite

* fix(ci): close hermetic process guard gaps

* fix(ci): preserve frontend package-manager selection

* fix(ci): prepare frontend dependencies outside guard

* fix(ci): avoid races in network interposer lookup

* fix(ci): prefetch WebUI build toolchain for Cargo

* test(ci): keep failure probes on loopback

* test(ci): isolate Copilot refresh failures

* fix(ci): preserve isolated Playwright toolchain

* fix(ci): close connected UDP write bypasses

* fix(ci): expose Linux sendmmsg probe API

* fix(ci): allow IPv4-mapped loopback fakes

* fix(ci): preserve guard and one-time setup

* fix(ci): prepare coverage WebUI inputs once

* fix(ci): prepare QA WebUI inputs once

* fix(ci): preserve prepared Corepack cache

* fix(ci): prefetch hermetic Postgres image

* fix(ci): prepare direct WebUI crate bucket

* fix(ci): share Reborn package discovery

* fix(ci): preserve explicit Emulate fixture bearer

* fix(ci): close hermetic review gaps

* fix(e2e): reject empty hermetic guard path

This branch was successfully deployed

No deployments
ironclaw-ci-preview / ironclaw-pr-6883 — a82720d2 Deployed Jul 30, 2026 by railway-app[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contributor: core 20+ merged PRs risk: medium Business logic, config, or moderate-risk modules scope: ci CI/CD workflows scope: docs Documentation size: XL 500+ changed lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant