Files
MetaCrate/tools/ci-matrix/src/ci_gate.rs
Chili Palmer 27c860c225
All checks were successful
CI / required (push) Successful in 3m55s
Consolidate required CI gate (#115)
2026-08-13 00:27:47 +00:00

1425 lines
44 KiB
Rust

//! Consolidated, shell-free routine and release CI command graphs.
use super::{
MatrixError, Result, audit, audit_api_surface, audit_dependencies, audit_documentation,
audit_provenance, load, write_api_baseline, write_documentation_report,
};
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::collections::BTreeSet;
use std::ffi::{OsStr, OsString};
use std::fs::{self, OpenOptions};
use std::io::{Read as _, Write as _};
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::time::{Instant, SystemTime, UNIX_EPOCH};
const COVERAGE_PATH: &str = "ci/ci-coverage.json";
const REQUIRED_WORKFLOW: &str = ".gitea/workflows/ci.yml";
const RELEASE_WORKFLOW: &str = ".gitea/workflows/release.yml";
const LEGACY_WORKFLOW_COUNT: usize = 13;
const LEGACY_WORKFLOWS: [&str; LEGACY_WORKFLOW_COUNT] = [
"api-surface.yml",
"artifact-audit.yml",
"codegen.yml",
"concurrency-audit.yml",
"documentation.yml",
"imaging-meshing.yml",
"jpeg2000.yml",
"performance.yml",
"release-candidate.yml",
"release-matrix.yml",
"rust-workspace.yml",
"skia.yml",
"supply-chain.yml",
];
const SKIA_ARCHIVE: &str = "skia-binaries-a25a0fdb7d90429aa2d1-aarch64-unknown-linux-gnu-jpegd-jpege-pdf-svg-textlayout-vulkan-webpd-webpe.tar.gz";
const SKIA_SHA256: &str = "dd127f458a5e67a79f3936a8aa19f822fe90a1d6a11b50b5f84df2b0519d909c";
const SKIA_SUCCESS: &str = "DOWNLOAD AND INSTALL SUCCEEDED";
const SKIA_SOURCE_BUILD: &str = "STARTING A FULL BUILD";
#[derive(Debug, Deserialize)]
struct CoverageManifest {
schema: u32,
required_workflow: String,
release_workflow: String,
hard_timeout_minutes: u64,
internal_target_seconds: u64,
required_checks: Vec<String>,
legacy_workflows: Vec<LegacyWorkflow>,
}
#[derive(Debug, Deserialize)]
struct LegacyWorkflow {
workflow: String,
responsibility: String,
destination: String,
checks: Vec<String>,
rationale: String,
}
#[derive(Debug, Serialize)]
struct GateEvidence {
schema: u32,
gate: &'static str,
status: &'static str,
source_commit: String,
recorded_unix_seconds: u64,
runner_architecture: String,
rust_host: String,
rust_target: String,
cargo_cache_hit: Option<bool>,
dependency_cache_hit: Option<bool>,
native_cache_hit: Option<bool>,
tools_cache_hit: Option<bool>,
peak_memory_kib: Option<u64>,
elapsed_seconds: f64,
internal_target_seconds: u64,
skia: SkiaEvidence,
stages: Vec<StageEvidence>,
failure: Option<String>,
}
#[derive(Debug, Default, Serialize)]
struct SkiaEvidence {
archive: String,
sha256: String,
target: String,
download_and_install_succeeded: bool,
source_build_started: bool,
}
#[derive(Debug, Serialize)]
struct StageEvidence {
id: String,
elapsed_seconds: f64,
commands: usize,
status: &'static str,
}
#[derive(Clone, Copy)]
struct CommandSpec {
program: &'static str,
args: &'static [&'static str],
}
impl CommandSpec {
const fn new(program: &'static str, args: &'static [&'static str]) -> Self {
Self { program, args }
}
}
/// Validates the workflow split and the complete legacy-check coverage map.
///
/// # Errors
///
/// Returns an error when the manifest is incomplete, workflow triggers or
/// runners violate policy, or Skia can fall back to a source build.
pub fn audit_consolidated_ci(root: &Path) -> Result<()> {
let manifest = coverage(root)?;
validate_coverage(&manifest)?;
validate_workflows(root, &manifest)?;
validate_skia_configuration(root)?;
Ok(())
}
/// Runs the routine code-ready gate and always emits a stage-timing record.
///
/// # Errors
///
/// Returns an error for an invalid host/native identity, a failed validation
/// command, stale evidence, or exhaustion of the internal runtime target.
pub fn run_required_gate(root: &Path, evidence_path: &Path) -> Result<()> {
audit_consolidated_ci(root)?;
let manifest = coverage(root)?;
prepare_new_evidence(evidence_path)?;
let started = Instant::now();
let rust_host = rust_host(root)?;
let expected_host = std::env::var("METACRATE_EXPECTED_HOST")
.unwrap_or_else(|_| "aarch64-unknown-linux-gnu".to_owned());
let mut evidence = GateEvidence {
schema: 1,
gate: "required",
status: "failed",
source_commit: command_line(root, "git", &["rev-parse", "--verify", "HEAD"])
.unwrap_or_else(|_| "unknown".to_owned()),
recorded_unix_seconds: unix_seconds()?,
runner_architecture: std::env::consts::ARCH.to_owned(),
rust_host: rust_host.clone(),
rust_target: expected_host.clone(),
cargo_cache_hit: cache_hit("METACRATE_CARGO_CACHE_HIT"),
dependency_cache_hit: cache_hit("METACRATE_DEPENDENCY_CACHE_HIT"),
native_cache_hit: cache_hit("METACRATE_NATIVE_CACHE_HIT"),
tools_cache_hit: cache_hit("METACRATE_TOOLS_CACHE_HIT"),
peak_memory_kib: peak_memory_kib(),
elapsed_seconds: 0.0,
internal_target_seconds: manifest.internal_target_seconds,
skia: SkiaEvidence {
archive: SKIA_ARCHIVE.to_owned(),
sha256: SKIA_SHA256.to_owned(),
target: expected_host.clone(),
..SkiaEvidence::default()
},
stages: Vec::new(),
failure: None,
};
let result = run_required(
root,
&manifest,
&rust_host,
&expected_host,
started,
&mut evidence,
);
evidence.elapsed_seconds = started.elapsed().as_secs_f64();
evidence.peak_memory_kib = peak_memory_kib();
match &result {
Ok(()) => evidence.status = "ok",
Err(error) => evidence.failure = Some(error.to_string()),
}
write_evidence(evidence_path, &evidence)?;
result
}
/// Runs the explicitly non-routine clean-build, cross-target, packaging, and soak graph.
///
/// # Errors
///
/// Returns an error when the release matrix is invalid, a release command
/// fails, or its create-new evidence record cannot be written.
#[allow(clippy::too_many_lines)] // This is the declarative release command inventory.
pub fn run_release_gate(root: &Path, evidence_path: &Path) -> Result<()> {
audit_consolidated_ci(root)?;
let matrix = load(root)?;
audit(root, &matrix)?;
prepare_new_evidence(evidence_path)?;
let started = Instant::now();
let target_dir = root.join("target/release-gate");
let environment = [
(OsString::from("CARGO_INCREMENTAL"), OsString::from("0")),
(
OsString::from("CARGO_TARGET_DIR"),
target_dir.into_os_string(),
),
];
let stages: [(&str, Vec<CommandSpec>); 4] = [
(
"msrv-and-portable-cross-targets",
vec![
CommandSpec::new(
"cargo",
&[
"+1.96.0",
"check",
"--locked",
"--all-targets",
"--no-default-features",
"-p",
"libremetaverse-types",
"-p",
"libremetaverse-structured-data",
"-p",
"libremetaverse-imaging",
"-p",
"libremetaverse-prim-mesher",
],
),
CommandSpec::new(
"cargo",
&[
"+1.97.1",
"check",
"--locked",
"--target",
"x86_64-pc-windows-gnu",
"--no-default-features",
"-p",
"libremetaverse-types",
"-p",
"libremetaverse-structured-data",
"-p",
"libremetaverse-imaging",
"-p",
"libremetaverse-prim-mesher",
],
),
CommandSpec::new(
"cargo",
&[
"+1.97.1",
"check",
"--locked",
"--target",
"x86_64-apple-darwin",
"--no-default-features",
"-p",
"libremetaverse-types",
"-p",
"libremetaverse-structured-data",
"-p",
"libremetaverse-imaging",
"-p",
"libremetaverse-prim-mesher",
],
),
],
),
(
"benchmarks-and-resource-soak",
vec![
CommandSpec::new(
"cargo",
&[
"+1.97.1",
"bench",
"--locked",
"-p",
"libremetaverse-imaging",
"--bench",
"image_pipeline",
"--no-run",
],
),
CommandSpec::new(
"cargo",
&[
"+1.97.1",
"bench",
"--locked",
"-p",
"libremetaverse-prim-mesher",
"--bench",
"meshing",
"--no-run",
],
),
CommandSpec::new(
"cargo",
&[
"+1.97.1",
"run",
"--locked",
"-p",
"metacrate-concurrency-audit",
"--",
"--cycles",
"16",
"--evidence",
"artifacts/release/concurrency-audit.json",
],
),
],
),
(
"source-packages-and-native-binaries",
vec![
CommandSpec::new(
"cargo",
&[
"+1.97.1",
"package",
"--locked",
"--no-verify",
"-p",
"libremetaverse-types",
"-p",
"libremetaverse-structured-data",
"-p",
"libremetaverse-imaging",
"-p",
"libremetaverse-imaging-skia",
"-p",
"libremetaverse-openjpeg",
"-p",
"libremetaverse-opus",
"-p",
"libremetaverse-prim-mesher",
"-p",
"libremetaverse-lsl-tools",
"-p",
"libremetaverse",
"-p",
"libremetaverse-rendering-simple",
"-p",
"libremetaverse-rendering-mesh-foundry",
"-p",
"libremetaverse-rlv",
"-p",
"libremetaverse-utilities",
"-p",
"libremetaverse-voice-vivox",
"-p",
"libremetaverse-voice-webrtc",
"-p",
"libremetaverse-programs",
],
),
CommandSpec::new(
"cargo",
&[
"+1.97.1",
"build",
"--locked",
"--release",
"-p",
"libremetaverse-programs",
"--bins",
],
),
],
),
(
"release-audits",
vec![
CommandSpec::new(
"cargo",
&[
"+1.97.1",
"run",
"--locked",
"-p",
"metacrate-ci-matrix",
"--",
"artifact-audit",
"--artifact-dir",
"target/release-gate/release",
"--package-dir",
"target/release-gate/package",
"--evidence",
"artifacts/release/artifact-audit.json",
],
),
CommandSpec::new(
"cargo",
&[
"+1.97.1",
"run",
"--locked",
"-p",
"metacrate-ci-matrix",
"--",
"release-candidate-audit",
"--evidence",
"artifacts/release/release-candidate.json",
],
),
],
),
];
let mut recorded = Vec::new();
let mut failure = None;
for (id, commands) in stages {
let stage_started = Instant::now();
let mut status = "ok";
for spec in &commands {
println!("ci-release {id}: {} {}", spec.program, spec.args.join(" "));
let command_status = configured_command(root, spec, &environment)
.stdin(Stdio::null())
.status()?;
if !command_status.success() {
status = "failed";
failure = Some(format!(
"release stage {id} failed while running {}",
spec.program
));
break;
}
}
recorded.push(StageEvidence {
id: id.to_owned(),
elapsed_seconds: stage_started.elapsed().as_secs_f64(),
commands: commands.len(),
status,
});
if failure.is_some() {
break;
}
}
let value = serde_json::json!({
"schema": 1,
"gate": "release",
"status": if failure.is_none() { "ok" } else { "failed" },
"source_commit": command_line(root, "git", &["rev-parse", "--verify", "HEAD"]).unwrap_or_else(|_| "unknown".to_owned()),
"recorded_unix_seconds": unix_seconds()?,
"elapsed_seconds": started.elapsed().as_secs_f64(),
"stages": recorded,
"failure": failure,
});
write_json_evidence(evidence_path, &value)?;
if let Some(message) = value["failure"].as_str() {
return Err(MatrixError::new(message));
}
Ok(())
}
fn run_required(
root: &Path,
manifest: &CoverageManifest,
rust_host: &str,
expected_host: &str,
started: Instant,
evidence: &mut GateEvidence,
) -> Result<()> {
if rust_host != expected_host {
return Err(MatrixError::new(format!(
"required CI must use {expected_host}; rustc reports {rust_host}"
)));
}
let archive = skia_archive_path()?;
validate_skia_archive(&archive)?;
validate_openjpeg_identity()?;
let skia_url = file_url(&archive)?;
let target_dir = std::env::var_os("CARGO_TARGET_DIR")
.map_or_else(|| root.join("target/required"), PathBuf::from);
let jobs = std::env::var("CARGO_BUILD_JOBS").unwrap_or_else(|_| "2".to_owned());
let common_env = [
(OsString::from("CARGO_INCREMENTAL"), OsString::from("0")),
(OsString::from("CARGO_BUILD_JOBS"), OsString::from(jobs)),
(
OsString::from("CARGO_TARGET_DIR"),
target_dir.into_os_string(),
),
(
OsString::from("SKIA_BINARIES_URL"),
OsString::from(skia_url),
),
];
run_stage(
root,
"static-generated-api",
&static_commands(),
&common_env,
started,
manifest,
evidence,
)?;
run_report_audits(root)?;
evidence.stages.push(StageEvidence {
id: "reviewed-reports".to_owned(),
elapsed_seconds: 0.0,
commands: 4,
status: "ok",
});
prove_skia_binary(root, &archive, &common_env, evidence)?;
enforce_budget(started, manifest)?;
run_stage(
root,
"compile-test-features",
&test_commands(),
&common_env,
started,
manifest,
evidence,
)?;
run_stage(
root,
"program-api-smoke",
&program_commands(),
&common_env,
started,
manifest,
evidence,
)?;
run_stage(
root,
"clippy-docs",
&quality_commands(),
&common_env,
started,
manifest,
evidence,
)?;
run_stage(
root,
"policy-evidence",
&policy_commands(),
&common_env,
started,
manifest,
evidence,
)?;
Ok(())
}
fn static_commands() -> Vec<CommandSpec> {
vec![
CommandSpec::new("cargo", &["fmt", "--all", "--", "--check"]),
CommandSpec::new("python3", &["tools/generate_rust_mapping.py", "--check"]),
CommandSpec::new("python3", &["tools/generate_api_shims.py", "--check"]),
CommandSpec::new("python3", &["tools/check_api_coverage.py"]),
CommandSpec::new("python3", &["tools/check_test_parity.py"]),
CommandSpec::new("python3", &["tools/generate_lsl_tables.py", "--check"]),
CommandSpec::new("python3", &["tools/check_milestone_06.py"]),
CommandSpec::new("python3", &["tools/check_milestone_09.py"]),
CommandSpec::new("python3", &["tools/check_milestone_10.py"]),
CommandSpec::new(
"cargo",
&["test", "--locked", "-p", "libremetaverse-codegen"],
),
CommandSpec::new(
"cargo",
&[
"run",
"--locked",
"-p",
"libremetaverse-codegen",
"--",
"check",
],
),
]
}
fn test_commands() -> Vec<CommandSpec> {
vec![
// Build every product/compatibility library and integration test in
// one graph. Package-qualified feature selection covers every core
// feature without enabling unrelated optional features on consumers.
CommandSpec::new(
"cargo",
&[
"test",
"--workspace",
"--lib",
"--test",
"*",
"--features",
"libremetaverse/jpeg2000,libremetaverse/vorbis",
"--exclude",
"libremetaverse-programs",
"--exclude",
"libremetaverse-codegen",
"--exclude",
"metacrate-performance",
"--exclude",
"metacrate-ci-matrix",
"--exclude",
"metacrate-concurrency-audit",
"--jobs",
"1",
"--locked",
],
),
CommandSpec::new(
"cargo",
&[
"check",
"-p",
"libremetaverse",
"--lib",
"--no-default-features",
"--locked",
],
),
CommandSpec::new(
"cargo",
&[
"check",
"-p",
"libremetaverse-voice-webrtc",
"--all-targets",
"--features",
"real-audio",
"--locked",
],
),
CommandSpec::new(
"cargo",
&[
"test",
"-p",
"libremetaverse-imaging",
"--no-default-features",
"--features",
"jpeg2000",
"--locked",
],
),
]
}
fn program_commands() -> Vec<CommandSpec> {
vec![
CommandSpec::new(
"cargo",
&[
"test",
"--locked",
"-p",
"libremetaverse-programs",
"--test",
"*",
],
),
CommandSpec::new(
"cargo",
&[
"run",
"--locked",
"-p",
"libremetaverse-programs",
"--bin",
"live-grid-smoke",
"--",
"--audit-only",
],
),
CommandSpec::new(
"cargo",
&[
"run",
"--locked",
"-p",
"libremetaverse-programs",
"--bin",
"live-grid-smoke",
"--",
"--fake",
"--evidence",
"artifacts/ci/fake-grid-smoke.jsonl",
],
),
CommandSpec::new(
"cargo",
&[
"check",
"--locked",
"--manifest-path",
"tests/api-compile/Cargo.toml",
],
),
CommandSpec::new(
"cargo",
&[
"run",
"--locked",
"--manifest-path",
"tests/semver-port/Cargo.toml",
],
),
]
}
fn quality_commands() -> Vec<CommandSpec> {
vec![
CommandSpec::new(
"cargo",
&[
"clippy",
"--workspace",
"--all-targets",
"--all-features",
"--locked",
"--",
"-D",
"warnings",
],
),
CommandSpec::new(
"cargo",
&[
"doc",
"--workspace",
"--all-features",
"--no-deps",
"--locked",
],
),
]
}
fn policy_commands() -> Vec<CommandSpec> {
vec![
CommandSpec::new(
"cargo",
&[
"deny",
"check",
"advisories",
"licenses",
"bans",
"sources",
"--hide-inclusion-graph",
],
),
// Invoke the pinned standalone executable directly. In a `cargo run`
// child process, some Cargo installations forward the plugin name to
// cargo-machete, which 0.9.2 interprets as a directory to scan.
CommandSpec::new("cargo-machete", &["--with-metadata"]),
CommandSpec::new(
"cargo",
&[
"run",
"--locked",
"-p",
"metacrate-performance",
"--",
"audit",
"--fixture-root",
"benchmarks/fixtures",
"--rust",
"benchmarks/results/rust-linux-x86_64.json",
"--reference",
"benchmarks/results/csharp-linux-x86_64.json",
"--comparison",
"benchmarks/results/comparison.json",
],
),
]
}
fn run_stage(
root: &Path,
id: &str,
commands: &[CommandSpec],
environment: &[(OsString, OsString)],
gate_started: Instant,
manifest: &CoverageManifest,
evidence: &mut GateEvidence,
) -> Result<()> {
enforce_budget(gate_started, manifest)?;
let stage_started = Instant::now();
for command in commands {
println!(
"ci-required {id}: {} {}",
command.program,
command.args.join(" ")
);
let status = configured_command(root, command, environment)
.stdin(Stdio::null())
.status()?;
if !status.success() {
evidence.stages.push(StageEvidence {
id: id.to_owned(),
elapsed_seconds: stage_started.elapsed().as_secs_f64(),
commands: commands.len(),
status: "failed",
});
return Err(MatrixError::new(format!(
"stage {id} failed while running {}",
command.program
)));
}
enforce_budget(gate_started, manifest)?;
}
evidence.stages.push(StageEvidence {
id: id.to_owned(),
elapsed_seconds: stage_started.elapsed().as_secs_f64(),
commands: commands.len(),
status: "ok",
});
Ok(())
}
fn prove_skia_binary(
root: &Path,
archive: &Path,
environment: &[(OsString, OsString)],
evidence: &mut GateEvidence,
) -> Result<()> {
let proof_target = environment
.iter()
.find(|(name, _)| name == "CARGO_TARGET_DIR")
.map(|(_, value)| PathBuf::from(value))
.ok_or_else(|| MatrixError::new("CARGO_TARGET_DIR is required for the Skia proof"))?;
let started = Instant::now();
let spec = CommandSpec::new(
"cargo",
&[
"test",
"-vv",
"--locked",
"-p",
"libremetaverse-imaging-skia",
"--no-default-features",
"--features",
"skia",
],
);
let mut command = configured_command(root, &spec, environment);
command
.env("CARGO_TARGET_DIR", &proof_target)
.env("SKIA_BINARIES_URL", file_url(archive)?)
.env_remove("FORCE_SKIA_BINARIES_DOWNLOAD")
.env_remove("FORCE_SKIA_BUILD")
.stdin(Stdio::null());
let output = command.output()?;
std::io::stdout().write_all(&output.stdout)?;
std::io::stderr().write_all(&output.stderr)?;
let mut log = format!(
"{}\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
append_skia_build_output(&proof_target, &mut log)?;
evidence.skia.download_and_install_succeeded = log.contains(SKIA_SUCCESS);
evidence.skia.source_build_started = log.contains(SKIA_SOURCE_BUILD);
let status = if output.status.success()
&& evidence.skia.download_and_install_succeeded
&& !evidence.skia.source_build_started
{
"ok"
} else {
"failed"
};
evidence.stages.push(StageEvidence {
id: "skia-binary-proof".to_owned(),
elapsed_seconds: started.elapsed().as_secs_f64(),
commands: 1,
status,
});
if status != "ok" {
return Err(MatrixError::new(
"Skia proof did not install the pinned binary archive without starting a source build",
));
}
Ok(())
}
fn append_skia_build_output(target_dir: &Path, log: &mut String) -> Result<()> {
let build_dir = target_dir.join("debug/build");
if !build_dir.is_dir() {
return Ok(());
}
for entry in fs::read_dir(build_dir)? {
let entry = entry?;
if !entry
.file_name()
.to_string_lossy()
.starts_with("skia-bindings-")
{
continue;
}
let output = entry.path().join("output");
if output.is_file() {
log.push('\n');
log.push_str(&fs::read_to_string(output)?);
}
}
Ok(())
}
fn run_report_audits(root: &Path) -> Result<()> {
write_api_baseline(root)?;
write_documentation_report(root)?;
ensure_git_clean_paths(
root,
&[
"api/SEMVER-BASELINE.json",
"api/SEMVER-AUDIT.md",
"api/DOCUMENTATION-COVERAGE.md",
],
)?;
let artifacts = root.join("artifacts/ci");
fs::create_dir_all(&artifacts)?;
let audits = [
("api-audit.json", "ci/evidence/api-audit.json"),
(
"documentation-audit.json",
"ci/evidence/documentation-audit.json",
),
("dependency-audit.json", ""),
("provenance-audit.json", "ci/evidence/provenance-audit.json"),
];
for (name, _) in audits {
let path = artifacts.join(name);
if path.exists() {
fs::remove_file(path)?;
}
}
audit_api_surface(root, &artifacts.join("api-audit.json"))?;
audit_documentation(root, &artifacts.join("documentation-audit.json"))?;
audit_dependencies(root, &artifacts.join("dependency-audit.json"))?;
audit_provenance(root, &artifacts.join("provenance-audit.json"))?;
for (name, committed) in audits.into_iter().filter(|(_, path)| !path.is_empty()) {
if !evidence_matches_except_timestamp(&artifacts.join(name), &root.join(committed))? {
return Err(MatrixError::new(format!(
"{committed} does not match freshly generated audit evidence"
)));
}
}
Ok(())
}
fn evidence_matches_except_timestamp(actual: &Path, expected: &Path) -> Result<bool> {
let mut actual: serde_json::Value = serde_json::from_slice(&fs::read(actual)?)?;
let mut expected: serde_json::Value = serde_json::from_slice(&fs::read(expected)?)?;
for value in [&mut actual, &mut expected] {
if let Some(object) = value.as_object_mut() {
for volatile in [
"recorded_unix_seconds",
"source_file_count",
"distribution_manifest_sha256",
] {
object.remove(volatile);
}
}
}
Ok(actual == expected)
}
fn validate_coverage(manifest: &CoverageManifest) -> Result<()> {
if manifest.schema != 1
|| manifest.required_workflow != REQUIRED_WORKFLOW
|| manifest.release_workflow != RELEASE_WORKFLOW
|| manifest.hard_timeout_minutes != 15
|| manifest.internal_target_seconds > 720
|| manifest.legacy_workflows.len() != LEGACY_WORKFLOW_COUNT
{
return Err(MatrixError::new(
"CI coverage manifest has an invalid gate shape",
));
}
let required = unique(
manifest.required_checks.iter().map(String::as_str),
"required check",
)?;
let workflows = unique(
manifest
.legacy_workflows
.iter()
.map(|entry| entry.workflow.as_str()),
"legacy workflow",
)?;
if workflows != BTreeSet::from(LEGACY_WORKFLOWS) {
return Err(MatrixError::new("legacy workflow inventory is incomplete"));
}
let mut routed_required = BTreeSet::new();
for entry in &manifest.legacy_workflows {
if entry.responsibility.trim().is_empty()
|| entry.rationale.trim().is_empty()
|| entry.checks.is_empty()
|| !matches!(
entry.destination.as_str(),
"required" | "release" | "split" | "retired"
)
{
return Err(MatrixError::new(format!(
"{} has an incomplete coverage route",
entry.workflow
)));
}
if matches!(entry.destination.as_str(), "required" | "split") {
routed_required.extend(
entry
.checks
.iter()
.filter(|check| required.contains(check.as_str()))
.map(String::as_str),
);
}
}
if routed_required != required {
return Err(MatrixError::new(
"not every required check is routed from the legacy inventory",
));
}
Ok(())
}
fn validate_workflows(root: &Path, manifest: &CoverageManifest) -> Result<()> {
let directory = root.join(".gitea/workflows");
let mut workflow_paths = Vec::new();
for entry in fs::read_dir(&directory)? {
let path = entry?.path();
if matches!(
path.extension().and_then(OsStr::to_str),
Some("yml" | "yaml")
) {
workflow_paths.push(path);
}
}
workflow_paths.sort();
if workflow_paths.len() > 3 || workflow_paths.len() != 2 {
return Err(MatrixError::new(
"exactly the required and non-routine release workflows must remain",
));
}
let required = fs::read_to_string(root.join(&manifest.required_workflow))?;
let release = fs::read_to_string(root.join(&manifest.release_workflow))?;
for marker in [
"push:",
"pull_request:",
"timeout-minutes: 15",
"cancel-in-progress: true",
"runs-on: ubuntu-latest",
"required-gate",
"python3 tools/normalize_git_mtimes.py --state",
".metacrate-mtimes.json\" --check",
"'**/Cargo.toml'",
"METACRATE_DEPENDENCY_CACHE_HIT",
"cp -al \"$previous_target\" \"$cargo_target\"",
] {
if !required.contains(marker) {
return Err(MatrixError::new(format!(
"required workflow is missing {marker}"
)));
}
}
if required.contains("cargo clean --target-dir") {
return Err(MatrixError::new(
"cold dependency/native validation must retain the keyed compiled target",
));
}
if required.contains("rm -rf -- \"$CARGO_HOME/registry\"") {
return Err(MatrixError::new(
"cold validation must preserve immutable extracted sources for Cargo fingerprints",
));
}
if required.contains("git show -s --format=%ct HEAD") {
return Err(MatrixError::new(
"tracked mtimes must be blob-stable across commits, not commit-wide",
));
}
if release.contains("pull_request:") || !release.contains("workflow_dispatch:") {
return Err(MatrixError::new(
"release workflow must be explicitly non-routine",
));
}
for path in &workflow_paths {
let text = fs::read_to_string(path)?;
if text
.lines()
.filter_map(|line| line.trim().strip_prefix("runs-on:"))
.any(|runner| runner.trim() != "ubuntu-latest")
{
return Err(MatrixError::new(format!(
"{} violates the ubuntu-only runner policy",
path.display()
)));
}
if text.contains("FORCE_SKIA_BINARIES_DOWNLOAD") {
return Err(MatrixError::new(format!(
"{} misuses FORCE_SKIA_BINARIES_DOWNLOAD",
path.display()
)));
}
}
Ok(())
}
fn validate_skia_configuration(root: &Path) -> Result<()> {
let manifest = fs::read_to_string(root.join("crates/libremetaverse-imaging-skia/Cargo.toml"))?;
if manifest.matches("no-compile").count() < 3 || !manifest.contains("binary-cache") {
return Err(MatrixError::new(
"every Skia target must fail fast instead of compiling from source",
));
}
Ok(())
}
fn validate_skia_archive(path: &Path) -> Result<()> {
if path.file_name().and_then(OsStr::to_str) != Some(SKIA_ARCHIVE) {
return Err(MatrixError::new(
"Skia archive name does not select the pinned ARM64 GNU feature tuple",
));
}
if hash_file(path)? != SKIA_SHA256 {
return Err(MatrixError::new(
"Skia archive SHA-256 does not match the reviewed binary",
));
}
Ok(())
}
fn validate_openjpeg_identity() -> Result<()> {
let prefix = std::env::var_os("OPENJPEG_PREFIX")
.map(PathBuf::from)
.ok_or_else(|| MatrixError::new("OPENJPEG_PREFIX is required"))?;
let identity = fs::read_to_string(prefix.join("metacrate-openjpeg.identity"))?;
for expected in [
"version=2.5.4",
"commit=6c4a29b00211eb0430fa0e5e890f1ce5c80f409f",
] {
if !identity.lines().any(|line| line == expected) {
return Err(MatrixError::new(format!(
"OpenJPEG cache identity is missing {expected}"
)));
}
}
Ok(())
}
fn coverage(root: &Path) -> Result<CoverageManifest> {
Ok(serde_json::from_slice(&fs::read(
root.join(COVERAGE_PATH),
)?)?)
}
fn configured_command(
root: &Path,
spec: &CommandSpec,
environment: &[(OsString, OsString)],
) -> Command {
let program: OsString = if spec.program == "cargo" {
std::env::var_os("CARGO").unwrap_or_else(|| "cargo".into())
} else {
spec.program.into()
};
let mut command = Command::new(program);
command.args(spec.args).current_dir(root);
for (key, value) in environment {
command.env(key, value);
}
command
}
fn enforce_budget(started: Instant, manifest: &CoverageManifest) -> Result<()> {
if started.elapsed().as_secs() >= manifest.internal_target_seconds {
return Err(MatrixError::new(format!(
"required CI exceeded its {} second internal target",
manifest.internal_target_seconds
)));
}
Ok(())
}
fn rust_host(root: &Path) -> Result<String> {
let verbose = command_line(root, "rustc", &["-vV"])?;
verbose
.lines()
.find_map(|line| line.strip_prefix("host: ").map(str::to_owned))
.ok_or_else(|| MatrixError::new("rustc -vV did not report a host"))
}
fn command_line(root: &Path, program: &str, args: &[&str]) -> Result<String> {
let output = Command::new(program)
.args(args)
.current_dir(root)
.output()?;
if !output.status.success() {
return Err(MatrixError::new(format!("{program} command failed")));
}
String::from_utf8(output.stdout)
.map(|text| text.trim().to_owned())
.map_err(|_| MatrixError::new(format!("{program} output was not UTF-8")))
}
fn ensure_git_clean_paths(root: &Path, paths: &[&str]) -> Result<()> {
let mut command = Command::new("git");
command
.args(["diff", "--exit-code", "--"])
.args(paths)
.current_dir(root);
if !command.status()?.success() {
return Err(MatrixError::new("reviewed generated reports are stale"));
}
Ok(())
}
fn skia_archive_path() -> Result<PathBuf> {
std::env::var_os("METACRATE_SKIA_ARCHIVE")
.map(PathBuf::from)
.ok_or_else(|| MatrixError::new("METACRATE_SKIA_ARCHIVE is required"))
}
fn hash_file(path: &Path) -> Result<String> {
let mut file = fs::File::open(path)?;
let mut hasher = Sha256::new();
let mut buffer = vec![0_u8; 64 * 1024].into_boxed_slice();
loop {
let read = file.read(&mut buffer)?;
if read == 0 {
break;
}
hasher.update(&buffer[..read]);
}
Ok(hasher
.finalize()
.iter()
.fold(String::with_capacity(64), |mut output, byte| {
use std::fmt::Write as _;
write!(output, "{byte:02x}").expect("writing to a String cannot fail");
output
}))
}
fn file_url(path: &Path) -> Result<String> {
let absolute = path.canonicalize()?;
let text = absolute
.to_str()
.ok_or_else(|| MatrixError::new("Skia archive path is not UTF-8"))?
.replace('\\', "/");
if text.starts_with('/') {
Ok(format!("file://{text}"))
} else {
Ok(format!("file:///{text}"))
}
}
fn cache_hit(name: &str) -> Option<bool> {
std::env::var(name)
.ok()
.and_then(|value| match value.as_str() {
"true" => Some(true),
"false" => Some(false),
_ => None,
})
}
fn peak_memory_kib() -> Option<u64> {
if let Ok(bytes) = fs::read_to_string("/sys/fs/cgroup/memory.peak")
&& let Ok(bytes) = bytes.trim().parse::<u64>()
{
return Some(bytes / 1024);
}
fs::read_to_string("/proc/self/status")
.ok()
.and_then(|status| {
status.lines().find_map(|line| {
line.strip_prefix("VmHWM:")?
.split_whitespace()
.next()?
.parse()
.ok()
})
})
}
fn unix_seconds() -> Result<u64> {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|duration| duration.as_secs())
.map_err(|_| MatrixError::new("system clock predates Unix epoch"))
}
fn prepare_new_evidence(path: &Path) -> Result<()> {
if path.exists() {
return Err(MatrixError::new(format!(
"{} already exists",
path.display()
)));
}
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)?;
}
Ok(())
}
fn write_evidence(path: &Path, evidence: &GateEvidence) -> Result<()> {
let mut file = OpenOptions::new().write(true).create_new(true).open(path)?;
serde_json::to_writer_pretty(&mut file, evidence)?;
file.write_all(b"\n")?;
file.sync_all()?;
Ok(())
}
fn write_json_evidence(path: &Path, evidence: &serde_json::Value) -> Result<()> {
let mut file = OpenOptions::new().write(true).create_new(true).open(path)?;
serde_json::to_writer_pretty(&mut file, evidence)?;
file.write_all(b"\n")?;
file.sync_all()?;
Ok(())
}
fn unique<'a>(values: impl Iterator<Item = &'a str>, kind: &str) -> Result<BTreeSet<&'a str>> {
let mut result = BTreeSet::new();
for value in values {
if value.trim().is_empty() || !result.insert(value) {
return Err(MatrixError::new(format!(
"{kind} values must be nonempty and unique"
)));
}
}
Ok(result)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn checked_in_coverage_routes_every_required_check() {
let manifest: CoverageManifest =
serde_json::from_str(include_str!("../../../ci/ci-coverage.json")).unwrap();
validate_coverage(&manifest).unwrap();
}
#[test]
fn checked_in_workflow_split_is_bounded_and_ubuntu_only() {
let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../..");
audit_consolidated_ci(&root).unwrap();
}
#[test]
fn pinned_skia_archive_identity_is_exact() {
assert!(SKIA_ARCHIVE.contains("aarch64-unknown-linux-gnu"));
assert!(SKIA_ARCHIVE.contains("jpegd-jpege-pdf-svg-textlayout-vulkan-webpd-webpe"));
assert_eq!(SKIA_SHA256.len(), 64);
}
#[test]
fn product_and_compatibility_graph_is_the_only_serial_command() {
let commands = test_commands();
assert_eq!(
commands[0].args,
[
"test",
"--workspace",
"--lib",
"--test",
"*",
"--features",
"libremetaverse/jpeg2000,libremetaverse/vorbis",
"--exclude",
"libremetaverse-programs",
"--exclude",
"libremetaverse-codegen",
"--exclude",
"metacrate-performance",
"--exclude",
"metacrate-ci-matrix",
"--exclude",
"metacrate-concurrency-audit",
"--jobs",
"1",
"--locked",
]
);
assert!(
commands[1..]
.iter()
.all(|command| !command.args.windows(2).any(|pair| pair == ["--jobs", "1"]))
);
}
#[test]
fn machete_uses_the_standalone_cli_contract() {
let commands = policy_commands();
let machete = commands
.iter()
.find(|command| command.program == "cargo-machete")
.expect("policy gate invokes cargo-machete directly");
assert_eq!(machete.args, ["--with-metadata"]);
assert!(
!commands
.iter()
.any(|command| command.program == "cargo"
&& command.args.first() == Some(&"machete"))
);
}
#[test]
fn performance_audit_reuses_the_required_gate_build_profile() {
let commands = policy_commands();
let performance = commands
.iter()
.find(|command| {
command.program == "cargo"
&& command
.args
.windows(2)
.any(|pair| pair == ["-p", "metacrate-performance"])
})
.expect("policy gate runs the performance evidence audit");
assert!(performance.args.starts_with(&["run", "--locked"]));
assert!(
!performance.args.contains(&"--profile"),
"the audit must reuse the gate's existing build artifacts instead of compiling a second profile"
);
}
}