Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/holger

server/cli/tests/tier1_plain_cargo.rs

//! **Tier 1: the plain-`cargo build` server, a RON with a local source and the steps**
//! (Holger G0, owner order 2026-10-23).
//!
//! This is the binary a lone clone's `cargo build --release` gives (`holger`, the
//! default features). It is started as a process with `holger start --config`, and:
//!
//! * a wheel PUT into `incoming` as the Importer is INGESTED from source `team`;
//! * `/-/intake/state` and `holger intake state` show its state, its source and its
//!   effective policy;
//! * it moves on through every step the RON turns on, to AVAILABLE, and production
//!   serves it;
//! * the RON's refusals are named: an unknown key, a source that loosens the floor.

use std::io::{Read, Write};
use std::net::TcpStream;
use std::path::Path;
use std::process::{Child, Command, Stdio};
use std::time::{Duration, Instant};

const BIN: &str = env!("CARGO_BIN_EXE_holger");
const WHEEL: &str = "demo_pkg-1.0.0-py3-none-any.whl";

fn token(who: &str) -> String {
    format!("{who}-token-of-sufficient-length-for-holger")
}

/// The tier 1 RON: four raw repositories for the steps, one upload source, the steps
/// with one approval, the default floor, and four principals with their duties.
fn tier1_ron(d: &Path, grpc: u16, http: u16, tier1: &str) -> String {
    let d = d.display();
    let repo = |n: &str| {
        format!(
            r#"(ron_name: "{n}", ron_repo_type: "raw", ron_upstreams: [], ron_in: None,
              ron_out: Some((ron_storage_endpoint: "disk", ron_exposed_endpoint: "door")), ron_data_dir: Some("{d}/{n}")),"#
        )
    };
    let methods: Vec<String> = ["ida", "bob", "adm", "aud"]
        .iter()
        .map(|p| {
            format!(
                r#"StaticToken(subject: "{p}", token: Some("{}"))"#,
                token(p)
            )
        })
        .collect();
    format!(
        r#"(
    exposed_endpoints: [ (ron_name: "door", ron_url: "127.0.0.1:{grpc}", ron_http_url: Some("127.0.0.1:{http}")) ],
    storage_endpoints: [ (ron_name: "disk", ron_storage_type: "znippy", ron_path: "{d}/store") ],
    repositories: [ {} {} {} {} ],
    audit: (dir: "{d}/audit", enabled: true),
    auth: Some((
        methods: [ {} ],
        duties: {{ "ida": [Importer], "bob": [SecurityApprover], "adm": [RepositoryAdmin], "aud": [Auditor] }},
    )),
    {tier1}
)"#,
        repo("incoming"),
        repo("quarantine"),
        repo("approved"),
        repo("production"),
        methods.join(", ")
    )
}

const TIER1: &str = r#"sources: [ (name: "team", kind: upload, gates: (license: (deny: ["AGPL-3.0-only"]))) ],
    steps: (approvals: 1, unknown_license: Pass),
    rules: (sandbox: off, require_signed: false, require_provenance: false),"#;

struct Server {
    child: Child,
    _dir: tempfile::TempDir,
    http: u16,
    grpc: u16,
}

impl Drop for Server {
    fn drop(&mut self) {
        let _ = self.child.kill();
        let _ = self.child.wait();
    }
}

fn free_port() -> u16 {
    std::net::TcpListener::bind("127.0.0.1:0")
        .unwrap()
        .local_addr()
        .unwrap()
        .port()
}

fn start(tier1: &str) -> Server {
    let dir = tempfile::tempdir().unwrap();
    let (grpc, http) = (free_port(), free_port());
    let cfg = dir.path().join("holger.ron");
    std::fs::write(&cfg, tier1_ron(dir.path(), grpc, http, tier1)).unwrap();
    let child = Command::new(BIN)
        .args(["start", "--config"])
        .arg(&cfg)
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .spawn()
        .expect("spawn holger");
    let s = Server {
        child,
        _dir: dir,
        http,
        grpc,
    };
    let deadline = Instant::now() + Duration::from_secs(30);
    while Instant::now() < deadline {
        if let Ok((200, _)) = request(s.http, "GET", "/healthz", None, b"") {
            return s;
        }
        std::thread::sleep(Duration::from_millis(50));
    }
    panic!("holger never answered /healthz");
}

/// One HTTP/1.1 request; the status and the body.
fn request(
    port: u16,
    method: &str,
    path: &str,
    who: Option<&str>,
    body: &[u8],
) -> std::io::Result<(u16, String)> {
    let mut c = TcpStream::connect(("127.0.0.1", port))?;
    c.set_read_timeout(Some(Duration::from_secs(20)))?;
    let auth = who
        .map(|w| format!("Authorization: Bearer {}\r\n", token(w)))
        .unwrap_or_default();
    write!(
        c,
        "{method} {path} HTTP/1.1\r\nHost: 127.0.0.1\r\n{auth}Content-Length: {}\r\nConnection: close\r\n\r\n",
        body.len()
    )?;
    c.write_all(body)?;
    let mut raw = Vec::new();
    c.read_to_end(&mut raw)?;
    let text = String::from_utf8_lossy(&raw).to_string();
    let status = text
        .split(' ')
        .nth(1)
        .and_then(|s| s.parse().ok())
        .unwrap_or(0);
    let body = text
        .split_once("\r\n\r\n")
        .map(|(_, b)| b.to_string())
        .unwrap_or_default();
    Ok((status, body))
}

fn wheel() -> Vec<u8> {
    zip_entry::fixture::zip(&[
        ("demo_pkg/__init__.py", b"".as_slice()),
        (
            "demo_pkg-1.0.0.dist-info/METADATA",
            b"Metadata-Version: 2.1\nName: demo-pkg\nVersion: 1.0.0\nLicense-Expression: MIT\n"
                .as_slice(),
        ),
    ])
}

fn state(s: &Server) -> serde_json::Value {
    let (code, body) = request(
        s.http,
        "GET",
        &format!("/-/intake/state?name={WHEEL}"),
        Some("aud"),
        b"",
    )
    .unwrap();
    assert_eq!(code, 200, "{body}");
    serde_json::from_str(body.trim()).unwrap_or_else(|e| panic!("{e}: {body}"))
}

#[test]
fn an_upload_is_ingested_and_moves_through_the_steps_the_ron_turns_on() {
    let s = start(TIER1);
    let (code, body) = request(
        s.http,
        "PUT",
        &format!("/incoming/{WHEEL}"),
        Some("ida"),
        &wheel(),
    )
    .unwrap();
    assert_eq!(code, 201, "the Importer's upload is INGESTED: {body}");

    let st = state(&s);
    assert_eq!(st["state"], "INGESTED");
    assert_eq!(st["source"], "team");
    assert_eq!(st["effective_policy"]["source"], "team");
    assert!(
        st["effective_policy"]["deny_licenses"]
            .to_string()
            .contains("AGPL-3.0-only"),
        "{st}"
    );

    // The CLI shows the same state, with the source.
    let out = Command::new(BIN)
        .args([
            "intake",
            "state",
            "--server",
            &format!("127.0.0.1:{}", s.grpc),
            "--name",
            WHEEL,
        ])
        .env("HOLGER_TOKEN", token("aud"))
        .output()
        .unwrap();
    let text = String::from_utf8_lossy(&out.stdout);
    assert!(
        out.status.success(),
        "{text}{}",
        String::from_utf8_lossy(&out.stderr)
    );
    assert!(
        text.starts_with("INGESTED") && text.contains("source team"),
        "{text}"
    );

    // Every step the RON turns on, by the duty that may take it.
    for (who, want) in [
        ("bob", "SCANNED"),
        ("bob", "POLICY_CHECKED"),
        ("bob", "APPROVED"),
        ("adm", "SEALED"),
        ("bob", "PROMOTED"),
        ("adm", "AVAILABLE"),
    ] {
        let (code, body) = request(
            s.http,
            "POST",
            &format!("/-/intake/advance?name={WHEEL}&verb=advance"),
            Some(who),
            b"",
        )
        .unwrap();
        assert_eq!(code, 200, "{who} → {want}: {body}");
        assert_eq!(state(&s)["state"], want);
    }
    let (code, _) = request(
        s.http,
        "GET",
        &format!("/production/{WHEEL}"),
        Some("aud"),
        b"",
    )
    .unwrap();
    assert_eq!(code, 200, "production serves it once AVAILABLE");
    let st = state(&s);
    let scanned = st["history"]
        .as_array()
        .unwrap()
        .iter()
        .find(|e| e["to"] == "SCANNED")
        .expect("a SCANNED line");
    assert_eq!(scanned["origin"], "team", "the source rides on every line");
}

/// The binary refuses a RON it cannot honour, and says what.
fn refusal(tier1: &str) -> String {
    let dir = tempfile::tempdir().unwrap();
    let cfg = dir.path().join("holger.ron");
    std::fs::write(&cfg, tier1_ron(dir.path(), free_port(), free_port(), tier1)).unwrap();
    let out = Command::new(BIN)
        .args(["start", "--config"])
        .arg(&cfg)
        .output()
        .expect("run holger");
    assert!(!out.status.success(), "must not start: {tier1}");
    format!(
        "{}{}",
        String::from_utf8_lossy(&out.stdout),
        String::from_utf8_lossy(&out.stderr)
    )
}

#[test]
fn the_rons_refusals_are_named() {
    let e = refusal(r#"sources: [ (name: "team", kind: upload) ], steps: (aprovals: 1),"#);
    assert!(e.contains("aprovals"), "an unknown key in steps: {e}");
    let e =
        refusal(r#"sources: [ (name: "team", kind: upload, gates: (malware: off)) ], steps: (),"#);
    assert!(
        e.contains("source 'team'") && e.contains("malware: on") && e.contains("loosens"),
        "{e}"
    );
    let e = refusal(r#"sources: [ (name: "pypi", kind: python) ], steps: (),"#);
    assert!(e.contains("python"), "{e}");
}