stow_types/capture.rs
1//! Rustc capture records shared between the capture wrapper and the build
2//! stage.
3//!
4//! The wrapper runs inside the untrusted sandbox and hands each record to the
5//! host over heel's IPC channel, so a record on the host is the host's own
6//! copy of what rustc did — never a file the sandbox could rewrite after the
7//! fact. Keeping the type here means the wrapper side and the collector side
8//! serialize exactly the same shape.
9
10use std::path::PathBuf;
11
12use crate::platform::Profile;
13
14/// One rustc invocation the capture wrapper observed, recorded as it exited.
15///
16/// Every cargo unit routed through the wrapper produces a record — not only
17/// the ones whose outputs are restorable artifacts — so that a record forged
18/// inside the sandbox collides with the genuine one the wrapper sent. An
19/// invocation with no `-C metadata` is not a cargo unit (a build script or
20/// cargo itself probing rustc); it runs unrecorded, so an empty `c_metadata`
21/// arriving on the channel can only be a forgery.
22#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
23pub struct CapturedRustcArtifact {
24 /// The `--crate-name` rustc was invoked with.
25 pub crate_name: String,
26 /// The crate version this invocation actually compiled, read from the
27 /// registry source path.
28 ///
29 /// Recorded because a dependency graph can legitimately contain two
30 /// versions of one crate (bitflags 1.3.2 alongside 2.5.0, say), and they
31 /// share a library target name. Attributing captures by name alone let one
32 /// version's compiled bytes be registered under the other's identity.
33 #[serde(default)]
34 pub crate_version: Option<String>,
35 /// The `--crate-type` list rustc was invoked with.
36 pub crate_types: Vec<String>,
37 /// The `--emit` list rustc was invoked with.
38 pub emit: Vec<String>,
39 /// The `--target` triple rustc was invoked with, when cargo passed one.
40 pub target: Option<String>,
41 /// Full compile key of this invocation: the 64-hex blake3 stable identity
42 /// for registry crates, or cargo's ephemeral `-C metadata` for
43 /// non-registry roots. `c_metadata` is its 16-hex stable prefix.
44 ///
45 pub compile_key: String,
46 /// Cargo's `-C metadata` for this invocation, or its stable prefix when
47 /// the invocation was rewritten under a stable identity. Never empty in a
48 /// genuine record.
49 pub c_metadata: String,
50 /// Cargo's `-C extra-filename` for this invocation.
51 pub extra_filename: String,
52 /// Resolved dependency identities for restorable units; always empty for
53 /// observed ones (nothing downstream resolves their externs).
54 pub dependencies: Vec<CapturedDependencyIdentity>,
55 /// The effective rustc profile (`opt-level`, `debuginfo`, …) of this
56 /// invocation.
57 pub profile: Profile,
58 /// Cargo's `--out-dir` for this invocation; empty when the unit took
59 /// none.
60 pub out_dir: PathBuf,
61 /// The `CARGO_TARGET_DIR` the invocation ran under. The same unit is
62 /// legitimately compiled once per cargo phase, and the phase's target dir
63 /// is what tells those records apart.
64 #[serde(default)]
65 pub target_dir: PathBuf,
66 /// Cargo's `OUT_DIR` env for crates with a build script: the exact
67 /// per-invocation build dir, recorded so native-artifact capture never
68 /// has to guess which `{crate}-{hash}` directory belongs to this
69 /// invocation.
70 #[serde(default)]
71 pub build_script_out_dir: Option<PathBuf>,
72 /// The outputs rustc wrote, each with the digest taken as rustc exited.
73 pub outputs: Vec<CapturedRustcOutput>,
74 /// `true` when this unit's outputs are artifacts the pipeline plans and
75 /// publishes; `false` for cargo units that produce nothing publishable
76 /// (build-script compiles, binaries, tests), which are recorded purely so
77 /// a forged record has something to collide with.
78 #[serde(default)]
79 pub restorable: bool,
80 /// `true` when the unit was served from a verified published artifact
81 /// instead of compiled: no rustc ran, so nothing is planned, but the
82 /// record still carries the artifact's identity and output paths so
83 /// dependents can resolve their `--extern` edges against it and the
84 /// publish stage can check the claim against the signed index.
85 #[serde(default)]
86 pub consumed: bool,
87 /// Wall-clock milliseconds the rustc invocation took — what a cache hit
88 /// on this artifact saves a consumer. Records captured before the field
89 /// existed carry no timing and count as zero.
90 #[serde(default)]
91 pub compile_millis: u64,
92}
93
94/// One dependency edge of a captured invocation: which `--extern` it was
95/// given and which stable identity that extern resolved to.
96#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
97pub struct CapturedDependencyIdentity {
98 /// The crate name the `--extern` flag names.
99 pub crate_name: String,
100 /// The artifact path the `--extern` flag points at.
101 pub path: PathBuf,
102 /// The full stable compile key of that dependency's own invocation.
103 pub compile_key: String,
104 /// The 16-hex stable `-C metadata` prefix of that dependency.
105 pub stable_c_metadata: String,
106}
107
108/// The kind of artifact one captured rustc output is.
109#[derive(
110 Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
111)]
112pub enum CapturedRustcOutputKind {
113 /// A `lib*.rlib` static Rust crate archive.
114 Rlib,
115 /// A `lib*.rmeta` metadata-only output.
116 Rmeta,
117 /// A `lib*.{so,dylib,dll}` dynamic library output.
118 DynamicLibrary,
119}
120
121/// One file rustc wrote for a captured invocation.
122#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
123pub struct CapturedRustcOutput {
124 /// Which kind of artifact this output is.
125 pub kind: CapturedRustcOutputKind,
126 /// Where rustc wrote it inside the invocation's `--out-dir`.
127 pub path: PathBuf,
128 /// The frozen copy the wrapper took at rustc exit, when one exists.
129 #[serde(default)]
130 pub snapshot_path: Option<PathBuf>,
131 /// SHA-256 of the bytes at `path`, computed by the wrapper the moment
132 /// rustc exited. The scan re-hashes the file it is about to plan and
133 /// requires equality, so an output rewritten after rustc finished can
134 /// never reach the plan.
135 pub sha256: String,
136}