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