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 /// Wall-clock milliseconds the rustc invocation took — what a cache hit
81 /// on this artifact saves a consumer. Records captured before the field
82 /// existed carry no timing and count as zero.
83 #[serde(default)]
84 pub compile_millis: u64,
85}
86
87/// One dependency edge of a captured invocation: which `--extern` it was
88/// given and which stable identity that extern resolved to.
89#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
90pub struct CapturedDependencyIdentity {
91 /// The crate name the `--extern` flag names.
92 pub crate_name: String,
93 /// The artifact path the `--extern` flag points at.
94 pub path: PathBuf,
95 /// The full stable compile key of that dependency's own invocation.
96 pub compile_key: String,
97 /// The 16-hex stable `-C metadata` prefix of that dependency.
98 pub stable_c_metadata: String,
99}
100
101/// The kind of artifact one captured rustc output is.
102#[derive(
103 Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
104)]
105pub enum CapturedRustcOutputKind {
106 /// A `lib*.rlib` static Rust crate archive.
107 Rlib,
108 /// A `lib*.rmeta` metadata-only output.
109 Rmeta,
110 /// A `lib*.{so,dylib,dll}` dynamic library output.
111 DynamicLibrary,
112}
113
114/// One file rustc wrote for a captured invocation.
115#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
116pub struct CapturedRustcOutput {
117 /// Which kind of artifact this output is.
118 pub kind: CapturedRustcOutputKind,
119 /// Where rustc wrote it inside the invocation's `--out-dir`.
120 pub path: PathBuf,
121 /// The frozen copy the wrapper took at rustc exit, when one exists.
122 #[serde(default)]
123 pub snapshot_path: Option<PathBuf>,
124 /// SHA-256 of the bytes at `path`, computed by the wrapper the moment
125 /// rustc exited. The scan re-hashes the file it is about to plan and
126 /// requires equality, so an output rewritten after rustc finished can
127 /// never reach the plan.
128 pub sha256: String,
129}