1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
//! `cargo package` invocation for the determinism harness.
//!
//! Allow-listed entry point for `Command::new("cargo")` calls that drive
//! the `.crate` packaging side of the determinism harness. The harness
//! itself lives in `crates/cli/` which is forbid-listed for direct
//! subprocess spawn (see `.claude/rules/module-boundaries.md`); this
//! module owns the call site so the security surface stays small.
//!
//! Why `cargo package` and not `cargo publish`: `package` is the
//! offline-equivalent of `publish` minus the registry upload. It writes
//! the same `.crate` tarball that would have been pushed, so probing it
//! for byte-stability surfaces packaging non-determinism (mtimes, tar
//! ordering, `.cargo_vcs_info.json` content) without any network reach.
//!
//! Known non-determinism the harness will detect when this stage runs:
//!
//! - **File mtimes inside the tar**: cargo canonicalizes these to
//! `SOURCE_DATE_EPOCH` since cargo 1.74 — the harness exports it via
//! its hermetic env block so the workaround takes effect.
//! - **`.cargo_vcs_info.json` contents**: cargo writes the current git
//! sha + dirty flag + timestamp. The harness's per-run worktree is
//! detached at the same commit, so the sha line is stable; the dirty
//! flag depends on whether `Cargo.lock` was touched between checkout
//! and `cargo package`. The harness shells `cargo package` from a
//! fresh worktree so the dirty flag should be `false` on both runs.
//! - **tar member ordering**: cargo sorts entries since 1.74; no
//! per-call workaround needed.
//!
//! When the harness detects drift after these workarounds, the failure
//! is a real regression in cargo's reproducibility story — surface the
//! drift via the report and don't silently pass.
use ;
use HashMap;
use Path;
use crateStageLogger;
use Command;
/// Run `cargo package --workspace --no-verify --allow-dirty
/// --no-metadata` against `manifest_dir` with the supplied isolated env.
///
/// Pinning args:
/// - `--workspace` — assemble every workspace member's `.crate` in one
/// invocation. For a non-workspace single-crate repo cargo accepts
/// this flag and packages the single crate (verified against cargo
/// 1.95). Single-call avoids per-crate manifest enumeration in the
/// harness.
/// - `--no-verify` — skip the compile-then-test pass cargo would
/// otherwise run inside the unpacked `.crate`. The harness only
/// cares about the packaging stage's byte output, not whether the
/// packaged bytes themselves compile (the prior `build` stage
/// already covered that).
/// - `--allow-dirty` — the per-run worktree may carry a `Cargo.lock`
/// diff from the harness's lockfile generation, or the harness's
/// `--remap-path-prefix` `RUSTFLAGS` may surface as a worktree
/// modification; the dirty check would otherwise abort with a hard
/// error that has nothing to do with packaging determinism.
/// - `--no-metadata` — suppress the warning cargo emits when a
/// `Cargo.toml` is missing `description` / `license` / `repository`.
/// Minimal fixture crates the harness's integration tests
/// bootstrap may legitimately lack these; the harness only cares
/// about byte-stability of whatever cargo emits.
///
/// `cargo_target_dir` is set as `CARGO_TARGET_DIR` (already exported
/// via `env`) so the `.crate` lands at
/// `<cargo_target_dir>/package/<name>-<version>.crate` — the location
/// the harness's discover step walks to pick up the artifacts.
///
/// `env` carries the harness's hermetic env block —
/// `SOURCE_DATE_EPOCH`, `CARGO_HOME`, `HOME`, `RUSTFLAGS`, `PATH`,
/// etc. The function `env_clear`s the child first so host env vars
/// cannot perturb the packaging step.
///
/// `log` governs cargo's packaging chatter: at default verbosity the
/// `Packaging`/`Archiving` lines are captured silently (surfaced only on
/// failure), and at `-v` they stream live — the same `status` vs `verbose`
/// register every other subprocess obeys.
///
/// Returns `Ok(())` on cargo exit 0; bubbles a context-wrapped error
/// otherwise so the harness's per-run loop can attach the run number.
/// Run `cargo package -p <crate_name> --no-verify --allow-dirty
/// --no-metadata` against `manifest_dir` with the supplied isolated env.
///
/// Same flag rationale as [`package_workspace`], but scoped to a single
/// crate via `-p` so the publish path's content-vs-version poison guard can
/// reproduce the exact `.crate` tarball one crate's `cargo publish` would
/// upload (the guard sha256s it and compares against crates.io's recorded
/// `cksum`). `--workspace` cannot be used here: a per-crate publish in a
/// mixed-cadence workspace must package only the crate being published, at
/// its own version, into `<CARGO_TARGET_DIR>/package/<name>-<version>.crate`.
///
/// `env` carries the hermetic block (`CARGO_TARGET_DIR`, `PATH`, `HOME`,
/// `CARGO_HOME`, ...); the child is `env_clear`ed first so host env vars cannot
/// perturb the packaged bytes. The poison guard deliberately does NOT pass
/// `SOURCE_DATE_EPOCH`: cargo does not consult it for the `.crate` tarball, so
/// identical source at the same commit reproduces the published bytes without
/// it (the determinism-harness path [`package_workspace`] sets it for its own
/// hermetic env block, which is harmless but not what makes the `.crate`
/// reproducible).