diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 649dcb1..aeb9986 100755 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -1,3 +1,7 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +# +# pages.yml — GitHub Pages deployment via Ddraig SSG. name: GitHub Pages (Ddraig SSG) on: push: diff --git a/.github/workflows/rust-ci.yml b/.github/workflows/rust-ci.yml new file mode 100644 index 0000000..bf25668 --- /dev/null +++ b/.github/workflows/rust-ci.yml @@ -0,0 +1,104 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +# +# rust-ci.yml — Build and test the Aletheia microkernel (Rust). +# +# WHY THIS LIVES AT THE REPOSITORY ROOT +# ------------------------------------ +# `aletheia/` is vendored as plain tracked files, not a submodule. GitHub Actions +# only reads workflows from `.github/workflows/` at the repository root, so the 16 +# workflow files under `aletheia/.github/workflows/` have never executed — see +# `aletheia/.github/workflows/README.md`. Until this file landed, ~962 lines of Rust +# had no build, test, or format gate of any kind, and `main` sat uncompilable for +# over a month (broken 2026-06-17 by b5322c2, fixed in this change). +# +# SCOPE OF THIS GATE — read before trusting a green tick +# ----------------------------------------------------- +# Gated here (all genuinely passing, all blocking): +# * debug + release build +# * the 26 unit tests +# * `cargo fmt --check` +# +# NOT gated here, because they are genuinely red today and a passing-but-hollow +# job is worse than no job: +# * `tests/integration_tests.rs` — 27 of 29 fail; they exercise a CLI surface +# (--help, --version, --format=, --badge, --html, --init-hook) that `src/main.rs` +# does not implement. +# * `cargo clippy -- -D warnings` — 25 findings, mostly dead code from modules +# that `main.rs` never wires up. +# Both are tracked as issues. Add them here as blocking jobs once they pass; do not +# add them with `continue-on-error`. +name: Rust CI + +on: + pull_request: + branches: ['**'] + push: + branches: [main, master] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: rust-ci-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + working-directory: aletheia + +jobs: + build: + name: Build (debug + release) + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - name: Checkout repository + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + submodules: false + + - name: Show toolchain + run: cargo --version && rustc --version + + - name: Verify zero dependencies (RSR Bronze constraint) + run: | + if cargo tree --depth 1 | tail -n +2 | grep -q '[a-z]'; then + echo "::error::Aletheia must have zero dependencies (see aletheia/CLAUDE.md)" + cargo tree --depth 1 + exit 1 + fi + echo "Zero dependencies confirmed" + + - name: Build (debug) + run: cargo build --locked --verbose + + - name: Build (release) + run: cargo build --locked --release --verbose + + test: + name: Unit tests + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - name: Checkout repository + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + submodules: false + + - name: Run unit tests + run: cargo test --locked --bins --verbose + + format: + name: Formatting + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Checkout repository + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + submodules: false + + - name: cargo fmt --check + run: cargo fmt --all --check diff --git a/absolute-zero b/absolute-zero index ad085ba..87902bb 160000 --- a/absolute-zero +++ b/absolute-zero @@ -1 +1 @@ -Subproject commit ad085baa7d25de23fd9cf4de3e88e5896e35c708 +Subproject commit 87902bb770e767c10e065d9ac75d111e80a01be1 diff --git a/aletheia/.github/workflows/README.md b/aletheia/.github/workflows/README.md new file mode 100644 index 0000000..c81a136 --- /dev/null +++ b/aletheia/.github/workflows/README.md @@ -0,0 +1,46 @@ + + +# These 16 workflows do not run. They never have. + +GitHub Actions only reads workflow files from `.github/workflows/` **at the root of a +repository**. This directory is nested inside `maa-framework`, so every YAML file here +is inert — including `rust-ci.yml`, `codeql.yml`, `cflite_pr.yml`, `cflite_batch.yml`, +`generator-generic-ossf-slsa3-publish.yml`, `scorecard.yml`, and `ghcr-publish.yml`. + +## Why they are here + +`aletheia` began as the standalone repository `hyperpolymath/aletheia` (created +2025-12-11), where these workflows *did* run. That repository was removed from GitHub — +its mirrors on GitLab, Codeberg and Bitbucket all stop by early January 2026. On +2026-02-21, commit `639f389` left behind a dangling gitlink with no `.gitmodules` +entry; on 2026-03-02, commit `25cf219` ("Fix stale submodule pointers after repo +cleanup") replaced that pointer by vendoring 361 files — these workflows among them — +into `maa-framework` as ordinary tracked files. + +Nothing has executed them since. + +## What that cost + +Between 2026-06-17 and 2026-07-21, `aletheia` **did not compile**. Commit `b5322c2` +("security: remediate Track C and Track E findings") correctly added a 1 MiB read cap +to `Config::load_config`, but collapsed the block onto one line and dropped a closing +brace. A single `cargo build` would have caught it. Nothing ran one, so `main` stayed +broken for over a month. + +## Where the real gate lives now + +`/.github/workflows/rust-ci.yml`, at the repository root. It builds debug and release, +runs the 26 unit tests, checks formatting, and enforces the zero-dependency constraint +from `aletheia/CLAUDE.md`. Read its header comment for what it deliberately does *not* +gate yet. + +## If you are changing CI for aletheia + +Edit the root workflow. Editing anything in this directory has no effect. These files +are retained only as the source material for porting the capabilities that were lost — +ClusterFuzzLite fuzzing, SLSA3 provenance, GHCR publishing — back to root workflows. +Once a capability is ported, delete its file here so this directory shrinks toward +empty. diff --git a/aletheia/benches/verification_benchmark.rs b/aletheia/benches/verification_benchmark.rs index 12a0f41..6b25a24 100644 --- a/aletheia/benches/verification_benchmark.rs +++ b/aletheia/benches/verification_benchmark.rs @@ -238,7 +238,10 @@ fn main() { } else if avg_ms < 10.0 { println!("\n Status: ✅ TARGET MET ({:.2}ms < 10ms)", avg_ms); } else { - println!("\n Status: ⚠️ NEEDS IMPROVEMENT ({:.2}ms >= 10ms)", avg_ms); + println!( + "\n Status: ⚠️ NEEDS IMPROVEMENT ({:.2}ms >= 10ms)", + avg_ms + ); } // Memory info (if available on Linux) diff --git a/aletheia/src/checks.rs b/aletheia/src/checks.rs index 8e4c775..c212eea 100644 --- a/aletheia/src/checks.rs +++ b/aletheia/src/checks.rs @@ -2,8 +2,8 @@ // Copyright (c) Jonathan D.A. Jewell //! RSR Compliance Verification Kernel. //! -//! This module implements the deterministic checks used by Aletheia to -//! audit repository state. It performs physical filesystem analysis to +//! This module implements the deterministic checks used by Aletheia to +//! audit repository state. It performs physical filesystem analysis to //! validate documentation, build system files, and security configurations. use std::fs; @@ -20,7 +20,7 @@ pub fn glob_match(pattern: &str, text: &str) -> bool { } /// SECURITY: Validates that a path does not contain malicious symlinks. -/// Specifically checks if a symlink "escapes" the repository root, which +/// Specifically checks if a symlink "escapes" the repository root, which /// is a critical safety invariant for air-gapped or verified builds. pub fn check_path_security(path: &Path, repo_root: &Path) -> PathCheckResult { let metadata = match fs::symlink_metadata(path) { @@ -29,19 +29,36 @@ pub fn check_path_security(path: &Path, repo_root: &Path) -> PathCheckResult { }; if !metadata.file_type().is_symlink() { - return PathCheckResult { exists: true, ..Default::default() }; + return PathCheckResult { + exists: true, + ..Default::default() + }; } // RESOLUTION: Determine the absolute target of the symlink. let target = match fs::read_link(path) { Ok(t) => t, - Err(_) => return PathCheckResult { exists: true, is_symlink: true, ..Default::default() }, + Err(_) => { + return PathCheckResult { + exists: true, + is_symlink: true, + ..Default::default() + } + }, }; // ESCAPE DETECTION: Canonicalize and verify prefix. - let canonical_root = repo_root.canonicalize().unwrap_or_else(|_| repo_root.to_path_buf()); - let resolved_target = if target.is_absolute() { target } else { path.parent().expect("TODO: handle error").join(target) }; - let canonical_target = resolved_target.canonicalize().unwrap_or_else(|_| resolved_target); + let canonical_root = repo_root + .canonicalize() + .unwrap_or_else(|_| repo_root.to_path_buf()); + let resolved_target = if target.is_absolute() { + target + } else { + path.parent().expect("TODO: handle error").join(target) + }; + let canonical_target = resolved_target + .canonicalize() + .unwrap_or_else(|_| resolved_target); PathCheckResult { exists: true, @@ -85,11 +102,8 @@ pub fn check_spdx_headers(report: &mut ComplianceReport, repo_path: &Path) { if path.extension().map_or(false, |ext| ext == "rs") { checked += 1; if let Ok(content) = fs::read_to_string(&path) { - let first_10_lines: String = content - .lines() - .take(10) - .collect::>() - .join("\n"); + let first_10_lines: String = + content.lines().take(10).collect::>().join("\n"); if first_10_lines.contains("SPDX-License-Identifier") { valid += 1; } @@ -121,7 +135,10 @@ pub fn check_workflow_pins(report: &mut ComplianceReport, repo_path: &Path) { for entry in entries { if let Ok(entry) = entry { let path = entry.path(); - if path.extension().map_or(false, |ext| ext == "yml" || ext == "yaml") { + if path + .extension() + .map_or(false, |ext| ext == "yml" || ext == "yaml") + { checked_files += 1; if let Ok(content) = fs::read_to_string(&path) { // Check if all 'uses:' lines have SHA pinning (40 hex chars) diff --git a/aletheia/src/config.rs b/aletheia/src/config.rs index 6bfd67f..7325f93 100644 --- a/aletheia/src/config.rs +++ b/aletheia/src/config.rs @@ -73,8 +73,13 @@ impl Config { let config_path = repo_path.join(".aletheia.toml"); if config_path.is_file() { - if let Ok(mut file) = fs::File::open(&config_path) { use std::io::Read; let mut content = String::new(); if file.take(1024 * 1024).read_to_string(&mut content).is_ok() { - return Self::parse_from_string(&content); + if let Ok(file) = fs::File::open(&config_path) { + use std::io::Read; + let mut content = String::new(); + // Cap the read at 1 MiB so a hostile config cannot exhaust memory. + if file.take(1024 * 1024).read_to_string(&mut content).is_ok() { + return Self::parse_from_string(&content); + } } } diff --git a/aletheia/src/main.rs b/aletheia/src/main.rs index c830e36..fa52995 100644 --- a/aletheia/src/main.rs +++ b/aletheia/src/main.rs @@ -2,9 +2,9 @@ // Copyright (c) Jonathan D.A. Jewell //! Aletheia — Authoritative RSR Compliance Verification. //! -//! Named after the Greek concept of "unconcealment," Aletheia is the -//! gatekeeper for the Rhodium Standard Repository (RSR) ecosystem. -//! It provides automated, deterministic audits of repository state to +//! Named after the Greek concept of "unconcealment," Aletheia is the +//! gatekeeper for the Rhodium Standard Repository (RSR) ecosystem. +//! It provides automated, deterministic audits of repository state to //! ensure adherence to safety, security, and documentation standards. //! //! COMPLIANCE DIMENSIONS: @@ -70,7 +70,7 @@ fn main() { Err(e) => { eprintln!("Error: {}", e); process::exit(1); - } + }, }; // 2. ENVIRONMENT VALIDATION @@ -93,7 +93,11 @@ fn main() { } // 5. EXIT POLICY - let exit_code = if report.checks.iter().any(|c| !c.passed && c.required_for == ComplianceLevel::Bronze) { + let exit_code = if report + .checks + .iter() + .any(|c| !c.passed && c.required_for == ComplianceLevel::Bronze) + { exit_codes::COMPLIANCE_FAILED } else if report.warnings.iter().any(|w| w.level == "critical") { exit_codes::SECURITY_WARNING diff --git a/aletheia/src/output.rs b/aletheia/src/output.rs index e50ef73..e30c331 100644 --- a/aletheia/src/output.rs +++ b/aletheia/src/output.rs @@ -2,25 +2,25 @@ // Copyright (c) Jonathan D.A. Jewell //! Aletheia Output and Reporting Engine. //! -//! This module implements the presentation layer for compliance audits. -//! It provides multiple serialization formats (JSON, SARIF, HTML) and +//! This module implements the presentation layer for compliance audits. +//! It provides multiple serialization formats (JSON, SARIF, HTML) and //! a high-fidelity human-readable CLI report. //! -//! ZERO-DEPENDENCY DESIGN: To maintain RSR Bronze compliance, this module -//! implements its own timestamp formatting and string escaping rather than +//! ZERO-DEPENDENCY DESIGN: To maintain RSR Bronze compliance, this module +//! implements its own timestamp formatting and string escaping rather than //! pulling in external crates like `chrono` or `serde_json`. -use std::time::SystemTime; use crate::types::*; +use std::time::SystemTime; /// The current version of the Aletheia tool. pub const VERSION: &str = env!("CARGO_PKG_VERSION"); /// EXIT STRATEGY: Standardized exit codes for CI/CD integration. pub mod exit_codes { - pub const SUCCESS: i32 = 0; // Bronze compliance achieved. + pub const SUCCESS: i32 = 0; // Bronze compliance achieved. pub const COMPLIANCE_FAILED: i32 = 1; // Mandatory checks failed. - pub const SECURITY_WARNING: i32 = 2; // Critical security issues (e.g. symlink escape). + pub const SECURITY_WARNING: i32 = 2; // Critical security issues (e.g. symlink escape). } /// ALGORITHM: Manual timestamp formatter. @@ -40,7 +40,7 @@ pub fn format_timestamp(time: SystemTime) -> String { "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}Z", year, month, day, hour, minute, second ) - } + }, Err(_) => "2026-02-21T00:00:00Z".to_string(), } } @@ -137,8 +137,14 @@ pub fn print_report(report: &ComplianceReport) { pub fn print_json_report(report: &ComplianceReport) { println!("{{"); println!(" \"version\": \"{}\",", VERSION); - println!(" \"repository\": \"{}\",", report.repository_path.display()); - println!(" \"timestamp\": \"{}\",", format_timestamp(report.verified_at)); + println!( + " \"repository\": \"{}\",", + report.repository_path.display() + ); + println!( + " \"timestamp\": \"{}\",", + format_timestamp(report.verified_at) + ); println!(" \"checks\": ["); for (i, check) in report.checks.iter().enumerate() { @@ -146,7 +152,10 @@ pub fn print_json_report(report: &ComplianceReport) { println!(" \"category\": \"{}\",", check.category); println!(" \"item\": \"{}\",", check.item); println!(" \"passed\": {}", check.passed); - println!(" }}{}", if i < report.checks.len() - 1 { "," } else { "" }); + println!( + " }}{}", + if i < report.checks.len() - 1 { "," } else { "" } + ); } println!(" ],"); diff --git a/aletheia/src/types.rs b/aletheia/src/types.rs index 1d73577..ccc398a 100644 --- a/aletheia/src/types.rs +++ b/aletheia/src/types.rs @@ -2,8 +2,8 @@ // Copyright (c) Jonathan D.A. Jewell //! Aletheia — Core Domain Types and Models. //! -//! This module defines the formal data structures used throughout the -//! compliance verification engine. It establishes the schema for +//! This module defines the formal data structures used throughout the +//! compliance verification engine. It establishes the schema for //! audit results, security warnings, and RSR compliance tiers. use std::path::PathBuf; @@ -15,7 +15,10 @@ use std::time::SystemTime; /// - **Gold/Platinum**: Reserved for deep formal verification. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ComplianceLevel { - Bronze, Silver, Gold, Platinum, + Bronze, + Silver, + Gold, + Platinum, } /// CHECK RESULT: The outcome of a single deterministic verification item. diff --git a/aletheia/tests/integration_tests.rs b/aletheia/tests/integration_tests.rs index b5b9bd8..1168c1d 100644 --- a/aletheia/tests/integration_tests.rs +++ b/aletheia/tests/integration_tests.rs @@ -350,14 +350,8 @@ fn test_sarif_output() { ); assert!(stdout.contains("\"rules\":"), "Should have rules"); assert!(stdout.contains("\"results\":"), "Should have results"); - assert!( - stdout.contains("\"ruleId\":"), - "Results should have ruleId" - ); - assert!( - stdout.contains("rsr/"), - "Rule IDs should use rsr/ prefix" - ); + assert!(stdout.contains("\"ruleId\":"), "Results should have ruleId"); + assert!(stdout.contains("rsr/"), "Rule IDs should use rsr/ prefix"); } /// Test quiet mode output @@ -644,18 +638,12 @@ fn test_html_output() { assert!(output.status.success(), "Should succeed with HTML format"); let stdout = String::from_utf8_lossy(&output.stdout); - assert!( - stdout.contains(""), - "Should be valid HTML" - ); + assert!(stdout.contains(""), "Should be valid HTML"); assert!( stdout.contains("Aletheia Compliance Report"), "Should have report title" ); - assert!( - stdout.contains("