Implement credential-safe programs smoke gate (#97)
Some checks failed
Native code generation / deterministic (push) Failing after 2m12s
Imaging and meshing gate / native (push) Failing after 5m40s
JPEG 2000 feature / linux (push) Successful in 2m50s
Native Rust workspace compile / compile (push) Failing after 56s
Skia feature / linux (push) Successful in 31m24s
Some checks failed
Native code generation / deterministic (push) Failing after 2m12s
Imaging and meshing gate / native (push) Failing after 5m40s
JPEG 2000 feature / linux (push) Successful in 2m50s
Native Rust workspace compile / compile (push) Failing after 56s
Skia feature / linux (push) Successful in 31m24s
This commit is contained in:
203
programs/src/completeness.rs
Normal file
203
programs/src/completeness.rs
Normal file
@@ -0,0 +1,203 @@
|
||||
//! Compile-time-backed audit of every pinned upstream program and `TestClient` command.
|
||||
|
||||
use crate::commands::TEST_CLIENT_COMMANDS;
|
||||
use crate::test_client::{IMPLEMENTED_TEST_CLIENT_COMMANDS, registered_test_client_command_count};
|
||||
use serde::Deserialize;
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
const CARGO_MANIFEST: &str = include_str!("../Cargo.toml");
|
||||
const SOURCE_MANIFEST: &str = include_str!("../upstream-programs.json");
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub struct ProgramTarget {
|
||||
pub project: &'static str,
|
||||
pub binary: &'static str,
|
||||
binary_source: &'static str,
|
||||
offline_test_source: &'static str,
|
||||
}
|
||||
|
||||
pub const ORIGINAL_PROGRAMS: &[ProgramTarget] = &[
|
||||
ProgramTarget {
|
||||
project: "OSDInspector",
|
||||
binary: "osd-inspector",
|
||||
binary_source: include_str!("bin/osd_inspector.rs"),
|
||||
offline_test_source: include_str!("../tests/osd_inspector_cli.rs"),
|
||||
},
|
||||
ProgramTarget {
|
||||
project: "SimpleBot",
|
||||
binary: "simple-bot",
|
||||
binary_source: include_str!("bin/simple_bot.rs"),
|
||||
offline_test_source: include_str!("../tests/simple_bot_cli.rs"),
|
||||
},
|
||||
ProgramTarget {
|
||||
project: "PacketDump",
|
||||
binary: "packet-dump",
|
||||
binary_source: include_str!("bin/packet_dump.rs"),
|
||||
offline_test_source: include_str!("../tests/packet_dump_cli.rs"),
|
||||
},
|
||||
ProgramTarget {
|
||||
project: "PrimInspector",
|
||||
binary: "prim-inspector",
|
||||
binary_source: include_str!("bin/prim_inspector.rs"),
|
||||
offline_test_source: include_str!("../tests/prim_inspector_cli.rs"),
|
||||
},
|
||||
ProgramTarget {
|
||||
project: "InventoryExplorer",
|
||||
binary: "inventory-explorer",
|
||||
binary_source: include_str!("bin/inventory_explorer.rs"),
|
||||
offline_test_source: include_str!("../tests/inventory_explorer_cli.rs"),
|
||||
},
|
||||
ProgramTarget {
|
||||
project: "IRCGateway",
|
||||
binary: "irc-gateway",
|
||||
binary_source: include_str!("bin/irc_gateway.rs"),
|
||||
offline_test_source: include_str!("../tests/irc_gateway_cli.rs"),
|
||||
},
|
||||
ProgramTarget {
|
||||
project: "TestClient",
|
||||
binary: "test-client",
|
||||
binary_source: include_str!("bin/test_client.rs"),
|
||||
offline_test_source: include_str!("../tests/test_client_services_cli.rs"),
|
||||
},
|
||||
ProgramTarget {
|
||||
project: "VivoxTest",
|
||||
binary: "vivox-test",
|
||||
binary_source: include_str!("bin/vivox_test.rs"),
|
||||
offline_test_source: include_str!("../tests/vivox_test_cli.rs"),
|
||||
},
|
||||
ProgramTarget {
|
||||
project: "WebRtcTest",
|
||||
binary: "webrtc-test",
|
||||
binary_source: include_str!("bin/webrtc_test.rs"),
|
||||
offline_test_source: include_str!("../tests/webrtc_test_cli.rs"),
|
||||
},
|
||||
];
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct CompletenessReport {
|
||||
pub programs: usize,
|
||||
pub source_files: usize,
|
||||
pub test_client_commands: usize,
|
||||
pub pending_programs: usize,
|
||||
pub pending_commands: usize,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct SourceManifest {
|
||||
upstream_commit: String,
|
||||
projects: Vec<SourceProject>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct SourceProject {
|
||||
project: String,
|
||||
files: Vec<SourceFile>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct SourceFile {
|
||||
path: String,
|
||||
sha256: String,
|
||||
}
|
||||
|
||||
/// Audits the pinned source manifest, all original Rust program targets, their
|
||||
/// offline test entry points, and every generated `TestClient` command.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error when the pinned source manifest is malformed or differs
|
||||
/// from the native target, test, implementation, or runtime registries.
|
||||
pub fn audit_program_completeness() -> Result<CompletenessReport, String> {
|
||||
let manifest: SourceManifest = serde_json::from_str(SOURCE_MANIFEST)
|
||||
.map_err(|_| "program source manifest is not valid JSON".to_owned())?;
|
||||
if manifest.upstream_commit.len() != 40
|
||||
|| !manifest
|
||||
.upstream_commit
|
||||
.bytes()
|
||||
.all(|byte| byte.is_ascii_hexdigit())
|
||||
{
|
||||
return Err("program source manifest has an invalid upstream commit".into());
|
||||
}
|
||||
let mut projects = BTreeMap::new();
|
||||
let mut source_paths = BTreeSet::new();
|
||||
let mut source_files = 0_usize;
|
||||
for project in &manifest.projects {
|
||||
if project.files.is_empty() || projects.insert(project.project.as_str(), project).is_some()
|
||||
{
|
||||
return Err("program source manifest has an empty or duplicate project".into());
|
||||
}
|
||||
for file in &project.files {
|
||||
if !source_paths.insert(file.path.as_str())
|
||||
|| file.sha256.len() != 64
|
||||
|| !file.sha256.bytes().all(|byte| byte.is_ascii_hexdigit())
|
||||
{
|
||||
return Err("program source manifest has an invalid file record".into());
|
||||
}
|
||||
source_files += 1;
|
||||
}
|
||||
}
|
||||
let expected_projects: BTreeSet<_> = ORIGINAL_PROGRAMS
|
||||
.iter()
|
||||
.map(|target| target.project)
|
||||
.collect();
|
||||
if projects.keys().copied().collect::<BTreeSet<_>>() != expected_projects {
|
||||
return Err("Rust program targets do not exactly match the source manifest".into());
|
||||
}
|
||||
for target in ORIGINAL_PROGRAMS {
|
||||
let cargo_marker = format!("name = \"{}\"", target.binary);
|
||||
if !CARGO_MANIFEST.contains(&cargo_marker)
|
||||
|| target.binary_source.contains("pending_program")
|
||||
|| !target.binary_source.contains("main_entry")
|
||||
|| !target.offline_test_source.contains("#[test]")
|
||||
{
|
||||
return Err(format!(
|
||||
"program {} lacks a native target or offline test",
|
||||
target.project
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let source_commands: BTreeSet<_> = projects["TestClient"]
|
||||
.files
|
||||
.iter()
|
||||
.filter_map(|file| {
|
||||
file.path
|
||||
.contains("/Commands/")
|
||||
.then(|| file.path.rsplit('/').next())
|
||||
.flatten()
|
||||
.and_then(|name| name.strip_suffix(".cs"))
|
||||
})
|
||||
.collect();
|
||||
let generated_commands: BTreeSet<_> = TEST_CLIENT_COMMANDS.iter().copied().collect();
|
||||
let implemented_commands: BTreeSet<_> =
|
||||
IMPLEMENTED_TEST_CLIENT_COMMANDS.iter().copied().collect();
|
||||
if source_commands != generated_commands
|
||||
|| implemented_commands != generated_commands
|
||||
|| registered_test_client_command_count() != generated_commands.len()
|
||||
{
|
||||
return Err("TestClient source, implementation, and runtime registries differ".into());
|
||||
}
|
||||
|
||||
Ok(CompletenessReport {
|
||||
programs: ORIGINAL_PROGRAMS.len(),
|
||||
source_files,
|
||||
test_client_commands: generated_commands.len(),
|
||||
pending_programs: 0,
|
||||
pending_commands: 0,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn every_source_program_and_command_has_a_native_tested_target() {
|
||||
let report = audit_program_completeness().unwrap();
|
||||
assert_eq!(report.programs, 9);
|
||||
assert!(report.source_files > report.programs);
|
||||
assert_eq!(report.test_client_commands, TEST_CLIENT_COMMANDS.len());
|
||||
assert_eq!(report.pending_programs, 0);
|
||||
assert_eq!(report.pending_commands, 0);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user