Skip to content

M1.c U1a: the probe build runs a concrete, identified toolchain under a constructed environment - #12496

Closed
briansrls wants to merge 1 commit into
m1c-native-compiler-reusefrom
m1c-u1a-hermetic-toolchain
Closed

briansrls wants to merge 1 commit into
m1c-native-compiler-reusefrom
m1c-u1a-hermetic-toolchain

Conversation

@briansrls

Copy link
Copy Markdown
Contributor

M1.c U1a. Stacked on #12474 (U2); review that first. M1.c is native-compiler cross-run reuse, whose delivery the operator assigned to this lane on 2026-09-27, with U0–U2 admitted against pinned base eb5987e38f5.

M1.c will key a stored compiler on the inputs that produce its bytes. So every input the probe build can see must either be in the key or be unable to reach the build. Before this PR:

  • the build inherited the whole process environment;
  • it ran whatever $CARGO or cargo on PATH resolved at spawn time;
  • RUSTC was usually a rustup proxy.

As a result, an ambient CARGO_PROFILE_*, CARGO_INCREMENTAL, RUSTC_BOOTSTRAP or CC could change the executable under an unchanged key, and the receipt named the proxy rather than the compiler that ran.

Changes (v1_compiler.emitted_closure_compile_host)

  • Constructed environment. The environment is cleared and rebuilt from the exact names in v2.extdeps.languages.rust rust_host_build_environment: PATH, HOME, TMPDIR, CARGO_HOME, RUSTUP_HOME, RUSTUP_TOOLCHAIN. A SHA-256 is taken over the length-framed names and values. The identity probes run under the same environment.
  • Concrete toolchain. The entry compiler (RUSTC or PATH) is asked --print sysroot. The build then runs that sysroot's own cargo, bound to that sysroot's own rustc. Both are identified (-vV / -Vv) from the crate's directory. A sysroot with no cargo refuses with ProbeToolchainUnresolved.
  • Configuration observed. Every cargo configuration file that discovery would read (crate ancestors' .cargo/config[.toml], then CARGO_HOME) is recorded with a streamed digest. An unreadable one refuses with CargoConfigurationUnreadable.
  • One streamed-digest home. The digest now lives in sha256_feed_file / sha256_file_streamed, moved here from the native lane runner, which reads through it.
  • Printed until the receipt carries them. The facts print on the route's new build inputs line. U7 carries them into the receipt, and U3 reads them into the key.

RUSTFLAGS and admission are unchanged. The cargo spawn and the self-host receipt now name the real sysroot rustc rather than the proxy.

Controls

control kind result
exact-name allowlist, asserted on the constructed VALUE: planted CARGO_PROFILE_RELEASE_OPT_LEVEL, CARGO_INCREMENTAL, RUSTC_BOOTSTRAP, CC, CARGO_BUILD_TARGET, RUSTFLAGS, CARGO_HOME_EXTRA all excluded; the digest changes with an admitted value and not with a foreign one unit pass
the spawn runs the toolchain's cargo even with CARGO=/planted/cargo unit pass
configuration in an ancestor and in CARGO_HOME observed with digests; a mode-000 file refuses unit pass
a sysroot without cargo refuses unit pass
wet: one tiny crate built at one path, with and without planted CARGO_PROFILE_RELEASE_OPT_LEVEL=0, CARGO_PROFILE_RELEASE_DEBUG=true, CARGO_INCREMENTAL=1 → identical bytes #[ignore] receipt pass
RED for the wet control: env_clear locally removed → the bytes differ (4399e0… vs 339f80…) local revert red, as required
clippy -p v1-compiler --all-targets -D warnings lint clean
emit-compile host + runner tests unit 43 passed, 3 ignored
tools.seed_growth_change_population main over the committed diff (U2+U1a) diagnostic exit 0

Real path (the pairing obligation). gunbc test //gunbc/instruments:self-host with the U1a seed, on a git-archive snapshot of this commit, exit 0 in 19m04s:

  • the build ran under argv[0]=<sysroot>/bin/cargo and compiler=<sysroot>/bin/rustc, with environment_names=["HOME","PATH"] and cargo_configuration=[];
  • closure=18eae89c…f070 is unchanged;
  • the red was established, and both door controls held.

binary=f2b32eb5… still differs from another run's (960f4ee6…), because build paths reach the bytes. That is U1c.

Stated divergence (not a fork)

v1_compiler.v1_interpreter emit_host_constructed_build_environment, emit_host_cargo_configuration_digest and observe_tool_identity answer the same questions for the emit-host transport, but with a 64-bit non-cryptographic hash and whole-file reads. This host needs SHA-256 over streamed bytes for a cross-run key.

Trigger for unifying them: extdeps.realization.emit_on_demand_host ResolvedBuildContext moving to a cryptographic std.content_hash family. The admitted-name list is a seed copy of the .dag row. Its executing drift control is the U7 admission clause, and until then it rests on review diligence. This is recorded in gunbc.native_compiler_reuse_seed_growth.

Not in this PR

🤖 Generated with Claude Code

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-28T02:45:36.204058Z 31744cb PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 31744cb4a0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1137 to +1141
if let Some(cargo_home) =
value("CARGO_HOME").or_else(|| value("HOME").map(|h| h.join(".cargo")))
{
candidates.push(cargo_home.join("config"));
candidates.push(cargo_home.join("config.toml"));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Resolve relative CARGO_HOME from the crate directory

When CARGO_HOME is relative, Cargo resolves it from the child command's working directory (crate_dir), but this observer resolves the candidate against the host process's current directory. Cargo 1.93 accepts this form and reads <crate_dir>/<CARGO_HOME>/config.toml; consequently, changing that file can change the executable while this code continues to report no configuration and the same environment digest. Resolve relative CARGO_HOME against crate_dir before hashing its configuration.

Useful? React with 👍 / 👎.

Comment on lines +416 to +420
let invocation_cargo_path = invocation.cargo_path.clone();
let invocation_cargo_identity = invocation.cargo_identity.clone();
let invocation_environment_names = invocation.environment_names.clone();
let invocation_environment_digest = invocation.environment_digest.clone();
let invocation_cargo_configuration = invocation.cargo_configuration.clone();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Capture build inputs from the command that actually runs

When an admitted environment value, Cargo configuration, or toolchain changes between this preflight resolution and the build, these copied fields describe the first resolution, while run_cargo below independently calls probe_cargo_command again and executes the second. The new build inputs line can therefore report paths and digests for a command that never ran, defeating its provenance purpose; carry the already-bound command and invocation into execution, or return the actual invocation from run_cargo.

Useful? React with 👍 / 👎.

… a constructed environment

M1.c keys a stored compiler on the inputs that produce its bytes, so nothing the
build can see may sit outside the key:
- The environment is cleared and rebuilt from the exact names in
  v2.extdeps.languages.rust rust_host_build_environment (PATH, HOME, TMPDIR,
  CARGO_HOME, RUSTUP_HOME, RUSTUP_TOOLCHAIN), with a SHA-256 over the
  length-framed names and values. Ambient CARGO_PROFILE_*, CARGO_INCREMENTAL,
  RUSTC_BOOTSTRAP, CC and the like can no longer reach the build.
- The entry compiler (RUSTC or PATH, usually a rustup proxy) is asked for its
  sysroot. The build then runs that sysroot's own cargo, never $CARGO or a PATH
  lookup at spawn time, and binds RUSTC to that sysroot's own rustc. Both are
  identified (-vV / -Vv) under the build's environment, from the crate's
  directory.
- Every cargo configuration file discovery would read is recorded with a
  streamed digest; an unreadable one refuses.
- The streamed digest has one home (emitted_closure_compile_host
  sha256_feed_file), and the native lane runner reads through it.

The facts print on the route's build-inputs line until U7 carries them in the
receipt.

Controls: exact-name allowlist asserted on the constructed value; the spawn runs
the toolchain's cargo even with CARGO planted; configuration observed, and an
unreadable file refuses; a sysroot without cargo refuses. Wet (operator
receipt): the same crate built at one path with and without planted
CARGO_PROFILE_RELEASE_OPT_LEVEL/DEBUG and CARGO_INCREMENTAL gives identical
bytes. RED: with env_clear removed, the bytes differ.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant