gha_container_proof/
engine.rs1use anyhow::Result;
5
6use crate::model::ContainerProofReceipt;
7use crate::plan::{ActionPlanInput, JobPlanInput, plan_action, plan_job};
8use crate::probe::{ProbeInput, probe};
9use crate::workflow::{CheckWorkflowOptions, scan_workflows};
10
11pub fn run_check_workflow(options: &CheckWorkflowOptions) -> Result<ContainerProofReceipt> {
12 let scan = scan_workflows(options)?;
13 Ok(ContainerProofReceipt::build(
14 "check-workflow",
15 scan.subjects,
16 scan.checks,
17 ))
18}
19
20pub fn run_plan_job(input: &JobPlanInput) -> Result<ContainerProofReceipt> {
21 let subject = plan_job(input);
22 Ok(ContainerProofReceipt::build(
23 "plan-job",
24 vec![subject],
25 Vec::new(),
26 ))
27}
28
29pub fn run_plan_action(input: &ActionPlanInput) -> Result<ContainerProofReceipt> {
30 let subject = plan_action(input);
31 Ok(ContainerProofReceipt::build(
32 "plan-action",
33 vec![subject],
34 Vec::new(),
35 ))
36}
37
38pub fn run_probe(input: &ProbeInput) -> Result<ContainerProofReceipt> {
39 let subject = probe(input);
40 Ok(ContainerProofReceipt::build(
41 "probe",
42 vec![subject],
43 Vec::new(),
44 ))
45}
46
47pub fn apply_strict(receipt: &mut ContainerProofReceipt) {
54 for subject in &mut receipt.subjects {
55 for check in &mut subject.checks {
56 if check.status == crate::model::CheckStatus::Warn {
57 check.status = crate::model::CheckStatus::Fail;
58 }
59 }
60 subject.finalize();
61 }
62 for check in &mut receipt.checks {
63 if check.status == crate::model::CheckStatus::Warn {
64 check.status = crate::model::CheckStatus::Fail;
65 }
66 }
67 let mut summary = crate::model::ReceiptSummary::from_checks(&receipt.checks);
69 for subject in &receipt.subjects {
70 summary.add(&subject.summary);
71 }
72 receipt.summary = summary;
73 receipt.compatibility = receipt
74 .subjects
75 .iter()
76 .map(|subject| subject.classification)
77 .fold(
78 crate::model::Compatibility::Exact,
79 crate::model::Compatibility::worse,
80 );
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86 use crate::model::{Compatibility, RunnerOs};
87
88 #[test]
89 fn run_plan_job_smoke() {
90 let receipt = run_plan_job(&JobPlanInput {
91 job_id: "build".to_owned(),
92 runner_os: RunnerOs::Linux,
93 runs_on: vec!["ubuntu-22.04".to_owned()],
94 container_image: Some("node:22-bookworm".to_owned()),
95 env: Vec::new(),
96 ports: Vec::new(),
97 volumes: Vec::new(),
98 options: String::new(),
99 credentials_username_present: false,
100 credentials_password_present: false,
101 location: None,
102 })
103 .unwrap();
104 assert_eq!(receipt.mode, "plan-job");
105 assert_eq!(receipt.subjects.len(), 1);
106 assert!(receipt.compatibility != Compatibility::Unsupported);
107 }
108
109 #[test]
110 fn apply_strict_promotes_warnings() {
111 let mut receipt = run_plan_job(&JobPlanInput {
112 job_id: "build".to_owned(),
113 runner_os: RunnerOs::Linux,
114 runs_on: vec!["ubuntu-22.04".to_owned()],
115 container_image: Some("node:latest".to_owned()),
116 env: Vec::new(),
117 ports: Vec::new(),
118 volumes: Vec::new(),
119 options: String::new(),
120 credentials_username_present: false,
121 credentials_password_present: false,
122 location: None,
123 })
124 .unwrap();
125 assert!(receipt.summary.warnings >= 1);
126 apply_strict(&mut receipt);
127 assert_eq!(receipt.summary.warnings, 0);
128 assert!(receipt.summary.failed >= 1);
129 }
130}