server/cli/tests/e2e_internet_to_build_systems.rs
//! **H6: Holger's end-to-end proof gate** (Holger v2.0, `docs/HOLGER-V2.md`).
//!
//! The whole chain of the picture, with real binaries and real build systems:
//!
//! ```text
//! FAKE INTERNET ──pull──► UPSTREAM (holger) ──signed znippy bundle──► USB ──► DOWNSTREAM ──► pip, uv, cargo,
//! PyPI, crates, pull, verify, scan, + the signed sync (holger-downstream, mvn, skopeo, go
//! Maven, OCI, GOPROXY two-person approve, manifest airgapped: dials
//! sign the sync nothing)
//! ▲ │
//! └──────────── the signed ack, back on the USB ──────┘
//! ```
//!
//! 1. **The internet** is a local HTTP server speaking each registry's protocol (PEP 503,
//! the cargo sparse index, a Maven 2 layout with checksums, the OCI distribution API,
//! GOPROXY) over SMALL packages made here: `demo-pkg` (a wheel), `demo-crate`,
//! `org.demo:demo-lib` (a JAR compiled here with `javac`), the image `demo/hello` and the
//! module `example.com/hello`. No test ever touches the real internet.
//! 2. **The upstream** is the real `holger` binary: each package is asked for at its door,
//! pulled into the intake chain as `pull-through:<source>`, scanned (vulnerability, SBOM,
//! secrets; the evidence DSSE-signed), and waits at POLICY_CHECKED until TWO approvers
//! (`bob`, `carl`, neither the importer) approve it over `holger intake advance`.
//! 3. **The USB**: `holger export` writes the candidate (the sync manifest in it),
//! `holger-cli bundle approve` twice (security-reviewer, system-owner) and `holger-cli
//! bundle finalize` (a distinct release signer) write the signed `.holger.znippy` into a
//! directory, the "stick".
//! 4. **The downstream** is the real `holger-downstream` binary (`cargo install
//! holger-downstream`): `bundle import` verifies and lands everything, `start` serves
//! it, and the connect trap proves it dials nothing at all.
//! 5. **The build systems** build against it: `pip` and `uv` install the wheel and import it,
//! `cargo` builds and runs a crate that depends on `demo-crate`, `mvn` compiles and packages
//! a project that calls `org.demo.Demo`, `skopeo` copies the image, `podman` pulls it, `go` builds and runs a
//! module that imports `example.com/hello`.
//! 6. **The invalidation**: the upstream invalidates the wheel (`sync invalidate`), the next
//! sync goes over on the stick (`sync manifest`), the downstream holds it (`sync apply`),
//! `pip` and `uv` then FAIL naming `demo-pkg` while `cargo` still builds, and the signed ack
//! goes back (`sync ack`): the upstream's board (`sync board`) shows the invalidation
//! reached `onprem`.
//!
//! **Where it runs:** `cargo xtask e2e` runs this file inside the `holger-e2e-clients` image
//! (`distribution/e2e-clients/Containerfile`) with `--network none` and
//! `HOLGER_E2E_REQUIRED=1`. Anywhere a client is missing it SKIPS BY NAME (and fails when
//! required). Every step's wall time and outcome go to the receipt (`HOLGER_E2E_RECEIPT`).
//!
//! Binaries beside the test's `holger`, or named by env: `holger-downstream`
//! (`HOLGER_DOWNSTREAM_BIN`) and `holger-cli` (`HOLGER_CLI_BIN`), whose `bundle` verbs sign
//! the bundle (the retired `holger-bundle` program's).
use std::collections::BTreeMap;
use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};
use std::path::{Path, PathBuf};
use std::process::{Child, Command, Output, Stdio};
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
use traits::test_support::hold_port;
const BIN: &str = env!("CARGO_BIN_EXE_holger");
const WHEEL: &str = "demo_pkg-1.0.0-py3-none-any.whl";
const IMAGE: &str = "demo/hello";
const TAG: &str = "1.0";
const GREETING: &str = "hello from holger";
/// The client programs the gate drives (and `cc` for the connect trap).
const CLIENTS: &[&str] = &[
"python3", "uv", "cargo", "mvn", "javac", "jar", "java", "go", "skopeo", "podman", "cc",
"clamd",
];
/// The gate's clamd configuration (the clients image's, `distribution/e2e-clients/clamav/`):
/// the pinned signature set only, a unix socket, no freshclam.
const CLAMD_CONF: &str = "/etc/holger-e2e/clamd.conf";
/// The gate's pinned YARA rules (the clients image's, `distribution/e2e-clients/yara/`).
const YARA_RULES: &str = "/opt/holger-e2e/yara";
fn text(o: &Output) -> String {
format!(
"{}{}",
String::from_utf8_lossy(&o.stdout),
String::from_utf8_lossy(&o.stderr)
)
}
fn sha256(b: &[u8]) -> String {
update_bundle::digest::sha256_hex(b)
}
fn on_path(prog: &str) -> bool {
std::env::var_os("PATH")
.is_some_and(|p| std::env::split_paths(&p).any(|d| d.join(prog).is_file()))
}
// ── the receipt ─────────────────────────────────────────────────────────────
/// One step of the gate: its name, whether it held, its wall time and what it saw.
#[derive(Default)]
struct Receipt {
steps: Vec<serde_json::Value>,
started: Option<Instant>,
}
impl Receipt {
fn step<T>(&mut self, name: &str, f: impl FnOnce() -> Result<(T, String), String>) -> T {
let t = Instant::now();
let r = f();
let ms = t.elapsed().as_millis() as u64;
let (ok, detail) = match &r {
Ok((_, d)) => (true, d.clone()),
Err(e) => (false, e.clone()),
};
eprintln!(
"── e2e {name}: {} in {ms} ms ──\n{detail}",
if ok { "ok" } else { "RED" }
);
self.steps.push(
serde_json::json!({ "step": name, "ok": ok, "ms": ms, "detail": tail(&detail, 4000) }),
);
self.write();
match r {
Ok((v, _)) => v,
Err(e) => panic!("e2e step '{name}' is RED:\n{e}"),
}
}
fn write(&self) {
let Ok(path) = std::env::var("HOLGER_E2E_RECEIPT") else {
return;
};
let all_ok = self.steps.iter().all(|s| s["ok"] == true);
let doc = serde_json::json!({
"schema": "holger.e2e-receipt/v1",
"gate": "H6 internet → upstream → USB → downstream → build systems + invalidation",
"ok": all_ok,
"wall_ms": self.started.map(|t| t.elapsed().as_millis() as u64).unwrap_or(0),
"steps": self.steps,
});
let _ = std::fs::write(path, serde_json::to_vec_pretty(&doc).unwrap());
}
}
fn tail(s: &str, n: usize) -> String {
if s.len() <= n {
return s.to_string();
}
let mut i = s.len() - n;
while !s.is_char_boundary(i) {
i += 1;
}
format!("…{}", &s[i..])
}
// ── the packages the internet publishes ─────────────────────────────────────
const METADATA: &str =
"Metadata-Version: 2.1\nName: demo-pkg\nVersion: 1.0.0\nLicense-Expression: MIT\n";
fn wheel() -> Vec<u8> {
zip_entry::fixture::zip(&[
("demo_pkg/__init__.py", b"__version__ = \"1.0.0\"\n\ndef greet():\n return \"hello from holger\"\n"),
("demo_pkg-1.0.0.dist-info/METADATA", METADATA.as_bytes()),
("demo_pkg-1.0.0.dist-info/WHEEL", b"Wheel-Version: 1.0\nGenerator: holger-e2e\nRoot-Is-Purelib: true\nTag: py3-none-any\n"),
("demo_pkg-1.0.0.dist-info/RECORD", b""),
])
}
fn tar_gz(entries: &[(&str, &[u8])]) -> (Vec<u8>, Vec<u8>) {
let mut tar = tar::Builder::new(Vec::new());
for (path, body) in entries {
let mut h = tar::Header::new_gnu();
h.set_size(body.len() as u64);
h.set_mode(0o644);
h.set_mtime(0);
h.set_cksum();
tar.append_data(&mut h, path, *body).unwrap();
}
let raw = tar.into_inner().unwrap();
let mut gz = flate2::write::GzEncoder::new(Vec::new(), flate2::Compression::default());
gz.write_all(&raw).unwrap();
(gz.finish().unwrap(), raw)
}
const CRATE_MANIFEST: &str = "[package]\nname = \"demo-crate\"\nversion = \"0.1.0\"\nedition = \"2021\"\ndescription = \"a demo\"\nlicense = \"MIT\"\n";
fn dot_crate() -> Vec<u8> {
tar_gz(&[
("demo-crate-0.1.0/Cargo.toml", CRATE_MANIFEST.as_bytes()),
(
"demo-crate-0.1.0/src/lib.rs",
b"pub fn greet() -> &'static str { \"hello from holger\" }\n",
),
])
.0
}
fn crate_index_line() -> String {
serde_json::json!({
"name": "demo-crate", "vers": "0.1.0", "deps": [], "cksum": sha256(&dot_crate()),
"features": {}, "yanked": false
})
.to_string()
}
const POM: &str = r#"<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>org.demo</groupId>
<artifactId>demo-lib</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
</project>
"#;
/// `org.demo:demo-lib:1.0.0`'s JAR, compiled here (the gate's image has a JDK).
fn jar(work: &Path) -> Result<Vec<u8>, String> {
let src = work.join("demo-lib/org/demo");
std::fs::create_dir_all(&src).map_err(|e| e.to_string())?;
std::fs::write(src.join("Demo.java"), format!("package org.demo;\n\npublic class Demo {{\n public static String greet() {{ return \"{GREETING}\"; }}\n}}\n"))
.map_err(|e| e.to_string())?;
let classes = work.join("demo-lib/classes");
let out = Command::new("javac")
.arg("--release")
.arg("17")
.arg("-d")
.arg(&classes)
.arg(src.join("Demo.java"))
.output()
.map_err(|e| format!("javac: {e}"))?;
if !out.status.success() {
return Err(format!("javac: {}", text(&out)));
}
let jar = work.join("demo-lib/demo-lib-1.0.0.jar");
let out = Command::new("jar")
.arg("cf")
.arg(&jar)
.arg("-C")
.arg(&classes)
.arg(".")
.output()
.map_err(|e| format!("jar: {e}"))?;
if !out.status.success() {
return Err(format!("jar: {}", text(&out)));
}
std::fs::read(&jar).map_err(|e| e.to_string())
}
const GO_MOD: &str = "module example.com/hello\n\ngo 1.21\n";
fn go_zip() -> Vec<u8> {
zip_entry::fixture::zip(&[
("example.com/hello@v1.0.0/go.mod", GO_MOD.as_bytes()),
(
"example.com/hello@v1.0.0/hello.go",
b"package hello\n\nfunc Hello() string { return \"hello from holger\" }\n",
),
])
}
// ── the packages the gate must HOLD (A29-11: ClamAV and YARA in the gate) ─────
/// The wheel that carries the EICAR test file: ClamAV's to hold.
const EVIL_WHEEL: &str = "evil_pkg-1.0.0-py3-none-any.whl";
/// The crate that carries the YARA fixture's marker: YARA's to hold.
const DROPPER_CRATE: &str = "dropper-crate";
/// The YARA fixture rule's string (the gate's pinned rule,
/// `distribution/e2e-clients/yara/holger-e2e.yar`). Written in two halves here so this
/// source is not a match itself.
fn yara_marker() -> String {
format!("{}{}", "HOLGER-E2E-YARA-FIXTURE", ": a dropper's marker")
}
/// The YARA fixture rule's name, as the scanner reports it.
const YARA_RULE: &str = "Holger_E2E_Fixture_Marker";
/// The pinned ClamAV signature's name (`distribution/e2e-clients/clamav/holger-e2e.ndb`).
const CLAM_SIG: &str = "Holger-E2E-Eicar";
/// The EICAR test file, in two halves so this source is not a match itself.
fn eicar() -> Vec<u8> {
format!(
"{}{}",
"X5O!P%@AP[4\\PZX54(P^)7CC)7}$", "EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*"
)
.into_bytes()
}
fn evil_wheel() -> Vec<u8> {
let eicar = eicar();
zip_entry::fixture::zip(&[
("evil_pkg/__init__.py", b"__version__ = \"1.0.0\"\n".as_slice()),
("evil_pkg/eicar.txt", eicar.as_slice()),
("evil_pkg-1.0.0.dist-info/METADATA", b"Metadata-Version: 2.1\nName: evil-pkg\nVersion: 1.0.0\nLicense-Expression: MIT\n".as_slice()),
("evil_pkg-1.0.0.dist-info/WHEEL", b"Wheel-Version: 1.0\nGenerator: holger-e2e\nRoot-Is-Purelib: true\nTag: py3-none-any\n".as_slice()),
("evil_pkg-1.0.0.dist-info/RECORD", b"".as_slice()),
])
}
const DROPPER_MANIFEST: &str = "[package]\nname = \"dropper-crate\"\nversion = \"0.1.0\"\nedition = \"2021\"\ndescription = \"a dropper\"\nlicense = \"MIT\"\n";
fn dropper_crate() -> Vec<u8> {
let lib = format!("pub const MARK: &str = \"{}\";\n", yara_marker());
tar_gz(&[
(
"dropper-crate-0.1.0/Cargo.toml",
DROPPER_MANIFEST.as_bytes(),
),
("dropper-crate-0.1.0/src/lib.rs", lib.as_bytes()),
])
.0
}
fn dropper_index_line() -> String {
serde_json::json!({
"name": DROPPER_CRATE, "vers": "0.1.0", "deps": [], "cksum": sha256(&dropper_crate()),
"features": {}, "yanked": false
})
.to_string()
}
/// The states a package reaches only by passing the scan.
const PASSED_THE_SCAN: &[&str] = &[
"SCANNED",
"POLICY_CHECKED",
"APPROVED",
"SEALED",
"PROMOTED",
"AVAILABLE",
];
/// Pure: **is this package held at the scan, by `scanner`, naming `signature`?** `state` is
/// `holger intake state`'s first line (or its refusal), `said` everything the upstream said
/// about it (the door's answer, the state's history, the server log). `Some(Err)`: it
/// passed the scan, which the gate is red on BY NAME; `Some(Ok)`: held, and the scanner and
/// its signature are named; `None`: not settled yet.
fn held_at_the_scan(
name: &str,
state: &str,
said: &str,
scanner: &str,
signature: &str,
) -> Option<Result<String, String>> {
if PASSED_THE_SCAN.iter().any(|s| state.starts_with(s)) {
return Some(Err(format!(
"{name} PASSED the scan: it stands at {state}; {scanner} never held it"
)));
}
let named = format!("{scanner}: {signature}");
let line = said.lines().find(|l| l.contains(&named))?;
Some(Ok(format!(
"{name} is held at the scan by {scanner} ({signature}): {}",
line.trim()
)))
}
/// The image `demo/hello:1.0`: one layer, a file and the package catalog an image scan
/// reads (a Wolfi `os-release` and its apk database; an image whose packages cannot be
/// read is refused at SCANNED, by design).
struct Image {
digest: String,
manifest: Vec<u8>,
config: (String, Vec<u8>),
layer: (String, Vec<u8>),
}
fn image() -> Image {
let (layer, raw) = tar_gz(&[
("hello.txt", b"hello from holger\n"),
("etc/os-release", b"ID=wolfi\nNAME=\"Wolfi\"\n"),
("lib/apk/db/installed", b"P:hello\nV:1.0-r0\no:hello\n\n"),
]);
let digest = |b: &[u8]| format!("sha256:{}", sha256(b));
let config = serde_json::to_vec(&serde_json::json!({
"architecture": "amd64", "os": "linux",
"rootfs": { "type": "layers", "diff_ids": [digest(&raw)] },
"config": {}
}))
.unwrap();
let manifest = serde_json::to_vec(&serde_json::json!({
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": { "mediaType": "application/vnd.oci.image.config.v1+json", "digest": digest(&config), "size": config.len() },
"layers": [ { "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", "digest": digest(&layer), "size": layer.len() } ]
}))
.unwrap();
Image {
digest: digest(&manifest),
manifest,
config: (digest(&config), config),
layer: (digest(&layer), layer),
}
}
// ── the fake internet ───────────────────────────────────────────────────────
/// One reply of the fake internet: content type, body, extra headers.
type Route = (String, Vec<u8>, Vec<(String, String)>);
struct Internet {
base: String,
hits: Arc<Mutex<BTreeMap<String, usize>>>,
}
impl Internet {
fn hit(&self, path: &str) -> usize {
self.hits.lock().unwrap().get(path).copied().unwrap_or(0)
}
}
/// Every path the internet answers (GET and HEAD), each registry under its own prefix.
fn internet_routes(base: &str, jar: &[u8]) -> BTreeMap<String, Route> {
let mut r: BTreeMap<String, Route> = BTreeMap::new();
let mut put = |p: &str, ctype: &str, body: Vec<u8>, h: Vec<(String, String)>| {
r.insert(p.to_string(), (ctype.to_string(), body, h));
};
// PyPI (PEP 503).
let whl = wheel();
put(
"/pypi/simple/demo-pkg/",
"text/html",
format!("<!DOCTYPE html><html><body><a href=\"/pypi/files/{WHEEL}#sha256={}\">{WHEEL}</a></body></html>\n", sha256(&whl)).into_bytes(),
vec![],
);
put(
&format!("/pypi/files/{WHEEL}"),
"application/octet-stream",
whl,
vec![],
);
let evil = evil_wheel();
put(
"/pypi/simple/evil-pkg/",
"text/html",
format!("<!DOCTYPE html><html><body><a href=\"/pypi/files/{EVIL_WHEEL}#sha256={}\">{EVIL_WHEEL}</a></body></html>\n", sha256(&evil)).into_bytes(),
vec![],
);
put(
&format!("/pypi/files/{EVIL_WHEEL}"),
"application/octet-stream",
evil,
vec![],
);
// crates.io (the sparse index and its downloads).
put(
"/crates/index/config.json",
"application/json",
serde_json::json!({ "dl": format!("{base}/crates/dl") })
.to_string()
.into_bytes(),
vec![],
);
put(
"/crates/index/de/mo/demo-crate",
"text/plain",
format!("{}\n", crate_index_line()).into_bytes(),
vec![],
);
put(
"/crates/dl/demo-crate/0.1.0/download",
"application/x-tar",
dot_crate(),
vec![],
);
put(
"/crates/index/dr/op/dropper-crate",
"text/plain",
format!("{}\n", dropper_index_line()).into_bytes(),
vec![],
);
put(
"/crates/dl/dropper-crate/0.1.0/download",
"application/x-tar",
dropper_crate(),
vec![],
);
// Maven Central (a Maven 2 layout with its `.sha256` checksums).
let dir = "/maven2/org/demo/demo-lib";
for (file, body) in [
("demo-lib-1.0.0.pom", POM.as_bytes().to_vec()),
("demo-lib-1.0.0.jar", jar.to_vec()),
] {
put(
&format!("{dir}/1.0.0/{file}.sha256"),
"text/plain",
sha256(&body).into_bytes(),
vec![],
);
put(
&format!("{dir}/1.0.0/{file}"),
"application/octet-stream",
body,
vec![],
);
}
put(
&format!("{dir}/maven-metadata.xml"),
"text/xml",
b"<metadata><groupId>org.demo</groupId><artifactId>demo-lib</artifactId><versioning><latest>1.0.0</latest><release>1.0.0</release><versions><version>1.0.0</version></versions></versioning></metadata>\n".to_vec(),
vec![],
);
// An OCI registry.
let img = image();
put("/v2/", "application/json", b"{}".to_vec(), vec![]);
let mh = vec![("Docker-Content-Digest".to_string(), img.digest.clone())];
put(
&format!("/v2/{IMAGE}/manifests/{TAG}"),
"application/vnd.oci.image.manifest.v1+json",
img.manifest.clone(),
mh.clone(),
);
put(
&format!("/v2/{IMAGE}/manifests/{}", img.digest),
"application/vnd.oci.image.manifest.v1+json",
img.manifest,
mh,
);
put(
&format!("/v2/{IMAGE}/blobs/{}", img.config.0),
"application/octet-stream",
img.config.1,
vec![],
);
put(
&format!("/v2/{IMAGE}/blobs/{}", img.layer.0),
"application/octet-stream",
img.layer.1,
vec![],
);
put(
&format!("/v2/{IMAGE}/tags/list"),
"application/json",
serde_json::json!({ "name": IMAGE, "tags": [TAG] })
.to_string()
.into_bytes(),
vec![],
);
// proxy.golang.org (GOPROXY).
put(
"/goproxy/example.com/hello/@v/list",
"text/plain",
b"v1.0.0\n".to_vec(),
vec![],
);
put(
"/goproxy/example.com/hello/@v/v1.0.0.info",
"application/json",
br#"{"Version":"v1.0.0","Time":"2026-10-01T00:00:00Z"}"#.to_vec(),
vec![],
);
put(
"/goproxy/example.com/hello/@v/v1.0.0.mod",
"text/plain",
GO_MOD.as_bytes().to_vec(),
vec![],
);
put(
"/goproxy/example.com/hello/@v/v1.0.0.zip",
"application/zip",
go_zip(),
vec![],
);
put(
"/goproxy/example.com/hello/@latest",
"application/json",
br#"{"Version":"v1.0.0","Time":"2026-10-01T00:00:00Z"}"#.to_vec(),
vec![],
);
r
}
fn internet(jar: &[u8]) -> Internet {
let l = TcpListener::bind("127.0.0.1:0").unwrap();
let base = format!("http://{}", l.local_addr().unwrap());
let routes = Arc::new(internet_routes(&base, jar));
let hits: Arc<Mutex<BTreeMap<String, usize>>> = Arc::default();
let h2 = Arc::clone(&hits);
std::thread::spawn(move || {
for s in l.incoming().flatten() {
let (r, h) = (Arc::clone(&routes), Arc::clone(&h2));
std::thread::spawn(move || serve_one(s, &r, &h));
}
});
Internet { base, hits }
}
fn serve_one(
mut s: TcpStream,
routes: &BTreeMap<String, Route>,
hits: &Mutex<BTreeMap<String, usize>>,
) {
let _ = s.set_read_timeout(Some(Duration::from_secs(10)));
let mut buf = Vec::new();
let mut chunk = [0u8; 4096];
while !buf.windows(4).any(|w| w == b"\r\n\r\n") {
match s.read(&mut chunk) {
Ok(0) | Err(_) => return,
Ok(n) => buf.extend_from_slice(&chunk[..n]),
}
}
let head = String::from_utf8_lossy(&buf).to_string();
let mut first = head.lines().next().unwrap_or("").split_whitespace();
let method = first.next().unwrap_or("GET").to_string();
let path = first
.next()
.unwrap_or("/")
.split('?')
.next()
.unwrap_or("/")
.to_string();
*hits.lock().unwrap().entry(path.clone()).or_default() += 1;
let (status, (ctype, body, headers)) = match routes.get(&path) {
Some(r) => (200, r.clone()),
None => (
404,
("text/plain".to_string(), b"not found".to_vec(), vec![]),
),
};
let mut out = format!("HTTP/1.1 {status} X\r\nContent-Length: {}\r\nContent-Type: {ctype}\r\nConnection: close\r\n", body.len());
for (k, v) in headers {
out.push_str(&format!("{k}: {v}\r\n"));
}
out.push_str("\r\n");
let _ = s.write_all(out.as_bytes());
if method != "HEAD" {
let _ = s.write_all(&body);
}
}
// ── HTTP to a Holger ────────────────────────────────────────────────────────
struct Reply {
status: u16,
body: Vec<u8>,
}
impl Reply {
fn text(&self) -> String {
String::from_utf8_lossy(&self.body).to_string()
}
}
fn get(port: u16, path: &str, accept: Option<&str>) -> Reply {
let Ok(mut s) = TcpStream::connect(("127.0.0.1", port)) else {
return Reply {
status: 0,
body: Vec::new(),
};
};
let _ = s.set_read_timeout(Some(Duration::from_secs(90)));
let mut req = format!("GET {path} HTTP/1.1\r\nHost: 127.0.0.1\r\nConnection: close\r\n");
if let Some(a) = accept {
req.push_str(&format!("Accept: {a}\r\n"));
}
req.push_str("\r\n");
if s.write_all(req.as_bytes()).is_err() {
return Reply {
status: 0,
body: Vec::new(),
};
}
let mut raw = Vec::new();
let _ = s.read_to_end(&mut raw);
let split = raw
.windows(4)
.position(|w| w == b"\r\n\r\n")
.map(|i| i + 4)
.unwrap_or(raw.len());
let head = String::from_utf8_lossy(&raw[..split]).to_string();
let status = head
.split_whitespace()
.nth(1)
.and_then(|s| s.parse().ok())
.unwrap_or(0);
let mut body = raw[split..].to_vec();
if head
.to_ascii_lowercase()
.contains("transfer-encoding: chunked")
{
let mut out = Vec::new();
let mut rest = &body[..];
while let Some(nl) = rest.windows(2).position(|w| w == b"\r\n") {
let n =
usize::from_str_radix(std::str::from_utf8(&rest[..nl]).unwrap_or("0").trim(), 16)
.unwrap_or(0);
if n == 0 || rest.len() < nl + 2 + n {
break;
}
out.extend_from_slice(&rest[nl + 2..nl + 2 + n]);
rest = &rest[nl + 2 + n + 2..];
}
body = out;
}
Reply { status, body }
}
// ── processes ───────────────────────────────────────────────────────────────
fn beside(env: &str, name: &str, build: &str) -> PathBuf {
if let Ok(p) = std::env::var(env) {
return PathBuf::from(p);
}
let p = Path::new(BIN).with_file_name(name);
assert!(
p.exists(),
"no {name}: build it first with `{build}` (into this target directory), or set {env}"
);
p
}
fn downstream_bin() -> PathBuf {
beside("HOLGER_DOWNSTREAM_BIN", "holger-downstream", "cargo build --manifest-path holger-downstream/Cargo.toml --features sandbox-off --target-dir <this target directory>")
}
/// `holger-cli`, whose `bundle approve|finalize` sign the export (lane HOL-PRODUCTS).
fn cli_bin() -> PathBuf {
beside("HOLGER_CLI_BIN", "holger-cli", "cargo build -p holger-cli")
}
/// A running server: killed when dropped.
struct Server {
child: Option<Child>,
log: PathBuf,
}
impl Server {
fn start(
bin: &Path,
config: &Path,
http: u16,
log: &Path,
trap: Option<&Path>,
) -> Result<Server, String> {
let f = std::fs::File::create(log).map_err(|e| e.to_string())?;
let mut c = Command::new(bin);
if let Some(t) = trap {
trapped(&mut c, t);
}
let child = c
.args(["start", "--config"])
.arg(config)
.stdout(Stdio::from(f.try_clone().unwrap()))
.stderr(Stdio::from(f))
.spawn()
.map_err(|e| format!("{}: {e}", bin.display()))?;
let s = Server {
child: Some(child),
log: log.to_path_buf(),
};
let t = Instant::now();
let mut s = s;
while TcpStream::connect(("127.0.0.1", http)).is_err() {
let exited = s.child.as_mut().and_then(|c| c.try_wait().ok().flatten());
if let Some(status) = exited {
return Err(format!(
"the server exited ({status}) before it listened on :{http}:\n{}",
s.log()
));
}
if t.elapsed() > Duration::from_secs(60) {
return Err(format!(
"the server on :{http} never listened:\n{}",
s.log()
));
}
std::thread::sleep(Duration::from_millis(100));
}
Ok(s)
}
fn log(&self) -> String {
std::fs::read_to_string(&self.log).unwrap_or_default()
}
fn stop(&mut self) {
if let Some(mut c) = self.child.take() {
let _ = c.kill();
let _ = c.wait();
}
}
}
impl Drop for Server {
fn drop(&mut self) {
self.stop();
}
}
/// Run a CLI verb; `Ok(output text)` when it exits 0.
fn run(c: &mut Command) -> Result<String, String> {
let out = c.output().map_err(|e| format!("{c:?}: {e}"))?;
let t = text(&out);
if out.status.success() {
Ok(t)
} else {
Err(format!("{c:?} exited {}:\n{t}", out.status))
}
}
// ── the connect trap (zero egress at run time) ──────────────────────────────
/// An `LD_PRELOAD` shim recording every `connect`/`sendto` to an IP address and every
/// `getaddrinfo` into `$HOLGER_CONNECT_LOG` (the same trap as the H3 serve test).
const TRAP_C: &str = r#"
#define _GNU_SOURCE
#include <dlfcn.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
static void note(const char *line) {
const char *p = getenv("HOLGER_CONNECT_LOG");
if (!p) return;
int f = open(p, O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, 0644);
if (f < 0) return;
int n = 0; while (line[n]) n++;
ssize_t w = write(f, line, n); (void)w;
close(f);
}
static void note_addr(const struct sockaddr *a) {
char host[INET6_ADDRSTRLEN] = "?", line[160]; int port = 0;
if (!a) return;
if (a->sa_family == AF_INET) {
const struct sockaddr_in *s = (const void *)a;
inet_ntop(AF_INET, &s->sin_addr, host, sizeof host); port = ntohs(s->sin_port);
} else if (a->sa_family == AF_INET6) {
const struct sockaddr_in6 *s = (const void *)a;
inet_ntop(AF_INET6, &s->sin6_addr, host, sizeof host); port = ntohs(s->sin6_port);
} else return;
snprintf(line, sizeof line, "inet %s %d\n", host, port);
note(line);
}
int connect(int fd, const struct sockaddr *a, socklen_t l) {
static int (*real)(int, const struct sockaddr *, socklen_t);
if (!real) real = dlsym(RTLD_NEXT, "connect");
note_addr(a);
return real(fd, a, l);
}
ssize_t sendto(int fd, const void *b, size_t n, int fl, const struct sockaddr *a, socklen_t l) {
static ssize_t (*real)(int, const void *, size_t, int, const struct sockaddr *, socklen_t);
if (!real) real = dlsym(RTLD_NEXT, "sendto");
note_addr(a);
return real(fd, b, n, fl, a, l);
}
int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) {
static int (*real)(const char *, const char *, const struct addrinfo *, struct addrinfo **);
if (!real) real = dlsym(RTLD_NEXT, "getaddrinfo");
char line[300];
snprintf(line, sizeof line, "dns %s\n", node ? node : "?");
note(line);
return real(node, service, hints, res);
}
"#;
/// The trap, built with `cc` and proven to record (a bash `/dev/tcp` connect must show up).
fn trap(dir: &Path) -> Result<PathBuf, String> {
let (c, so) = (dir.join("trap.c"), dir.join("trap.so"));
std::fs::write(&c, TRAP_C).map_err(|e| e.to_string())?;
run(Command::new("cc")
.args(["-shared", "-fPIC", "-O1", "-o"])
.arg(&so)
.arg(&c)
.arg("-ldl"))?;
let l = TcpListener::bind("127.0.0.1:0").map_err(|e| e.to_string())?;
let port = l.local_addr().unwrap().port();
let log = dir.join("control.log");
run(Command::new("bash")
.args(["-c", &format!("exec 3<>/dev/tcp/127.0.0.1/{port}")])
.env("LD_PRELOAD", &so)
.env("HOLGER_CONNECT_LOG", &log))?;
let seen = std::fs::read_to_string(&log).unwrap_or_default();
if !seen.contains(&format!("inet 127.0.0.1 {port}")) {
return Err(format!(
"the trap records nothing; it would prove nothing: {seen:?}"
));
}
Ok(so)
}
static TRAP_SO: std::sync::OnceLock<PathBuf> = std::sync::OnceLock::new();
fn trapped<'a>(c: &'a mut Command, log: &Path) -> &'a mut Command {
c.env(
"LD_PRELOAD",
TRAP_SO.get().expect("the trap is built first"),
)
.env("HOLGER_CONNECT_LOG", log)
}
/// `--network none` when asked: no default route out of this namespace.
fn no_route_out() -> Result<String, String> {
let route = std::fs::read_to_string("/proc/net/route").unwrap_or_default();
let default = route
.lines()
.skip(1)
.any(|l| l.split_whitespace().nth(1) == Some("00000000"));
if default {
return Err(format!(
"this namespace has a default route (the gate runs with --network none):\n{route}"
));
}
Ok("no default route: the whole gate runs with --network none".into())
}
// ── clamd, the gate's sidecar (A29-11) ──────────────────────────────────────
/// Pure: the unix socket a clamd configuration names (`LocalSocket <path>`).
fn clamd_socket(conf: &str) -> Option<String> {
conf.lines()
.map(str::trim)
.filter(|l| !l.starts_with('#'))
.find_map(|l| {
l.strip_prefix("LocalSocket")
.filter(|r| r.starts_with(char::is_whitespace))
.map(|r| r.trim().to_string())
})
.filter(|p| !p.is_empty())
}
/// Pure: clamd's answer to `zPING\0` is `PONG\0`.
fn clamd_ponged(reply: &[u8]) -> bool {
reply.strip_suffix(b"\0").unwrap_or(reply) == b"PONG"
}
/// clamd, started in the gate's own `--network none` run with the pinned signatures, and
/// stopped with it.
struct Clamd {
child: Child,
socket: String,
}
impl Clamd {
fn start(conf: &Path) -> Result<(Clamd, String), String> {
let conf_text =
std::fs::read_to_string(conf).map_err(|e| format!("{}: {e}", conf.display()))?;
let socket = clamd_socket(&conf_text)
.ok_or_else(|| format!("{} names no LocalSocket", conf.display()))?;
let _ = std::fs::remove_file(&socket);
let child = Command::new("clamd")
.arg(format!("--config-file={}", conf.display()))
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
.map_err(|e| format!("clamd: {e}"))?;
let mut me = Clamd { child, socket };
let t = Instant::now();
loop {
if let Ok(mut s) = std::os::unix::net::UnixStream::connect(&me.socket) {
let _ = s.set_read_timeout(Some(Duration::from_secs(10)));
let mut reply = Vec::new();
if s.write_all(b"zPING\0").is_ok()
&& s.read_to_end(&mut reply).is_ok()
&& clamd_ponged(&reply)
{
break;
}
}
if let Ok(Some(st)) = me.child.try_wait() {
return Err(format!(
"clamd exited {st} before it answered:\n{}",
std::fs::read_to_string("/tmp/holger-e2e-clamd.log").unwrap_or_default()
));
}
if t.elapsed() > Duration::from_secs(120) {
me.stop();
return Err(format!("clamd never answered PING on {}", me.socket));
}
std::thread::sleep(Duration::from_millis(250));
}
let version = Command::new("clamd")
.arg("--version")
.output()
.map(|o| text(&o))
.unwrap_or_default();
let detail = format!(
"{} answers PONG on {} with the pinned signature set only (no freshclam)",
version.trim(),
me.socket
);
Ok((me, detail))
}
fn stop(&mut self) {
let _ = self.child.kill();
let _ = self.child.wait();
}
}
impl Drop for Clamd {
fn drop(&mut self) {
self.stop();
}
}
// ── the configs ─────────────────────────────────────────────────────────────
fn token(who: &str) -> String {
format!("{who}-token-of-sufficient-length-for-the-holger-e2e-gate")
}
fn repo(d: &Path, name: &str) -> String {
format!(
r#"(ron_name: "{name}", ron_repo_type: "raw", ron_upstreams: [], ron_in: None,
ron_out: Some((ron_storage_endpoint: "storage", ron_exposed_endpoint: "door")), ron_data_dir: Some("{}/{name}")),"#,
d.display()
)
}
fn ladder(intake_extra: &str) -> String {
format!(
r#"promotion: Some((
ladder_name: "intake",
stages: [
(name: "incoming", repo: "incoming"), (name: "quarantine", repo: "quarantine"),
(name: "approved", repo: "approved"), (name: "production", repo: "production"),
],
intake: Some((
incoming: "incoming", quarantine: "quarantine", approved: "approved", production: "production",
{intake_extra}
)),
)),"#
)
}
/// Pure: the upstream intake's scan rules: two approvers, ClamAV (the gate's clamd) and YARA
/// (the gate's pinned rules) REQUIRED at ingest and at SCANNED beside vulnerability, SBOM and
/// secrets (A29-11). `sandbox: off`: the gate cannot nest the scan worker's podman.
fn intake_scanners(clamd: &str, yara: &str) -> String {
format!(
r#"rules: (sandbox: off), approvals: 2,
inspect: (clamav: Some((socket: Some("{clamd}"), required: true)), yara: Some((rules: Some("{yara}"), required: true))),
scan: Some((required: [vulnerability, sbom, secrets, malware])),"#
)
}
struct Upstream {
config: PathBuf,
grpc: u16,
http: u16,
dir: PathBuf,
}
/// The upstream: the pull-through sources at the internet, two approvers, the scanners,
/// the evidence signer, the sync key and its one downstream.
fn upstream_config(
root: &Path,
net: &Internet,
pki: &bench_scenarios::secure_update::AttestPki,
sync: &str,
clamd: &str,
yara: &str,
) -> Upstream {
let d = root.join("upstream");
std::fs::create_dir_all(&d).unwrap();
let (grpc, http) = (hold_port(), hold_port());
let methods: Vec<String> = ["bob", "carl"]
.iter()
.map(|p| {
format!(
r#"StaticToken(subject: "{p}", token: Some("{}"))"#,
token(p)
)
})
.collect();
let base = &net.base;
let ron = format!(
r#"(
repositories: [ {incoming} {quarantine} {approved} {production} ],
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: "storage", ron_storage_type: "znippy", ron_path: "{dd}") ],
audit: (dir: "{dd}/audit", enabled: true),
auth: Some((
methods: [ {methods} ],
duties: {{ "bob": [SecurityApprover], "carl": [SecurityApprover] }},
)),
attestation: Some((
trust_roots: ["{root}"],
signer_key: Some("{key}"),
signer_cert: Some("{cert}"),
signer_alg: Some("ecdsa-p256"),
)),
{ladder}
pull_through: Some((
sources: [
(name: "pypi", kind: python, url: "{base}/pypi/simple/"),
(name: "crates", kind: crates, url: "{base}/crates/index/"),
(name: "maven", kind: maven, url: "{base}/maven2/"),
(name: "cgr", kind: oci, url: "{base}"),
(name: "go", kind: go, url: "{base}/goproxy/"),
],
rules: (require_signed: false, allow_auto_approve: false),
retry_after_secs: Some(1),
)),
sync: Some(({sync})),
)"#,
incoming = repo(&d, "incoming"),
quarantine = repo(&d, "quarantine"),
approved = repo(&d, "approved"),
production = repo(&d, "production"),
dd = d.display(),
methods = methods.join(", "),
root = pki.root_der.display(),
key = pki.key_pkcs8.display(),
cert = pki.cert_der.display(),
ladder = ladder(&intake_scanners(clamd, yara)),
);
let config = root.join("upstream.ron");
std::fs::write(&config, ron).unwrap();
Upstream {
config,
grpc,
http,
dir: d,
}
}
struct Downstream {
config: PathBuf,
http: u16,
dir: PathBuf,
}
/// The downstream: serve-only sources of the same names, the upstream's evidence signer,
/// the site's bundle trust policy, the sync key and its one upstream. No line out.
fn downstream_config(
root: &Path,
pki: &bench_scenarios::secure_update::AttestPki,
policy: &Path,
sync: &str,
) -> Downstream {
let d = root.join("downstream");
std::fs::create_dir_all(&d).unwrap();
let (grpc, http) = (hold_port(), hold_port());
let ron = format!(
r#"(
repositories: [ {incoming} {quarantine} {approved} {production} ],
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: "storage", ron_storage_type: "znippy", ron_path: "{dd}") ],
audit: (dir: "{dd}/audit", enabled: true),
attestation: Some((
trust_roots: ["{root}"],
enrolled_signers: ["{cert}"],
)),
{ladder}
pull_through: Some((sources: [
(name: "pypi", kind: python),
(name: "crates", kind: crates),
(name: "maven", kind: maven),
(name: "cgr", kind: oci),
(name: "go", kind: go),
])),
sync: Some(({sync})),
// Its signed ack goes back on the stick: a receipt, so `boundary: Fetch` (a `fetch` build).
boundary: Fetch,
)"#,
incoming = repo(&d, "incoming"),
quarantine = repo(&d, "quarantine"),
approved = repo(&d, "approved"),
production = repo(&d, "production"),
dd = d.display(),
root = pki.root_der.display(),
cert = pki.cert_der.display(),
ladder = ladder(&format!(
r#"rules: (sandbox: off), trust_policy: Some("{}"),"#,
policy.display()
)),
);
let config = root.join("downstream.ron");
std::fs::write(&config, ron).unwrap();
Downstream {
config,
http,
dir: d,
}
}
// ── the release signers (two approvers and a distinct release signer) ───────
struct Signer {
cert: PathBuf,
key: PathBuf,
fingerprint: String,
}
fn mint_signer(dir: &Path, cn: &str) -> Signer {
let key = rcgen::KeyPair::generate_for(&rcgen::PKCS_ED25519).unwrap();
let mut params = rcgen::CertificateParams::new(vec![]).unwrap();
params
.distinguished_name
.push(rcgen::DnType::CommonName, cn);
let cert = params.self_signed(&key).unwrap();
let s = Signer {
cert: dir.join(format!("{cn}.der")),
key: dir.join(format!("{cn}.pk8")),
fingerprint: sha256(cert.der()),
};
std::fs::write(&s.cert, cert.der()).unwrap();
std::fs::write(&s.key, key.serialize_der()).unwrap();
s
}
/// The site's bundle trust policy: two distinct approvers, a distinct release signer.
fn trust_policy(reviewer: &Signer, owner: &Signer, release: &Signer) -> String {
format!(
r#"(
schema_version: "holger.bundle-trust-policy/v1",
trust_mode: Some(PinnedSigners),
trusted_roots: [],
certificate_validity: Enforce,
approved_signers: [
(fingerprint: "{}", subject: None, roles: ["security-reviewer"]),
(fingerprint: "{}", subject: None, roles: ["system-owner"]),
],
required_approval_roles: ["security-reviewer", "system-owner"],
minimum_distinct_approvers: 2,
trusted_release_signers: ["{}"],
release_signer_must_be_distinct: true,
maximum_bundle_age_secs: None,
require_expiry: true,
require_sbom: false,
require_vex: false,
require_scan: false,
on_expired_metadata: Some(ReadOnly),
)"#,
reviewer.fingerprint, owner.fingerprint, release.fingerprint
)
}
// ── the build systems ───────────────────────────────────────────────────────
/// A client run: `(ok, output)`. Each gets its own HOME.
fn client(home: &Path, cwd: &Path, env: &[(&str, String)], script: &str) -> (bool, String) {
std::fs::create_dir_all(home).unwrap();
let mut c = Command::new("sh");
c.arg("-c").arg(script).current_dir(cwd).env("HOME", home);
for (k, v) in env {
c.env(k, v);
}
match c.output() {
Ok(o) => (o.status.success(), text(&o)),
Err(e) => (false, format!("sh: {e}")),
}
}
/// Did the client succeed and say `want`?
fn says(name: &str, (ok, out): (bool, String), want: &str) -> Result<((), String), String> {
if ok && out.contains(want) {
Ok(((), tail(&out, 1500)))
} else {
Err(format!(
"{name}: expected success and {want:?}; ok={ok}\n{out}"
))
}
}
/// Did the client FAIL, naming `name_in_output`?
fn fails_naming(
name: &str,
(ok, out): (bool, String),
name_in_output: &str,
) -> Result<((), String), String> {
if !ok && out.contains(name_in_output) {
Ok(((), tail(&out, 1500)))
} else {
Err(format!(
"{name}: expected a failure naming {name_in_output:?}; ok={ok}\n{out}"
))
}
}
struct Clients {
work: PathBuf,
base: String,
}
impl Clients {
fn pip(&self, tag: &str) -> (bool, String) {
let w = self.work.join(format!("pip-{tag}"));
client(&w, &self.work, &[], &format!(
"python3 -m venv {v} && {v}/bin/pip install --no-cache-dir --disable-pip-version-check --index-url {b}/production/simple/ --trusted-host 127.0.0.1 demo-pkg==1.0.0 \
&& {v}/bin/python -c 'import demo_pkg; print(\"pip:\", demo_pkg.__version__, demo_pkg.greet())'",
v = w.join("venv").display(), b = self.base
))
}
fn uv(&self, tag: &str) -> (bool, String) {
let w = self.work.join(format!("uv-{tag}"));
client(&w, &self.work, &[("UV_PYTHON_DOWNLOADS", "never".into()), ("UV_NO_CACHE", "1".into())], &format!(
"uv venv --quiet --python python3 {v} && uv pip install --python {v}/bin/python --index-url {b}/production/simple/ --allow-insecure-host 127.0.0.1 demo-pkg==1.0.0 \
&& {v}/bin/python -c 'import demo_pkg; print(\"uv:\", demo_pkg.__version__, demo_pkg.greet())'",
v = w.join("venv").display(), b = self.base
))
}
fn cargo(&self, tag: &str) -> (bool, String) {
let w = self.work.join(format!("cargo-{tag}"));
std::fs::create_dir_all(w.join("app/src")).unwrap();
std::fs::create_dir_all(w.join("app/.cargo")).unwrap();
std::fs::write(w.join("app/Cargo.toml"), "[package]\nname = \"app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\ndemo-crate = { version = \"0.1\", registry = \"holger\" }\n").unwrap();
std::fs::write(
w.join("app/src/main.rs"),
"fn main() { println!(\"cargo: {}\", demo_crate::greet()); }\n",
)
.unwrap();
std::fs::write(
w.join("app/.cargo/config.toml"),
format!(
"[registries.holger]\nindex = \"sparse+{}/production/crates/\"\n",
self.base
),
)
.unwrap();
client(
&w,
&w.join("app"),
&[
("CARGO_HOME", w.join("cargo-home").display().to_string()),
("CARGO_TARGET_DIR", w.join("target").display().to_string()),
],
"cargo run -q",
)
}
fn mvn(&self, tag: &str) -> (bool, String) {
let w = self.work.join(format!("mvn-{tag}"));
let app = w.join("app");
std::fs::create_dir_all(app.join("src/main/java/app")).unwrap();
std::fs::write(
app.join("pom.xml"),
r#"<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>app</groupId>
<artifactId>app</artifactId>
<version>1</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.release>21</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency><groupId>org.demo</groupId><artifactId>demo-lib</artifactId><version>1.0.0</version></dependency>
</dependencies>
</project>
"#,
)
.unwrap();
std::fs::write(app.join("src/main/java/app/Main.java"), "package app;\n\npublic class Main {\n public static void main(String[] a) { System.out.println(\"mvn: \" + org.demo.Demo.greet()); }\n}\n").unwrap();
std::fs::write(
w.join("settings.xml"),
format!("<settings><mirrors><mirror><id>holger</id><mirrorOf>*</mirrorOf><url>{}/production/maven</url></mirror></mirrors></settings>\n", self.base),
)
.unwrap();
let repo = w.join("m2");
client(&w, &app, &[], &format!(
"mvn -B -q -s {s} -gs {s} -Dmaven.repo.local={r} -Dmaven.repo.local.tail=/opt/m2 package \
&& java -cp target/classes:{r}/org/demo/demo-lib/1.0.0/demo-lib-1.0.0.jar app.Main",
s = w.join("settings.xml").display(), r = repo.display()
))
}
fn skopeo(&self, tag: &str, port: u16) -> (bool, String) {
let w = self.work.join(format!("skopeo-{tag}"));
client(&w, &self.work, &[], &format!(
"skopeo --insecure-policy copy --src-tls-verify=false docker://127.0.0.1:{port}/production/cgr/{IMAGE}:{TAG} oci:{d}:{TAG} \
&& skopeo inspect --tls-verify=false --format 'skopeo: {{{{.Digest}}}}' docker://127.0.0.1:{port}/production/cgr/{IMAGE}:{TAG}",
d = w.join("img").display()
))
}
/// RA1-10: a real container runtime's pull (H6 had dropped `podman pull`): podman with its
/// storage (vfs) and run state under this step's own directory, no cgroups, no daemon.
fn podman(&self, tag: &str, port: u16) -> (bool, String) {
let w = self.work.join(format!("podman-{tag}"));
client(&w, &self.work, &[], &format!(
"P='podman --root {d}/root --runroot {d}/run --storage-driver vfs --cgroup-manager cgroupfs --events-backend file' \
&& $P pull --tls-verify=false 127.0.0.1:{port}/production/cgr/{IMAGE}:{TAG} \
&& $P image inspect --format 'podman: {{{{.Digest}}}}' 127.0.0.1:{port}/production/cgr/{IMAGE}:{TAG}",
d = w.display()
))
}
fn go(&self, tag: &str) -> (bool, String) {
let w = self.work.join(format!("go-{tag}"));
let app = w.join("app");
std::fs::create_dir_all(&app).unwrap();
std::fs::write(
app.join("go.mod"),
"module app\n\ngo 1.21\n\nrequire example.com/hello v1.0.0\n",
)
.unwrap();
std::fs::write(app.join("main.go"), "package main\n\nimport (\n\t\"fmt\"\n\n\t\"example.com/hello\"\n)\n\nfunc main() { fmt.Println(\"go:\", hello.Hello()) }\n").unwrap();
client(
&w,
&app,
&[
("GOPROXY", format!("{}/production/go", self.base)),
("GOSUMDB", "off".into()),
("GOFLAGS", "-mod=mod".into()),
("GOTOOLCHAIN", "local".into()),
("GOPATH", w.join("gopath").display().to_string()),
("GOCACHE", w.join("gocache").display().to_string()),
],
"go run .",
)
}
}
// ── the gate ────────────────────────────────────────────────────────────────
/// Ask the upstream's door for `path` until it stops answering 503 (the pull job runs).
fn ask_until_settled(port: u16, path: &str, accept: Option<&str>) -> Reply {
let t = Instant::now();
loop {
let r = get(port, path, accept);
if !(r.status == 503 || r.status == 0) || t.elapsed() > Duration::from_secs(120) {
return r;
}
std::thread::sleep(Duration::from_millis(250));
}
}
/// `holger intake state` of `name`: its first line.
fn state(up: &Upstream, name: &str) -> Result<String, String> {
let t = run(Command::new(BIN)
.args([
"intake",
"state",
"--server",
&format!("127.0.0.1:{}", up.grpc),
"--name",
name,
])
.env("HOLGER_TOKEN", token("bob")))?;
Ok(t.lines().next().unwrap_or_default().to_string())
}
fn wait_state(up: &Upstream, name: &str, want: &str) -> Result<String, String> {
let t = Instant::now();
loop {
let s = state(up, name).unwrap_or_else(|e| e);
if s.starts_with(want) {
return Ok(s);
}
if t.elapsed() > Duration::from_secs(120) {
return Err(format!("{name} never reached {want}; it stands at: {s}"));
}
std::thread::sleep(Duration::from_millis(250));
}
}
/// ★ **H6**: the internet to the build systems, and an invalidation back.
#[test]
fn internet_to_upstream_to_usb_to_downstream_to_real_build_systems_and_an_invalidation_back() {
let missing: Vec<&str> = CLIENTS.iter().copied().filter(|c| !on_path(c)).collect();
if !missing.is_empty() {
let required = std::env::var("HOLGER_E2E_REQUIRED").as_deref() == Ok("1");
assert!(!required, "HOLGER_E2E_REQUIRED=1 but the gate's clients are missing: {missing:?} (run it in the holger-e2e-clients image: cargo xtask e2e)");
eprintln!("SKIP h6-e2e: the build systems {missing:?} are not here; run `cargo xtask e2e` (the holger-e2e-clients image)");
return;
}
use server_lib::sync::protocol::SyncKey;
let mut rc = Receipt {
started: Some(Instant::now()),
..Default::default()
};
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path().to_path_buf();
let usb = root.join("usb");
std::fs::create_dir_all(&usb).unwrap();
let work = root.join("clients");
std::fs::create_dir_all(&work).unwrap();
if std::env::var("HOLGER_TEST_NETWORK_NONE").as_deref() == Ok("1") {
rc.step("airgap: --network none", || no_route_out().map(|d| ((), d)));
}
rc.step("connect trap", || {
let so = trap(&root)?;
let _ = TRAP_SO.set(so.clone());
Ok(((), format!("built and proven: {}", so.display())))
});
// 1. The internet.
let jar = rc.step("internet: compile org.demo:demo-lib with javac", || {
jar(&root).map(|j| (j.clone(), format!("{} bytes", j.len())))
});
let net = internet(&jar);
let img = image();
// 2. The upstream.
let keys = root.join("keys");
std::fs::create_dir_all(&keys).unwrap();
let (up_key, down_key) = (keys.join("cloud.sync.key"), keys.join("onprem.sync.key"));
let up_hex = SyncKey::open_or_mint(&up_key).unwrap().public_hex();
let down_hex = SyncKey::open_or_mint(&down_key).unwrap().public_hex();
let pki =
bench_scenarios::secure_update::mint_attestation_pki(&keys.join("scan"), "upstream-scan")
.unwrap();
// The scanners' sidecar: clamd with the pinned signature set, in this same run.
let clamd_conf = std::env::var("HOLGER_E2E_CLAMD_CONF").unwrap_or_else(|_| CLAMD_CONF.into());
let yara_rules = std::env::var("HOLGER_E2E_YARA_RULES").unwrap_or_else(|_| YARA_RULES.into());
let mut clamd = rc.step(
"clamd: start with the pinned signature set (no network)",
|| Clamd::start(Path::new(&clamd_conf)),
);
let up = upstream_config(
&root,
&net,
&pki,
&format!(
r#"name: "cloud", key: Some("{}"), downstreams: [(name: "onprem", key: "{down_hex}")], ack_deadline_secs: 3600"#,
up_key.display()
),
&clamd.socket,
&yara_rules,
);
let mut upstream = rc.step("upstream: holger start", || {
let s = Server::start(
Path::new(BIN),
&up.config,
up.http,
&up.dir.join("server.log"),
None,
)?;
Ok((s, format!("upstream on :{} (gRPC :{})", up.http, up.grpc)))
});
// What a client of the upstream asks for, the id the pull lands under, and the
// internet path that proves the pull went out.
let wanted: Vec<(&str, String, Option<&str>, String, String)> = vec![
(
"pip",
"/production/simple/demo-pkg/".into(),
Some("application/vnd.pypi.simple.v1+json"),
format!("pypi/{WHEEL}"),
format!("/pypi/files/{WHEEL}"),
),
(
"cargo",
"/production/crates/de/mo/demo-crate".into(),
None,
"crates/demo-crate/demo-crate-0.1.0.crate".into(),
"/crates/dl/demo-crate/0.1.0/download".into(),
),
(
"maven pom",
"/production/maven/org/demo/demo-lib/1.0.0/demo-lib-1.0.0.pom".into(),
None,
"maven/org/demo/demo-lib/1.0.0/demo-lib-1.0.0.pom".into(),
"/maven2/org/demo/demo-lib/1.0.0/demo-lib-1.0.0.pom".into(),
),
(
"maven jar",
"/production/maven/org/demo/demo-lib/1.0.0/demo-lib-1.0.0.jar".into(),
None,
"maven/org/demo/demo-lib/1.0.0/demo-lib-1.0.0.jar".into(),
"/maven2/org/demo/demo-lib/1.0.0/demo-lib-1.0.0.jar".into(),
),
(
"oci",
format!("/v2/production/cgr/{IMAGE}/manifests/{TAG}"),
Some("application/vnd.oci.image.manifest.v1+json"),
server_lib::pull_intake::oci_id("cgr", IMAGE, &img.digest).name,
format!("/v2/{IMAGE}/blobs/{}", img.layer.0),
),
(
"go",
"/production/go/example.com/hello/@v/v1.0.0.zip".into(),
None,
"go/example.com/hello/@v/v1.0.0.zip".into(),
"/goproxy/example.com/hello/@v/v1.0.0.zip".into(),
),
];
for (what, path, accept, id, internet_path) in &wanted {
rc.step(&format!("upstream: pull, verify and scan {what}"), || {
let r = ask_until_settled(up.http, path, *accept);
let s = wait_state(&up, id, "POLICY_CHECKED").map_err(|e| {
format!(
"{e}\nthe door said {} {}\n{}",
r.status,
r.text(),
tail(&upstream.log(), 3000)
)
})?;
if net.hit(internet_path) == 0 {
return Err(format!(
"{id} is in the chain, yet the internet never served {internet_path}"
));
}
Ok((
(),
format!(
"{id}: {s} (the door said {} while it waited for people)",
r.status
),
))
});
}
// ★ A29-11: the packages the scanners must hold. Each is asked for at its door as a
// client would; it must never pass the scan (never SCANNED, POLICY_CHECKED, approved or
// exported), and the upstream must say which scanner held it and why.
let held: Vec<(&str, String, Option<&str>, String, &str, &str)> = vec![
(
"the EICAR file in evil-pkg",
"/production/simple/evil-pkg/".into(),
Some("application/vnd.pypi.simple.v1+json"),
format!("pypi/{EVIL_WHEEL}"),
"clamav",
CLAM_SIG,
),
(
"the YARA fixture in dropper-crate",
"/production/crates/dr/op/dropper-crate".into(),
None,
"crates/dropper-crate/dropper-crate-0.1.0.crate".into(),
"yara",
YARA_RULE,
),
];
for (what, path, accept, id, scanner, signature) in &held {
rc.step(&format!("upstream: {what} is held at the scan by {scanner}"), || {
let t = Instant::now();
loop {
let r = ask_until_settled(up.http, path, *accept);
let full = run(Command::new(BIN).args(["intake", "state", "--server", &format!("127.0.0.1:{}", up.grpc), "--name", id]).env("HOLGER_TOKEN", token("bob"))).unwrap_or_else(|e| e);
let s = full.lines().next().unwrap_or_default().to_string();
let said = format!("door {} {}\n{full}\n{}", r.status, r.text(), upstream.log());
if let Some(v) = held_at_the_scan(id, &s, &said, scanner, signature) {
return v.map(|d| ((), d));
}
if t.elapsed() > Duration::from_secs(60) {
return Err(format!("{id}: no word from {scanner} naming {signature} within 60 s; it stands at {s}\nthe door said {} {}\n{}", r.status, r.text(), tail(&upstream.log(), 3000)));
}
std::thread::sleep(Duration::from_millis(500));
}
});
}
rc.step(
"upstream: a package held at the scan cannot be approved",
|| {
let mut said = Vec::new();
for (_, _, _, id, _, _) in &held {
let r = run(Command::new(BIN)
.args([
"intake",
"advance",
"--server",
&format!("127.0.0.1:{}", up.grpc),
"--name",
id,
"--to",
"APPROVED",
"--reason",
"trying to approve a held package",
])
.env("HOLGER_TOKEN", token("bob")));
match r {
Ok(t) => {
return Err(format!("{id} was approved although the scan held it: {t}"))
}
Err(e) => said.push(format!(
"{id}: refused ({})",
e.lines().last().unwrap_or_default()
)),
}
}
Ok(((), said.join("\n")))
},
);
for (what, _, _, id, _) in &wanted {
rc.step(&format!("upstream: two-person approval of {what}"), || {
let mut said = Vec::new();
for who in ["bob", "carl"] {
said.push(run(Command::new(BIN)
.args([
"intake",
"advance",
"--server",
&format!("127.0.0.1:{}", up.grpc),
"--name",
id,
"--to",
"APPROVED",
"--reason",
"reviewed for the e2e gate",
])
.env("HOLGER_TOKEN", token(who)))?);
}
Ok(((), said.join("")))
});
}
for (what, path, accept, id, _) in &wanted {
rc.step(&format!("upstream: {what} walks to AVAILABLE"), || {
let t = Instant::now();
loop {
let r = get(up.http, path, *accept);
let s = state(&up, id).unwrap_or_else(|e| e);
if s.starts_with("AVAILABLE") && r.status == 200 {
return Ok(((), format!("{id}: {s}")));
}
if t.elapsed() > Duration::from_secs(60) {
return Err(format!(
"{id} stands at {s}; the door says {} {}",
r.status,
r.text()
));
}
std::thread::sleep(Duration::from_millis(250));
}
});
}
upstream.stop();
clamd.stop();
// 3. The USB: the export, two approvals and the release signature.
let signers = root.join("signers");
std::fs::create_dir_all(&signers).unwrap();
let (reviewer, owner, release) = (
mint_signer(&signers, "security-reviewer"),
mint_signer(&signers, "system-owner"),
mint_signer(&signers, "release-signer"),
);
let policy = root.join("site-trust-policy.ron");
std::fs::write(&policy, trust_policy(&reviewer, &owner, &release)).unwrap();
let cand = root.join("onprem-1.cand");
let bundle = usb.join("onprem-1.holger.znippy");
rc.step(
"upstream: export the candidate (with the signed sync manifest)",
|| {
let t = run(Command::new(BIN)
.args(["export", "--config"])
.arg(&up.config)
.arg("--candidate")
.arg(&cand)
.args([
"--bundle-id",
"onprem-1",
"--sequence",
"1",
"--supplier",
"cloud",
"--product",
"onprem",
"--release-version",
"1",
]))?;
Ok(((), t))
},
);
rc.step(
"upstream: holger-cli bundle approve ×2 and finalize onto the USB",
|| {
let mut said = String::new();
for (role, s) in [("security-reviewer", &reviewer), ("system-owner", &owner)] {
said += &run(Command::new(cli_bin())
.args(["bundle", "approve", "--candidate"])
.arg(&cand)
.args(["--role", role, "--cert"])
.arg(&s.cert)
.arg("--key")
.arg(&s.key))?;
}
said += &run(Command::new(cli_bin())
.args(["bundle", "finalize", "--candidate"])
.arg(&cand)
.arg("--policy")
.arg(&policy)
.arg("--release-cert")
.arg(&release.cert)
.arg("--release-key")
.arg(&release.key)
.arg("--output")
.arg(&bundle))?;
Ok((
(),
format!(
"{said}{} bytes on the stick",
std::fs::metadata(&bundle).map(|m| m.len()).unwrap_or(0)
),
))
},
);
// 4. The downstream.
let ds = downstream_config(
&root,
&pki,
&policy,
&format!(
r#"name: "onprem", key: Some("{}"), upstreams: [(name: "cloud", key: "{up_hex}")]"#,
down_key.display()
),
);
let connects = ds.dir.join("connects.log");
rc.step(
"downstream: bundle import from the USB (verify, land, ack)",
|| {
run(trapped(&mut Command::new(downstream_bin()), &connects)
.args(["bundle", "allow-first-import", "--config"])
.arg(&ds.config)
.arg("--from-bundle")
.arg(&bundle))?;
let t = run(trapped(&mut Command::new(downstream_bin()), &connects)
.args(["bundle", "import", "--config"])
.arg(&ds.config)
.arg("--bundle")
.arg(&bundle)
.arg("--ack-out")
.arg(&usb))?;
let landed = t.matches("LANDED ").count();
if landed < wanted.len() {
return Err(format!(
"{landed} of {} packages landed:\n{t}",
wanted.len()
));
}
Ok(((), t))
},
);
let mut downstream = rc.step("downstream: holger-downstream start", || {
let s = Server::start(
&downstream_bin(),
&ds.config,
ds.http,
&ds.dir.join("server.log"),
Some(&connects),
)?;
let log = s.log();
if !log.contains("downstream: zero egress") {
return Err(format!(
"the downstream does not say what it may dial:\n{log}"
));
}
Ok((s, "serving; it says: downstream: zero egress".into()))
});
// 5. The build systems.
let cl = Clients {
work: work.clone(),
base: format!("http://127.0.0.1:{}", ds.http),
};
rc.step("pip installs demo-pkg from the downstream", || {
says("pip", cl.pip("1"), &format!("pip: 1.0.0 {GREETING}"))
});
rc.step("uv installs demo-pkg from the downstream", || {
says("uv", cl.uv("1"), &format!("uv: 1.0.0 {GREETING}"))
});
rc.step(
"cargo builds against demo-crate from the downstream",
|| says("cargo", cl.cargo("1"), &format!("cargo: {GREETING}")),
);
rc.step(
"mvn builds against org.demo:demo-lib from the downstream",
|| says("mvn", cl.mvn("1"), &format!("mvn: {GREETING}")),
);
rc.step("skopeo pulls demo/hello:1.0 from the downstream", || {
says(
"skopeo",
cl.skopeo("1", ds.http),
&format!("skopeo: {}", img.digest),
)
});
rc.step("podman pulls demo/hello:1.0 from the downstream", || {
says(
"podman",
cl.podman("1", ds.http),
&format!("podman: {}", img.digest),
)
});
rc.step(
"go builds against example.com/hello from the downstream",
|| says("go", cl.go("1"), &format!("go: {GREETING}")),
);
downstream.stop();
// 6. The invalidation, there and back.
let wheel_id = format!("pypi/{WHEEL}");
let manifest = rc.step(
"upstream: sync invalidate the wheel and write the next sync onto the USB",
|| {
let a = run(Command::new(BIN)
.args(["sync", "invalidate", "--config"])
.arg(&up.config)
.args([
"--coordinate",
&wheel_id,
"--reason",
"malware",
"--detail",
"found after its approval (the e2e gate)",
]))?;
let b = run(Command::new(BIN)
.args(["sync", "manifest", "--config"])
.arg(&up.config)
.arg("--out")
.arg(&usb))?;
let m = b
.lines()
.find_map(|l| l.strip_prefix("MANIFEST "))
.map(|s| PathBuf::from(s.trim()))
.ok_or_else(|| format!("no MANIFEST line:\n{b}"))?;
Ok((m, format!("{a}{b}")))
},
);
rc.step(
"downstream: sync apply holds the wheel and writes its ack",
|| {
let t = run(trapped(&mut Command::new(downstream_bin()), &connects)
.args(["sync", "apply", "--config"])
.arg(&ds.config)
.arg("--manifest")
.arg(&manifest)
.arg("--ack-out")
.arg(&usb))?;
if !t.contains(&format!("HELD {wheel_id}")) && !t.contains(&format!("HELD {WHEEL}")) {
return Err(format!("the wheel is not held:\n{t}"));
}
Ok(((), t))
},
);
let mut downstream = rc.step("downstream: start again", || {
let s = Server::start(
&downstream_bin(),
&ds.config,
ds.http,
&ds.dir.join("server-2.log"),
Some(&connects),
)?;
Ok((s, "serving".into()))
});
rc.step("pip now FAILS, naming demo-pkg", || {
fails_naming("pip", cl.pip("2"), "demo-pkg")
});
rc.step("uv now FAILS, naming demo-pkg", || {
fails_naming("uv", cl.uv("2"), "demo-pkg")
});
rc.step(
"cargo still builds (only the wheel was invalidated)",
|| says("cargo", cl.cargo("2"), &format!("cargo: {GREETING}")),
);
downstream.stop();
rc.step(
"upstream: sync ack from the USB; the board shows the invalidation reached onprem",
|| {
let ack = std::fs::read_dir(&usb)
.map_err(|e| e.to_string())?
.flatten()
.map(|e| e.path())
.filter(|p| {
p.file_name()
.unwrap()
.to_string_lossy()
.starts_with("holger-sync-ack-onprem-")
})
.max()
.ok_or("no ack on the stick")?;
let a = run(Command::new(BIN)
.args(["sync", "ack", "--config"])
.arg(&up.config)
.arg("--ack")
.arg(&ack))?;
let b = run(Command::new(BIN)
.args(["sync", "board", "--config"])
.arg(&up.config))?;
let start = b.find('{').ok_or_else(|| format!("no JSON board:\n{b}"))?;
let board: serde_json::Value =
serde_json::from_str(b[start..].trim()).map_err(|e| format!("{e}:\n{b}"))?;
let row = board["downstreams"]
.as_array()
.and_then(|d| d.iter().find(|r| r["name"] == "onprem"))
.ok_or_else(|| format!("no onprem row:\n{board:#}"))?;
if row["invalidations_reached"] != 1
|| row["invalidations_total"] != 1
|| row["alarm"] != false
{
return Err(format!(
"the board does not show the invalidation reached onprem:\n{row:#}"
));
}
if row["pending"].as_array().is_none_or(|p| !p.is_empty()) || board["alarm"] != false {
return Err(format!(
"the board still shows something pending or an alarm:\n{board:#}"
));
}
// The board as holger-ui draws it (its Sync pane), kept beside the receipt.
if let Some(dir) = std::env::var_os("HOLGER_E2E_RECEIPT")
.and_then(|p| Path::new(&p).parent().map(Path::to_path_buf))
{
let _ = std::fs::write(
dir.join("sync-board.json"),
serde_json::to_vec_pretty(&board).unwrap(),
);
}
Ok((
(),
format!(
"{a}board: onprem {} — {} of {} invalidation(s) reached; {}",
row["state"],
row["invalidations_reached"],
row["invalidations_total"],
row["headline"]
),
))
},
);
// ★ Zero egress on the downstream: it dialled nothing at any step.
rc.step("downstream: zero egress (the connect trap)", || {
let dials: std::collections::BTreeSet<String> = std::fs::read_to_string(&connects)
.unwrap_or_default()
.lines()
.map(String::from)
.collect();
if dials.is_empty() {
Ok((
(),
"the downstream's import, server and sync apply dialled nothing".into(),
))
} else {
Err(format!("the USB downstream dialled: {dials:#?}"))
}
});
rc.write();
}
/// ★ A29-11: the held-at-the-scan judge, pure.
#[test]
fn a_package_held_at_the_scan_names_its_scanner_and_one_that_passed_is_red_by_name() {
let said = "door 403 refused: inspect: malware evil_pkg/eicar.txt: clamav: Holger-E2E-Eicar.UNOFFICIAL";
let ok = held_at_the_scan(
"pypi/evil.whl",
"error: no such artifact",
said,
"clamav",
CLAM_SIG,
)
.unwrap()
.unwrap();
assert!(
ok.contains("held at the scan by clamav") && ok.contains(CLAM_SIG),
"{ok}"
);
for passed in [
"SCANNED sha256 x",
"POLICY_CHECKED sha256 x imported by y",
"AVAILABLE sha256 x",
] {
let red = held_at_the_scan("pypi/evil.whl", passed, said, "clamav", CLAM_SIG)
.unwrap()
.unwrap_err();
assert!(
red.contains("pypi/evil.whl PASSED the scan") && red.contains("clamav never held it"),
"{red}"
);
}
// Held by another scanner, or not named yet: not settled.
assert!(
held_at_the_scan("c", "INGESTED", "malware x: yara: Other", "yara", YARA_RULE).is_none()
);
assert!(held_at_the_scan("c", "BLOCKED", "", "yara", YARA_RULE).is_none());
}
/// ★ A29-11: the fixtures carry what the pinned signatures look for, and the clean packages
/// do not.
#[test]
fn the_held_fixtures_carry_their_signatures_and_the_clean_packages_none() {
let has = |hay: &[u8], needle: &[u8]| hay.windows(needle.len()).any(|w| w == needle);
let unzip = |z: &[u8], member: &str| -> Vec<u8> {
zip_entry::find_member(z, |n| n == member)
.unwrap()
.unwrap()
.1
};
assert_eq!(unzip(&evil_wheel(), "evil_pkg/eicar.txt"), eicar());
assert_eq!(eicar().len(), 68, "the standard EICAR test file");
let mut raw = Vec::new();
flate2::read::GzDecoder::new(&dropper_crate()[..])
.read_to_end(&mut raw)
.unwrap();
assert!(has(&raw, yara_marker().as_bytes()));
assert!(dropper_index_line().contains(&sha256(&dropper_crate())));
let marker = yara_marker();
for clean in [wheel(), dot_crate(), go_zip()] {
assert!(!has(&clean, b"EICAR-STANDARD") && !has(&clean, marker.as_bytes()));
}
}
/// ★ A29-11: the clamd sidecar's socket and PING, and the intake's scan rules, pure.
#[test]
fn the_gate_requires_clamav_and_yara_at_the_intake_and_reads_clamds_socket() {
let conf = "# a comment\nForeground yes\n#LocalSocket /nope\nLocalSocketMode 660\nLocalSocket /tmp/holger-e2e-clamd.sock\n";
assert_eq!(
clamd_socket(conf).as_deref(),
Some("/tmp/holger-e2e-clamd.sock")
);
assert_eq!(clamd_socket("Foreground yes\nLocalSocket \n"), None);
let shipped = include_str!("../../../distribution/e2e-clients/clamav/clamd.conf");
assert_eq!(
clamd_socket(shipped).as_deref(),
Some("/tmp/holger-e2e-clamd.sock")
);
assert!(
clamd_ponged(b"PONG\0") && clamd_ponged(b"PONG") && !clamd_ponged(b"UNKNOWN COMMAND\0")
);
let r = intake_scanners("/tmp/c.sock", "/opt/y");
assert!(
r.contains(r#"clamav: Some((socket: Some("/tmp/c.sock"), required: true))"#),
"{r}"
);
assert!(
r.contains(r#"yara: Some((rules: Some("/opt/y"), required: true))"#),
"{r}"
);
assert!(
r.contains("required: [vulnerability, sbom, secrets, malware]"),
"{r}"
);
// The pinned signature and rule name what the held steps look for.
let ndb = include_str!("../../../distribution/e2e-clients/clamav/holger-e2e.ndb");
assert!(ndb.starts_with(&format!("{CLAM_SIG}:0:*:")), "{ndb}");
let hex: String = "EICAR-STANDARD-ANTIVIRUS-TEST-FILE"
.bytes()
.map(|b| format!("{b:02x}"))
.collect();
assert_eq!(ndb.trim().rsplit(':').next(), Some(hex.as_str()));
let yar = include_str!("../../../distribution/e2e-clients/yara/holger-e2e.yar");
assert!(
yar.contains(&format!("rule {YARA_RULE}")) && yar.contains(&yara_marker()[..23]),
"{yar}"
);
}