Skip to main content

allow_report/
contracts.rs

1pub const REPORT_SCHEMA_VERSION: u32 = 1;
2pub const REPORT_SCHEMA_ID: &str = "cargo-allow.report.v1";
3pub const RECEIPT_SCHEMA_VERSION: u32 = 1;
4pub const RECEIPT_SCHEMA_ID: &str = "cargo-allow.receipt.v1";
5pub const WORKLIST_SCHEMA_VERSION: u32 = 1;
6pub const WORKLIST_SCHEMA_ID: &str = "cargo-allow.worklist.v1";
7pub const LIST_SCHEMA_VERSION: u32 = 1;
8pub const LIST_SCHEMA_ID: &str = "cargo-allow.list.v1";
9pub const EXPLAIN_SCHEMA_VERSION: u32 = 1;
10pub const EXPLAIN_SCHEMA_ID: &str = "cargo-allow.explain.v1";
11pub const PRUNE_SCHEMA_VERSION: u32 = 1;
12pub const PRUNE_SCHEMA_ID: &str = "cargo-allow.prune.v1";
13pub const DOCTOR_SCHEMA_VERSION: u32 = 1;
14pub const DOCTOR_SCHEMA_ID: &str = "cargo-allow.doctor.v1";
15pub const PROPOSE_SCHEMA_VERSION: u32 = 1;
16pub const PROPOSE_SCHEMA_ID: &str = "cargo-allow.propose.v1";
17pub const ADD_SCHEMA_VERSION: u32 = 1;
18pub const ADD_SCHEMA_ID: &str = "cargo-allow.add.v1";
19pub const MIGRATE_SCHEMA_VERSION: u32 = 1;
20pub const MIGRATE_SCHEMA_ID: &str = "cargo-allow.migrate.v1";
21pub const SPEC_SYSTEM_SCHEMA_VERSION: u32 = 1;
22pub const SPEC_SYSTEM_SCHEMA_ID: &str = "cargo-allow.spec-system.v1";
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub struct ArtifactContract {
26    pub name: &'static str,
27    pub schema_id: &'static str,
28    pub schema_version: u32,
29    pub inventory_scanner: &'static str,
30    pub fixed_command: Option<&'static str>,
31}
32
33pub const ARTIFACT_STATUS_PASSED: &str = "passed";
34pub const ARTIFACT_STATUS_FAILED: &str = "failed";
35pub const ARTIFACT_STATUS_ERROR: &str = "error";
36pub const ARTIFACT_STATUSES: &[&str] = &[ARTIFACT_STATUS_PASSED, ARTIFACT_STATUS_FAILED];
37pub const RECEIPT_STATUSES: &[&str] = &[
38    ARTIFACT_STATUS_PASSED,
39    ARTIFACT_STATUS_FAILED,
40    ARTIFACT_STATUS_ERROR,
41];
42pub const RECEIPT_ENFORCEMENT_ADVISORY: &str = "advisory";
43pub const RECEIPT_ENFORCEMENT_ENFORCING: &str = "enforcing";
44
45pub const REPORT_COMMAND_AUDIT: &str = "audit";
46pub const REPORT_COMMAND_CHECK: &str = "check";
47pub const REPORT_COMMAND_DIFF: &str = "diff";
48pub const REPORT_COMMANDS: &[&str] = &[
49    REPORT_COMMAND_AUDIT,
50    REPORT_COMMAND_CHECK,
51    REPORT_COMMAND_DIFF,
52];
53pub const RECEIPT_COMMAND_CHECK: &str = "check";
54
55pub const INVENTORY_SCOPE_SOURCE_TREE: &str = "source_tree";
56pub const INVENTORY_SCANNER_SOURCE_SYNTAX: &str = "source_syntax";
57pub const INVENTORY_SCANNER_POLICY_MIGRATION: &str = "policy_migration";
58pub const INVENTORY_SCANNER_SOURCE_TREE_GRAPH: &str = "source_tree_graph";
59pub const INVENTORY_SOURCE_UNKNOWN: &str = "unknown";
60
61pub(crate) const ADD_ARTIFACT: ArtifactContract = ArtifactContract {
62    name: "add",
63    schema_id: ADD_SCHEMA_ID,
64    schema_version: ADD_SCHEMA_VERSION,
65    inventory_scanner: INVENTORY_SCANNER_SOURCE_SYNTAX,
66    fixed_command: Some("add"),
67};
68
69pub(crate) const DOCTOR_ARTIFACT: ArtifactContract = ArtifactContract {
70    name: "doctor",
71    schema_id: DOCTOR_SCHEMA_ID,
72    schema_version: DOCTOR_SCHEMA_VERSION,
73    inventory_scanner: INVENTORY_SCANNER_SOURCE_SYNTAX,
74    fixed_command: Some("doctor"),
75};
76
77pub(crate) const EXPLAIN_ARTIFACT: ArtifactContract = ArtifactContract {
78    name: "explain",
79    schema_id: EXPLAIN_SCHEMA_ID,
80    schema_version: EXPLAIN_SCHEMA_VERSION,
81    inventory_scanner: INVENTORY_SCANNER_SOURCE_SYNTAX,
82    fixed_command: Some("explain"),
83};
84
85pub(crate) const LIST_ARTIFACT: ArtifactContract = ArtifactContract {
86    name: "list",
87    schema_id: LIST_SCHEMA_ID,
88    schema_version: LIST_SCHEMA_VERSION,
89    inventory_scanner: INVENTORY_SCANNER_SOURCE_SYNTAX,
90    fixed_command: Some("list"),
91};
92
93pub(crate) const MIGRATE_ARTIFACT: ArtifactContract = ArtifactContract {
94    name: "migrate",
95    schema_id: MIGRATE_SCHEMA_ID,
96    schema_version: MIGRATE_SCHEMA_VERSION,
97    inventory_scanner: INVENTORY_SCANNER_POLICY_MIGRATION,
98    fixed_command: Some("migrate"),
99};
100
101pub(crate) const PROPOSE_ARTIFACT: ArtifactContract = ArtifactContract {
102    name: "propose",
103    schema_id: PROPOSE_SCHEMA_ID,
104    schema_version: PROPOSE_SCHEMA_VERSION,
105    inventory_scanner: INVENTORY_SCANNER_SOURCE_SYNTAX,
106    fixed_command: Some("propose"),
107};
108
109pub(crate) const PRUNE_ARTIFACT: ArtifactContract = ArtifactContract {
110    name: "prune",
111    schema_id: PRUNE_SCHEMA_ID,
112    schema_version: PRUNE_SCHEMA_VERSION,
113    inventory_scanner: INVENTORY_SCANNER_SOURCE_SYNTAX,
114    fixed_command: Some("prune"),
115};
116
117pub(crate) const RECEIPT_ARTIFACT: ArtifactContract = ArtifactContract {
118    name: "receipt",
119    schema_id: RECEIPT_SCHEMA_ID,
120    schema_version: RECEIPT_SCHEMA_VERSION,
121    inventory_scanner: INVENTORY_SCANNER_SOURCE_SYNTAX,
122    fixed_command: Some(RECEIPT_COMMAND_CHECK),
123};
124
125pub(crate) const REPORT_ARTIFACT: ArtifactContract = ArtifactContract {
126    name: "report",
127    schema_id: REPORT_SCHEMA_ID,
128    schema_version: REPORT_SCHEMA_VERSION,
129    inventory_scanner: INVENTORY_SCANNER_SOURCE_SYNTAX,
130    fixed_command: None,
131};
132
133pub(crate) const SPEC_SYSTEM_ARTIFACT: ArtifactContract = ArtifactContract {
134    name: "spec-system",
135    schema_id: SPEC_SYSTEM_SCHEMA_ID,
136    schema_version: SPEC_SYSTEM_SCHEMA_VERSION,
137    inventory_scanner: INVENTORY_SCANNER_SOURCE_TREE_GRAPH,
138    fixed_command: None,
139};
140
141pub(crate) const WORKLIST_ARTIFACT: ArtifactContract = ArtifactContract {
142    name: "worklist",
143    schema_id: WORKLIST_SCHEMA_ID,
144    schema_version: WORKLIST_SCHEMA_VERSION,
145    inventory_scanner: INVENTORY_SCANNER_SOURCE_SYNTAX,
146    fixed_command: Some("worklist"),
147};
148
149pub const ARTIFACT_CONTRACTS: &[ArtifactContract] = &[
150    ADD_ARTIFACT,
151    DOCTOR_ARTIFACT,
152    EXPLAIN_ARTIFACT,
153    LIST_ARTIFACT,
154    MIGRATE_ARTIFACT,
155    PROPOSE_ARTIFACT,
156    PRUNE_ARTIFACT,
157    RECEIPT_ARTIFACT,
158    REPORT_ARTIFACT,
159    SPEC_SYSTEM_ARTIFACT,
160    WORKLIST_ARTIFACT,
161];
162
163pub fn artifact_contract_for_schema_id(schema_id: &str) -> Option<ArtifactContract> {
164    ARTIFACT_CONTRACTS
165        .iter()
166        .copied()
167        .find(|contract| contract.schema_id == schema_id)
168}
169
170pub const CLAIM_BOUNDARY: &[&str] = &[
171    "source_tree_inventory",
172    "source_syntax_only",
173    "cargo_metadata_not_invoked",
174    "cargo_commands_not_invoked",
175    "rustc_not_invoked",
176    "clippy_not_invoked",
177    "build_scripts_not_executed",
178    "proc_macros_not_executed",
179    "macro_expansion_not_analyzed",
180    "macro_token_tree_contents_not_analyzed",
181    "type_information_not_analyzed",
182    "mir_not_analyzed",
183    "build_output_not_analyzed",
184    "control_flow_not_analyzed",
185    "data_flow_not_analyzed",
186    "external_evidence_tools_not_invoked",
187    "repository_code_not_executed",
188];
189
190pub const SCANNER_LIMITATIONS: &[&str] = &[
191    "cargo_metadata_not_invoked",
192    "cargo_commands_not_invoked",
193    "rustc_not_invoked",
194    "clippy_not_invoked",
195    "build_scripts_not_executed",
196    "proc_macros_not_executed",
197    "macro_expansion_not_analyzed",
198    "macro_token_tree_contents_not_analyzed",
199    "type_information_not_analyzed",
200    "mir_not_analyzed",
201    "build_output_not_analyzed",
202    "control_flow_not_analyzed",
203    "data_flow_not_analyzed",
204    "external_evidence_tools_not_invoked",
205    "repository_code_not_executed",
206];
207
208pub const SPEC_SYSTEM_CLAIM_BOUNDARY: &[&str] = &[
209    "source_tree_inventory",
210    "source_tree_graph_validation",
211    "proof_commands_not_executed",
212    "cargo_metadata_not_invoked",
213    "cargo_commands_not_invoked",
214    "rustc_not_invoked",
215    "clippy_not_invoked",
216    "build_scripts_not_executed",
217    "proc_macros_not_executed",
218    "macro_expansion_not_analyzed",
219    "macro_token_tree_contents_not_analyzed",
220    "type_information_not_analyzed",
221    "mir_not_analyzed",
222    "build_output_not_analyzed",
223    "control_flow_not_analyzed",
224    "data_flow_not_analyzed",
225    "external_evidence_tools_not_invoked",
226    "repository_code_not_executed",
227    "network_not_used",
228    "github_api_not_used",
229];
230
231pub const SPEC_SYSTEM_SCANNER_LIMITATIONS: &[&str] = &[
232    "proof_commands_not_executed",
233    "cargo_metadata_not_invoked",
234    "cargo_commands_not_invoked",
235    "rustc_not_invoked",
236    "clippy_not_invoked",
237    "build_scripts_not_executed",
238    "proc_macros_not_executed",
239    "macro_expansion_not_analyzed",
240    "macro_token_tree_contents_not_analyzed",
241    "type_information_not_analyzed",
242    "mir_not_analyzed",
243    "build_output_not_analyzed",
244    "control_flow_not_analyzed",
245    "data_flow_not_analyzed",
246    "external_evidence_tools_not_invoked",
247    "repository_code_not_executed",
248    "network_not_used",
249    "github_api_not_used",
250];
251
252pub fn claim_boundary_for_schema_id(schema_id: &str) -> &'static [&'static str] {
253    if schema_id == SPEC_SYSTEM_SCHEMA_ID {
254        SPEC_SYSTEM_CLAIM_BOUNDARY
255    } else {
256        CLAIM_BOUNDARY
257    }
258}
259
260pub fn scanner_limitations_for_schema_id(schema_id: &str) -> &'static [&'static str] {
261    if schema_id == SPEC_SYSTEM_SCHEMA_ID {
262        SPEC_SYSTEM_SCANNER_LIMITATIONS
263    } else {
264        SCANNER_LIMITATIONS
265    }
266}
267
268pub const CLAIM_BOUNDARY_TEXT: &str = "Claim boundary: scanned source-tree/source syntax only; cargo-allow did not invoke Cargo metadata, Cargo commands, rustc, Clippy, build scripts, proc macros, external evidence tools, or repository code. Macro expansion, macro token-tree contents, type information, MIR, build output, control flow, and data flow were not analyzed.";
269
270#[derive(Debug, Clone, Copy)]
271pub struct InventoryContext<'a> {
272    pub scope: &'a str,
273    pub scanner: &'a str,
274    pub source: &'a str,
275    pub root: Option<&'a str>,
276    pub files_scanned: Option<usize>,
277}
278
279impl<'a> InventoryContext<'a> {
280    pub const fn new(
281        scope: &'a str,
282        scanner: &'a str,
283        source: &'a str,
284        root: Option<&'a str>,
285        files_scanned: Option<usize>,
286    ) -> Self {
287        Self {
288            scope,
289            scanner,
290            source,
291            root,
292            files_scanned,
293        }
294    }
295
296    pub const fn source_syntax(
297        source: &'a str,
298        root: Option<&'a str>,
299        files_scanned: Option<usize>,
300    ) -> Self {
301        Self::new(
302            INVENTORY_SCOPE_SOURCE_TREE,
303            INVENTORY_SCANNER_SOURCE_SYNTAX,
304            source,
305            root,
306            files_scanned,
307        )
308    }
309
310    pub const fn unknown_source_syntax() -> InventoryContext<'static> {
311        InventoryContext::source_syntax(INVENTORY_SOURCE_UNKNOWN, None, None)
312    }
313
314    pub const fn policy_migration(
315        source: &'a str,
316        root: Option<&'a str>,
317        files_scanned: Option<usize>,
318    ) -> Self {
319        Self::new(
320            INVENTORY_SCOPE_SOURCE_TREE,
321            INVENTORY_SCANNER_POLICY_MIGRATION,
322            source,
323            root,
324            files_scanned,
325        )
326    }
327}
328
329impl<'a> Default for InventoryContext<'a> {
330    fn default() -> Self {
331        Self::unknown_source_syntax()
332    }
333}
334
335#[derive(Debug, Clone, Copy, Default)]
336pub struct ReportContext<'a> {
337    pub inventory: InventoryContext<'a>,
338    pub baseline_debt_entries: Option<usize>,
339    pub policy_missing_evidence_entries: Option<usize>,
340    pub broken_evidence_links: Option<usize>,
341    pub weak_evidence_references: Option<usize>,
342    pub mode: Option<&'a str>,
343    pub enforcement: Option<&'a str>,
344    pub policy_config: Option<&'a str>,
345    pub tool_version: Option<&'a str>,
346}
347
348impl<'a> ReportContext<'a> {
349    pub const fn source_syntax(
350        inventory_source: &'a str,
351        source_tree_root: Option<&'a str>,
352        inventory_files: Option<usize>,
353        baseline_debt_entries: Option<usize>,
354    ) -> Self {
355        Self {
356            inventory: InventoryContext::source_syntax(
357                inventory_source,
358                source_tree_root,
359                inventory_files,
360            ),
361            baseline_debt_entries,
362            policy_missing_evidence_entries: None,
363            broken_evidence_links: None,
364            weak_evidence_references: None,
365            mode: None,
366            enforcement: None,
367            policy_config: None,
368            tool_version: None,
369        }
370    }
371}
372
373impl<'a> From<ReportContext<'a>> for InventoryContext<'a> {
374    fn from(context: ReportContext<'a>) -> Self {
375        context.inventory
376    }
377}