Skip to main content

crypto/ci_verdict/
body_details.rs

1// SPDX-License-Identifier: Apache-2.0
2//! Outcome, execution, and reproduction sections of a CI verdict body.
3
4use std::collections::BTreeMap;
5
6use serde::{Deserialize, Serialize};
7
8/// Terminal outcome of a check.
9#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
10#[serde(rename_all = "snake_case")]
11pub struct Outcome {
12    /// Terminal conclusion.
13    pub conclusion: Conclusion,
14    /// Structured triage detail when the check failed.
15    #[serde(default, skip_serializing_if = "Option::is_none")]
16    pub failure: Option<FailureDetail>,
17}
18
19/// Exhaustive terminal check conclusions.
20#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
21#[serde(rename_all = "snake_case")]
22pub enum Conclusion {
23    /// Check passed.
24    #[default]
25    Success,
26    /// Check failed with code or assertion evidence.
27    Failure,
28    /// Check was cancelled before completion.
29    Cancelled,
30    /// Check was intentionally skipped.
31    Skipped,
32    /// Check exceeded its deadline.
33    TimedOut,
34    /// Check could not run because of infrastructure.
35    InfraError,
36}
37
38/// Failure details suitable for routing a repair attempt.
39#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
40#[serde(rename_all = "snake_case")]
41pub struct FailureDetail {
42    /// Broad failure class.
43    pub class: FailureClass,
44    /// Optional finer-grained failure subclass.
45    #[serde(default, skip_serializing_if = "Option::is_none")]
46    pub subclass: Option<String>,
47    /// Failing step or check name.
48    #[serde(default, skip_serializing_if = "Option::is_none")]
49    pub failing_step: Option<String>,
50    /// ANSI-stripped, producer-capped, untrusted error excerpt.
51    pub excerpt: String,
52    /// Encoding of the excerpt, such as `utf8`.
53    pub excerpt_encoding: String,
54}
55
56/// Broad class of a check failure.
57#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
58#[serde(rename_all = "snake_case")]
59pub enum FailureClass {
60    /// Compile or build failure.
61    #[default]
62    Build,
63    /// Test assertion or panic.
64    Test,
65    /// Lint failure.
66    Lint,
67    /// Benchmark failure or regression.
68    Bench,
69    /// Runner or service infrastructure failure.
70    Infra,
71    /// Execution timeout.
72    Timeout,
73    /// Speculative merge conflict.
74    MergeConflict,
75}
76
77/// Runner, timing, and attestation metadata.
78#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
79#[serde(rename_all = "snake_case")]
80pub struct Execution {
81    /// Leased run identifier; absent for purely local execution.
82    #[serde(default, skip_serializing_if = "Option::is_none")]
83    pub pick_id: Option<String>,
84    /// One-based run attempt.
85    pub attempt: u32,
86    /// Runner principal identifier.
87    #[serde(default, skip_serializing_if = "Option::is_none")]
88    pub runner: Option<String>,
89    /// RFC3339 execution start.
90    pub started_at: String,
91    /// RFC3339 execution finish.
92    pub finished_at: String,
93    /// Wall-clock duration in milliseconds.
94    pub duration_ms: u64,
95    /// Suites that actually ran.
96    pub ran_suites: Vec<String>,
97    /// Suites intentionally skipped.
98    pub skipped_suites: Vec<String>,
99    /// Runner pool that produced the verdict.
100    #[serde(default, skip_serializing_if = "Option::is_none")]
101    pub runner_pool: Option<String>,
102    /// Runner trust tier.
103    #[serde(default, skip_serializing_if = "Option::is_none")]
104    pub trust_tier: Option<String>,
105    /// Sandbox isolation tier.
106    #[serde(default, skip_serializing_if = "Option::is_none")]
107    pub isolation_tier: Option<String>,
108    /// Proof that the evaluated tree was materialized.
109    #[serde(default, skip_serializing_if = "Option::is_none")]
110    pub materialization_proof: Option<String>,
111    /// Names of secret grants; values never enter the verdict.
112    #[serde(default, skip_serializing_if = "Vec::is_empty")]
113    pub secret_grants: Vec<String>,
114}
115
116/// Pointer to a finalized log blob.
117#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
118#[serde(rename_all = "snake_case")]
119pub struct LogRef {
120    /// Digest of the log manifest.
121    pub manifest_digest: String,
122    /// Total log size in bytes.
123    pub size_bytes: u64,
124}
125
126/// Exact local reproduction recipe.
127#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
128#[serde(rename_all = "snake_case")]
129pub struct Repro {
130    /// Argument vector to execute.
131    pub command: Vec<String>,
132    /// Sorted environment variables to set.
133    pub env: BTreeMap<String, String>,
134    /// Optional container image.
135    #[serde(default, skip_serializing_if = "Option::is_none")]
136    pub image: Option<String>,
137    /// Required service containers.
138    pub services: Vec<String>,
139}