pushkin 0.2.0

Schema-first enforcement harness that gates AI coding agents' file writes against project contracts
//! Distribution stream S2(c) — adapter resolution-failure semantics (D6,
//! ratified: guard where the host has no fail-open story, document where
//! it does; one enforcement layer per invariant).
//!
//! Per-agent verdicts: hermes already carries both legs (manifest probe +
//! loud `OSError` fail-open) — documented, unchanged. opencode is proven
//! conformant by the committed dialect pin (`hook opencode` exits 0 with
//! the verdict in JSON, so the plugin's error branch never swallows a
//! deny) — documented, unchanged. claude and codex emit JSON command
//! strings, unguardable in-band — documented at the emission sites.
//! auggie is the one guardable artifact: its emitted `pushkin.sh` gains
//! the same N13 guard the floors carry, exercised here by running the
//! real emitted script.
//!
//! Committed first (RED), read-only hereafter (N10, product-gated).

use assert_cmd::Command;
use std::fs;
use std::path::Path;
use std::process::Command as StdCommand;

type TestResult = Result<(), Box<dyn std::error::Error>>;

const MANIFEST: &str = r#"
version = 1
canonical = "json-schema-2020-12"
authoring = "zod"

[[contracts]]
name = "user"
source = "contracts/user.zod.ts"
emit = ["zod"]

[[mappings]]
glob = "app/api/**/*.ts"
contracts = ["user"]
require = "boundary-validation"

[gates]
protected_paths = ["pushkin.toml"]
"#;

const SCRIPT: &str = ".augment/hooks/pushkin.sh";

fn repo() -> Result<tempfile::TempDir, Box<dyn std::error::Error>> {
    let dir = tempfile::tempdir()?;
    fs::write(dir.path().join("pushkin.toml"), MANIFEST)?;
    Ok(dir)
}

fn binary_dir() -> Result<String, Box<dyn std::error::Error>> {
    Ok(Path::new(env!("CARGO_BIN_EXE_pushkin"))
        .parent()
        .ok_or("binary under test has no parent")?
        .to_string_lossy()
        .into_owned())
}

fn install_auggie(dir: &Path) -> Result<(), Box<dyn std::error::Error>> {
    let output = Command::cargo_bin("pushkin")?
        .current_dir(dir)
        .env("PATH", binary_dir()?)
        .env("HERMES_HOME", dir.join(".hermes-home"))
        .args(["init", "--agent", "auggie"])
        .output()?;
    if output.status.code() != Some(0) {
        return Err(format!(
            "auggie install failed: {}",
            String::from_utf8_lossy(&output.stderr)
        )
        .into());
    }
    Ok(())
}

/// Runs the REAL emitted script under /bin/sh with an explicit PATH and
/// cwd — the same execution discipline the floor suites use.
fn run_script(
    script: &Path,
    cwd: &Path,
    path: &str,
) -> Result<(Option<i32>, String), Box<dyn std::error::Error>> {
    let output = StdCommand::new("/bin/sh")
        .current_dir(cwd)
        .env("PATH", path)
        .arg(script)
        .output()?;
    Ok((
        output.status.code(),
        String::from_utf8_lossy(&output.stderr).into_owned(),
    ))
}

#[test]
fn the_auggie_hook_fails_open_with_the_notice_when_unprovisioned() -> TestResult {
    let dir = repo()?;
    install_auggie(dir.path())?;
    let script = dir.path().join(SCRIPT);

    // PATH deliberately without pushkin: the binary-absence leg.
    let (code, stderr) = run_script(&script, dir.path(), "/usr/bin:/bin")?;
    assert_eq!(
        code,
        Some(0),
        "an unprovisioned teammate's tool call must not break: {stderr}"
    );
    assert!(
        stderr.contains("failing open") && stderr.contains("cargo install pushkin"),
        "the notice is loud and actionable: {stderr}"
    );
    Ok(())
}

#[test]
fn the_auggie_hook_fails_open_when_the_manifest_is_absent() -> TestResult {
    let dir = repo()?;
    install_auggie(dir.path())?;
    let script = dir.path().join(SCRIPT);
    let elsewhere = tempfile::tempdir()?;

    // Provisioned, but run from a repo with no pushkin.toml: the
    // manifest-absence leg.
    let provisioned = format!("{}:/usr/bin:/bin", binary_dir()?);
    let (code, stderr) = run_script(&script, elsewhere.path(), &provisioned)?;
    assert_eq!(
        code,
        Some(0),
        "an ungated repo must not be blocked by the hook: {stderr}"
    );
    assert!(
        stderr.contains("failing open"),
        "the manifest leg fails open loudly, like the floor: {stderr}"
    );
    Ok(())
}

#[test]
fn the_provisioned_auggie_hook_never_prints_the_notice() -> TestResult {
    let dir = repo()?;
    install_auggie(dir.path())?;
    let script = dir.path().join(SCRIPT);

    // Both probes pass: the guard's provisioned branch reaches pushkin
    // itself, whatever the payload outcome (pushkin's own malformed-payload
    // handling may legitimately fail open) — the GUARD's absence notice
    // belongs to positively probed absence ONLY.
    let provisioned = format!("{}:/usr/bin:/bin", binary_dir()?);
    let (_, stderr) = run_script(&script, dir.path(), &provisioned)?;
    assert!(
        !stderr.contains("not installed or no pushkin.toml"),
        "the guard's absence notice never fires when both probes pass: {stderr}"
    );
    Ok(())
}