Skip to main content

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}