server/lib/tests/mirror_mtls_e2e.rs
//! **Two holgers, real TLS, real loopback: an on-prem mirror authenticating to
//! a cloud upstream with a client certificate.**
//!
//! `mirror_declaration.rs` proves the CYCLE against an in-memory fake upstream.
//! It cannot prove any of this, because everything here happens below the
//! `MirrorUpstream` trait: a TLS handshake, a client certificate, a CN turning
//! into a principal, and a read door refusing one repository while serving
//! another on the same connection. So this file stands a REAL upstream holger up
//! on a real port and points a REAL mirror at it.
//!
//! # The shape being proven
//!
//! An on-prem holger mirroring from a cloud holger must be able to authenticate.
//! Before this lane it could not: the mirror read anonymously, which worked only
//! because `holger.rs` happens to serve reads open. A customer's mirror against
//! a real cloud does not get that.
//!
//! The upstream here is configured the way the owner ruled it could be — mTLS
//! required **per repository**:
//!
//! * `gated` declares `ron_require_auth: true`,
//! * `open` declares nothing and stays open,
//! * the endpoint sets `client_ca` (so a certificate is verified) AND
//! `client_auth_optional` (so a certless client still reaches a repository
//! NAME and can be refused by name rather than by a dropped handshake).
//!
//! # The four proofs
//!
//! 1. [`the_mirror_with_a_certificate_pulls_the_gated_repository`] — the bytes
//! arrive and are byte-identical, digest compared.
//! 2. [`the_mirror_without_a_certificate_is_refused_on_the_gated_repository`] —
//! refused, and the pair comes back as an `Err`, NOT as a clean cycle that
//! silently moved nothing.
//! 3. [`an_open_repository_on_the_same_upstream_mirrors_either_way`] — the
//! ungated repository is served to both mirrors.
//! 4. [`a_declared_credential_that_cannot_be_loaded_refuses_at_boot`] — the
//! refusal is at `wire_holger`, before anything serves, not on the first
//! cycle.
// A server's test, never a gateway build's (lane HOL-CLEANUP): a gateway build is a
// downstream, and several Holgers in one process, and a downstream's egress pin is process-wide.
#![cfg(not(feature = "gateway"))]
use std::io::Write;
use std::sync::Arc;
use traits::test_support::hold_port;
use holger_server_lib::{mirror_cycle, read_ron_config, wire_holger, Holger};
use traits::{ArtifactId, RepositoryBackendTrait};
// ───────────────────────────── a throwaway PKI ─────────────────────────────
/// One CA, and the certificates it signs. `rcgen` is this crate's existing
/// dev-dependency for exactly this (`integration_oci_tls.rs`), and it is the
/// same material `holger-mannequin`'s PKI door issues — the mannequin is the
/// standalone version of this for a human driving it by hand, and pulling that
/// whole daemon in as a dev-dependency to get two certificates would be the
/// wrong trade for a `cargo test`.
struct Pki {
ca_pem: String,
/// rcgen 0.14 (2026-10-02, W3): the CA's params + key sign the leaves.
issuer: rcgen::Issuer<'static, rcgen::KeyPair>,
}
struct Issued {
cert_pem: String,
key_pem: String,
}
impl Pki {
fn new() -> Self {
let mut params = rcgen::CertificateParams::new(Vec::<String>::new()).unwrap();
params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
params
.distinguished_name
.push(rcgen::DnType::CommonName, "holger-lane-mtls-ca");
let ca_key = rcgen::KeyPair::generate().unwrap();
let ca_cert = params.self_signed(&ca_key).unwrap();
Self {
ca_pem: ca_cert.pem(),
issuer: rcgen::Issuer::new(params, ca_key),
}
}
/// A SERVER certificate valid for `names` alone (loopback: `localhost`, `127.0.0.1`).
fn server_for(&self, cn: &str, names: &[&str]) -> Issued {
let mut params =
rcgen::CertificateParams::new(names.iter().map(|n| n.to_string()).collect::<Vec<_>>())
.unwrap();
params
.distinguished_name
.push(rcgen::DnType::CommonName, cn);
params.use_authority_key_identifier_extension = true;
let key = rcgen::KeyPair::generate().unwrap();
let cert = params.signed_by(&key, &self.issuer).unwrap();
Issued {
cert_pem: cert.pem(),
key_pem: key.serialize_pem(),
}
}
/// A CLIENT certificate. **`cn` is the principal**: holger turns the leaf's
/// Common Name into the subject every role map keys on.
fn client(&self, cn: &str) -> Issued {
let mut params = rcgen::CertificateParams::new(Vec::<String>::new()).unwrap();
params
.distinguished_name
.push(rcgen::DnType::CommonName, cn);
params.use_authority_key_identifier_extension = true;
params.extended_key_usages = vec![rcgen::ExtendedKeyUsagePurpose::ClientAuth];
let key = rcgen::KeyPair::generate().unwrap();
let cert = params.signed_by(&key, &self.issuer).unwrap();
Issued {
cert_pem: cert.pem(),
key_pem: key.serialize_pem(),
}
}
}
fn write_to(dir: &std::path::Path, name: &str, body: &str) -> String {
let p = dir.join(name);
std::fs::write(&p, body).unwrap();
std::fs::set_permissions(
&p,
<std::fs::Permissions as std::os::unix::fs::PermissionsExt>::from_mode(0o600),
)
.unwrap();
p.to_string_lossy().into_owned()
}
fn sha256_hex(data: &[u8]) -> String {
use sha2::{Digest, Sha256};
let mut h = Sha256::new();
h.update(data);
hex::encode(h.finalize())
}
// ───────────────────────────── the upstream ─────────────────────────────
struct Upstream {
_data: tempfile::TempDir,
_certs: tempfile::TempDir,
_cfg: tempfile::NamedTempFile,
/// Kept ALIVE, not read: dropping the config drops the served backends.
_holger: Holger,
endpoint: String,
ca_path: String,
/// `(repo, coord) -> bytes`, so a proof can compare what arrived against
/// what was published.
published: Vec<(String, ArtifactId, Vec<u8>)>,
}
/// Stand up an upstream holger with TWO repositories — one gated behind
/// `ron_require_auth`, one open — on a real TLS gRPC port, and publish one
/// artifact into each.
///
/// `mirror-node` is granted `Reader`. The role map keys on the CLIENT
/// CERTIFICATE'S CN; nothing else in this config mentions it.
fn start_upstream(pki: &Pki) -> Upstream {
start_upstream_for(pki, &["localhost", "127.0.0.1"])
}
/// [`start_upstream`] whose certificate names `names` alone.
fn start_upstream_for(pki: &Pki, names: &[&str]) -> Upstream {
let data = tempfile::tempdir().unwrap();
let certs = tempfile::tempdir().unwrap();
let srv = pki.server_for("upstream.holger.test", names);
let cert_path = write_to(certs.path(), "server.crt", &srv.cert_pem);
let key_path = write_to(certs.path(), "server.key", &srv.key_pem);
let ca_path = write_to(certs.path(), "ca.crt", &pki.ca_pem);
let gated_dir = data.path().join("gated");
let open_dir = data.path().join("open");
std::fs::create_dir_all(&gated_dir).unwrap();
std::fs::create_dir_all(&open_dir).unwrap();
let grpc = hold_port();
let config = format!(
r#"(
repositories: [
(
ron_name: "gated",
ron_repo_type: "rust",
ron_upstreams: [],
ron_in: None,
ron_out: Some((ron_storage_endpoint: "storage", ron_exposed_endpoint: "default")),
ron_data_dir: Some("{gated}"),
ron_require_auth: true,
),
(
ron_name: "open",
ron_repo_type: "rust",
ron_upstreams: [],
ron_in: None,
ron_out: Some((ron_storage_endpoint: "storage", ron_exposed_endpoint: "default")),
ron_data_dir: Some("{open}"),
),
],
// Several boxes share this test process, and the egress guard is per process: the box
// that names no upstream says `network: Online` so its neighbours may dial (B2).
network: Online,
exposed_endpoints: [
(
ron_name: "default",
ron_url: "127.0.0.1:{grpc}",
ron_tls: Some((
cert: "{cert}",
key: "{key}",
client_ca: Some("{ca}"),
client_auth_optional: true,
)),
),
],
storage_endpoints: [
(ron_name: "storage", ron_storage_type: "file", ron_path: "{root}"),
],
access: (reads: Open, front: Open), auth: Some((
methods: [ Mtls(ca_cert: "{ca}") ],
roles: {{ "mirror-node": Reader }},
)),
)"#,
gated = gated_dir.display(),
open = open_dir.display(),
root = data.path().display(),
grpc = grpc,
cert = cert_path,
key = key_path,
ca = ca_path,
);
let mut cfg = tempfile::NamedTempFile::new().unwrap();
cfg.write_all(config.as_bytes()).unwrap();
let mut holger: Holger = read_ron_config(cfg.path()).unwrap();
holger.instantiate_backends().unwrap();
wire_holger(&mut holger).unwrap();
// Publish through the BACKEND, before the door exists. The proofs are about
// reads; putting bytes in over the wire would need a write credential and
// would prove nothing extra.
let mut published = Vec::new();
for (repo, name, body) in [
(
"gated",
"secret-crate",
b"GATED BYTES -- only with a client certificate".to_vec(),
),
(
"open",
"public-crate",
b"OPEN BYTES -- anyone may take these".to_vec(),
),
] {
let id = ArtifactId {
namespace: None,
name: name.to_string(),
version: "1.0.0".to_string(),
};
let backend: Arc<dyn RepositoryBackendTrait> = holger.backend_named(repo).unwrap();
backend.put(&id, &body).unwrap();
published.push((repo.to_string(), id, body));
}
holger.start().unwrap();
Upstream {
_data: data,
_certs: certs,
_cfg: cfg,
_holger: holger,
endpoint: format!("https://localhost:{grpc}"),
ca_path,
published,
}
}
// ───────────────────────────── the mirror ─────────────────────────────
struct Mirror {
_data: tempfile::TempDir,
_certs: tempfile::TempDir,
_cfg: tempfile::NamedTempFile,
holger: Holger,
data_root: std::path::PathBuf,
}
/// A downstream holger whose `mirror:` block points at `upstream`, with or
/// without a client certificate.
///
/// `identity: None` is the mirror a customer has TODAY — `ron_credential:
/// Anonymous`, the only thing that ever ran.
fn build_mirror(up: &Upstream, identity: Option<&Issued>) -> Mirror {
build_mirror_at(up, &up.endpoint, identity, None)
}
/// [`build_mirror`] dialling `endpoint`, its certless `Tls` credential naming `server_name`.
fn build_mirror_at(
up: &Upstream,
endpoint: &str,
identity: Option<&Issued>,
server_name: Option<&str>,
) -> Mirror {
let data = tempfile::tempdir().unwrap();
let certs = tempfile::tempdir().unwrap();
let credential = match identity {
// NOT `Anonymous`. The upstream is an HTTPS server, and a mirror that
// only wants its OPEN repositories still has to speak TLS to ask for
// them — `Tls` is "verify the server, present nothing", which is exactly
// the certless customer this proof is about. (`Anonymous` against an
// `https://` endpoint is refused at boot, which is its own proof below.)
None => match server_name {
None => format!("Tls( ron_ca_cert: Some(\"{}\") )", up.ca_path),
Some(n) => format!(
"Tls( ron_ca_cert: Some(\"{}\"), ron_server_name: Some(\"{n}\") )",
up.ca_path
),
},
Some(id) => {
let c = write_to(certs.path(), "mirror.crt", &id.cert_pem);
let k = write_to(certs.path(), "mirror.key", &id.key_pem);
format!(
"Mtls( ron_client_cert: \"{c}\", ron_client_key: \"{k}\", \
ron_ca_cert: Some(\"{ca}\") )",
ca = up.ca_path
)
}
};
let gated_dir = data.path().join("gated");
let open_dir = data.path().join("open");
std::fs::create_dir_all(&gated_dir).unwrap();
std::fs::create_dir_all(&open_dir).unwrap();
let config = format!(
r#"(
repositories: [
(
ron_name: "gated",
ron_repo_type: "rust",
ron_upstreams: [],
ron_in: None,
ron_out: Some((ron_storage_endpoint: "storage", ron_exposed_endpoint: "default")),
ron_data_dir: Some("{gated}"),
),
(
ron_name: "open",
ron_repo_type: "rust",
ron_upstreams: [],
ron_in: None,
ron_out: Some((ron_storage_endpoint: "storage", ron_exposed_endpoint: "default")),
ron_data_dir: Some("{open}"),
),
],
// Several boxes share this test process, and the egress guard is per process: the box
// that names no upstream says `network: Online` so its neighbours may dial (B2).
network: Online,
exposed_endpoints: [
(ron_name: "default", ron_url: "127.0.0.1:{grpc}"),
],
storage_endpoints: [
(ron_name: "storage", ron_storage_type: "file", ron_path: "{root}"),
],
mirror: Some((
ron_state_dir: "holger-mirror",
ron_sources: [
(
ron_name: "cloud",
ron_kind: Holger,
ron_endpoint: "{endpoint}",
ron_credential: {credential},
ron_every_secs: 300,
ron_repositories: [
( ron_from: "gated", ron_to: "gated" ),
( ron_from: "open", ron_to: "open" ),
],
),
],
)),
)"#,
gated = gated_dir.display(),
open = open_dir.display(),
root = data.path().display(),
grpc = hold_port(),
endpoint = endpoint,
credential = credential,
);
let mut cfg = tempfile::NamedTempFile::new().unwrap();
cfg.write_all(config.as_bytes()).unwrap();
let mut holger: Holger = read_ron_config(cfg.path()).unwrap();
holger.instantiate_backends().unwrap();
// THE BOOT. A declared credential that will not load stops here.
wire_holger(&mut holger).unwrap();
let data_root = data.path().to_path_buf();
Mirror {
_data: data,
_certs: certs,
_cfg: cfg,
holger,
data_root,
}
}
/// One cycle over every declared pair, as `holger-server mirror --once` runs it.
async fn cycle(m: &Mirror) -> Vec<anyhow::Result<mirror_cycle::PairReport>> {
mirror_cycle::run_once(&m.holger, Some(&m.data_root), None, None)
.await
.expect("the mirror block is declared, so a cycle has pairs to run")
}
/// Wait for the upstream's gRPC door to answer. `start()` spawns; nothing
/// promises the listener is up when it returns.
async fn wait_ready(up: &Upstream) {
for _ in 0..200 {
if tokio::net::TcpStream::connect(up.endpoint.trim_start_matches("https://"))
.await
.is_ok()
{
return;
}
tokio::time::sleep(std::time::Duration::from_millis(25)).await;
}
panic!("upstream never started listening on {}", up.endpoint);
}
fn report_for<'a>(
out: &'a [anyhow::Result<mirror_cycle::PairReport>],
from: &str,
) -> &'a anyhow::Result<mirror_cycle::PairReport> {
// The pairs come back in declaration order; find by name rather than index
// so a reordering of the RON cannot make a proof lie.
out.iter()
.find(|r| match r {
Ok(rep) => rep.from == from,
Err(e) => format!("{e:#}").contains(from),
})
.unwrap_or_else(|| panic!("no slot for pair '{from}' in {} results", out.len()))
}
// ───────────────────────────── PROOF 1 + 3 (with cert) ─────────────────────
/// **Proof 1.** The mirror that presents `CN=mirror-node` pulls the GATED
/// repository, and the bytes are byte-identical.
///
/// **Proof 3, first half.** The same cycle also takes the OPEN repository.
#[tokio::test]
async fn the_mirror_with_a_certificate_pulls_the_gated_repository() {
holger_server_lib::exposed::tls::ensure_crypto_provider();
let pki = Pki::new();
let up = start_upstream(&pki);
wait_ready(&up).await;
let id = pki.client("mirror-node");
let mirror = build_mirror(&up, Some(&id));
let out = cycle(&mirror).await;
for repo in ["gated", "open"] {
let rep = report_for(&out, repo)
.as_ref()
.unwrap_or_else(|e| panic!("pair '{repo}' must succeed with a certificate: {e:#}"));
assert_eq!(
rep.listed, 1,
"{repo}: the upstream must list its one artifact"
);
assert_eq!(rep.fetched, 1, "{repo}: it must be fetched");
assert_eq!(rep.failed, 0, "{repo}: nothing may fail");
}
// BYTE-IDENTICAL, both repositories, compared by digest.
for (repo, id, body) in &up.published {
let local = mirror.holger.backend_named(repo).unwrap();
let got = local
.fetch(id)
.unwrap()
.unwrap_or_else(|| panic!("'{repo}' did not hold the mirrored artifact"));
assert_eq!(
sha256_hex(&got),
sha256_hex(body),
"'{repo}': mirrored bytes must be byte-identical to the upstream's"
);
assert_eq!(&got[..], &body[..]);
}
}
// ───────────────────────────── PROOF 2 + 3 (no cert) ───────────────────────
/// **Proof 2.** The mirror with NO certificate is refused on the gated
/// repository — and refused LOUDLY. The pair comes back as an `Err`, not as a
/// clean report that happens to have moved nothing.
///
/// This is the requirement that matters most. A mirror that silently skipped
/// the repository it could not authenticate for would report a green cycle and
/// hold nothing, and nobody would look again for months.
///
/// **Proof 3, second half.** The OPEN repository on the SAME upstream, over the
/// SAME certless connection, still mirrors.
#[tokio::test]
async fn the_mirror_without_a_certificate_is_refused_on_the_gated_repository() {
holger_server_lib::exposed::tls::ensure_crypto_provider();
let pki = Pki::new();
let up = start_upstream(&pki);
wait_ready(&up).await;
let mirror = build_mirror(&up, None); // ron_credential: Anonymous
let out = cycle(&mirror).await;
// The gated pair FAILED, by name, and said why.
let gated = report_for(&out, "gated");
let err = match gated {
Err(e) => format!("{e:#}"),
Ok(rep) => panic!(
"a certless mirror must be REFUSED on a gated repository, not handed a clean \
cycle: {}",
rep.line()
),
};
eprintln!("PROOF 2 refusal: {err}");
assert!(
err.contains("gated"),
"the refusal must name the repository it is about: {err}"
);
assert!(
err.contains("Unauthenticated") || err.contains("credentials"),
"the refusal must be an AUTH refusal, not an incidental transport failure — \
a proof that passed because the port was shut would prove nothing: {err}"
);
// …and it is not a silent skip: nothing landed locally.
let local = mirror.holger.backend_named("gated").unwrap();
let gated_id = &up.published.iter().find(|(r, ..)| r == "gated").unwrap().1;
assert!(
local.fetch(gated_id).unwrap().is_none(),
"the gated artifact must NOT be present on a mirror that was refused"
);
// The OPEN repository, same upstream, same certless connection: mirrored.
let open = report_for(&out, "open")
.as_ref()
.expect("an ungated repository must still mirror without a certificate");
assert_eq!(open.fetched, 1, "{}", open.line());
let (_, open_id, open_body) = up.published.iter().find(|(r, ..)| r == "open").unwrap();
let got = mirror
.holger
.backend_named("open")
.unwrap()
.fetch(open_id)
.unwrap()
.expect("the open artifact must be here");
assert_eq!(sha256_hex(&got), sha256_hex(open_body));
}
/// **Proof 3, stated on its own**: ONE upstream, one repository gated and one
/// not, and the open one behaves identically for both mirrors.
///
/// Proofs 1 and 2 each cover half of this; this one puts the two halves beside
/// each other so a regression that made the open repository depend on the
/// certificate fails HERE, with that sentence in the name, rather than as a
/// confusing assertion inside one of the others.
#[tokio::test]
async fn an_open_repository_on_the_same_upstream_mirrors_either_way() {
holger_server_lib::exposed::tls::ensure_crypto_provider();
let pki = Pki::new();
let up = start_upstream(&pki);
wait_ready(&up).await;
let (_, open_id, open_body) = up.published.iter().find(|(r, ..)| r == "open").unwrap();
let id = pki.client("mirror-node");
for (label, identity) in [("with a certificate", Some(&id)), ("without one", None)] {
let mirror = build_mirror(&up, identity);
let out = cycle(&mirror).await;
let open = report_for(&out, "open")
.as_ref()
.unwrap_or_else(|e| panic!("the open repository must mirror {label}: {e:#}"));
assert_eq!(open.fetched, 1, "{label}: {}", open.line());
let got = mirror
.holger
.backend_named("open")
.unwrap()
.fetch(open_id)
.unwrap()
.unwrap_or_else(|| panic!("{label}: the open artifact must be here"));
assert_eq!(
sha256_hex(&got),
sha256_hex(open_body),
"{label}: byte-identical either way"
);
}
}
// ───────────────────────────── PROOF 4 ─────────────────────────────────────
/// **Proof 4.** A declared-but-unloadable credential refuses at BOOT — in
/// `wire_holger`, before a port is opened — not on the first cycle.
///
/// The distinction is the whole security posture. A mirror that started, served,
/// and only discovered five minutes later that it had no credential is a mirror
/// that was running with an unknown posture for five minutes; and the tempting
/// alternative, carrying on anonymously, is the one thing a credential
/// declaration must never mean.
#[tokio::test]
async fn a_declared_credential_that_cannot_be_loaded_refuses_at_boot() {
holger_server_lib::exposed::tls::ensure_crypto_provider();
let pki = Pki::new();
let up = start_upstream(&pki);
let data = tempfile::tempdir().unwrap();
let repo_dir = data.path().join("open");
std::fs::create_dir_all(&repo_dir).unwrap();
let config = format!(
r#"(
repositories: [
(
ron_name: "open",
ron_repo_type: "rust",
ron_upstreams: [],
ron_in: None,
ron_out: Some((ron_storage_endpoint: "storage", ron_exposed_endpoint: "default")),
ron_data_dir: Some("{repo}"),
),
],
// Several boxes share this test process, and the egress guard is per process: the box
// that names no upstream says `network: Online` so its neighbours may dial (B2).
network: Online,
exposed_endpoints: [ (ron_name: "default", ron_url: "127.0.0.1:{grpc}") ],
storage_endpoints: [ (ron_name: "storage", ron_storage_type: "file", ron_path: "{root}") ],
mirror: Some((
ron_sources: [
(
ron_name: "cloud",
ron_kind: Holger,
ron_endpoint: "{endpoint}",
ron_credential: Mtls(
ron_client_cert: "{root}/not-here.crt",
ron_client_key: "{root}/not-here.key",
),
ron_repositories: [ ( ron_from: "open", ron_to: "open" ) ],
),
],
)),
)"#,
repo = repo_dir.display(),
root = data.path().display(),
grpc = hold_port(),
endpoint = up.endpoint,
);
let mut cfg = tempfile::NamedTempFile::new().unwrap();
cfg.write_all(config.as_bytes()).unwrap();
let mut holger: Holger =
read_ron_config(cfg.path()).expect("the shape parses — the operator must be told WHY");
holger.instantiate_backends().unwrap();
let e = wire_holger(&mut holger).expect_err("a credential that cannot load must stop the boot");
let msg = format!("{e:#}");
assert!(msg.contains("cloud"), "names the source: {msg}");
assert!(msg.contains("not-here.crt"), "names the path: {msg}");
assert!(msg.contains("REFUSES"), "says it refuses: {msg}");
assert!(
!msg.to_lowercase().contains("anonymous") || msg.contains("declare Anonymous"),
"the only mention of anonymous may be the instruction to declare it on purpose: {msg}"
);
}
// ───────────────────────────── the TLS name (lane OX-WGDS3) ─────────────────
/// ★ **An upstream reached at an ADDRESS, its certificate checked against a NAME** (lane
/// OX-WGDS3): a downstream reaches its estate's front at `https://10.0.2.2:<port>` while the
/// front's certificate is `repo.<estate>`'s. `Tls(ron_server_name: Some(..))` is the name the
/// certificate is checked against; without it the address is, and the handshake is refused.
#[tokio::test]
async fn a_mirror_reaching_its_upstream_by_address_checks_the_certificates_name() {
holger_server_lib::exposed::tls::ensure_crypto_provider();
let pki = Pki::new();
let up = start_upstream_for(&pki, &["repo.estate.test"]);
wait_ready(&up).await;
let by_address = up.endpoint.replace("localhost", "127.0.0.1");
let (_, open_id, open_body) = up.published.iter().find(|(r, ..)| r == "open").unwrap();
let named = build_mirror_at(&up, &by_address, None, Some("repo.estate.test"));
let out = cycle(&named).await;
let said = |out: &[anyhow::Result<mirror_cycle::PairReport>]| {
out.iter()
.map(|r| match r {
Ok(p) => p.line(),
Err(e) => format!("{e:#}"),
})
.collect::<Vec<_>>()
.join(" | ")
};
let open = out
.iter()
.find_map(|r| r.as_ref().ok().filter(|p| p.from == "open"))
.unwrap_or_else(|| {
panic!(
"the name the certificate carries lets the mirror in: {}",
said(&out)
)
});
assert_eq!(open.fetched, 1, "{}", open.line());
let got = named
.holger
.backend_named("open")
.unwrap()
.fetch(open_id)
.unwrap()
.expect("the open artifact must be here");
assert_eq!(sha256_hex(&got), sha256_hex(open_body));
let unnamed = build_mirror_at(&up, &by_address, None, None);
let out = cycle(&unnamed).await;
assert!(
out.iter().all(|r| r.is_err()),
"the address is not the certificate's name: the handshake is refused: {}",
said(&out)
);
assert!(
unnamed
.holger
.backend_named("open")
.unwrap()
.fetch(open_id)
.unwrap()
.is_none(),
"nothing arrived without the name"
);
}