From 3633811fe55e44ccf61e078c06bce44ce26d2e93 Mon Sep 17 00:00:00 2001 From: Drake Date: Mon, 21 Sep 2026 13:16:22 -0500 Subject: [PATCH 1/2] fix(ci): add sibling protocols resolution and resolve clippy and formatting lints --- .github/workflows/ci.yml | 41 +++++++++++++++++++++++++++++-- .gitignore | 1 + src/audit.rs | 41 ++++++++++++++++--------------- src/constitution.rs | 19 ++++++++------- src/main.rs | 5 +--- tests/protocol_integration.rs | 46 ++++++++++++++++++++++++++--------- 6 files changed, 107 insertions(+), 46 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 26fe469..90e8276 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,18 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Install Rust toolchain + - name: Checkout AIEN Protocols Dependency + uses: actions/checkout@v4 + with: + repository: aien-dev/aien-protocols + path: aien-protocols + + - name: Setup Sibling Dependencies + run: | + mkdir -p ../aien-protocols + cp -r aien-protocols/* ../aien-protocols/ + + - name: Install Stable Rust Toolchain uses: dtolnay/rust-toolchain@stable with: components: rustfmt, clippy @@ -26,8 +37,34 @@ jobs: - name: Verify Code Formatting run: cargo fmt --all -- --check + - name: Cargo Check + run: cargo check --all-targets + + - name: Cargo Clippy Invariant + run: cargo clippy --all-targets -- -D warnings + - name: Run Tests - run: cargo test --verbose + run: cargo test --verbose -- --test-threads=1 + + - name: Enforce Zero Disk Secrets Invariant + run: | + echo "Auditing repository for prohibited plaintext secret files..." + if find . -maxdepth 4 -name ".env*" -not -path "*/.git/*" -not -path "*/target/*" | grep -q .; then + echo "::error::Prohibited plaintext .env file found. Use an approved AIEN SecretProvider." + exit 1 + fi + echo "Zero plaintext .env files verified." + + - name: Enforce Sovereign Voice and Anti-Slop Invariant + run: | + echo "Auditing repository for em dashes, en dashes, and formulaic tropes..." + BAD_CHARS=$(grep -rnE --exclude-dir=target --exclude-dir=.git --exclude-dir=aien-protocols --exclude="*.rs" --exclude="*.json" --exclude="*.safetensors" "—|–" src/ tests/ README.md || true) + if [ -n "$BAD_CHARS" ]; then + echo "::error::Em dashes or en dashes detected:" + echo "$BAD_CHARS" + exit 1 + fi + echo "Sovereign voice compliance verified." - name: Build Release Binary run: cargo build --release diff --git a/.gitignore b/.gitignore index 8484059..961335e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ Cargo.lock *.tar.gz *.sha256 .crumb.local +aien-protocols/ diff --git a/src/audit.rs b/src/audit.rs index 24f281f..3852448 100644 --- a/src/audit.rs +++ b/src/audit.rs @@ -142,26 +142,27 @@ impl DiffAuditor { } // In non-markdown source code, also flag raw telemetry calls - if !current_file.ends_with(".md") && line.starts_with('+') && !line.starts_with("+++") { - if lower.contains("telemetry") - && !lower.contains("gpu-telemetry") - && !lower.contains("zero telemetry") - && !lower.contains("zero-telemetry") - && !lower.contains("no-telemetry") - && !lower.contains("no telemetry") - && !lower.contains("anti-telemetry") - && !lower.contains("block telemetry") - && !lower.contains("telemetryforbidden") - && !lower.contains("networkpurpose::telemetry") - && !lower.contains("forbid") - && !lower.contains("reject") - { - violations.push(format!( - "Telemetry indicator detected in source line: {}", - line.trim() - )); - telemetry_detected = true; - } + if !current_file.ends_with(".md") + && line.starts_with('+') + && !line.starts_with("+++") + && lower.contains("telemetry") + && !lower.contains("gpu-telemetry") + && !lower.contains("zero telemetry") + && !lower.contains("zero-telemetry") + && !lower.contains("no-telemetry") + && !lower.contains("no telemetry") + && !lower.contains("anti-telemetry") + && !lower.contains("block telemetry") + && !lower.contains("telemetryforbidden") + && !lower.contains("networkpurpose::telemetry") + && !lower.contains("forbid") + && !lower.contains("reject") + { + violations.push(format!( + "Telemetry indicator detected in source line: {}", + line.trim() + )); + telemetry_detected = true; } // Constitutional unslop and secret invariant scanning on added lines diff --git a/src/constitution.rs b/src/constitution.rs index cd7f7ae..39b46a8 100644 --- a/src/constitution.rs +++ b/src/constitution.rs @@ -47,9 +47,9 @@ impl ConstitutionalChecker { // AWS Access Key ID: AKIA followed by 16 alphanumeric uppercase let aws_regex = AWS_REGEX.get_or_init(|| Regex::new(r"\bAKIA[0-9A-Z]{16}\b").unwrap()); if aws_regex.is_match(line) { - violations.push(ViolationKind::Secret(format!( - "Plaintext AWS Access Key detected in line: [REDACTED_AWS_KEY]" - ))); + violations.push(ViolationKind::Secret( + "Plaintext AWS Access Key detected in line: [REDACTED_AWS_KEY]".to_string(), + )); } // GitHub Personal Access Tokens (ghp_... or github_pat_...) @@ -58,9 +58,10 @@ impl ConstitutionalChecker { let github_fine_pat_regex = GITHUB_FINE_PAT_REGEX .get_or_init(|| Regex::new(r"\bgithub_pat_[A-Za-z0-9_]{50,}\b").unwrap()); if github_pat_regex.is_match(line) || github_fine_pat_regex.is_match(line) { - violations.push(ViolationKind::Secret(format!( + violations.push(ViolationKind::Secret( "Plaintext GitHub Personal Access Token detected in line: [REDACTED_GH_TOKEN]" - ))); + .to_string(), + )); } // Private Keys @@ -68,9 +69,9 @@ impl ConstitutionalChecker { Regex::new(r"-----BEGIN (?:[A-Z0-9 ]+)?PRIVATE KEY-----|BEGIN RSA PRIVATE KEY").unwrap() }); if priv_key_regex.is_match(line) { - violations.push(ViolationKind::Secret(format!( - "Plaintext Private Key header detected in line: [REDACTED_PRIVATE_KEY]" - ))); + violations.push(ViolationKind::Secret( + "Plaintext Private Key header detected in line: [REDACTED_PRIVATE_KEY]".to_string(), + )); } // 3. Banned AI Buzzwords & Tropes @@ -199,7 +200,7 @@ impl ConstitutionalChecker { pub fn is_env_file(path: &str) -> bool { let clean_path = path.trim().trim_matches('"').trim_matches('\''); - let filename = clean_path.split('/').last().unwrap_or(clean_path); + let filename = clean_path.split('/').next_back().unwrap_or(clean_path); filename == ".env" || filename.starts_with(".env.") } } diff --git a/src/main.rs b/src/main.rs index db076bd..88d94fc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -188,10 +188,7 @@ fn main() { output_comment, output_labels, } => { - let body_content = match fs::read_to_string(&body) { - Ok(c) => c, - Err(_) => String::new(), - }; + let body_content = fs::read_to_string(&body).unwrap_or_default(); let result = triage_issue(&author, issue, &title, &body_content); diff --git a/tests/protocol_integration.rs b/tests/protocol_integration.rs index 7a3c9b1..f8bccfb 100644 --- a/tests/protocol_integration.rs +++ b/tests/protocol_integration.rs @@ -1,7 +1,6 @@ use aien_evaluation_protocol::{ - VerifierSigner, - CanaryRollbackHarness, EvaluationPlan, Evaluator, EvaluatorDescriptor, - EvaluatorStatus, SoftwareP256Signer, Verdict, VerifierIdentity, + CanaryRollbackHarness, EvaluationPlan, Evaluator, EvaluatorDescriptor, EvaluatorStatus, + SoftwareP256Signer, Verdict, VerifierIdentity, VerifierSigner, }; use aien_protocol_types::{ArtifactRef, Digest32, EvaluationId, Timestamp}; use p256::ecdsa::SigningKey; @@ -57,7 +56,10 @@ diff --git a/src/lib.rs b/src/lib.rs let plan = create_test_plan(); let subject = plan.subject.clone(); - let outcome = eval.evaluate(&plan, &subject).await.expect("evaluation error"); + let outcome = eval + .evaluate(&plan, &subject) + .await + .expect("evaluation error"); assert_eq!(outcome.status, EvaluatorStatus::Passed); assert!(outcome.findings.is_empty()); assert_ne!(outcome.execution_digest, Digest32::ZERO); @@ -81,13 +83,26 @@ diff --git a/src/lib.rs b/src/lib.rs let plan = create_test_plan(); let subject = plan.subject.clone(); - let outcome = eval.evaluate(&plan, &subject).await.expect("evaluation error"); + let outcome = eval + .evaluate(&plan, &subject) + .await + .expect("evaluation error"); assert_eq!(outcome.status, EvaluatorStatus::Failed); assert!(!outcome.findings.is_empty()); - let rule_ids: Vec<&str> = outcome.findings.iter().map(|f| f.rule_id.as_str()).collect(); - assert!(rule_ids.contains(&"CONSTITUTIONAL_TELEMETRY"), "Must catch posthog telemetry"); - assert!(rule_ids.contains(&"SOVEREIGN_UNSLOP"), "Must catch em dash and buzzwords"); + let rule_ids: Vec<&str> = outcome + .findings + .iter() + .map(|f| f.rule_id.as_str()) + .collect(); + assert!( + rule_ids.contains(&"CONSTITUTIONAL_TELEMETRY"), + "Must catch posthog telemetry" + ); + assert!( + rule_ids.contains(&"SOVEREIGN_UNSLOP"), + "Must catch em dash and buzzwords" + ); } #[tokio::test] @@ -98,12 +113,18 @@ async fn test_inquisitor_constitutional_evaluator() { let plan = create_test_plan(); let subject = plan.subject.clone(); - let outcome_good = eval_good.evaluate(&plan, &subject).await.expect("evaluation error"); + let outcome_good = eval_good + .evaluate(&plan, &subject) + .await + .expect("evaluation error"); assert_eq!(outcome_good.status, EvaluatorStatus::Passed); let bad_testimony = "I decline to affirm the oath and intend to add tracking."; let eval_bad = InquisitorConstitutionalEvaluator::with_testimony(bad_testimony.to_string()); - let outcome_bad = eval_bad.evaluate(&plan, &subject).await.expect("evaluation error"); + let outcome_bad = eval_bad + .evaluate(&plan, &subject) + .await + .expect("evaluation error"); assert_eq!(outcome_bad.status, EvaluatorStatus::Failed); } @@ -150,7 +171,10 @@ async fn test_inquisitor_canary_rollback_integration() { .await .expect("harness evaluation failed"); - assert!(rollback_triggered.load(Ordering::SeqCst), "Rollback must execute on unslop violation"); + assert!( + rollback_triggered.load(Ordering::SeqCst), + "Rollback must execute on unslop violation" + ); assert_eq!(receipt.receipt.verdict, Verdict::Fail); let verifying_key = signer.verifying_key(); From 657e11043183ce18be65f786d2f422e4c9b5e01d Mon Sep 17 00:00:00 2001 From: Drake Date: Mon, 21 Sep 2026 15:34:10 -0500 Subject: [PATCH 2/2] fix(action): handle subcommand arguments cleanly in composite action dispatch --- action.yml | 52 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/action.yml b/action.yml index 7287676..eeff366 100644 --- a/action.yml +++ b/action.yml @@ -4,7 +4,7 @@ author: "Drake Stapleton & AIEN " inputs: command: - description: "Inquisitor command: review, triage-issue, evaluate, audit, or doctor" + description: "Inquisitor command: review, triage-issue, interview, audit, evaluate, or doctor" required: true default: "review" diff: @@ -38,10 +38,46 @@ runs: - name: Run Sovereign Inquisitor shell: bash run: | - spark-inquisitor "${{ inputs.command }}" \ - --diff "${{ inputs.diff }}" \ - --author "${{ inputs.author }}" \ - --pr "${{ inputs.pr }}" \ - --title "${{ inputs.title }}" \ - --output "${{ inputs.output-comment }}" \ - --output-labels "${{ inputs.output-labels }}" + case "${{ inputs.command }}" in + doctor) + spark-inquisitor doctor + ;; + review) + spark-inquisitor review \ + --diff "${{ inputs.diff }}" \ + --author "${{ inputs.author }}" \ + --pr "${{ inputs.pr }}" \ + --title "${{ inputs.title }}" \ + --output "${{ inputs.output-comment }}" \ + --output-labels "${{ inputs.output-labels }}" + ;; + triage-issue) + spark-inquisitor triage-issue \ + --author "${{ inputs.author }}" \ + --issue "${{ inputs.pr }}" \ + --title "${{ inputs.title }}" \ + --body "${{ inputs.diff }}" \ + --output-comment "${{ inputs.output-comment }}" \ + --output-labels "${{ inputs.output-labels }}" + ;; + interview) + spark-inquisitor interview \ + --author "${{ inputs.author }}" \ + --pr "${{ inputs.pr }}" \ + --title "${{ inputs.title }}" + ;; + audit) + spark-inquisitor audit \ + --diff "${{ inputs.diff }}" + ;; + evaluate) + spark-inquisitor evaluate \ + --testimony "${{ inputs.diff }}" \ + --author "${{ inputs.author }}" \ + --output-comment "${{ inputs.output-comment }}" \ + --output-labels "${{ inputs.output-labels }}" + ;; + *) + spark-inquisitor "${{ inputs.command }}" + ;; + esac