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

nordisk/holger

server/lib/src/exposed/http.rs

//! HTTP/OCI gateway: the one non-gRPC ingress, letting HTTP-only clients (helm,
//! pip, cargo, OCI registry pushes via `oci://…`) reach the same repository
//! backends the tonic service in `grpc.rs` serves — each request is routed to a
//! backend and dispatched through its `handle_http2_request`. [`GatewaySettings`]
//! carries the shared [`FastRoutes`], auth config, optional TLS, body cap, and
//! the audit sink into every connection.
//!
//! Security-app rules, deliberately kept in lockstep with the gRPC path:
//! TLS terminates here and mTLS CN is lifted from the handshake once per
//! connection; reads (GET/HEAD) stay open and audit as `anonymous`, while writes
//! must pass `auth::validate_request` then `authorize_http_write` (RBAC mirror of
//! `grpc::authorize_write`, DELETE = admin, other writes = writer-or-admin,
//! fail-closed under a configured policy). Only `/healthz`, `/livez`, `/readyz`, and the
//! `/v2` OCI version probe are unauthenticated and unaudited. Routing keys off
//! the first path segment (`/v2/{name}/…` for OCI, else `/{repo}/…`) via
//! [`route_key`]; backends strip their own prefix from the passed-through path.
//!
//! Gotcha: the read-only write-gate (`backend.is_writable()`) and the body-size
//! cap both fire BEFORE the body is collected, so a rejected write never buffers
//! the upload — this is intentional, closing the DoS surface the pre-gate HTTP
//! path left open (it used to hand writes to a read-only backend that silently
//! swallowed them).
//
// HTTP/OCI gateway: bridges HTTP clients (helm, pip, cargo, OCI registry) to
// the repository backends' `handle_http2_request` handlers. Helm and friends
// speak HTTP, not gRPC, so this listener is required for any ecosystem interop;
// the modern Helm flow (`helm push/pull oci://…`) rides the OCI Distribution
// API served here.
//
// Security posture (this is a security application):
//   * TLS is terminated here when the endpoint has `ron_tls`; client certs are
//     requested but optional, so anonymous pulls and Kubernetes probes work
//     while writes are gated on identity at the application layer.
//   * mTLS identity (client-cert CN) is extracted once per connection and fed
//     into auth alongside any Bearer token.
//   * Request bodies are size-capped to bound memory use (upload DoS guard).
//   * Reserved unauthenticated paths: GET /healthz, GET /livez, GET /readyz, GET /v2/.
//
// Routing: `/v2/{name}/…` → repo named by the first OCI name segment (OCI);
// `/{repo}/…` → repo named by the first path segment (classic). The full
// path+query is passed through; backends strip their own prefix.

use crate::lock::LockOrRecover as _;
use std::sync::Arc;

/// Per-repo listing cap for the `/metrics` artifact-count gauge. The gauge is an
/// operability signal, not an inventory, so a very large repo is counted up to
/// this bound rather than paying an unbounded scan on every scrape.
pub(crate) const METRICS_LIST_CAP: usize = 100_000;

/// How many rows the front page's "Recently changed" list carries.
///
/// A front page answers "is anything happening here", and a reader gets that
/// from a screenful. `releases` is deliberately uncapped — it is the roster a
/// package manager is pointed at — but a recency list of ten thousand rows is
/// a scroll, not an answer, and it would be the bulk of the `/-/releases`
/// document for nothing.
#[cfg_attr(not(feature = "front"), allow(dead_code))]
const FRONT_RECENT_ROWS: usize = 20;

/// Server ceiling on the `/-/search` per-kind hit cap, applied when the query
/// string is parsed so no caller-supplied `limit` ever reaches the engine above
/// it. A cross-repo search walks EVERY repository's listing, so `limit` is the
/// one knob that buys work with a single GET; it may only ever ask for LESS than
/// the server's own default. Raising the ceiling is a server decision, not a
/// query parameter.
const MAX_SEARCH_LIMIT: usize = crate::search::DEFAULT_SEARCH_LIMIT;

/// Connections the gateway serves at once. The slot is taken BEFORE `accept()`,
/// so anything over the ceiling waits in the kernel's listen backlog (and is
/// refused by the OS once that fills) instead of being accepted into a task,
/// socket and TLS session we then have to hold. Without it one peer could open
/// sockets until the process hit EMFILE and every door stopped answering.
const MAX_CONCURRENT_CONNECTIONS: usize = 1024;

/// How long a TLS peer has to complete its handshake. rustls waits for a
/// ClientHello forever; a peer that connects and says nothing used to hold a
/// task and a connection slot until it felt like leaving (the slowloris shape,
/// one layer below the header-read timeout `serve` already arms).
const TLS_HANDSHAKE_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);

/// First back-off after a failed `accept()`, doubled on each consecutive
/// failure up to [`AcceptLimits::accept_backoff_max`]. A failing accept used to
/// `continue` straight into another accept — under EMFILE/ENFILE that is a hot
/// spin that burns a core and floods the log for as long as the condition lasts.
const ACCEPT_BACKOFF_MIN: std::time::Duration = std::time::Duration::from_millis(5);

use http_body_util::{BodyExt, Full, Limited, StreamBody};
use hyper::body::{Bytes, Frame, Incoming};
use hyper::service::service_fn;
use hyper::{Request, Response};
use hyper_util::rt::{TokioExecutor, TokioIo};
use hyper_util::server::conn::auto::Builder as ConnBuilder;
use rustls::ServerConfig;
use tokio_rustls::TlsAcceptor;
use tokio_stream::wrappers::ReceiverStream;

use crate::audit::{AuditAction, AuditEvent, AuditLog};
use crate::auth::{self, AuthConfig};
use crate::exposed::fast_routes::FastRoutes;
use crate::exposed::tls::leaf_common_name;

/// The one reply body type of this door: a whole reply (`Full`) and a streamed
/// one (`StreamBody` off a backend's `fetch_chunks`) behind the same box, so a
/// large `GET` leaves in pieces while every other reply is unchanged.
type ReplyBody = http_body_util::combinators::BoxBody<Bytes, std::convert::Infallible>;

/// Everything a gateway connection needs, shared behind an `Arc`.
/// See [`GatewaySettings::admit_upload`].
pub type UploadAdmission = Arc<dyn Fn(&str, u64) -> Result<(), String> + Send + Sync>;

pub struct GatewaySettings {
    pub routes: FastRoutes,
    pub auth_config: Arc<AuthConfig>,
    /// **The per-repository read scope**, shared verbatim with the gRPC services
    /// ([`crate::grpc::HolgerGrpc::read_gate`]). Both transports serve the same
    /// repositories, so a repository that demands a credential on one and not
    /// the other would be a repository that does not demand one at all — the
    /// hole the reserved-property floor already found once, when a Writer
    /// refused at the gRPC door simply used this one.
    pub read_gate: Arc<crate::auth::ReadGate>,
    pub tls: Option<Arc<ServerConfig>>,
    pub max_body_bytes: usize,
    /// Append-only audit sink, shared with the gRPC services. Reads
    /// (GET/HEAD) record as anonymous downloads; gated writes record the
    /// resolved identity (Bearer sub / mTLS CN).
    pub audit: Arc<dyn AuditLog>,
    /// Network mutation posture. `ReadOnly` refuses every PUT/POST/PATCH/DELETE
    /// (and the `/-/properties` write door) before the body is collected.
    pub operation_mode: crate::OperationMode,
    /// **What this box IS** — the declared role and the `twin ≥ primary` store
    /// verdict, shared verbatim with the gRPC services
    /// ([`crate::grpc::HolgerGrpc::twin`]). Both transports serve the same
    /// repositories, so a door that accepted a write the other refuses would be
    /// a twin that accepts writes.
    ///
    /// A `Twin` refuses every mutation here by name (`holger-twin-1`) and
    /// answers the read-only `GET /-/twin` door with its posture.
    pub twin: Arc<crate::twin::TwinPosture>,
    /// **The growth's write hold**, the SAME one the gRPC gates and every held
    /// backend ask (`crate::grow::Hold`): while a growth drains, every mutation is
    /// answered `503` + `Retry-After` by name (`holger-grow-1`).
    pub grow: Arc<crate::grow::Hold>,
    /// Security posture. In `Critical`, `/metrics` is served only to loopback peers.
    pub security_profile: crate::SecurityProfile,
    /// Hosted-SBOM store, shared with the `SbomService` gRPC RPCs. Backs the
    /// read-only `GET /-/sbom` door (attach is gRPC/CLI-only). `None` ⇒ the door
    /// answers 404 (SBOM hosting not configured on this server).
    #[cfg(feature = "intake")]
    pub sboms: Option<crate::sbom::SharedSbomStore>,
    /// The digest-keyed attestation store, shared with the promote gate. Backs
    /// the read-only OCI 1.1 referrers door (`GET /v2/<name>/referrers/<digest>`)
    /// and the envelope door it points at. `None` ⇒ referrers answers an EMPTY
    /// index, never a 404: "this server holds no evidence" and "this server does
    /// not do evidence" look the same from an OCI client, and neither is a
    /// missing page.
    #[cfg(feature = "intake")]
    pub attest: Option<std::sync::Arc<crate::attest::AttestStore>>,
    /// **The evidence public key** (lane HOL-OCI-EVIDENCE): the public half of
    /// `attestation.signer_cert`, served open and read-only at `/-/evidence-key` (PEM),
    /// `.pem`, `.jwks` and `.crt`. `None` ⇒ those paths answer 404 and say why.
    #[cfg(feature = "intake")]
    pub evidence_key: Option<std::sync::Arc<crate::evidence_key::EvidenceKey>>,
    /// **The box's repository signing key** (lane HOL-SIGNED-APT-DNF): its public half is
    /// served open at `/-/repo-key.asc` (apt's `signed-by=`, dnf's `gpgkey=`). `None` ⇒ that
    /// path answers 404 and names `holger repo-key create`.
    pub repo_key: Option<std::sync::Arc<crate::repo_sign::RepoKey>>,
    /// Custom-property store, shared with the gRPC `Search` property axis. Backs
    /// the read-only `GET /-/properties` door AND the `property=` filter on
    /// `GET /-/search` (property WRITES are CLI/in-process for now). `None` ⇒ the
    /// door answers 404 and a `property=` filter matches nothing (fail-closed).
    #[cfg(feature = "intake")]
    pub properties: Option<crate::properties::SharedPropertyStore>,
    /// The passkey ceremony store, backing the `/-/auth/passkey/…` doors. `None`
    /// ⇒ that whole surface answers 404, which is how a console tells "this server
    /// does not do passkeys" from "it does and refused you".
    #[cfg(feature = "auth-passkey")]
    pub passkeys: Option<crate::passkey::SharedPasskeyDoor>,
    /// **The intake chain** ([`crate::promote::intake`]), shared with the gRPC
    /// door. `Some` ⇒ an upload into its `incoming` repository is INGESTED
    /// through the chain (gates, fail-closed audit, record), a write into its
    /// other three repositories is refused by name, its incoming, quarantine and
    /// approved repositories serve nothing, and its production repository serves
    /// only AVAILABLE artifacts, from the sealed store. `None` ⇒ no chain.
    #[cfg(feature = "intake")]
    pub intake: Option<Arc<crate::promote::intake::IntakeChain>>,
    /// **The box's import doors** (lane W4, [`crate::import_door`]), shared
    /// with the gRPC `AdminService.ImportIntelBundle` / `ImportBundle` and the
    /// inbox jobs: `POST /-/intel/import` and `POST /-/bundle/import`. `None` ⇒
    /// both answer 404 by name.
    #[cfg(feature = "intake")]
    pub imports: Option<Arc<crate::import_door::ImportDoor>>,
    /// Property keys the SERVER reads as policy, which only an ADMIN may write —
    /// the configured set (`keep` by default) plus the promotion engine's
    /// `required_property`.
    ///
    /// This door writes the SAME store the gRPC `SetProperty` RPC does, so it must
    /// apply the SAME floor. It did not, and a Writer refused at the gRPC door
    /// simply used this one. See [`crate::properties::is_reserved_property`].
    #[cfg(feature = "intake")]
    pub reserved_properties: std::collections::BTreeSet<String>,
    /// The promotion gate's required property, when promotion is configured. Part
    /// of the reserved set above: forging it walks an unreviewed artifact into PROD.
    #[cfg(feature = "intake")]
    pub promotion_required_property: Option<(String, String)>,
    /// **Upload admission** — asked before a PUT/POST body is read, with the
    /// repository and the declared length; `Err(line)` refuses with 507 and
    /// the line. Only the metered build fills it (`metered::Quota`, the SAME
    /// check the gRPC `PutArtifact` asks); `None` everywhere else, so an open
    /// build carries a slot and no plan.
    pub admit_upload: Option<UploadAdmission>,
    /// **Who may say what the public face is** (HOL-DOCFIND a): the endpoint's
    /// `ron_trusted_proxies`. Only from a peer in it are `X-Forwarded-Proto` and
    /// `X-Forwarded-Host` believed when a link is written ([`public_base`]). `None`: nobody.
    pub trusted_proxies: Option<Arc<crate::listen::AllowList>>,
    /// **Which configured door this gateway IS** — the exposed endpoint's
    /// `ron_name`. The visitor tally counts per door, and a listener that did not
    /// know its own name could only count per server.
    pub door: String,
    /// The per-door, per-repository request and distinct-consumer tally drawn on
    /// the flow picture. ONE per server, shared with the gRPC services. See
    /// [`crate::visitors`] for why no address is ever kept in it.
    pub visitors: Arc<crate::visitors::Visitors>,
    /// **When this server's console last called** (HOL-SYNC-SKEW): ONE per server, shared
    /// with the gRPC services; marked here, by a call carrying the console's own proof.
    pub console: crate::flow::ConsoleSeen,
    /// The paired holgers ([`crate::peers`]), shared with the gRPC services and
    /// drawn on the flow picture.
    pub peers: Arc<crate::peers::PeerBoard>,
    /// **The estate board's evidence** (lane E3): what `GET /-/estate.json` serves —
    /// the SAME [`crate::topology::Sources`] the gRPC `AdminService.Topology` reads.
    /// `None` (a bare gateway in a test) answers 404.
    pub board: Option<crate::topology::Sources>,
    /// **The artifact flow** (lane HOL-SVG-RON): its shape read from the RON at boot and
    /// the quota reader. `GET /-/flow`, `/-/flow.svg` and `/-/flow.json` draw it with
    /// [`crate::flow::live`], the function `AdminService.FlowSvg` calls. `None`
    /// (`flow: (enabled: false)`, a bare gateway) answers 404.
    pub flow: Option<crate::flow::Door>,
    /// **The scan sandbox's probe door** (lane HOLGER-MEDIA): `GET /-/sandbox/probe`
    /// runs the worker's `probe` through the intake chain's own sandbox
    /// ([`ScanProbe`], set by the server when it has an intake chain). `None`
    /// (a bare gateway, no intake chain, a build without `supply-chain`) answers 404.
    pub scan_probe: Option<ScanProbe>,
    /// **What `/readyz` asks** (lane B4, [`crate::ready`]): the storage, the data
    /// root and the scan sandbox. `None` (a bare gateway in a test or a tool)
    /// answers ready as soon as the door is bound.
    pub ready: Option<ReadyCheck>,
    /// **Download and upload admission** ([`crate::admission`]) — ONE per server,
    /// shared with the gRPC door. `DoorAdmission::pass_through()` (no
    /// `admission:` block) refuses nothing and enforces no share.
    #[cfg(feature = "admission")]
    pub admission: Arc<crate::admission::DoorAdmission>,
}

/// Bind the HTTP/OCI gateway and start its accept loop.
///
/// The bind happens **synchronously, in the caller's context**, so a failure
/// (EADDRINUSE from a second holger or any other process on the port, EACCES on
/// a privileged port under a non-root unit) is returned as an `Err` and reaches
/// `Holger::start()` → `holger-server start`, which exits non-zero.
///
/// It used to bind inside the spawned task, where the only way to report failure
/// was an `eprintln!` and a bare `return` while this function returned `Ok(())`
/// regardless. The process then reported full success — exit status 0,
/// `server_started=true`, systemd `active (running)` — and blocked on Ctrl+C
/// while serving nothing. Every client got connection-refused and no automated
/// check ever fired. Only the accept LOOP belongs in the background; readiness
/// is a caller-visible fact.
pub fn start_http_gateway(
    addr: std::net::SocketAddr,
    settings: Arc<GatewaySettings>,
) -> anyhow::Result<()> {
    start_http_gateway_with_limits(addr, settings, AcceptLimits::default())
}

/// [`start_http_gateway`] for one `plane` of an endpoint (lane HOL-NCSC): the data listener
/// answers the admin doors with `holger-listen-3`, the admin listener the package doors; an
/// admin listener drops (and audits) every peer outside `allow`.
pub fn start_http_gateway_on(
    addr: std::net::SocketAddr,
    settings: Arc<GatewaySettings>,
    plane: crate::listen::Plane,
    allow: Option<Arc<crate::listen::AllowList>>,
) -> anyhow::Result<()> {
    start_http_gateway_inner(addr, settings, AcceptLimits::default(), plane, allow)
}

/// The accept loop's resource ceilings. Production always uses
/// [`AcceptLimits::default`] (the module constants); the parameter exists so the
/// loop's refusals can be asserted in a test at millisecond scale instead of
/// being argued about — a cap nothing exercises is a cap nobody knows is wired.
#[derive(Clone, Copy, Debug)]
pub(crate) struct AcceptLimits {
    /// Connections served at once; see [`MAX_CONCURRENT_CONNECTIONS`].
    pub max_connections: usize,
    /// Ceiling on one TLS handshake; see [`TLS_HANDSHAKE_TIMEOUT`].
    pub tls_handshake_timeout: std::time::Duration,
    /// Ceiling on the doubling back-off after a failed `accept()`.
    pub accept_backoff_max: std::time::Duration,
}

impl Default for AcceptLimits {
    fn default() -> Self {
        Self {
            max_connections: MAX_CONCURRENT_CONNECTIONS,
            tls_handshake_timeout: TLS_HANDSHAKE_TIMEOUT,
            accept_backoff_max: std::time::Duration::from_millis(500),
        }
    }
}

/// The next back-off after a failed `accept()`: [`ACCEPT_BACKOFF_MIN`] for the
/// first failure, doubling on each consecutive one, never above `max`. A
/// successful accept resets `previous` to `None`.
fn next_accept_backoff(
    previous: Option<std::time::Duration>,
    max: std::time::Duration,
) -> std::time::Duration {
    match previous {
        None => ACCEPT_BACKOFF_MIN.min(max),
        Some(d) => d.saturating_mul(2).min(max),
    }
}

pub(crate) fn start_http_gateway_with_limits(
    addr: std::net::SocketAddr,
    settings: Arc<GatewaySettings>,
    limits: AcceptLimits,
) -> anyhow::Result<()> {
    start_http_gateway_inner(addr, settings, limits, crate::listen::Plane::All, None)
}

fn start_http_gateway_inner(
    addr: std::net::SocketAddr,
    settings: Arc<GatewaySettings>,
    limits: AcceptLimits,
    plane: crate::listen::Plane,
    allow: Option<Arc<crate::listen::AllowList>>,
) -> anyhow::Result<()> {
    // Bind before spawning: std binds without needing the reactor, then
    // `from_std` adopts the socket into tokio inside the task.
    let std_listener = std::net::TcpListener::bind(addr)
        .map_err(|e| anyhow::anyhow!("HTTP/OCI gateway failed to bind {}: {}", addr, e))?;
    std_listener
        .set_nonblocking(true)
        .map_err(|e| anyhow::anyhow!("HTTP/OCI gateway {} set_nonblocking failed: {}", addr, e))?;

    // A32-14, stays a task: the HTTP/OCI gateway's accept loop, for the server's life.
    tokio::spawn(async move {
        let listener = match tokio::net::TcpListener::from_std(std_listener) {
            Ok(l) => l,
            Err(e) => {
                eprintln!("HTTP/OCI gateway failed to adopt listener {}: {}", addr, e);
                return;
            }
        };
        let scheme = if settings.tls.is_some() {
            "https"
        } else {
            "http (cleartext)"
        };
        println!("HTTP/OCI gateway listening on {} [{}]", addr, scheme);
        if settings.tls.is_none() {
            log::warn!(
                "SECURITY: HTTP/OCI gateway on {} runs WITHOUT TLS — credentials and \
                 artifacts travel in cleartext. Set ron_tls for any non-loopback use.",
                addr
            );
        }

        let acceptor = settings.tls.clone().map(TlsAcceptor::from);
        // One permit per in-flight connection. Held by the connection's task, so
        // it is released when the connection ends however it ends (clean close,
        // reset, hyper's header-read timeout, a TLS handshake that timed out).
        let slots = Arc::new(tokio::sync::Semaphore::new(limits.max_connections));
        // `None` = the last accept succeeded; `Some(d)` = how long we waited after
        // the previous consecutive failure.
        let mut backoff: Option<std::time::Duration> = None;

        loop {
            // Take the slot BEFORE accepting. Over the ceiling the excess stays in
            // the kernel's listen backlog instead of becoming a task we hold: the
            // process cannot be pushed into EMFILE by a peer that only opens
            // sockets, and the connections we DO serve keep their resources.
            let Ok(permit) = slots.clone().acquire_owned().await else {
                return; // semaphore closed — the gateway is going away
            };
            let (stream, peer) = match listener.accept().await {
                Ok(conn) => {
                    backoff = None;
                    conn
                }
                Err(e) => {
                    // Back off instead of spinning: under EMFILE/ENFILE every
                    // accept fails instantly, and the bare `continue` this
                    // replaces burned a core and filled the log until the
                    // condition cleared.
                    let wait = next_accept_backoff(backoff, limits.accept_backoff_max);
                    log::debug!("gateway accept error: {} (retrying in {:?})", e, wait);
                    backoff = Some(wait);
                    drop(permit);
                    tokio::time::sleep(wait).await;
                    continue;
                }
            };
            // HOL-NCSC: an admin listener takes only the peers its allow-list names.
            if let Some(a) = &allow {
                if !a.allows(peer.ip()) {
                    crate::refusals::record_to(
                        &settings.audit,
                        "admin listener",
                        "anonymous",
                        &peer.to_string(),
                        &crate::listen::AllowList::refusal(&peer),
                    );
                    drop(stream);
                    drop(permit);
                    continue;
                }
            }
            // TCP_NODELAY on every connection (HOL-PERF-3, X1): a streamed body goes
            // out in pieces, and with Nagle on, each small write waited for the
            // client's delayed ACK, about 40 ms per small download.
            let _ = stream.set_nodelay(true);
            let peer = peer.to_string();
            let settings = settings.clone();
            let acceptor = acceptor.clone();
            let handshake_timeout = limits.tls_handshake_timeout;
            // A32-14, stays a task: one task per HTTP connection.
            tokio::spawn(async move {
                // Released when this task ends, whatever ends it.
                let _permit = permit;
                match acceptor {
                    Some(acceptor) => {
                        // A peer that connects and never sends a ClientHello used
                        // to hold this task forever — rustls has no deadline of
                        // its own, and hyper's header-read timeout is a layer too
                        // late to fire.
                        let tls_stream =
                            match tokio::time::timeout(handshake_timeout, acceptor.accept(stream))
                                .await
                            {
                                Ok(Ok(s)) => s,
                                Ok(Err(e)) => {
                                    log::debug!("TLS handshake failed: {}", e);
                                    crate::refusals::handshake_refused(
                                        Some(&settings.audit),
                                        "HTTPS door",
                                        &peer,
                                        &e.to_string(),
                                    );
                                    return;
                                }
                                Err(_) => {
                                    log::debug!(
                                        "TLS handshake from {} timed out after {:?}",
                                        peer,
                                        handshake_timeout
                                    );
                                    crate::refusals::handshake_refused(
                                        Some(&settings.audit),
                                        "HTTPS door",
                                        &peer,
                                        &format!("no handshake within {handshake_timeout:?}"),
                                    );
                                    return;
                                }
                            };
                        // Pull the mTLS identity (if any) out of the handshake.
                        let client_cn = tls_stream
                            .get_ref()
                            .1
                            .peer_certificates()
                            .and_then(leaf_common_name);
                        serve(TokioIo::new(tls_stream), settings, client_cn, peer, plane).await;
                    }
                    None => serve(TokioIo::new(stream), settings, None, peer, plane).await,
                }
            });
        }
    });
    Ok(())
}

async fn serve<I>(
    io: TokioIo<I>,
    settings: Arc<GatewaySettings>,
    client_cn: Option<String>,
    peer: String,
    plane: crate::listen::Plane,
) where
    I: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + 'static,
{
    let svc = service_fn(move |req| {
        let settings = settings.clone();
        let client_cn = client_cn.clone();
        let peer = peer.clone();
        async move {
            let door = settings.door.clone();
            // HOL-NCSC: each listener serves its own plane's doors.
            let path = req.uri().path().to_owned();
            let mut answer = if plane.serves(&path) {
                handle(req, settings, client_cn, peer).await
            } else {
                Ok(text(404, &plane.refusal(&path)))
            };
            // Every answer names this Holger's security domain (lane HOL-CDS).
            if let (Ok(resp), Some(v)) = (&mut answer, crate::boundary::domain_header_value()) {
                resp.headers_mut().insert(crate::boundary::DOMAIN_HEADER, v);
            }
            // The flow's door box counts this door's 5xx answers (HOL-SVG-RON).
            if let Ok(resp) = &answer {
                crate::metrics::global().record_door_status(&door, resp.status().as_u16());
            }
            answer
        }
    });
    // A timer arms hyper's header-read timeout (a connection that never
    // finishes its request headers is dropped instead of holding a task,
    // socket and TLS state forever — the slowloris shape) and HTTP/2 keep-alive
    // pings.
    let mut builder = ConnBuilder::new(TokioExecutor::new());
    builder
        .http1()
        .timer(hyper_util::rt::TokioTimer::new())
        .header_read_timeout(std::time::Duration::from_secs(15));
    builder
        .http2()
        .timer(hyper_util::rt::TokioTimer::new())
        .keep_alive_interval(Some(std::time::Duration::from_secs(30)))
        .keep_alive_timeout(std::time::Duration::from_secs(20));
    if let Err(e) = builder.serve_connection(io, svc).await {
        log::debug!("gateway connection error: {}", e);
    }
}

/// The Bearer token a request presents, if any. One spelling of the lookup so
/// the read gate, the write gates and the meta doors cannot drift apart on what
/// counts as a credential.
fn bearer_of(req: &Request<Incoming>) -> Option<&str> {
    req.headers()
        .get("authorization")
        .and_then(|v| v.to_str().ok())
        .and_then(|v| v.strip_prefix("Bearer "))
}

/// The credential a request presents, in EITHER spelling the ecosystems use.
///
/// `Bearer <token>` is what holger's own tools and every gRPC-shaped caller
/// send. `Basic base64(user:pass)` is what the package managers send, and they
/// do not offer a choice: `docker login` / `podman push`, `npm publish`,
/// `mvn deploy`, `pip`, `nuget push` and `helm push` all speak Basic and have
/// no Bearer mode at all. MEASURED on holger.rs 2026-09-21: a `podman push` to
/// the OCI door failed with `authentication required` and never retried,
/// because the door read Bearer only and answered the 401 with no challenge.
///
/// The token is taken from the PASSWORD field, which is where every one of
/// those clients puts a token, and from the username when the password is
/// empty, which is what a `-u <token>` invocation produces. The username is
/// otherwise ignored on purpose: the identity comes from the token (the
/// configured method resolves the subject), so honouring a username would
/// invent a second, weaker way to say who you are.
///
/// It resolves a STRING and nothing else — Basic is a transport spelling of the
/// same secret, not a second authentication method, so `validate_request` is
/// reached by one path and the gates cannot drift.
/// `POST /<repo>/legacy/` (twine's upload URL) or `POST /<repo>/`.
#[cfg(feature = "intake")]
fn is_twine_upload_path(path: &str, repo: &str) -> bool {
    let rest = path.strip_prefix('/').unwrap_or(path);
    let rest = rest.strip_prefix(repo).unwrap_or(rest);
    matches!(rest.trim_matches('/'), "" | "legacy")
}

fn credential_of(req: &Request<Incoming>) -> Option<String> {
    let raw = req.headers().get("authorization")?.to_str().ok()?;
    if let Some(token) = raw.strip_prefix("Bearer ") {
        return Some(token.to_owned());
    }
    // ★ cargo's spelling: the token VERBATIM, with no scheme at all. It is what
    // the cargo registry specification prescribes and what `cargo publish`
    // sends, so a registry that insists on a scheme cannot be published to.
    // MEASURED 2026-09-21: `cargo publish --registry holger` answered 401 with
    // the token on the wire and correct.
    //
    // A scheme is `<name> SP <parameter>`, so a value with NO space cannot be
    // one — that is the whole discrimination, and it is why this arm can sit
    // beside the other two without swallowing them. A malformed scheme reaches
    // `validate_request` as a token and fails there, which is the same refusal
    // it would have got.
    if !raw.contains(' ') {
        return (!raw.is_empty()).then(|| raw.to_owned());
    }
    let encoded = raw.strip_prefix("Basic ")?;
    use base64::Engine as _;
    let decoded = base64::engine::general_purpose::STANDARD
        .decode(encoded.trim())
        .ok()?;
    let pair = String::from_utf8(decoded).ok()?;
    // ★ `split_once`, not `split`: a token may itself contain a colon and
    // splitting on every one would truncate it to its first segment — a
    // credential that is refused for a reason nothing in the log explains.
    let (user, pass) = pair.split_once(':')?;
    let token = if pass.is_empty() { user } else { pass };
    (!token.is_empty()).then(|| token.to_owned())
}

/// A 401 that a package manager can act on.
///
/// A bare 401 is where `podman push` stopped: the client asks once, is told
/// "no", and has nothing to retry WITH. `WWW-Authenticate` is the header that
/// turns a refusal into a challenge, and `Basic` is the scheme those clients
/// implement — so this is what makes a `docker login`ed push reach the door at
/// all. The realm is the server's name rather than a repository's: one
/// credential covers this holger, and a per-repository realm would ask a client
/// to log in again for every shelf.
fn unauthorized() -> Response<ReplyBody> {
    Response::builder()
        .status(401)
        .header("Content-Type", "text/plain")
        .header("WWW-Authenticate", "Basic realm=\"holger\"")
        .body(Full::new(Bytes::from_static(b"Unauthorized")).boxed())
        .expect("static response")
}

/// **A gated read with no sign-in, refused by name** (HCON-5): `[read-gated]` and the
/// repository, with the same challenge as [`unauthorized`], so a package client asks for a token.
fn read_gated(repo: &str) -> Response<ReplyBody> {
    Response::builder()
        .status(401)
        .header("Content-Type", "text/plain")
        .header("WWW-Authenticate", "Basic realm=\"holger\"")
        .body(Full::new(Bytes::from(crate::posture::read_gated(repo))).boxed())
        .expect("static response")
}

/// **A repository token refused by its own code**: the status, `[holger-token-<n>] words` as
/// the body, and on a 401 the challenge, so a package client says the server's sentence.
#[cfg(feature = "auth-passkey")]
fn token_refused(why: &crate::repo_token::Refused) -> Response<ReplyBody> {
    let mut r = Response::builder()
        .status(why.status)
        .header("Content-Type", "text/plain");
    if why.status == 401 {
        r = r.header("WWW-Authenticate", "Basic realm=\"holger\"");
    }
    r.body(Full::new(Bytes::from(why.line())).boxed())
        .expect("static response")
}

/// What a meta-door read resolved to.
///
/// `who` is the principal to audit. `identity` is the resolved principal itself,
/// which the cross-repo `/-/search` door needs rather than just its name: it
/// authorizes EACH repository it is about to walk, and `authorize_read` takes an
/// identity. `identity == None` means nothing was authenticated (the gate is off,
/// or no auth method is configured) — with the gate ON a `None` never gets past
/// `authorize_read`, so `identity.is_some()` is exactly "this caller
/// authenticated".
struct MetaRead {
    who: String,
    identity: Option<auth::AuthIdentity>,
}

impl MetaRead {
    /// The open-read answer: nobody authenticated, and nobody had to.
    fn anonymous() -> Self {
        Self {
            who: "anonymous".to_string(),
            identity: None,
        }
    }
}

/// HCON-5: **`front: Gated` on a gated box needs a sign-in** for the front's doors. Not
/// [`gate_meta_read`]`("")`: on a box with public repositories the catalog answers an anonymous
/// caller (it lists the public ones), and the front then stayed open under `front: Gated`.
/// A signed-in caller still passes the Reader floor, as [`gate_meta_read`] holds it.
#[cfg(feature = "front")]
async fn front_needs_a_sign_in(
    settings: &GatewaySettings,
    req: &Request<Incoming>,
    client_cn: Option<&str>,
) -> bool {
    if !settings.auth_config.require_auth_for_reads {
        return false;
    }
    match auth::validate_request(&settings.auth_config, bearer_of(req), client_cn).await {
        Ok(Some(identity)) => crate::auth::authorize_read_identity_scoped(
            &settings.auth_config,
            &settings.read_gate,
            Some(&identity),
            "",
        )
        .is_err(),
        _ => true,
    }
}

/// Read-gate the cross-repo `/-/` doors. With `require_auth_for_reads` on, the
/// request must authenticate and pass the Reader floor for `repo` (`""` = the
/// global floor, for cross-repo `/-/search`); otherwise a ready 401/403 is
/// returned. With the gate OFF it returns the anonymous principal, preserving the
/// open-read posture — so behavior is unchanged unless the operator opted in
/// (and the Critical profile forces the gate on). Closes the gap where these
/// doors returned before the per-repo read gate.
async fn gate_meta_read(
    settings: &GatewaySettings,
    req: &Request<Incoming>,
    client_cn: Option<&str>,
    repo: &str,
) -> Result<MetaRead, Response<ReplyBody>> {
    // Global gate, or this repository`s own `ron_require_auth`. `""` (the
    // cross-repo floor for `/-/search`) is never a repository name, so it can
    // only ever be gated globally.
    if !settings.read_gate.applies(&settings.auth_config, repo) {
        // …but with per-repository gates on, the cross-repo door must still
        // know WHO is asking, or every gated repository is filtered out for
        // everybody (`HolgerGrpc::authorize_catalog`, the gRPC twin). Resolved,
        // not required: no credential is the anonymous caller.
        if repo.is_empty() && settings.read_gate.catalog_resolves() {
            if bearer_of(req).is_none() && client_cn.is_none() {
                return Ok(MetaRead::anonymous());
            }
            return match auth::validate_request(&settings.auth_config, bearer_of(req), client_cn)
                .await
            {
                Ok(identity) => Ok(MetaRead {
                    who: identity
                        .as_ref()
                        .map(|i| i.subject.clone())
                        .unwrap_or_else(|| "anonymous".to_string()),
                    identity,
                }),
                Err(_) => Err(text(401, "Unauthorized")),
            };
        }
        return Ok(MetaRead::anonymous());
    }
    let identity =
        match auth::validate_request(&settings.auth_config, bearer_of(req), client_cn).await {
            Ok(id) => id,
            Err(_) => return Err(text(401, "Unauthorized")),
        };
    if let Err((status, _detail)) = crate::auth::authorize_read_identity_scoped(
        &settings.auth_config,
        &settings.read_gate,
        identity.as_ref(),
        repo,
    ) {
        let msg = if status == 403 {
            "Forbidden"
        } else {
            "Unauthorized"
        };
        return Err(text(status, msg));
    }
    Ok(MetaRead {
        who: identity
            .as_ref()
            .map(|i| i.subject.clone())
            .unwrap_or_else(|| "anonymous".to_string()),
        identity,
    })
}

/// The estate board's HTTP path (lane E3): the board as JSON (H2 #1; the server draws nothing).
pub const ESTATE_JSON_PATH: &str = "/-/estate.json";
/// The scan sandbox's probe door (lane HOLGER-MEDIA): admin-read, JSON.
pub const SANDBOX_PROBE_PATH: &str = "/-/sandbox/probe";
/// What answers the probe door: the worker's `probe` through the server's own
/// sandbox, as JSON, or the refusal's words (a `holger-sandbox-<n>` tag).
/// `Ok(None)`: the server has no scan worker yet (no intake chain opened).
pub type ScanProbe = Arc<dyn Fn() -> Result<Option<serde_json::Value>, String> + Send + Sync>;

/// What answers `/readyz`: `Ok`, or every reason the server is not ready.
pub type ReadyCheck = Arc<dyn Fn() -> Result<(), String> + Send + Sync>;

/// **Admin-read gate for a `/-/` admin door** (the HTTP twin of the gRPC
/// `authorize_admin_identity_for(.., auditor_reads: true)`): with no auth method
/// configured the dev/test door is open, as every admin read is; otherwise the
/// request must authenticate (401), and with RBAC on its role must be Admin or its
/// duties include Auditor (403).
async fn gate_admin_read(
    settings: &GatewaySettings,
    req: &Request<Incoming>,
    client_cn: Option<&str>,
) -> Result<(), Response<ReplyBody>> {
    if settings.auth_config.methods.is_empty() {
        return Ok(());
    }
    let identity =
        match auth::validate_request(&settings.auth_config, bearer_of(req), client_cn).await {
            Ok(Some(id)) => id,
            Ok(None) | Err(_) => return Err(text(401, "Unauthorized")),
        };
    if settings.auth_config.rbac_enabled() {
        let role = settings
            .auth_config
            .role_for_identity_in_repo("", &identity);
        let auditor = settings
            .auth_config
            .duties_for_identity(&identity)
            .contains(&auth::Duty::Auditor);
        if !role.can_admin() && !auditor {
            return Err(text(403, "Forbidden"));
        }
    }
    Ok(())
}

/// **Who sent this request, for the visitor tally** — borrowed, never copied.
///
/// Only the LAST `X-Forwarded-For` line is read: the client is the right-most
/// entry, which is the address the proxy in front of this door wrote, and that
/// entry is always on the last line. [`crate::visitors::client_of`] believes it
/// only from a loopback peer.
fn visitor_of<'a>(
    peer: &'a str,
    headers: &'a hyper::HeaderMap,
) -> Option<crate::visitors::Client<'a>> {
    crate::visitors::client_of(peer, last_xff(headers))
}

/// The last non-empty `X-Forwarded-For` line.
fn last_xff(headers: &hyper::HeaderMap) -> Option<&str> {
    headers
        .get_all("x-forwarded-for")
        .iter()
        .filter_map(|v| v.to_str().ok())
        .rfind(|v| !v.trim().is_empty())
}

/// Is `peer` in the endpoint's `ron_trusted_proxies`?
fn from_trusted_proxy(peer: &str, trusted: Option<&crate::listen::AllowList>) -> bool {
    trusted.is_some_and(|t| {
        peer.parse::<std::net::SocketAddr>()
            .is_ok_and(|a| t.allows(a.ip()))
    })
}

/// **The client of a request** (SEC-REVIEW 2026-11-01 F1): [`visitor_of`], and from a peer in
/// `ron_trusted_proxies` (the estate's front dials from its WireGuard address, not loopback)
/// the right-most `X-Forwarded-For` entry that front wrote, believed as from loopback.
fn client_address<'a>(
    peer: &'a str,
    headers: &'a hyper::HeaderMap,
    trusted: Option<&crate::listen::AllowList>,
) -> Option<crate::visitors::Client<'a>> {
    if from_trusted_proxy(peer, trusted) {
        if let Some(c) = crate::visitors::client_of("127.0.0.1:0", last_xff(headers)) {
            return Some(c);
        }
    }
    visitor_of(peer, headers)
}

/// The source an audit row records (F1): the forwarded client and the front it came through
/// (`<client> via <front>`) from a trusted proxy, else the peer.
fn audit_source(
    peer: &str,
    headers: &hyper::HeaderMap,
    trusted: Option<&crate::listen::AllowList>,
) -> String {
    let client = last_xff(headers)
        .and_then(|l| l.rsplit(',').next())
        .map(str::trim)
        .filter(|c| c.parse::<std::net::IpAddr>().is_ok());
    match client {
        Some(c) if from_trusted_proxy(peer, trusted) => format!("{c} via {peer}"),
        _ => peer.to_string(),
    }
}

/// True if `peer` (a `host:port` socket-address string) is an IPv4/IPv6 loopback.
fn peer_is_loopback(peer: &str) -> bool {
    peer.starts_with("127.")
        || peer.starts_with("[::1]")
        || peer.starts_with("::1")
        || peer.starts_with("localhost")
}

async fn handle(
    req: Request<Incoming>,
    settings: Arc<GatewaySettings>,
    client_cn: Option<String>,
    peer: String,
) -> Result<Response<ReplyBody>, std::convert::Infallible> {
    // Request-handling clock: observed into the `holger_request_duration_seconds`
    // histogram at each door's exit, right where the request counter is bumped, so
    // latency is measured over the same handled-request population.
    let started = std::time::Instant::now();
    let method = req.method().as_str().to_owned();
    let path = req.uri().path().to_owned();
    let path_and_query = req
        .uri()
        .path_and_query()
        .map(|pq| pq.as_str().to_owned())
        .unwrap_or_else(|| path.clone());

    // ★ The visitor tally: one request through THIS door, whatever it asks for
    // and however it is answered. The repository half is counted below, where
    // the path has been resolved to a configured repository.
    settings.visitors.record(
        crate::visitors::now_unix(),
        Some(&settings.door),
        None,
        client_address(&peer, req.headers(), settings.trusted_proxies.as_deref()),
    );

    // ★ SEC-REVIEW 2026-11-01 P1: ONE canonical path, before any door. The router
    // (`route_key`) drops empty segments and the scanned registry's view
    // (`oci_push::rest_of`) does not, so `/v2//oci/…` keyed the `oci` repository and missed
    // its view: an unscanned tag write, and staged or BLOCKED bytes served. Every door
    // splits the path its own way, so a path that two splits could read differently is
    // refused here, by name, for every verb.
    if non_canonical_path(&path) {
        return Ok(text(
            400,
            &holger_errcode::SERVER_PATH_NOT_CANONICAL.tag(format!(
                "{path}: send the path without empty, `.` or `..` segments"
            )),
        ));
    }

    // Checksum-verify-on-deploy (Artifactory `X-Checksum-*` convention): a client
    // may advertise the digest of the bytes it is uploading. Capture the strong
    // digests NOW — before `req.into_body()` consumes the request — so the write
    // path can recompute and reject a corrupted upload before it reaches a
    // backend. Header lookups are case-insensitive (canonical lowercase names).
    let want_sha256 = req
        .headers()
        .get("x-checksum-sha256")
        .and_then(|v| v.to_str().ok())
        .map(str::to_owned);
    let want_sha512 = req
        .headers()
        .get("x-checksum-sha512")
        .and_then(|v| v.to_str().ok())
        .map(str::to_owned);

    // ReadOnly operation mode: refuse every network mutation here, BEFORE the
    // request body is collected and before any write door (artifact PUT/POST/
    // DELETE, the `/-/properties` write door). Reads (GET/HEAD) fall through to
    // the normal auth path. /healthz/readyz stay reachable (they are GET).
    //
    // A TWIN is asked FIRST and on the same terms — every verb that is not a
    // read — because a follower that took an upload would be a second primary with a
    // different store. The answer NAMES the primary: on a twin, "write there"
    // is an instruction and a bare 403 is an outage. Plan §3 W9;
    // `holger-twin-1`.
    // A box AWAITING ITS RECHARGE serves nothing — not a read, not a write —
    // until the recharge is whole (`holger-twin-15`). The probes and `/-/twin`
    // still answer: a supervisor and the recharge lane must see WHY.
    if let Some(refusal) = settings.twin.serve_refusal() {
        // `/-/estate.json` too: a held main is exactly the board an operator opens.
        let probe = method == "GET"
            && matches!(
                path.as_str(),
                "/healthz" | "/livez" | "/readyz" | "/-/twin" | ESTATE_JSON_PATH
            );
        if !probe {
            return Ok(text(503, &refusal));
        }
    }
    let mutating = !matches!(method.as_str(), "GET" | "HEAD");
    if mutating {
        if let Some(refusal) = settings.twin.write_refusal() {
            return Ok(text(403, &holger_errcode::TWIN_REFUSES_WRITES.tag(refusal)));
        }
        // A growth holds every upload while it drains (`crate::grow`): 503 with a
        // Retry-After, the answer a client retries on — refused, never queued.
        if let Some(held) = settings.grow.write_refusal() {
            return Ok(Response::builder()
                .status(503)
                .header("Content-Type", "text/plain")
                .header("Retry-After", crate::grow::RETRY_AFTER_SECS.to_string())
                .body(Full::new(Bytes::from(holger_errcode::GROW_WRITES_HELD.tag(held))).boxed())
                .expect("static response"));
        }
    }
    if settings.operation_mode == crate::OperationMode::ReadOnly && mutating {
        return Ok(text(403, "server is in read-only mode"));
    }

    // ── holger.rs's PUBLIC FRONT PAGE ───────────────────────────────────
    // `GET /` answered `404 Unknown repository` until this arm: the one
    // page served to somebody who is not anybody yet. The whole door — the
    // bytes, the JSON, the cache headers and every refusal — lives in
    // `holger-front`, a leaf that builds in seconds; this is the mount, and
    // deliberately nothing more.
    //
    // It is asked BEFORE the repository router and can only ever claim `/`,
    // `/holger.webp` and two paths under the already-reserved `/-/`
    // namespace, so it cannot shadow a repository. `route` answers `None`
    // for everything else and this falls straight through — the claim is
    // proved on its own side by `a_repository_path_is_never_this_doors`.
    //
    // ★ **Outside the `if method == "GET"` block below, and that is not a
    // detail.** Inside it, `HEAD /holger.webp` fell through to the repository
    // router and answered `404 Unknown repository` — so every health check and
    // every cache revalidation on the picture said the front page was not
    // there — and `POST /` got the same 404 instead of a method refusal.
    // Measured against a running dev-pair, which is the only way that class of
    // bug is ever found: it compiles, and `GET /` looks perfect.
    //
    // ★ **Behind `feature = "front"` since 2026-09-17.** Without it `holger-front`
    // is not a dependency of this crate, these paths fall through to the
    // repository router, and the artifact contains no HTML at all — the shape the
    // appliance tiers (`embedded`/`mini`/`mvp-server`) now build, and the shape
    // the product server takes when a separate BFF host mounts the page instead.
    #[cfg(feature = "front")]
    if let Some(front_path) = holger_front_path(&path) {
        // The same read gate `/-/search`, `/-/sbom`, `/-/properties` and
        // `/metrics` pass. A server with `require_auth_for_reads` on has no
        // public front page BY DEFINITION, and it says so by name
        // (`holger-front-3`) rather than 401-ing a browser into a blank tab
        // with nothing in it to search for.
        // HCON-5: `access.front: Open` (the default) keeps the front page readable on a gated
        // box; its release list is then only what the caller may read (anonymous: the public).
        if !settings.read_gate.front_open()
            && front_needs_a_sign_in(&settings, &req, client_cn.as_deref()).await
        {
            return Ok(front_reply(holger_front::reads_gated()));
        }
        // Only `/-/releases` pays for a listing. The page, the picture and
        // `/-/front` are constants, and walking every repository to serve a
        // 578 kB image would be a listing per page load.
        let catalogue = if front_path == holger_front::RELEASES_PATH {
            front_catalogue(
                &settings,
                front_caller(&settings, &req, client_cn.as_deref()).await,
            )
            .await
        } else {
            holger_front::Catalogue::default()
        };
        let front = holger_front::Front {
            // The server's own public name, from its environment — not
            // guessed from the request's Host, which is whatever a proxy or
            // a caller put there, and not from `location.origin` in the
            // page, which would print the proxy's address on any
            // deployment behind one. Absent is an honest answer: the page
            // simply does not print the line.
            base_url: std::env::var("HOLGER_PUBLIC_BASE_URL")
                .ok()
                .filter(|v| !v.is_empty()),
            // ★ **The console's door, when this deployment has one.**
            //
            // `None` stays the answer — and the honest one — for a server
            // with no console configured: holger-server itself authenticates
            // with mTLS, OIDC and bearer tokens, doors for `cargo`, `pip`
            // and `docker`, and it still issues no browser session of its
            // own. The page then says `holger-front-2` by name rather than
            // drawing a button wired to nothing.
            //
            // What changed is that the CONSOLE has a browser login — OIDC
            // authorization-code with PKCE, in `holger-ui` — and the front
            // page had no way to know, so it told every visitor this
            // product has no browser login at all. That sentence is true of
            // this server and false of holger.
            //
            // A PATH and not a URL, beside `base_url` because it is the same
            // kind of value: the page's button follows only a same-site
            // rooted path, which is its open-redirect defence, so the
            // console must be reachable on this origin for the button to
            // mean anything. `console_login` applies the page's own rule
            // here and answers `None` for anything the page would drop, so
            // a misconfiguration is the sentence the page already has
            // instead of a button that does nothing when pressed.
            //
            // ★ HOLDIRECT (owner 2026-10-28, holger.rs): with the passkey sign-in on this
            // server the front page's Log in runs the ceremony itself, one press, and lands on
            // the console's home; `/login` stays for a direct link and for enrolment.
            login: std::env::var("HOLGER_CONSOLE_PATH")
                .ok()
                .filter(|v| !v.is_empty())
                .and_then(|p| holger_front::console_sign_in(&p, front_has_passkeys(&settings))),
        };
        let doors = holger_front::Doors {
            front: &front,
            catalogue: &catalogue,
        };
        if let Some(reply) = holger_front::route(&method, &path, &doors) {
            crate::grpc::functional_status(
                "holger-http/front",
                "front_served",
                reply.status == 200,
                &format!("{path} {} {} bytes", reply.status, reply.body.len()),
            );
            return Ok(front_reply(reply));
        }
    }

    // ── PASSKEY ceremony doors (WebAuthn / FIDO2) ────────────────────────────
    //
    // Reserved under `/-/` so they can never collide with a repository name, and
    // placed HERE -- before the repository router and before the read-only gate's
    // artifact rules -- because a login is not an artifact operation.
    //
    // THE LISTENER MATTERS. holger runs two of them with disjoint door sets: gRPC
    // on `ron_url` and this HTTP gateway on `ron_http_url`. The console lane lost
    // a day to exactly this, so it is written down: the ceremony is HTTP only, and
    // a console pointed at the gRPC port gets 404 on every route below.
    //
    // Why these are on the HTTP door at all: a WebAuthn ceremony is driven by a
    // browser calling `navigator.credentials.*`, and a browser speaks HTTP. The
    // ceremony mints a bearer token, and THAT is what the gRPC door then accepts
    // through the ordinary auth seam -- so the split surface is the design, not a
    // gap in it.
    #[cfg(feature = "auth-passkey")]
    if path.starts_with("/-/auth/passkey") {
        let Some(store) = settings.passkeys.clone() else {
            // No `Passkey` method configured ⇒ the surface does not exist. A
            // console reads this as "this server does not do passkeys", which is a
            // different thing from "it does and refused you".
            return Ok(text(404, "passkey login is not configured on this server"));
        };

        // The ceremony partition key. `peer` is the transport peer -- what the
        // kernel saw -- and NOT a header, because a partition a caller can write
        // is a suggestion rather than a partition.
        //
        // ONE exception, and it is a credential rather than a header: holger's
        // console (holger-ui-server) carries every person's ceremony to this door,
        // so every ceremony would otherwise share the console's address and one
        // flood would close the login for everybody. A request that ALSO proves
        // an ADMIN identity in `x-holger-proxy-authorization` (the console's own
        // bearer) may name the client in `x-holger-ceremony-client`. An admin
        // can enrol anybody anyway; trusting its word on whose ceremony this is
        // grants nothing more, and an unproven hint is ignored.
        let hinted = req
            .headers()
            .get("x-holger-ceremony-client")
            .and_then(|v| v.to_str().ok())
            .map(str::trim)
            .filter(|c| !c.is_empty() && c.len() <= 64 && c.bytes().all(|b| b.is_ascii_graphic()))
            .map(str::to_owned);
        let proxy = req
            .headers()
            .get("x-holger-proxy-authorization")
            .and_then(|v| v.to_str().ok())
            .and_then(|v| v.strip_prefix("Bearer "))
            .map(str::to_owned);
        // The partition key is edda's `ClientKey` (IPv4 by address, IPv6 by /64,
        // A34-8): `split(':')` made every `[2001:…]` peer one client.
        let mut client = peer.clone();
        if let (Some(hint), Some(proxy)) = (hinted, proxy) {
            if let Ok(Some(by)) =
                auth::validate_request(&settings.auth_config, Some(&proxy), None).await
            {
                if settings.auth_config.role_for_identity(&by).can_admin() {
                    // holger-ui carries this ceremony with its own proof: the console called.
                    settings.console.mark();
                    client = format!(
                        "via {}: {}",
                        by.subject,
                        nornir_auth_webauthn::ceremony::ClientKey::of_peer(&hint)
                    );
                }
            }
        }

        // The config door is a GET and is deliberately open: `rp_id` is not a
        // secret (every ceremony hands it to an anonymous caller already), and a
        // console cannot tell an operator at a RENAMED box "your keys were
        // registered for X, you are at Y" without knowing X. `bootstrap_spent`
        // is the console's own long-standing public answer, moved here with the
        // rule it reports: the bootstrap credential no longer enrols once an
        // admin passkey exists.
        if method == "GET" && path == "/-/auth/passkey/config" {
            let mut config = store.config_json();
            config["bootstrap_spent"] =
                serde_json::json!(store.has_admin_passkey(&settings.auth_config));
            let body = config.to_string();
            crate::metrics::global().record_request(crate::metrics::Verb::Get, 200, 0);
            return Ok(json_response(200, &body));
        }
        if method != "POST" {
            return Ok(text(405, "Method not allowed"));
        }

        // Identity FIRST, before the body is collected: an unauthorized enrolment
        // must not buy an attacker a body-sized allocation.
        let bearer = credential_of(&req);
        let identity = auth::validate_request(
            &settings.auth_config,
            bearer.as_deref(),
            client_cn.as_deref(),
        )
        .await
        .ok()
        .flatten();

        // Ceremony bodies are JSON of a few kilobytes; cap them hard. The import
        // of a console's whole table is the one larger body, and it is bounded
        // by the same cap (a few hundred credentials).
        const PASSKEY_MAX_BODY: usize = 256 * 1024;
        let collected = match Limited::new(req.into_body(), PASSKEY_MAX_BODY)
            .collect()
            .await
        {
            Ok(c) => c.to_bytes(),
            Err(_) => return Ok(text(413, "Payload too large")),
        };
        let body: serde_json::Value = if collected.is_empty() {
            serde_json::json!({})
        } else {
            match serde_json::from_slice(&collected) {
                Ok(v) => v,
                Err(_) => return Ok(text(400, "body is not JSON")),
            }
        };

        // An admin floor shared by the administration doors. Minting an
        // enrolment grant IS an admin action -- it is how somebody becomes an
        // operator -- so it is gated exactly like one.
        let require_admin =
            |identity: &Option<auth::AuthIdentity>| -> Result<String, (u16, String)> {
                match identity {
                    Some(id) if settings.auth_config.role_for_identity(id).can_admin() => {
                        Ok(id.audit_name())
                    }
                    Some(_) => Err((403, "this action requires an admin identity".to_owned())),
                    None => Err((401, "this action requires an admin identity".to_owned())),
                }
            };
        // ...and step-up on top for the acts that hand out or take away a login:
        // a passkey session must be user-verified and fresh (the console's rule,
        // moved here); a machine credential is exempt.
        let stepped_up = |identity: &Option<auth::AuthIdentity>| -> Result<(), (u16, String)> {
            match identity {
                Some(id) if !store.caller_stepped_up(id, bearer.as_deref()) => {
                    Err((403, crate::passkey::STEP_UP_REFUSAL.to_owned()))
                }
                _ => Ok(()),
            }
        };
        let auth_cfg = &settings.auth_config;

        let outcome: Result<serde_json::Value, (u16, String)> = match path.as_str() {
            "/-/auth/passkey/login/start" => store.open_login(&body, &client),
            "/-/auth/passkey/login/finish" => store.close_login(&body),
            // A28 M9: a stale touch answered in place (the console's answer to `"code":"stepup"`).
            "/-/auth/passkey/step-up/start" => {
                store.open_step_up(identity.as_ref(), bearer.as_deref(), &client)
            }
            "/-/auth/passkey/step-up/finish" => {
                store.close_step_up(&body, identity.as_ref(), bearer.as_deref())
            }
            "/-/auth/passkey/register/start" => {
                // The admin path (no invite) is an enrolment by an admin's word: a passkey admin
                // must be stepped up for it. An invite or a sign-up is its own credential.
                if body.get("invite").is_none() && body.get("signup").is_none() {
                    stepped_up(&identity).and_then(|()| {
                        store.open_enrolment(
                            &body,
                            identity.as_ref(),
                            bearer.as_deref(),
                            auth_cfg,
                            &client,
                        )
                    })
                } else {
                    store.open_enrolment(
                        &body,
                        identity.as_ref(),
                        bearer.as_deref(),
                        auth_cfg,
                        &client,
                    )
                }
            }
            "/-/auth/passkey/register/finish" => store.close_enrolment(&body, auth_cfg),
            "/-/auth/passkey/invites" => require_admin(&identity)
                .and_then(|by| stepped_up(&identity).map(|()| by))
                .and_then(|by| {
                    store.mint_invite_as(
                        &crate::passkey::with_owners_of(&body, identity.as_ref()),
                        &by,
                        bearer.as_deref(),
                        auth_cfg,
                    )
                }),
            "/-/auth/passkey/invites/list" => {
                require_admin(&identity).map(|_| store.invites_json(auth_cfg))
            }
            "/-/auth/passkey/invites/revoke" => require_admin(&identity).and_then(|_| {
                let id = body.get("id").and_then(|v| v.as_str()).unwrap_or_default();
                store.withdraw_invite(id)
            }),
            // Who the caller is, for a console to render (never to decide with).
            "/-/auth/passkey/session" => match &identity {
                Some(id) => Ok(store.session_json(id, bearer.as_deref(), auth_cfg)),
                None => Err((401, "no session".to_owned())),
            },
            // A person's own logout: every session of theirs ends. Always answers ok — a
            // browser must be able to get rid of a session it cannot use.
            "/-/auth/passkey/logout" => match bearer
                .as_deref()
                .filter(|b| crate::identity_host::is_session_token(b))
            {
                Some(b) => store
                    .logout(b)
                    .or_else(|_| Ok(serde_json::json!({ "ok": true }))),
                None => Ok(serde_json::json!({ "ok": true })),
            },
            "/-/auth/passkey/sessions/revoke-all" => require_admin(&identity)
                .and_then(|_| stepped_up(&identity))
                .and_then(|()| store.revoke_all_sessions()),
            "/-/auth/passkey/credentials/list" => {
                require_admin(&identity).map(|_| store.credentials_json(auth_cfg))
            }
            "/-/auth/passkey/credentials/revoke" => require_admin(&identity)
                .and_then(|by| stepped_up(&identity).map(|()| by))
                .and_then(|by| {
                    let id = body.get("id").and_then(|v| v.as_str()).unwrap_or_default();
                    store.revoke_credential(id, &by, auth_cfg)
                }),
            _ => Err((404, "no such passkey door".to_owned())),
        };

        let (status, payload) = match outcome {
            Ok(v) => (200u16, v.to_string()),
            Err((status, msg)) => (status, crate::passkey::refusal_json(&msg).to_string()),
        };
        // Audited: enrolment and login are exactly the events an operator needs to
        // be able to reconstruct afterwards.
        let who = identity
            .as_ref()
            .map(|i| i.audit_name())
            .unwrap_or_else(|| "anonymous".to_owned());
        let ev = AuditEvent::new(&who, AuditAction::List, "-", &path, &peer, status, 0)
            .with_detail(format!("passkey door {path}"));
        if let Err(e) = settings.audit.record(ev) {
            log::warn!("audit record failed: {e}");
        }
        crate::metrics::global().record_request(crate::metrics::Verb::Put, status, 0);
        crate::metrics::global().observe_request_duration(started.elapsed().as_secs_f64());
        return Ok(json_response(status, &payload));
    }

    // **The sign-up page's two choices** (lane SU1): holger-ui's `/signup` asks this door and
    // renders what it answers — the ONE shop's account sign-up for this site, and its
    // private-estate order, carrying the signed-in person's `estate` ticket. A visitor (no
    // credential, or one that does not resolve) gets the links a visitor gets; never an error.
    if path == "/-/signup" {
        if method != "GET" && method != "HEAD" {
            return Ok(text(405, "Method not allowed"));
        }
        let bearer = credential_of(&req);
        let identity = auth::validate_request(
            &settings.auth_config,
            bearer.as_deref(),
            client_cn.as_deref(),
        )
        .await
        .ok()
        .flatten();
        let root = settings.board.as_ref().and_then(|b| b.data_root.clone());
        let auth_cfg = settings.auth_config.clone();
        let links = match tokio::task::spawn_blocking(move || {
            crate::room::signup_links(root.as_deref(), &auth_cfg, identity.as_ref())
        })
        .await
        {
            Ok(l) => l,
            Err(e) => {
                return Ok(text(
                    500,
                    &format!("the sign-up links could not be made: {e}"),
                ))
            }
        };
        let mut resp = json_response(
            200,
            &serde_json::to_string(&links).unwrap_or_else(|_| "{}".into()),
        );
        resp.headers_mut().insert(
            "Cache-Control",
            hyper::header::HeaderValue::from_static("no-store"),
        );
        return Ok(resp);
    }

    // **The relay's doors** (A12): holger's front runs the shared buy flow (monetize-site-buy)
    // over the site's bearer at the ONE box, and asks THIS box who a request's person is, for
    // that person's own actor ticket, and — with the console's own credential — whether a paid
    // sign-up's account holds its passkey yet. The vendor's way back (`/paid/…`, `/cancel/…`)
    // is the site's page (holger-ui), not this door's.
    #[cfg(feature = "metered")]
    if path == "/-/buy/me" || path == "/-/buy/ticket" || path == "/-/buy/account" {
        let bearer = credential_of(&req);
        let identity = auth::validate_request(
            &settings.auth_config,
            bearer.as_deref(),
            client_cn.as_deref(),
        )
        .await
        .ok()
        .flatten();
        let root = settings.board.as_ref().and_then(|b| b.data_root.clone());
        let (status, payload) = match (path.as_str(), method.as_str()) {
            ("/-/buy/me", "GET") => {
                let me = tokio::task::spawn_blocking(move || {
                    crate::room::buy_me(root.as_deref(), identity.as_ref())
                })
                .await
                .unwrap_or_default();
                (200u16, serde_json::to_value(&me).unwrap_or_default())
            }
            ("/-/buy/ticket", "POST") => {
                let collected = match Limited::new(req.into_body(), 4096).collect().await {
                    Ok(c) => c.to_bytes(),
                    Err(_) => return Ok(text(413, "Payload too large")),
                };
                let body: serde_json::Value =
                    serde_json::from_slice(&collected).unwrap_or(serde_json::Value::Null);
                let purpose = body
                    .get("purpose")
                    .and_then(|v| v.as_str())
                    .unwrap_or_default()
                    .to_owned();
                let caps: std::collections::BTreeMap<String, u64> = body
                    .get("caps")
                    .cloned()
                    .and_then(|c| serde_json::from_value(c).ok())
                    .unwrap_or_default();
                let minted = tokio::task::spawn_blocking(move || {
                    crate::room::buy_ticket(
                        root.as_deref(),
                        identity.as_ref(),
                        &purpose,
                        &caps,
                        crate::clock::now_unix_ms(),
                    )
                })
                .await;
                match minted {
                    Ok(Ok(ticket)) => (200, serde_json::json!({ "ticket": ticket })),
                    Ok(Err((status, why))) => (status, serde_json::json!({ "error": why })),
                    Err(e) => (
                        500,
                        serde_json::json!({ "error": format!("the ticket was not made: {e}") }),
                    ),
                }
            }
            ("/-/buy/account", "GET") => match &identity {
                None => (401, serde_json::json!({ "error": "the console asks this" })),
                Some(id) if !settings.auth_config.role_for_identity(id).can_admin() => {
                    (403, serde_json::json!({ "error": "the console asks this" }))
                }
                Some(_) => {
                    let user = req
                        .uri()
                        .query()
                        .unwrap_or("")
                        .split('&')
                        .find_map(|kv| kv.strip_prefix("user="))
                        .unwrap_or("")
                        .to_owned();
                    let answer = tokio::task::spawn_blocking(move || {
                        crate::room::signup_account(root.as_deref(), &user)
                    })
                    .await
                    .unwrap_or("none");
                    (200, serde_json::json!({ "account": answer }))
                }
            },
            _ => return Ok(text(405, "Method not allowed")),
        };
        let mut resp = json_response(status, &payload.to_string());
        resp.headers_mut().insert(
            "Cache-Control",
            hyper::header::HeaderValue::from_static("no-store"),
        );
        return Ok(resp);
    }

    // **This box's generic settings** (owner decision 2026-10-26, item 5): bytes under a name
    // the client chooses (`crate::settings`; a console's own switches). An administrator only;
    // every write audited with who, the name and old -> new; bounded, a refusal naming its
    // bound. GET answers `{"present", "value_hex"}`; PUT takes the value as the body and
    // answers `{"had", "previous_hex"}`.
    if let Some(name) = path.strip_prefix(crate::settings::DOOR) {
        let name = name.to_owned();
        let bearer = credential_of(&req);
        let identity = auth::validate_request(
            &settings.auth_config,
            bearer.as_deref(),
            client_cn.as_deref(),
        )
        .await
        .ok()
        .flatten();
        let who = identity
            .as_ref()
            .map(|i| i.subject.clone())
            .unwrap_or_else(|| "anonymous".to_owned());
        let mut admin = identity
            .as_ref()
            .is_some_and(|id| settings.auth_config.role_for_identity(id).can_admin());
        // **The console's proof READS, and never writes** (RA2-2). holger-ui sends its own bearer
        // ONLY as the proof in `x-holger-proxy-authorization`, never as anyone's credential;
        // with an administrator's proof the console reads its switch at start and after. A
        // write needs the person's own credential in `authorization`: the proof is not one.
        let mut who = who;
        if !admin && method == "GET" {
            let proof = req
                .headers()
                .get("x-holger-proxy-authorization")
                .and_then(|v| v.to_str().ok())
                .and_then(|v| v.strip_prefix("Bearer "))
                .map(str::to_owned);
            if let Some(proof) = proof {
                if let Ok(Some(by)) =
                    auth::validate_request(&settings.auth_config, Some(&proof), None).await
                {
                    if settings.auth_config.role_for_identity(&by).can_admin() {
                        // holger-ui reads its setting with its own proof: the console called.
                        settings.console.mark();
                        who = format!("console proof of {}", by.subject);
                        admin = true;
                    }
                }
            }
        }
        if !admin {
            let status = if identity.is_some() { 403 } else { 401 };
            if method == "PUT" {
                let ev = AuditEvent::new(&who, AuditAction::Other, "", &path, &peer, status, 0)
                    .with_detail(format!(
                        "setting {name}: refused, an administrator writes the settings"
                    ));
                if let Err(e) = settings.audit.record(ev) {
                    log::warn!("audit record failed: {e}");
                }
            }
            return Ok(json_response(status, &serde_json::json!({ "error": "only an administrator reads or writes this box's settings" }).to_string()));
        }
        let Some(root) = settings.board.as_ref().and_then(|b| b.data_root.clone()) else {
            return Ok(json_response(503, &serde_json::json!({ "error": "this box has no data root, so it keeps no settings" }).to_string()));
        };
        let (status, payload) = match method.as_str() {
            "GET" => match tokio::task::spawn_blocking(move || crate::settings::get(&root, &name))
                .await
            {
                Ok(Ok(v)) => (
                    200u16,
                    serde_json::json!({ "present": v.is_some(), "value_hex": crate::settings::hex(&v.unwrap_or_default()) }),
                ),
                // A damaged file is NO value (RA2-10): never a 200 that reads as "nothing
                // stored", so a console that asks keeps its switch OFF until a write recovers it.
                Ok(Err(why)) if why.starts_with(crate::settings::DAMAGED) => {
                    log::error!("ALERT {why}: every read answers 503 until an administrator writes a setting");
                    (503, serde_json::json!({ "error": why, "damaged": true }))
                }
                Ok(Err(why)) => (400, serde_json::json!({ "error": why })),
                Err(e) => (500, serde_json::json!({ "error": e.to_string() })),
            },
            "PUT" => {
                let value = match Limited::new(req.into_body(), crate::settings::MAX_VALUE_BYTES + 1).collect().await {
                    Ok(c) => c.to_bytes().to_vec(),
                    Err(_) => return Ok(json_response(413, &serde_json::json!({ "error": format!("a setting value is at most {} bytes", crate::settings::MAX_VALUE_BYTES) }).to_string())),
                };
                // Audited BEFORE it is applied (RA2-9): the record (who, the name, old -> new)
                // is written and flushed first, and a change the audit could not keep is refused.
                let (n, v, audit, who, path, peer, len) = (
                    name.clone(),
                    value.clone(),
                    settings.audit.clone(),
                    who.clone(),
                    path.clone(),
                    peer.clone(),
                    value.len() as u64,
                );
                let changed = tokio::task::spawn_blocking(move || {
                    crate::settings::change(&root, &n, &v, |line| {
                        let ev =
                            AuditEvent::new(&who, AuditAction::Other, "", &path, &peer, 200, len)
                                .with_detail(line.to_owned());
                        audit
                            .record(ev)
                            .and_then(|()| audit.flush())
                            .map_err(|e| format!("{e:?}"))
                    })
                })
                .await;
                match changed {
                    Ok(Ok(previous)) => (
                        200,
                        serde_json::json!({ "had": previous.is_some(), "previous_hex": crate::settings::hex(&previous.unwrap_or_default()) }),
                    ),
                    Ok(Err(why)) if why.starts_with("the change was not audited") => {
                        log::error!("ALERT setting {name}: {why}");
                        (503, serde_json::json!({ "error": why }))
                    }
                    Ok(Err(why)) => (400, serde_json::json!({ "error": why })),
                    Err(e) => (500, serde_json::json!({ "error": e.to_string() })),
                }
            }
            _ => return Ok(text(405, "Method not allowed")),
        };
        let mut resp = json_response(status, &payload.to_string());
        resp.headers_mut().insert(
            "Cache-Control",
            hyper::header::HeaderValue::from_static("no-store"),
        );
        return Ok(resp);
    }

    // ★ **The front's report** (lane HOL-FLOW-FRONT): the estate front tells this box its
    // doors, the names it serves and where each goes, proven under the key the pairing kept
    // (`crate::front_report`). No bearer: the proof is the credential. A box with no data root
    // (a bare gateway) has no front, and answers 404 as an older holger does.
    if path == holger_downstream_rules::front::PATH {
        let Some(root) = settings.board.as_ref().and_then(|b| b.data_root.clone()) else {
            return Ok(text(404, "this holger keeps no front's report"));
        };
        if method != "POST" {
            return Ok(text(405, "the front's report is a POST"));
        }
        let body = match Limited::new(req.into_body(), crate::front_report::MAX_BODY)
            .collect()
            .await
        {
            Ok(c) => c.to_bytes(),
            Err(_) => return Ok(text(413, "the front's report is too large")),
        };
        let now_ms = crate::clock::now_unix_ms();
        let done =
            tokio::task::spawn_blocking(move || crate::front_report::heard(&root, &body, now_ms))
                .await;
        return Ok(match done {
            Ok(Ok(kept)) => {
                log::info!(
                    "front: the report of '{}' is kept ({} doors, {} routes)",
                    kept.report.front,
                    kept.report.doors.len(),
                    kept.report.routes.len()
                );
                json_response(
                    200,
                    &serde_json::json!({ "kept": true, "front": kept.report.front }).to_string(),
                )
            }
            Ok(Err((status, why))) => {
                // Anybody may knock (the repository route carries this door): a refusal is
                // said at debug here; the front says its own refusal at warn.
                log::debug!("front: {why}");
                text(status, &why)
            }
            Err(e) => text(500, &format!("the front's report could not be heard: {e}")),
        });
    }

    // **The artifact flow** (lane HOL-SVG-RON): the RON's graph, the estate and the
    // counters, from `crate::flow::live` — the SAME function `AdminService.FlowSvg`
    // calls, so the console and this door never draw two pictures. Admin-read (it
    // names addresses). Mounted outside the GET block, so a HEAD or a write is answered
    // by this door and never falls through to the repository router.
    if let Some(flow_path) = holger_flow_path(&path) {
        let Some(door) = settings.flow.clone() else {
            return Ok(text(404, "the artifact flow is off on this holger"));
        };
        if method != "GET" && method != "HEAD" {
            return Ok(text(405, "the artifact flow is read-only: GET"));
        }
        if let Err(resp) = gate_admin_read(&settings, &req, client_cn.as_deref()).await {
            return Ok(resp);
        }
        let sources = crate::flow::Sources {
            shape: door.shape,
            repos: settings.routes.all_repos(),
            audit: Arc::clone(&settings.audit),
            visitors: Arc::clone(&settings.visitors),
            console: settings.console.clone(),
            board: settings.board.clone(),
            #[cfg(feature = "intake")]
            intake: settings.intake.clone(),
            quota: door.quota,
        };
        // The zoom (HOL-FLOW-SMART): no `open` is level 1, `?open=main` level 2, `all` 3.
        let open = crate::flow::Open::parse(&flow_open_words(req.uri().query().unwrap_or("")));
        let drawn = tokio::task::spawn_blocking(move || {
            let graph = crate::flow::live(&sources).zoom(&open);
            match flow_path {
                crate::flow::FLOW_SVG_PATH => (graph.render_svg(), "image/svg+xml; charset=utf-8"),
                crate::flow::FLOW_JSON_PATH => (graph.to_json(), "application/json"),
                _ => (
                    graph.render_page(graph.refresh_secs),
                    "text/html; charset=utf-8",
                ),
            }
        })
        .await;
        return Ok(match drawn {
            Ok((body, ct)) => Response::builder()
                .status(200)
                .header("Content-Type", ct)
                .header("Cache-Control", "no-store")
                .header("X-Content-Type-Options", "nosniff")
                .body(if method == "HEAD" {
                    Full::new(Bytes::new()).boxed()
                } else {
                    Full::new(Bytes::from(body)).boxed()
                })
                .expect("static response"),
            Err(e) => text(500, &format!("the artifact flow could not be drawn: {e}")),
        });
    }

    // Unauthenticated, backend-less endpoints. Probes are not artifact
    // operations, so they are not audited.
    if method == "GET" {
        // `/livez` is the same liveness probe under the name Kubernetes' own components use
        // (`listen::is_probe` names it; HOL-DOCFIND g).
        if path == "/healthz" || path == "/livez" {
            return Ok(text(200, "ok"));
        }
        // ★ The repository-key door (lane HOL-SIGNED-APT-DNF): the public half of the key the
        // deb and rpm views sign their metadata with, open on every box like the evidence key.
        if path == crate::repo_sign::KEY_PATH {
            return Ok(match settings.repo_key.as_ref() {
                Some(k) => Response::builder()
                    .status(200)
                    .header("Content-Type", "application/pgp-keys")
                    .header("Cache-Control", "public, max-age=300")
                    .header("X-Content-Type-Options", "nosniff")
                    .body(Full::new(Bytes::from(k.public_armor().to_owned())).boxed())
                    .expect("static response"),
                None => text(404, crate::repo_sign::NO_KEY),
            });
        }
        // ★ The evidence public-key door (lane HOL-OCI-EVIDENCE): open on every box, a
        // read-gated one too, before any gate. A verifier fetches it with no credential.
        #[cfg(feature = "intake")]
        if crate::evidence_key::is_door(&path) {
            return Ok(
                match settings.evidence_key.as_ref().and_then(|k| k.answer(&path)) {
                    Some((ctype, body)) => Response::builder()
                        .status(200)
                        .header("Content-Type", ctype)
                        .header("Cache-Control", "public, max-age=300")
                        .header("X-Content-Type-Options", "nosniff")
                        .body(Full::new(Bytes::from(body)).boxed())
                        .expect("static response"),
                    None => text(404, crate::evidence_key::NO_SIGNER),
                },
            );
        }
        // Readiness (lane B4): asked each time, off the reactor (it pings the
        // scan sidecar and writes one small file).
        if path == "/readyz" {
            let Some(check) = settings.ready.clone() else {
                return Ok(text(200, "ok"));
            };
            return Ok(match tokio::task::spawn_blocking(move || check()).await {
                Ok(Ok(())) => text(200, "ok"),
                Ok(Err(why)) => text(503, &format!("not ready: {why}")),
                Err(e) => text(503, &format!("not ready: the check did not finish: {e}")),
            });
        }
        // **The twin door** (plan §3 W9 / ?6). Read-only JSON: what this box is,
        // which primary it follows, whether it accepts writes, and the
        // `twin ≥ primary` store verdict with its named warning
        // (`holger-twin-2`) when the twin cannot hold what the primary has used.
        //
        // Unauthenticated beside the probes, and it carries no secret: a role, a
        // hostname the operator configured, and two byte counts. It exists so a
        // promotion is never the moment somebody discovers the twin is too
        // small. It never refuses — the invariant is REPORTED, not enforced.
        if path == "/-/twin" {
            return Ok(json_response(200, &settings.twin.door_json()));
        }
        // **The estate board** (lane E3): front | main | twin, the upstreams and the
        // downstreams, as DATA (H2 #1) from `crate::topology` — the same rows as
        // `AdminService.Topology`; holger-ui draws them. Admin-read (the rows name
        // addresses).
        if path == ESTATE_JSON_PATH {
            if let Err(resp) = gate_admin_read(&settings, &req, client_cn.as_deref()).await {
                return Ok(resp);
            }
            let Some(sources) = settings.board.clone() else {
                return Ok(text(404, "this door carries no estate board"));
            };
            return Ok(
                match tokio::task::spawn_blocking(move || crate::topology::board(&sources.gather()))
                    .await
                {
                    Ok(reply) => Response::builder()
                        .status(200)
                        .header("Content-Type", "application/json")
                        .header("Cache-Control", "no-store")
                        .header("X-Content-Type-Options", "nosniff")
                        .body(
                            Full::new(Bytes::from(crate::topology::json(&reply).to_string()))
                                .boxed(),
                        )
                        .expect("static response"),
                    Err(e) => text(500, &format!("the estate board could not be gathered: {e}")),
                },
            );
        }
        // **The scan sandbox, looked at from inside** (lane HOLGER-MEDIA): the worker's
        // `probe` mode through the same sandbox every scan runs in (no network, a
        // read-only root, the scratch cap, uid 65532, no capability, seccomp). Admin-read,
        // like the estate board; the install test's `sandbox` row reads it.
        if path == SANDBOX_PROBE_PATH {
            if let Err(resp) = gate_admin_read(&settings, &req, client_cn.as_deref()).await {
                return Ok(resp);
            }
            let Some(probe) = settings.scan_probe.clone() else {
                return Ok(text(404, "this door carries no scan sandbox to probe"));
            };
            return Ok(match tokio::task::spawn_blocking(move || probe()).await {
                Ok(Ok(Some(v))) => Response::builder()
                    .status(200)
                    .header("Content-Type", "application/json")
                    .header("Cache-Control", "no-store")
                    .body(Full::new(Bytes::from(v.to_string())).boxed())
                    .expect("static response"),
                Ok(Ok(None)) => text(
                    404,
                    "this door carries no intake chain, so there is no scan sandbox to probe",
                ),
                Ok(Err(e)) => text(503, &e),
                Err(e) => text(500, &format!("the probe task failed: {e}")),
            });
        }
        if path == "/v2" || path == "/v2/" {
            // The OCI version probe, and the ONE place a container client
            // decides whether it will ever send a credential.
            //
            // MEASURED 2026-09-21 against a real `podman push`: answered 200
            // with no `WWW-Authenticate`, the client concludes the registry
            // wants nothing, and it then never sends the credential a
            // `podman login` stored — not even after the upload POST refuses
            // it. The push dies on `authentication required` while the correct
            // credential sits unused on disk. That is the whole reason no image
            // could be pushed into holger.
            //
            // So: probe WITH a credential, or on a server that configures no
            // auth method at all ⇒ 200, exactly as before. Probe WITHOUT one on
            // a server that HAS a method ⇒ 401 and the challenge, which is what
            // makes the client attach its credential to everything that
            // follows.
            //
            // ⚠ This does NOT close anonymous pulls. A 401 on the probe is a
            // SUCCESSFUL v2 detection to a distribution client (it is how every
            // registry that gates pushes answers it); the client records the
            // challenge, and a puller with no credential goes on to request the
            // manifest anyway, which this door still serves openly while
            // `require_auth_for_reads` is false. The anonymous-pull proof is in
            // `a_credentialless_pull_still_works_when_the_probe_challenges`.
            let has_credential = credential_of(&req).is_some() || client_cn.is_some();
            let gated = !settings.auth_config.methods.is_empty();
            if gated && !has_credential {
                return Ok(Response::builder()
                    .status(401)
                    .header("Docker-Distribution-Api-Version", "registry/2.0")
                    .header("WWW-Authenticate", "Basic realm=\"holger\"")
                    .header("Content-Type", "application/json")
                    .body(Full::new(Bytes::from_static(
                        b"{\"errors\":[{\"code\":\"UNAUTHORIZED\",\"message\":\"authentication required\"}]}",
                    )).boxed())
                    .expect("static response"));
            }
            return Ok(Response::builder()
                .status(200)
                .header("Docker-Distribution-Api-Version", "registry/2.0")
                .body(Full::new(Bytes::from_static(b"{}")).boxed())
                .expect("static response"));
        }
        // Read-only cross-repo SEARCH door (parity §H). Reserved under `/-/` so it
        // never collides with a repository name; open read (anonymous), audited as
        // a List. Query axes come from the query string:
        //   /-/search?name=&namespace=&version=&checksum=&path=&repo=&repo=&limit=
        // Returns the same JSON shape the engine produces (artifacts + paths +
        // truncated). This is the read-only HTTP twin of the `SearchService` RPC.
        if path == "/-/search" {
            // Read gate (cross-repo → global Reader floor). Off unless
            // require_auth_for_reads is set (forced on by the Critical profile).
            let gate = match gate_meta_read(&settings, &req, client_cn.as_deref(), "").await {
                Ok(g) => g,
                Err(resp) => return Ok(resp),
            };
            let MetaRead {
                mut who,
                mut identity,
            } = gate;
            let query = parse_search_query(req.uri().query().unwrap_or(""));

            // The CHECKSUM axis is the one axis that fetches and hashes every
            // candidate (`search.rs`: `backend.fetch()` + sha256 per artifact).
            // On an open-read door there is no principal to attribute or throttle
            // that to, so one anonymous `GET /-/search?checksum=<64 hex>` turned
            // the entire store into a hashing job. It now requires an
            // authenticated identity: the gate resolved one when it is on, and
            // with the gate off the door authenticates a request that actually
            // carries a credential (so an open-read deployment that still issues
            // tokens keeps the axis) — otherwise 403.
            if query.checksum.is_some() {
                if identity.is_none() {
                    identity = auth::validate_request(
                        &settings.auth_config,
                        bearer_of(&req),
                        client_cn.as_deref(),
                    )
                    .await
                    .ok()
                    .flatten();
                    if let Some(id) = identity.as_ref() {
                        who = id.subject.clone();
                    }
                }
                if identity.is_none() {
                    let ev = AuditEvent::new(
                        &who,
                        AuditAction::List,
                        "",
                        &path_and_query,
                        &peer,
                        403,
                        0,
                    )
                    .with_detail("checksum search axis requires an authenticated identity");
                    if let Err(e) = settings.audit.record(ev) {
                        log::warn!("audit record failed: {e}");
                    }
                    crate::grpc::functional_status(
                        "holger-http/search",
                        "checksum_axis_authenticated",
                        false,
                        "anonymous checksum search refused",
                    );
                    crate::metrics::global().record_request(crate::metrics::Verb::Search, 403, 0);
                    crate::metrics::global()
                        .observe_request_duration(started.elapsed().as_secs_f64());
                    return Ok(text(
                        403,
                        "the checksum search axis requires authentication",
                    ));
                }
            }

            // Per-repository READ AUTHORIZATION, not just the global floor. The
            // door used to gate once at `repo = ""` and then hand `all_repos()`
            // to the engine, so an identity carved out of one repository with a
            // `Denied` role read it anyway — through search results instead of
            // through its own path. Each repository is now authorized for THIS
            // identity and the denied ones never enter the engine. With the gate
            // off `authorize_read` is `Ok(())` for every repo, so the open-read
            // posture is unchanged.
            //
            // Semantics are kept identical to the gRPC twin
            // (`HolgerGrpc::readable_repos`, which `Search` / `ListRepositories`
            // use): the denied repository is FILTERED OUT SILENTLY, not turned
            // into a 403 for the whole query — a refusal naming the repository
            // would itself confirm that a repository the caller may not read
            // exists. (It is spelled out here rather than shared because that
            // helper hangs off `HolgerGrpc`, and this door has only the
            // `FastRoutes` + `AuthConfig` the helper is built from.)
            let repos: Vec<(String, Arc<dyn traits::RepositoryBackendTrait>)> = settings
                .routes
                .all_repos()
                .into_iter()
                .filter(|(name, _)| {
                    crate::auth::authorize_read_identity_scoped(
                        &settings.auth_config,
                        &settings.read_gate,
                        identity.as_ref(),
                        name,
                    )
                    .is_ok()
                })
                .collect();
            #[cfg(feature = "intake")]
            let props = settings.properties.clone();
            let results = tokio::task::spawn_blocking(move || {
                #[cfg(feature = "intake")]
                let lookup = props
                    .as_deref()
                    .map(|p| p as &dyn crate::search::PropertyLookup);
                #[cfg(not(feature = "intake"))]
                let lookup: Option<&dyn crate::search::PropertyLookup> = None;
                crate::search::search_repos_with_properties(&repos, &query, lookup)
            })
            .await;
            let hit_count = results
                .as_ref()
                .map(|r| (r.artifacts.len() + r.paths.len()) as u64)
                .unwrap_or(0);
            let (status, body) = match results {
                Ok(r) => match serde_json::to_vec(&r) {
                    Ok(json) => (200u16, json),
                    Err(e) => (500, format!("serialize error: {e}").into_bytes()),
                },
                Err(e) => (500, format!("search task failed: {e}").into_bytes()),
            };
            // Audit the read as the resolved subject (real subject when gated).
            let ev = AuditEvent::new(
                who,
                AuditAction::List,
                "",
                &path_and_query,
                &peer,
                status,
                hit_count,
            );
            if let Err(e) = settings.audit.record(ev) {
                log::warn!("audit record failed: {e}");
            }
            crate::grpc::functional_status(
                "holger-http/search",
                "search_served",
                status == 200,
                &format!("{hit_count} hits"),
            );
            crate::metrics::global().record_request(
                crate::metrics::Verb::Search,
                status,
                body.len() as u64,
            );
            crate::metrics::global().observe_request_duration(started.elapsed().as_secs_f64());
            let ct = if status == 200 {
                "application/json"
            } else {
                "text/plain"
            };
            return Ok(Response::builder()
                .status(status)
                .header("Content-Type", ct)
                .body(Full::new(Bytes::from(body)).boxed())
                .unwrap_or_else(|_| text(500, "Internal error")));
        }
        // Read-only hosted-SBOM door (parity §6/§11). The read twin of the
        // `SbomService.FetchSbom` RPC — attach stays gRPC/CLI-only. Coordinate
        // comes from the query string:
        //   /-/sbom?repo=&namespace=&name=&version=
        // Serves the hosted CycloneDX document byte-identical (200), or 404 when
        // no SBOM is attached to that coordinate. Open read, audited as a Download.
        #[cfg(feature = "intake")]
        if path == "/-/sbom" {
            // Read gate, scoped to the target repo (global floor if repo absent).
            // The scope comes from the SAME parser the door serves from, so the
            // repository the gate authorizes is by construction the repository
            // the door reads. It used to come from a second, simpler parser that
            // knew only `repo=` and did not percent-decode, so `?repository=...`
            // or `?repo=team%2Da` scoped the gate somewhere other than the
            // coordinate that was then served -- stepping around a per-repo
            // `Denied` carve-out by respelling the query.
            let scope = parse_sbom_coord(req.uri().query().unwrap_or("")).repository;
            let who = match gate_meta_read(&settings, &req, client_cn.as_deref(), &scope).await {
                Ok(g) => g.who,
                Err(resp) => return Ok(resp),
            };
            let (status, ct, body, repo, label) =
                serve_sbom_door(settings.sboms.as_ref(), req.uri().query().unwrap_or(""));
            let ev = AuditEvent::new(
                who,
                AuditAction::Download,
                &repo,
                &label,
                &peer,
                status,
                if status == 200 { body.len() as u64 } else { 0 },
            );
            if let Err(e) = settings.audit.record(ev) {
                log::warn!("audit record failed: {e}");
            }
            crate::grpc::functional_status(
                "holger-http/sbom",
                "sbom_served",
                status == 200,
                &format!("{status} {label}"),
            );
            crate::metrics::global().record_request(
                crate::metrics::Verb::Sbom,
                status,
                if status == 200 { body.len() as u64 } else { 0 },
            );
            crate::metrics::global().observe_request_duration(started.elapsed().as_secs_f64());
            return Ok(Response::builder()
                .status(status)
                .header("Content-Type", ct)
                .body(Full::new(Bytes::from(body)).boxed())
                .unwrap_or_else(|_| text(500, "Internal error")));
        }
        // Read-only custom-PROPERTIES door (parity §8). The read twin of the
        // `property` search axis — property WRITES are CLI/in-process for now.
        //   /-/properties?repo=&namespace=&name=&version=
        // Serves the coordinate's `{ key: [values] }` map as JSON (200, `{}` when
        // none), or 400 when the coordinate is incomplete. Open read, audited.
        #[cfg(feature = "intake")]
        if path == "/-/properties" {
            // Read gate, scoped to the target repo (global floor if repo absent).
            // The scope comes from the SAME parser the door serves from, so the
            // repository the gate authorizes is by construction the repository
            // the door reads. It used to come from a second, simpler parser that
            // knew only `repo=` and did not percent-decode, so `?repository=...`
            // or `?repo=team%2Da` scoped the gate somewhere other than the
            // coordinate that was then served -- stepping around a per-repo
            // `Denied` carve-out by respelling the query.
            let scope = parse_sbom_coord(req.uri().query().unwrap_or("")).repository;
            let who = match gate_meta_read(&settings, &req, client_cn.as_deref(), &scope).await {
                Ok(g) => g.who,
                Err(resp) => return Ok(resp),
            };
            let (status, body, repo, label) = serve_properties_door(
                settings.properties.as_ref(),
                req.uri().query().unwrap_or(""),
            );
            let ev = AuditEvent::new(who, AuditAction::List, &repo, &label, &peer, status, 0);
            if let Err(e) = settings.audit.record(ev) {
                log::warn!("audit record failed: {e}");
            }
            crate::grpc::functional_status(
                "holger-http/properties",
                "properties_served",
                status == 200,
                &format!("{status} {label}"),
            );
            let ct = if status == 200 {
                "application/json"
            } else {
                "text/plain"
            };
            return Ok(Response::builder()
                .status(status)
                .header("Content-Type", ct)
                .body(Full::new(Bytes::from(body)).boxed())
                .unwrap_or_else(|_| text(500, "Internal error")));
        }
        // Read-only Prometheus scrape door (parity §K). Reserved (no `/-/` prefix
        // — Prometheus scrapes the conventional `/metrics`), unaudited (it exposes
        // only aggregate registry counters, not artifacts) but read-GATED like the
        // other meta doors. Counters come from the process-global registry every
        // verb bumps; the per-repo artifact gauge lists each backend at scrape
        // time, so it runs under `spawn_blocking` off the async reactor.
        if path == "/metrics" {
            // Critical profile: `/metrics` is served only to loopback peers.
            // Off-loopback scrapes get a 404 so the metrics surface is not exposed
            // on a real interface at all — checked first, so a Critical node
            // reveals nothing about its auth posture to a remote prober.
            if settings.security_profile == crate::SecurityProfile::Critical
                && !peer_is_loopback(&peer)
            {
                return Ok(text(404, "Not found"));
            }
            // Read gate (global Reader floor), the same one `/-/search`,
            // `/-/sbom` and `/-/properties` pass. `/metrics` is a read like any
            // other: it names every repository on the server and, until this
            // gate, did an unbounded per-repo listing for anyone who asked. Off
            // unless `require_auth_for_reads` is set, so an existing scrape
            // configuration is unchanged — and the Critical profile, which forces
            // the flag on, no longer has one unauthenticated door left.
            if let Err(resp) = gate_meta_read(&settings, &req, client_cn.as_deref(), "").await {
                return Ok(resp);
            }
            let repos = settings.routes.all_repos();
            let body = tokio::task::spawn_blocking(move || {
                let repo_counts: Vec<(String, Option<usize>)> = repos
                    .iter()
                    .map(|(name, backend)| {
                        // Bounded listing: the gauge is a health signal, not a
                        // census, so a huge repo caps at METRICS_LIST_CAP. An
                        // errored backend reports None, NOT 0 -- a zero here
                        // would make a broken disk read as an empty repository.
                        // render_prometheus turns None into an absent count
                        // sample plus holger_repo_listable{repo}=0.
                        let n = backend.list(None, METRICS_LIST_CAP).map(|v| v.len()).ok();
                        (name.clone(), n)
                    })
                    .collect();
                crate::metrics::global().render_prometheus(&repo_counts)
            })
            .await;
            let (status, body) = match body {
                Ok(text) => (200u16, text.into_bytes()),
                Err(e) => (500u16, format!("metrics task failed: {e}").into_bytes()),
            };
            crate::grpc::functional_status(
                "holger-http/metrics",
                "metrics_served",
                status == 200,
                &format!("{} bytes", body.len()),
            );
            return Ok(Response::builder()
                .status(status)
                // Prometheus text exposition format 0.0.4.
                .header("Content-Type", "text/plain; version=0.0.4; charset=utf-8")
                .body(Full::new(Bytes::from(body)).boxed())
                .unwrap_or_else(|_| text(500, "Internal error")));
        }
    }

    // ★ THE INTAKE CHAIN'S WIRE VERB (`crate::promote::duties`), the HTTP twin
    // of gRPC `PromotionService.AdvanceArtifact` / `GetArtifactState`:
    // ★ THE AUDIT TRAIL (lane S8), the HTTP twin of `AuditService`:
    //   GET /-/audit/trail?sha256=<hex>   the artifact's ordered trail + the chain verdict
    //   GET /-/audit/verify               the whole chain, first break named
    // An Auditor or an Admin (`holger-audit-10`); audit off is `holger-audit-8`.
    //   GET /-/audit/downloads?ident=&repo=&since_nanos=&until_nanos=&limit=
    //                                     "what did C download" (stinky SB #19)
    if path == "/-/audit/trail" || path == "/-/audit/verify" || path == "/-/audit/downloads" {
        if method != "GET" {
            return Ok(text(405, "Method not allowed"));
        }
        let bearer = credential_of(&req);
        let identity = match auth::validate_request(
            &settings.auth_config,
            bearer.as_deref(),
            client_cn.as_deref(),
        )
        .await
        {
            Ok(id) => id,
            Err(_) => {
                return Ok(text(
                    401,
                    &holger_errcode::AUTH_UNAUTHENTICATED.tag("invalid credentials"),
                ))
            }
        };
        if let Err(m) =
            crate::audit::trail::authorize_read(&settings.auth_config, identity.as_ref())
        {
            return Ok(text(403, &m));
        }
        let Some(source) = settings.audit.query_source() else {
            return Ok(text(
                409,
                &holger_errcode::AUDIT_QUERY_UNAVAILABLE
                    .tag("this server's audit sink keeps no readable records (audit is off)"),
            ));
        };
        let raw_q = req.uri().query().unwrap_or("").to_owned();
        let sha = raw_q
            .split('&')
            .find_map(|p| p.strip_prefix("sha256=").map(form_decode))
            .unwrap_or_default();
        let trail = path == "/-/audit/trail";
        if path == "/-/audit/downloads" {
            let param = |k: &str| {
                raw_q
                    .split('&')
                    .find_map(|p| p.strip_prefix(&format!("{k}=")[..]).map(form_decode))
                    .unwrap_or_default()
            };
            let num = |k: &str| -> Result<i64, String> {
                let v = param(k);
                if v.trim().is_empty() {
                    Ok(0)
                } else {
                    v.trim()
                        .parse::<i64>()
                        .map_err(|e| format!("{k}={v:?} is not a whole number: {e}"))
                }
            };
            let q = match (num("since_nanos"), num("until_nanos"), num("limit")) {
                (Ok(since), Ok(until), Ok(limit)) => crate::audit::query::DownloadQuery::of_wire(
                    &param("ident"),
                    &param("repo"),
                    since,
                    until,
                    limit.max(0) as u64,
                ),
                (Err(e), _, _) | (_, Err(e), _) | (_, _, Err(e)) => {
                    return Ok(text(400, &holger_errcode::SERVER_BAD_REQUEST.tag(e)))
                }
            };
            let found =
                tokio::task::spawn_blocking(move || crate::audit::query::downloads(&source, &q))
                    .await
                    .unwrap_or_else(|e| {
                        Err(crate::audit::AuditError::Other(format!(
                            "the query task: {e}"
                        )))
                    });
            crate::grpc::functional_status("holger-http/audit", "audit_read", found.is_ok(), &path);
            return Ok(match found {
                Ok(d) => Response::builder()
                    .status(200)
                    .header("Content-Type", "application/json")
                    .body(
                        Full::new(Bytes::from(serde_json::to_string(&d).unwrap_or_default()))
                            .boxed(),
                    )
                    .unwrap_or_else(|_| text(500, "response build failed")),
                Err(e) => text(400, &holger_errcode::SERVER_BAD_REQUEST.tag(e.to_string())),
            });
        }
        let reply = tokio::task::spawn_blocking(move || -> Result<String, (u16, String)> {
            let report = match &source {
                crate::audit::QuerySource::Directory(d) => {
                    Some(crate::audit::chain::verify_dir(d, &[]).map_err(|e| (500, e.tagged()))?)
                }
                crate::audit::QuerySource::Snapshot(_) => None,
            };
            let chain = report.as_ref().map(|r| {
                serde_json::json!({
                    "intact": r.is_intact(), "records": r.records, "checkpoints": r.checkpoints,
                    "signatures_verified": r.signatures_verified, "signatures_unchecked": r.signatures_unchecked,
                    "unsigned_checkpoints": r.unsigned_checkpoints, "head": r.head,
                    "break_line": r.first_break.as_ref().map(|b| b.line),
                    "break_seq": r.first_break.as_ref().and_then(|b| b.seq),
                    "break_reason": r.first_break.as_ref().map(|b| b.to_string()),
                    "summary": r.summary(),
                })
            });
            if !trail {
                return chain.map(|c| c.to_string()).ok_or((
                    409,
                    holger_errcode::AUDIT_QUERY_UNAVAILABLE.tag("this server's audit sink keeps no chain to verify"),
                ));
            }
            let entries = crate::audit::trail::artifact_trail(&source, &sha)
                .map_err(|e| (400, holger_errcode::SERVER_BAD_REQUEST.tag(e)))?;
            Ok(serde_json::json!({
                "sha256": sha.trim().trim_start_matches("sha256:").to_ascii_lowercase(),
                "entries": entries,
                "chain": chain,
            })
            .to_string())
        })
        .await
        .unwrap_or_else(|_| Err((500, "dispatch task failed".into())));
        crate::grpc::functional_status("holger-http/audit", "audit_read", reply.is_ok(), &path);
        return Ok(match reply {
            Ok(body) => Response::builder()
                .status(200)
                .header("Content-Type", "application/json")
                .body(Full::new(Bytes::from(body)).boxed())
                .unwrap_or_else(|_| text(500, "response build failed")),
            Err((code, m)) => text(code, &m),
        });
    }

    //   POST /-/intake/advance?namespace=&name=&version=&verb=advance|quarantine|release|block&to=&reason=
    //   GET  /-/intake/state?namespace=&name=&version=
    // The caller's duties decide (separation of duties); the twin, growth and
    // read-only holds above already refused a POST that must not mutate.
    #[cfg(feature = "intake")]
    if path == "/-/intake/advance" || path == "/-/intake/state" {
        let advance = path == "/-/intake/advance";
        if (advance && method != "POST") || (!advance && method != "GET") {
            return Ok(text(405, "Method not allowed"));
        }
        let Some(chain) = settings.intake.clone() else {
            return Ok(text(
                404,
                &holger_errcode::SERVER_CAPABILITY_NOT_CONFIGURED
                    .tag("this server declares no intake chain (`promotion.intake`)"),
            ));
        };
        let bearer = credential_of(&req);
        let identity = match auth::validate_request(
            &settings.auth_config,
            bearer.as_deref(),
            client_cn.as_deref(),
        )
        .await
        {
            Ok(id) => id,
            Err(_) => {
                return Ok(text(
                    401,
                    &holger_errcode::AUTH_UNAUTHENTICATED.tag("invalid credentials"),
                ))
            }
        };
        if settings.auth_config.rbac_enabled() && identity.is_none() {
            return Ok(text(
                401,
                &holger_errcode::AUTH_UNAUTHENTICATED
                    .tag("an authenticated identity is required to use the intake chain"),
            ));
        }
        let raw_q = req.uri().query().unwrap_or("").to_owned();
        let coord = parse_sbom_coord(&raw_q);
        let mut verb = String::new();
        let mut to = String::new();
        let mut reason = String::new();
        for pair in raw_q.split('&').filter(|p| !p.is_empty()) {
            let (k, v) = match pair.split_once('=') {
                Some((k, v)) => (k, form_decode(v)),
                None => (pair, String::new()),
            };
            match k {
                "verb" => verb = v,
                "to" => to = v,
                "reason" => reason = v,
                _ => {}
            }
        }
        let auth_cfg = Arc::clone(&settings.auth_config);
        let peer_s = peer.clone();
        let reply = tokio::task::spawn_blocking(move || -> Result<String, crate::promote::intake::IntakeError> {
            use crate::promote::duties;
            use crate::promote::intake::{ArtifactState, IntakeError};
            if advance {
                let Some(action) = duties::Action::parse(&verb) else {
                    return Err(IntakeError::Duty(duties::DutyError::NotPermitted {
                        principal: duties::principal_of(identity.as_ref()),
                        held: Vec::new(),
                        verb: format!("'{verb}' (verbs: advance, quarantine, release, block)"),
                        needs: Vec::new(),
                    }));
                };
                let to = if to.trim().is_empty() { None } else { Some(ArtifactState::parse(&to)?) };
                let ask = duties::AdvanceAsk { id: coord.id, action, to, reason, evidence: Vec::new(), source: peer_s };
                let a = duties::advance_as(&chain, &auth_cfg, identity.as_ref(), ask)?;
                Ok(serde_json::json!({
                    "from_state": a.from.name(), "state": a.state.name(),
                    "approvals": a.approvals, "approvals_required": a.approvals_required,
                    "evidence": a.evidence, "sha256": a.sha256, "actor": a.actor, "message": a.message,
                })
                .to_string())
            } else {
                let v = duties::read_as(&chain, &auth_cfg, identity.as_ref(), &coord.id)?;
                let last = v.history.last();
                Ok(serde_json::json!({
                    "source": last.map(|e| e.origin.clone()).unwrap_or_default(),
                    "effective_policy": last.and_then(|e| e.effective_policy.clone()),
                    "state": v.state.name(), "sha256": v.sha256, "importer": v.importer,
                    "approvals": v.pending.len(), "approvals_required": v.approvals_required,
                    "history": v.history,
                    "pending_approvals": v.pending.iter().map(|p| p.evidence()).collect::<Vec<_>>(),
                })
                .to_string())
            }
        })
        .await
        .unwrap_or_else(|_| Err(crate::promote::intake::IntakeError::Store("dispatch task failed".into())));
        crate::grpc::functional_status("holger-http/intake", "intake_verb", reply.is_ok(), &path);
        return Ok(match reply {
            Ok(body) => Response::builder()
                .status(200)
                .header("Content-Type", "application/json")
                .body(Full::new(Bytes::from(body)).boxed())
                .unwrap_or_else(|_| text(500, "Internal error")),
            Err(e) => text(e.status(), &e.tagged()),
        });
    }

    // ★ THE DEPENDENCY SETS (lane HOL-DEPSET-APPROVE, `crate::pull_intake::depset`): a
    // pull's whole closure, approved or refused as one set by the caller's duties.
    //   GET  /-/intake/sets[?status=awaiting-approval]   every set the caller may read
    //   GET  /-/intake/set?id=                            one set, its members and states
    //   POST /-/intake/set/approve?id=&reason=            the caller's vote on every waiting member
    //   POST /-/intake/set/refuse?id=&reason=             every waiting member BLOCKED
    #[cfg(all(feature = "intake", feature = "jobs"))]
    if matches!(
        path.as_str(),
        "/-/intake/sets" | "/-/intake/set" | "/-/intake/set/approve" | "/-/intake/set/refuse"
    ) {
        let post = path.starts_with("/-/intake/set/");
        if (post && method != "POST") || (!post && method != "GET") {
            return Ok(text(405, "Method not allowed"));
        }
        let Some(chain) = settings.intake.clone() else {
            return Ok(text(
                404,
                &holger_errcode::SERVER_CAPABILITY_NOT_CONFIGURED
                    .tag("this server declares no intake chain (`promotion.intake`)"),
            ));
        };
        if chain.pull().is_none() {
            return Ok(text(
                404,
                &holger_errcode::SERVER_CAPABILITY_NOT_CONFIGURED
                    .tag("this server pulls nothing through its intake chain (`pull_through`), so it has no dependency sets"),
            ));
        }
        let bearer = credential_of(&req);
        let identity = match auth::validate_request(
            &settings.auth_config,
            bearer.as_deref(),
            client_cn.as_deref(),
        )
        .await
        {
            Ok(id) => id,
            Err(_) => {
                return Ok(text(
                    401,
                    &holger_errcode::AUTH_UNAUTHENTICATED.tag("invalid credentials"),
                ))
            }
        };
        if settings.auth_config.rbac_enabled() && identity.is_none() {
            return Ok(text(
                401,
                &holger_errcode::AUTH_UNAUTHENTICATED
                    .tag("an authenticated identity is required to read or judge dependency sets"),
            ));
        }
        let (mut id, mut reason, mut status) = (String::new(), String::new(), String::new());
        let mut revision = String::new();
        for pair in req
            .uri()
            .query()
            .unwrap_or("")
            .split('&')
            .filter(|p| !p.is_empty())
        {
            let (k, v) = match pair.split_once('=') {
                Some((k, v)) => (k, form_decode(v)),
                None => (pair, String::new()),
            };
            match k {
                "id" => id = v,
                "revision" => revision = v,
                "reason" => reason = v,
                "status" => status = v,
                _ => {}
            }
        }
        let auth_cfg = Arc::clone(&settings.auth_config);
        let (peer_s, which) = (peer.clone(), path.clone());
        let reply = tokio::task::spawn_blocking(move || -> (u16, String) {
            let Some(pull) = chain.pull() else {
                return (404, "no pull-through".into());
            };
            let ok = |v: serde_json::Value| (200, v.to_string());
            let answer = |r: Result<crate::pull_intake::depset::SetAnswer, crate::pull_intake::depset::SetError>| match r {
                Ok(a) => ok(serde_json::to_value(a).unwrap_or_default()),
                Err(e) => (e.status, e.message),
            };
            match which.as_str() {
                "/-/intake/sets" => ok(serde_json::json!({
                    "sets": pull.sets_as(&chain, &auth_cfg, identity.as_ref(), Some(status.as_str())),
                    "approvals_required": chain.approvals_required(),
                })),
                "/-/intake/set" => match pull.set_as(&chain, &auth_cfg, identity.as_ref(), &id) {
                    Ok(v) => ok(serde_json::to_value(v).unwrap_or_default()),
                    Err(e) => (e.status, e.message),
                },
                "/-/intake/set/approve" => answer(pull.approve_set(
                    &chain, &auth_cfg, identity.as_ref(), &id, &revision, &reason, &peer_s,
                )),
                _ => answer(pull.refuse_set(
                    &chain, &auth_cfg, identity.as_ref(), &id, &revision, &reason, &peer_s,
                )),
            }
        })
        .await
        .unwrap_or_else(|_| (500, "dispatch task failed".into()));
        crate::grpc::functional_status("holger-http/intake", "intake_sets", reply.0 < 400, &path);
        return Ok(if reply.0 == 200 {
            Response::builder()
                .status(200)
                .header("Content-Type", "application/json")
                .body(Full::new(Bytes::from(reply.1)).boxed())
                .unwrap_or_else(|_| text(500, "Internal error"))
        } else {
            text(reply.0, &reply.1)
        });
    }

    // ★ THE SYNC DOORS (Holger v2.0 H4, `crate::sync`): the upstream's manifest, the
    // downstream's ack, the board's sync data, an invalidation, a stick's manifest.
    #[cfg(feature = "sync")]
    if path.starts_with("/-/sync/") {
        return Ok(sync_door(req, &settings, client_cn.as_deref(), &peer, &method, &path).await);
    }

    // ★ THE BOX'S IMPORT DOORS (lane W4, `crate::import_door`), the HTTP twin of
    // gRPC `AdminService.ImportIntelBundle` / `ImportBundle`, the same code as the
    // CLI verbs and the inbox jobs:
    //   POST /-/intel/import     body: the signed intel bundle
    //   POST /-/bundle/import    body: the signed update / airgap bundle
    //   POST /-/bundle/first-import?vendor=&product=&sequence=   an admin authorizes a first import
    // (`?first_import=` is REMOVED, lane HOL-CDS: `holger-import-10`).
    // Repository Admin or Security Approver (`holger-duty-2` otherwise); the
    // twin, growth and read-only holds above already refused a POST that must
    // not mutate. The body streams into a staged file under the data root.
    #[cfg(feature = "intake")]
    if path == "/-/bundle/first-import" {
        if method != "POST" {
            return Ok(text(405, "Method not allowed"));
        }
        let Some(door) = settings.imports.clone() else {
            return Ok(text(
                404,
                &holger_errcode::SERVER_CAPABILITY_NOT_CONFIGURED
                    .tag("this server has no import door"),
            ));
        };
        let bearer = credential_of(&req);
        let identity = match auth::validate_request(
            &settings.auth_config,
            bearer.as_deref(),
            client_cn.as_deref(),
        )
        .await
        {
            Ok(id) => id,
            Err(_) => {
                return Ok(text(
                    401,
                    &holger_errcode::AUTH_UNAUTHENTICATED.tag("invalid credentials"),
                ))
            }
        };
        if settings.auth_config.rbac_enabled() && identity.is_none() {
            return Ok(text(
                401,
                &holger_errcode::AUTH_UNAUTHENTICATED
                    .tag("an authenticated admin authorizes a first import"),
            ));
        }
        let principal = match crate::import_door::ImportDoor::authorize_admin(
            &settings.auth_config,
            identity.as_ref(),
        ) {
            Ok(p) => p,
            Err(e) => return Ok(text(e.status, &e.tagged())),
        };
        let q: Vec<(String, String)> = req
            .uri()
            .query()
            .unwrap_or("")
            .split('&')
            .filter_map(|p| {
                p.split_once('=')
                    .map(|(k, v)| (k.to_string(), form_decode(v)))
            })
            .collect();
        let get = |k: &str| {
            q.iter()
                .find(|(n, _)| n == k)
                .map(|(_, v)| v.clone())
                .unwrap_or_default()
        };
        let sequence = get("sequence").parse::<u64>().unwrap_or(0);
        let (vendor, product, source) = (get("vendor"), get("product"), peer.clone());
        let r = tokio::task::spawn_blocking(move || {
            door.allow_first_import(&vendor, &product, sequence, &principal, &source)
        })
        .await;
        return Ok(match r {
            Ok(Ok(g)) => Response::builder()
                .status(200)
                .header("Content-Type", "application/json")
                .body(Full::new(Bytes::from(serde_json::to_vec(&g).unwrap_or_default())).boxed())
                .unwrap_or_else(|_| text(500, "Internal error")),
            Ok(Err(e)) => text(e.status, &e.tagged()),
            Err(_) => text(500, "the authorization task failed"),
        });
    }

    #[cfg(feature = "intake")]
    if path == "/-/intel/import" || path == "/-/bundle/import" {
        use crate::import_door::{ImportDoor, ImportKind};
        let kind = if path == "/-/intel/import" {
            ImportKind::Intel
        } else {
            ImportKind::Bundle
        };
        if method != "POST" {
            return Ok(text(405, "Method not allowed"));
        }
        let Some(door) = settings.imports.clone() else {
            return Ok(text(
                404,
                &holger_errcode::SERVER_CAPABILITY_NOT_CONFIGURED
                    .tag("this server has no import door"),
            ));
        };
        let bearer = credential_of(&req);
        let identity = match auth::validate_request(
            &settings.auth_config,
            bearer.as_deref(),
            client_cn.as_deref(),
        )
        .await
        {
            Ok(id) => id,
            Err(_) => {
                return Ok(text(
                    401,
                    &holger_errcode::AUTH_UNAUTHENTICATED.tag("invalid credentials"),
                ))
            }
        };
        if settings.auth_config.rbac_enabled() && identity.is_none() {
            return Ok(text(
                401,
                &holger_errcode::AUTH_UNAUTHENTICATED
                    .tag("an authenticated identity is required to import a bundle"),
            ));
        }
        let principal = match ImportDoor::authorize(&settings.auth_config, identity.as_ref(), kind)
        {
            Ok(p) => p,
            Err(e) => {
                // HOL-NCSC: an unauthorised importer leaves an audit row.
                let who = crate::promote::duties::principal_of(identity.as_ref());
                crate::refusals::record_to(
                    &settings.audit,
                    "import authorization",
                    &who,
                    &peer,
                    &format!("{} import by {who}: {}", kind.as_str(), e.tagged()),
                );
                return Ok(text(e.status, &e.tagged()));
            }
        };
        if req
            .uri()
            .query()
            .unwrap_or("")
            .split('&')
            .any(|p| p == "first_import" || p.starts_with("first_import="))
        {
            let e = crate::import_door::first_import_flag_refusal("`?first_import=`");
            return Ok(text(e.status, &e.tagged()));
        }
        let mut staged = match door.stage() {
            Ok(s) => s,
            Err(e) => return Ok(text(e.status, &e.tagged())),
        };
        let mut limited = Limited::new(req.into_body(), settings.max_body_bytes);
        loop {
            match limited.frame().await {
                Some(Ok(frame)) => {
                    if let Ok(chunk) = frame.into_data() {
                        if let Err(e) = staged.write(&chunk) {
                            return Ok(text(e.status, &e.tagged()));
                        }
                    }
                }
                Some(Err(_)) => return Ok(text(413, "Payload too large")),
                None => break,
            }
        }
        if let Err(e) = staged.finish() {
            return Ok(text(e.status, &e.tagged()));
        }
        let source = peer.clone();
        let reply = tokio::task::spawn_blocking(
            move || -> Result<String, crate::import_door::ImportError> {
                let body = match kind {
                    ImportKind::Intel => serde_json::to_string(&door.import_intel(
                        &staged.path,
                        None,
                        &principal,
                        &source,
                    )?),
                    ImportKind::Bundle => serde_json::to_string(&door.import_bundle(
                        &staged.path,
                        None,
                        &Default::default(),
                        &principal,
                        &source,
                    )?),
                };
                drop(staged);
                Ok(body.unwrap_or_else(|e| format!("{{\"error\":\"{e}\"}}")))
            },
        )
        .await
        .unwrap_or_else(|_| {
            Err(crate::import_door::ImportError {
                code: &holger_errcode::IMPORT_STAGING_FAILED,
                message: "the import task failed".into(),
                status: 500,
            })
        });
        crate::grpc::functional_status(
            "holger-http/import",
            "bundle_imported",
            reply.is_ok(),
            &path,
        );
        return Ok(match reply {
            Ok(body) => Response::builder()
                .status(200)
                .header("Content-Type", "application/json")
                .body(Full::new(Bytes::from(body)).boxed())
                .unwrap_or_else(|_| text(500, "Internal error")),
            Err(e) => text(e.status, &e.tagged()),
        });
    }

    //   GET /-/intake/evidence?sha256=   every stored scan-evidence record (W5)
    //   GET /-/intake/sbom?sha256=       the SBOM the newest record carries
    // The SAME read as gRPC `PromotionService.GetArtifactEvidence`
    // (`duties::evidence_as`, by the coordinate holding these bytes): the read
    // duty of GetArtifactState, so a Developer reads only AVAILABLE bytes.
    #[cfg(feature = "intake")]
    if path == "/-/intake/evidence" || path == crate::promote::duties::SBOM_ROUTE {
        if method != "GET" {
            return Ok(text(405, "Method not allowed"));
        }
        let sbom_only = path == crate::promote::duties::SBOM_ROUTE;
        let Some(chain) = settings.intake.clone() else {
            return Ok(text(
                404,
                &holger_errcode::SERVER_CAPABILITY_NOT_CONFIGURED
                    .tag("this server declares no intake chain (`promotion.intake`)"),
            ));
        };
        let bearer = credential_of(&req);
        let identity = match auth::validate_request(
            &settings.auth_config,
            bearer.as_deref(),
            client_cn.as_deref(),
        )
        .await
        {
            Ok(id) => id,
            Err(_) => {
                return Ok(text(
                    401,
                    &holger_errcode::AUTH_UNAUTHENTICATED.tag("invalid credentials"),
                ))
            }
        };
        if settings.auth_config.rbac_enabled() && identity.is_none() {
            return Ok(text(
                401,
                &holger_errcode::AUTH_UNAUTHENTICATED
                    .tag("an authenticated identity is required to read intake evidence"),
            ));
        }
        let raw_q = req.uri().query().unwrap_or("").to_owned();
        let sha = raw_q
            .split('&')
            .filter_map(|p| p.split_once('='))
            .find(|(k, _)| *k == "sha256")
            .map(|(_, v)| form_decode(v))
            .unwrap_or_default();
        let digest =
            match crate::attest::ArtifactDigest::sha256(sha.trim().trim_start_matches("sha256:")) {
                Ok(d) => d,
                Err(e) => return Ok(text(400, &e.tagged())),
            };
        let auth_cfg = Arc::clone(&settings.auth_config);
        let reply = tokio::task::spawn_blocking(move || -> Result<(u16, &'static str, Vec<u8>), crate::promote::intake::IntakeError> {
            let v = crate::promote::duties::evidence_by_sha256_as(&chain, &auth_cfg, identity.as_ref(), digest.hex())?;
            if sbom_only {
                return Ok(match v.sbom() {
                    Some(doc) => (200, "application/vnd.cyclonedx+json", serde_json::to_vec_pretty(doc).unwrap_or_default()),
                    None => (
                        404,
                        "text/plain",
                        holger_errcode::SERVER_SBOM_UNKNOWN
                            .tag(format!("no stored scan evidence about sha256 {} carries an SBOM", v.sha256))
                            .into_bytes(),
                    ),
                });
            }
            use base64::Engine as _;
            let b64 = |b: &[u8]| base64::engine::general_purpose::STANDARD.encode(b);
            let records: Vec<serde_json::Value> = v
                .stored
                .iter()
                .map(|r| {
                    serde_json::json!({
                        "id": r.id, "scanned_at": r.evidence.scanned_at,
                        "verdict": r.evidence.verdict.as_str(), "reasons": r.evidence.reasons,
                        "evidence": r.evidence,
                        "envelope": r.envelope.as_deref().map(|e| String::from_utf8_lossy(e).into_owned()),
                        "signed": r.envelope.is_some(),
                        "stale": r.stale,
                    })
                })
                .collect();
            let body = serde_json::json!({
                "sha256": v.sha256,
                "state": v.state.name(),
                "policy": v.policy,
                "records": records,
                "signer_cert_der_base64": if v.signer_cert.is_empty() { None } else { Some(b64(&v.signer_cert)) },
                "sbom_link": v.sbom_link,
            });
            Ok((200, "application/json", body.to_string().into_bytes()))
        })
        .await
        .unwrap_or_else(|_| Err(crate::promote::intake::IntakeError::Store("dispatch task failed".into())));
        crate::grpc::functional_status(
            "holger-http/intake",
            "intake_evidence",
            reply.is_ok(),
            &path,
        );
        return Ok(match reply {
            Ok((code, ct, body)) => Response::builder()
                .status(code)
                .header("Content-Type", ct)
                .body(Full::new(Bytes::from(body)).boxed())
                .unwrap_or_else(|_| text(500, "Internal error")),
            Err(e) => text(e.status(), &e.tagged()),
        });
    }

    // Custom-PROPERTIES WRITE door (parity §8): set/remove a property remotely —
    // the write twin of the read door above + the gRPC `PropertyService.SetProperty`
    // RPC (property write was CLI/in-process only before this).
    //   PUT|POST /-/properties?repo=&namespace=&name=&version=&key=&value=&value=…
    //   DELETE   /-/properties?repo=&…&key=                       (remove the key)
    // Write-gated (writer/admin), SCOPED to the TARGET repo from the query string
    // (not the `-` path segment), mirroring the gRPC write gate. Values ride in
    // repeatable `value=` params, so there is no artifact body / checksum gate.
    #[cfg(feature = "intake")]
    if path == "/-/properties" && matches!(method.as_str(), "PUT" | "POST" | "DELETE") {
        let raw_q = req.uri().query().unwrap_or("").to_owned();
        let coord = parse_sbom_coord(&raw_q);
        // AuthN: resolve identity (OIDC sub / mTLS CN), or `None` when auth is open.
        let bearer = credential_of(&req);
        let identity = match auth::validate_request(
            &settings.auth_config,
            bearer.as_deref(),
            client_cn.as_deref(),
        )
        .await
        {
            Ok(id) => id,
            Err(_) => return Ok(text(401, "Unauthorized")),
        };
        // …and an ADMIN floor on top for the keys the SERVER ITSELF reads as
        // policy — the promotion gate's required property,
        // and the retention pin. Identical rule and identical placement to the
        // gRPC `SetProperty` handler, because this door writes the same store: a
        // Writer refused there must not simply come here instead. Applied BEFORE
        // the write gate's own refusal is recorded, so a reserved key is refused
        // the same way whether or not properties are configured at all.
        //
        // A note on method: PUT/POST with no `value=` REMOVES the key (see
        // `serve_properties_write`), so removal rides the writer-gated verb, not
        // the admin-gated DELETE. That is precisely why the floor cannot be left
        // to `authorize_http_write`'s DELETE-is-admin rule.
        {
            let (key, _) = property_key_and_values(&raw_q);
            if !key.is_empty()
                && crate::properties::is_reserved_property(
                    &key,
                    settings.promotion_required_property.as_ref(),
                    &settings.reserved_properties,
                )
                && settings.auth_config.rbac_enabled()
            {
                let permitted = identity.as_ref().is_some_and(|id| {
                    settings
                        .auth_config
                        .role_for_identity_in_repo(&coord.repository, id)
                        .can_admin()
                });
                if !permitted {
                    let who = identity
                        .as_ref()
                        .map(|i| i.subject.as_str())
                        .unwrap_or("anonymous");
                    let status = if identity.is_some() { 403 } else { 401 };
                    let ev = AuditEvent::new(
                        who,
                        AuditAction::Upload,
                        &coord.repository,
                        &path,
                        &peer,
                        status,
                        0,
                    )
                    .with_detail(format!("reserved property '{key}' requires admin"));
                    if let Err(e) = settings.audit.record(ev) {
                        log::warn!("audit record failed: {e}");
                    }
                    crate::grpc::functional_status(
                        "holger-http/properties",
                        "reserved_property_permitted",
                        false,
                        &key,
                    );
                    return Ok(text(status, "Forbidden"));
                }
            }
        }

        // AuthZ (writer/admin), scoped to the coordinate's repository.
        if let Err((status, detail)) = authorize_http_write_floored(
            &settings.auth_config,
            &settings.read_gate,
            identity.as_ref(),
            &method,
            &coord.repository,
        ) {
            let who = identity
                .as_ref()
                .map(|i| i.subject.as_str())
                .unwrap_or("anonymous");
            let ev = AuditEvent::new(
                who,
                AuditAction::Upload,
                &coord.repository,
                &path,
                &peer,
                status,
                0,
            )
            .with_detail(detail.to_string());
            if let Err(e) = settings.audit.record(ev) {
                log::warn!("audit record failed: {e}");
            }
            let msg = if status == 403 {
                "Forbidden"
            } else {
                "Unauthorized"
            };
            return Ok(text(status, msg));
        }
        let who = identity
            .map(|i| i.subject)
            .unwrap_or_else(|| "anonymous".to_string());
        let (status, body, repo, label) =
            serve_properties_write(settings.properties.as_ref(), &method, &raw_q);
        let action = if method == "DELETE" {
            AuditAction::Delete
        } else {
            AuditAction::Upload
        };
        let ev = AuditEvent::new(&who, action, &repo, &label, &peer, status, 0);
        if let Err(e) = settings.audit.record(ev) {
            log::warn!("audit record failed: {e}");
        }
        crate::grpc::functional_status(
            "holger-http/properties_write",
            "property_written",
            status == 200,
            &format!("{status} {label}"),
        );
        crate::metrics::global().record_request(
            if method == "DELETE" {
                crate::metrics::Verb::Delete
            } else {
                crate::metrics::Verb::Put
            },
            status,
            0,
        );
        crate::metrics::global().observe_request_duration(started.elapsed().as_secs_f64());
        let ct = if status == 200 {
            "application/json"
        } else {
            "text/plain"
        };
        return Ok(Response::builder()
            .status(status)
            .header("Content-Type", ct)
            .body(Full::new(Bytes::from(body)).boxed())
            .unwrap_or_else(|_| text(500, "Internal error")));
    }

    // Map the HTTP verb to an audit action: reads (GET/HEAD) are downloads,
    // DELETE removes, everything else (PUT/POST/PATCH) stores.
    let is_read = method == "GET" || method == "HEAD";
    let action = if is_read {
        AuditAction::Download
    } else if method == "DELETE" {
        AuditAction::Delete
    } else {
        AuditAction::Upload
    };
    // Repository name for the audit record: the first OCI/classic path segment.
    let repo_key = route_key(&path).unwrap_or_default().to_owned();
    // The repository half of the visitor tally. Only a name the configuration
    // declares is counted (the tally ignores any other), so a probe for
    // `/no-such-repo/x` cannot grow it.
    settings.visitors.record(
        crate::visitors::now_unix(),
        None,
        Some(&repo_key),
        client_address(&peer, req.headers(), settings.trusted_proxies.as_deref()),
    );
    // Prometheus verb for this request, via the ONE shared audit-action→verb
    // classifier (Law #5 — same mapping the gRPC `record_audit` choke point uses).
    // The artifact door only ever produces Download/Upload/Delete here, all of
    // which classify; `Get` is a safe default that can't be reached.
    let metric_verb =
        crate::metrics::Verb::from_audit_action(action).unwrap_or(crate::metrics::Verb::Get);
    // Best-effort audit append, mirroring the gRPC `record_audit` helper. Every
    // outcome also bumps the process-global metrics registry (`/metrics`), so a
    // verb, its bytes served, and any 5xx are counted at the one exit point.
    // F1: the client and the front it came through, from a trusted proxy.
    let source = audit_source(&peer, req.headers(), settings.trusted_proxies.as_deref());
    let record = |ident: &str, status: u16, bytes: u64, detail: &str| {
        crate::metrics::global().record_request(metric_verb, status, bytes);
        crate::metrics::global().observe_request_duration(started.elapsed().as_secs_f64());
        let mut ev = AuditEvent::new(ident, action, &repo_key, &path, &source, status, bytes);
        if !detail.is_empty() {
            ev = ev.with_detail(detail);
        }
        if let Err(e) = settings.audit.record(ev) {
            log::warn!("audit record failed: {e}");
        }
    };

    // Writes require a valid identity (Bearer or mTLS CN) and, when role policy
    // is configured, authorization. Reads are OPEN BY DEFAULT — the airgap mirror
    // posture — and record as the anonymous principal, UNLESS the operator opted
    // into the read gate (`require_auth_for_reads`), in which case a read
    // authenticates exactly like a write and is authorized against the Reader
    // floor, scoped to the target repo. Opt-in: with the gate off this branch is
    // the original two lines.
    // The writer's identity, kept for the intake chain's Importer rule (lane W7).
    #[allow(unused_mut, unused_variables)]
    let mut writer: Option<auth::AuthIdentity> = None;
    // A reader's identity, when the read named a valid one: a scanned registry lets a pusher
    // read its own staged manifest back by digest (lane HOL-FIELD-2).
    #[allow(unused_mut, unused_variables)]
    let mut reader: Option<auth::AuthIdentity> = None;
    let ident = if is_read {
        if settings.read_gate.applies(&settings.auth_config, &repo_key) {
            let bearer = credential_of(&req);
            let identity = match auth::validate_request_for(
                &settings.auth_config,
                bearer.as_deref(),
                client_cn.as_deref(),
                &repo_key,
                false,
            )
            .await
            {
                Ok(id) => id,
                #[cfg(feature = "auth-passkey")]
                Err(auth::DoorRefusal::Token(why)) => {
                    record("anonymous", why.status, 0, why.code.code);
                    return Ok(token_refused(&why));
                }
                Err(_) => {
                    record("anonymous", 401, 0, "unauthorized (read gate)");
                    crate::grpc::functional_status(
                        "holger-http/read_gate",
                        "rbac_read_permitted",
                        false,
                        "invalid or missing read credentials",
                    );
                    if bearer.is_none() && client_cn.is_none() {
                        return Ok(read_gated(&repo_key));
                    }
                    return Ok(unauthorized());
                }
            };
            if let Err((status, detail)) = crate::auth::authorize_read_identity_scoped(
                &settings.auth_config,
                &settings.read_gate,
                identity.as_ref(),
                &repo_key,
            ) {
                let who = identity
                    .as_ref()
                    .map(|i| i.subject.as_str())
                    .unwrap_or("anonymous");
                record(who, status, 0, detail);
                crate::grpc::functional_status(
                    "holger-http/read_gate",
                    "rbac_read_permitted",
                    false,
                    detail,
                );
                if status == 401 {
                    return Ok(read_gated(&repo_key));
                }
                return Ok(text(status, "Forbidden"));
            }
            #[cfg(feature = "intake")]
            {
                reader = identity.clone();
            }
            // Gated reads audit the REAL subject, not "anonymous" — the whole point
            // of authenticating a download is knowing who took it.
            let who = identity
                .map(|i| i.subject)
                .unwrap_or_else(|| "anonymous".to_string());
            crate::grpc::functional_status(
                "holger-http/read_gate",
                "rbac_read_permitted",
                true,
                &who,
            );
            who
        } else {
            // An OPEN read stays open — a missing or invalid credential reads as
            // anonymous, exactly as before — but a VALID one names its reader,
            // for the audit and for admission: the anonymous day share's own
            // refusal says "or authenticate" (MEASURED on the holger mock
            // 2026-09-29: an operator's authenticated fetch-back was charged to
            // the anonymous 5 GB/day and refused).
            let bearer = credential_of(&req);
            if bearer.is_some() || client_cn.is_some() {
                match auth::validate_request_for(
                    &settings.auth_config,
                    bearer.as_deref(),
                    client_cn.as_deref(),
                    &repo_key,
                    false,
                )
                .await
                {
                    Ok(Some(id)) => {
                        #[cfg(feature = "intake")]
                        {
                            reader = Some(id.clone());
                        }
                        id.subject
                    }
                    // A token that is revoked, expired or whose owner is gone is told so even
                    // on an open read: its holder must learn it stopped working. A live token
                    // for another repository reads here as anyone may.
                    #[cfg(feature = "auth-passkey")]
                    Err(auth::DoorRefusal::Token(why)) if why.status == 401 => {
                        record("anonymous", why.status, 0, why.code.code);
                        return Ok(token_refused(&why));
                    }
                    _ => "anonymous".to_string(),
                }
            } else {
                "anonymous".to_string()
            }
        }
    } else {
        let bearer = credential_of(&req);
        // AuthN: resolve the identity (OIDC sub / mTLS CN), or `None` when auth is
        // open (no methods configured).
        let identity = match auth::validate_request_for(
            &settings.auth_config,
            bearer.as_deref(),
            client_cn.as_deref(),
            &repo_key,
            true,
        )
        .await
        {
            Ok(id) => id,
            #[cfg(feature = "auth-passkey")]
            Err(auth::DoorRefusal::Token(why)) => {
                record("anonymous", why.status, 0, why.code.code);
                return Ok(token_refused(&why));
            }
            Err(_) => {
                record("anonymous", 401, 0, "unauthorized");
                return Ok(unauthorized());
            }
        };

        // AuthZ (RBAC) — mirrors `grpc::authorize_write`, scoped to the target repo
        // so a per-repo ACL (`repo_roles`) governs this write. `cargo yank` is cargo's
        // DELETE of `…/yank`: on the chain's cargo door it deletes nothing (it is recorded
        // beside the chain), so it is a write, and the door asks for its duty
        // (HOL-CARGO-PUBLISH-DOOR).
        #[cfg(feature = "intake")]
        let yank_on_door = method == "DELETE"
            && path.ends_with("/yank")
            && settings
                .intake
                .as_ref()
                .is_some_and(|c| c.cargo_door() == Some(repo_key.as_str()));
        #[cfg(not(feature = "intake"))]
        let yank_on_door = false;
        if let Err((status, detail)) = authorize_http_write_floored(
            &settings.auth_config,
            &settings.read_gate,
            identity.as_ref(),
            if yank_on_door { "PUT" } else { &method },
            &repo_key,
        ) {
            let who = identity
                .as_ref()
                .map(|i| i.subject.as_str())
                .unwrap_or("anonymous");
            record(who, status, 0, detail);
            // ★ A write refused for want of a credential is answered with the
            // CHALLENGE, not a bare 401: that is what makes `docker push`,
            // `npm publish` and `mvn deploy` send the credential they were given
            // instead of stopping at the first refusal.
            if status == 401 {
                return Ok(unauthorized());
            }
            return Ok(text(status, "Forbidden"));
        }

        #[cfg(feature = "intake")] // read only by the intake chain's rules
        {
            writer = identity.clone();
        }
        identity
            .map(|i| i.subject)
            .unwrap_or_else(|| "anonymous".to_string())
    };

    let backend = match routes_lookup(&settings.routes, &path) {
        Some(b) => b,
        None => {
            record(&ident, 404, 0, "unknown repository");
            return Ok(text(404, "Unknown repository"));
        }
    };

    // ★ DOWNLOAD / UPLOAD ADMISSION (`crate::admission`). Asked once the
    // repository and the principal are known and BEFORE any byte is read or a
    // body collected: a consumer over its share is answered at once with 503 +
    // Retry-After — never parked. A DELETE is not asked (it moves no bytes and
    // is how a full repository gets back under its limit). With no
    // `admission:` block this plans `Full`, refuses nothing and holds no share.
    #[cfg(not(feature = "admission"))]
    let ticket: Option<Arc<crate::admission::Ticket>> = None;
    #[cfg(feature = "admission")]
    let ticket: Option<Arc<crate::admission::Ticket>> = if method == "DELETE" {
        None
    } else {
        let who = admission_who(&settings, &ident, &peer, req.headers());
        let (work, hint) = if is_read {
            (crate::admission::WorkKind::Download, 0)
        } else {
            (
                crate::admission::WorkKind::Upload,
                declared_body_len(&req, settings.max_body_bytes) as u64,
            )
        };
        match settings.admission.enter(&who, work, hint) {
            Ok(t) => Some(Arc::new(t)),
            Err(busy) => {
                record(&ident, 503, 0, &busy.why);
                crate::grpc::functional_status(
                    "holger-http/admission",
                    "admitted",
                    false,
                    &busy.why,
                );
                return Ok(retry_later(
                    busy.retry_after_secs,
                    &holger_admission_line(&busy.why),
                ));
            }
        }
    };

    // ★ THE INTAKE CHAIN (`crate::promote::intake`). A repository in the chain
    // is never served by its backend: incoming, quarantine and approved serve
    // nothing, and production serves an AVAILABLE artifact from the SEALED
    // store. A write into quarantine, approved or production is refused by
    // name; the chain alone moves artifacts there.
    #[cfg(feature = "intake")]
    let intake_role = settings
        .intake
        .as_ref()
        .and_then(|c| c.role_of(&repo_key).map(|r| (Arc::clone(c), r)));
    // ★ THE CHAIN'S NPM DOOR (`crate::promote::npm`, lane P5): the repository
    // `promotion.intake.npm` names holds nothing of its own. `npm publish` is INGESTED into
    // the chain's incoming repository; the packument, the tarballs and the dist-tags are a
    // view of the AVAILABLE set. Unpublish and every rewrite are refused by policy.
    #[cfg(feature = "intake")]
    let npm_door: Option<(
        Arc<crate::promote::intake::IntakeChain>,
        crate::promote::npm::Route,
    )> = settings
        .intake
        .as_ref()
        .filter(|c| c.npm_door() == Some(repo_key.as_str()))
        .map(|c| {
            (
                Arc::clone(c),
                crate::promote::npm::route(
                    path.strip_prefix(&format!("/{repo_key}")).unwrap_or(""),
                ),
            )
        });
    #[cfg(feature = "intake")]
    let npm_write = npm_door.is_some() && !is_read;
    #[cfg(not(feature = "intake"))]
    let npm_write = false;
    #[cfg(feature = "intake")]
    if let Some((chain, route)) = &npm_door {
        use crate::promote::intake::IntakeError;
        use crate::promote::npm::{NpmError, Route};
        if is_read {
            let base = chain
                .npm_base()
                .map(str::to_string)
                .unwrap_or_else(|| npm_request_base(&req, &settings, &peer));
            let tarball_base = format!("{base}/{repo_key}");
            // A tarball streams from the sealed store (HOL-PERF-3).
            if let Some(id) = crate::promote::intake::IntakeChain::npm_tarball_id(route) {
                let c2 = Arc::clone(chain);
                let opened = tokio::task::spawn_blocking(move || {
                    c2.serve_stream(&id, STREAM_READ_PIECE_BYTES)
                })
                .await
                .unwrap_or_else(|_| Err(IntakeError::Store("dispatch task failed".into())));
                return Ok(match opened {
                    Ok(Some(chunks)) => {
                        let len = chunks.len.unwrap_or(0);
                        record(&ident, 200, len, "npm: a view of the AVAILABLE set");
                        let mut builder = Response::builder()
                            .status(200)
                            .header("Content-Type", "application/octet-stream")
                            .header("X-Holger-Intake-State", "AVAILABLE");
                        if let Some(n) = chunks.len {
                            builder = builder.header("Content-Length", n);
                        }
                        let body = if method == "HEAD" {
                            Full::new(Bytes::new()).boxed()
                        } else {
                            if let Some(t) = &ticket {
                                t.add_net_out(len);
                            }
                            reply_body(chunks, ticket.clone(), path.clone()).await
                        };
                        builder
                            .body(body)
                            .unwrap_or_else(|_| text(500, "Internal error"))
                    }
                    Ok(None) => {
                        record(&ident, 404, 0, "npm: nothing AVAILABLE here");
                        npm_reply(404, &serde_json::json!({ "error": "not found" }))
                    }
                    Err(e) => {
                        record(&ident, e.status(), 0, &e.tagged());
                        log::warn!("npm read of {path} failed: {e}");
                        npm_refusal(&e)
                    }
                });
            }
            let (c2, r2) = (Arc::clone(chain), route.clone());
            let read = tokio::task::spawn_blocking(move || c2.npm_read(&r2, &tarball_base))
                .await
                .unwrap_or_else(|_| Err(IntakeError::Store("dispatch task failed".into())));
            return Ok(match read {
                Ok(Some((ctype, body))) => {
                    let len = body.len() as u64;
                    record(&ident, 200, len, "npm: a view of the AVAILABLE set");
                    if let Some(t) = &ticket {
                        t.add_net_out(len);
                    }
                    let body = if method == "HEAD" { Bytes::new() } else { body };
                    Response::builder()
                        .status(200)
                        .header("Content-Type", ctype)
                        .header("Content-Length", len)
                        .header("X-Holger-Intake-State", "AVAILABLE")
                        .body(Full::new(body).boxed())
                        .unwrap_or_else(|_| text(500, "Internal error"))
                }
                Ok(None) => {
                    record(&ident, 404, 0, "npm: nothing AVAILABLE here");
                    npm_reply(404, &serde_json::json!({ "error": "not found" }))
                }
                Err(e) => {
                    record(&ident, e.status(), 0, &e.tagged());
                    log::warn!("npm read of {path} failed: {e}");
                    npm_refusal(&e)
                }
            });
        }
        // A write: what it is decides who may make it, before a byte of the body is read.
        let refusal = match (method.as_str(), route) {
            ("PUT", Route::Packument(_)) => {
                crate::promote::duties::may_ingest(&settings.auth_config, writer.as_ref())
                    .err()
                    .map(IntakeError::Duty)
            }
            ("PUT" | "DELETE", Route::DistTag { .. }) => {
                crate::promote::npm::may_tag(&settings.auth_config, writer.as_ref())
                    .err()
                    .map(IntakeError::Duty)
            }
            (_, Route::Rewrite(_)) | ("DELETE", _) => Some(IntakeError::Npm(NpmError::Rewrite(
                format!("{method} {path}"),
            ))),
            _ => Some(IntakeError::Npm(NpmError::Publish(format!(
                "{method} {path} is not a write the npm door takes (npm publish, npm dist-tag)"
            )))),
        };
        if let Some(e) = refusal {
            record(&ident, e.status(), 0, &e.tagged());
            return Ok(refuse_unread(req, npm_refusal(&e)).await);
        }
    }
    // ★ THE CHAIN'S CARGO DOOR (`crate::promote::cargo`, lane HOL-CARGO-PUBLISH-DOOR): the
    // repository `promotion.intake.cargo` names holds nothing of its own. `cargo publish` is
    // INGESTED into the chain's incoming repository; the sparse index and the downloads are a
    // view of the AVAILABLE set; `cargo yank` is recorded for AVAILABLE versions only.
    #[cfg(feature = "intake")]
    let cargo_door: Option<(
        Arc<crate::promote::intake::IntakeChain>,
        crate::promote::cargo::Route,
    )> = settings
        .intake
        .as_ref()
        .filter(|c| c.cargo_door() == Some(repo_key.as_str()))
        .map(|c| {
            (
                Arc::clone(c),
                crate::promote::cargo::route(
                    path.strip_prefix(&format!("/{repo_key}")).unwrap_or(""),
                ),
            )
        });
    #[cfg(feature = "intake")]
    let cargo_write = cargo_door.is_some() && !is_read;
    #[cfg(not(feature = "intake"))]
    let cargo_write = false;
    #[cfg(feature = "intake")]
    if let Some((chain, route)) = &cargo_door {
        use crate::promote::cargo::{CargoError, Route};
        use crate::promote::intake::IntakeError;
        if is_read {
            if let Route::Download { name, version } = route {
                let Some(id) = chain.cargo_download_id(name, version) else {
                    return Ok(cargo_reply(
                        404,
                        &crate::promote::cargo::errors_doc("not found"),
                    ));
                };
                let c2 = Arc::clone(chain);
                let opened = tokio::task::spawn_blocking(move || {
                    c2.serve_stream(&id, STREAM_READ_PIECE_BYTES)
                })
                .await
                .unwrap_or_else(|_| Err(IntakeError::Store("dispatch task failed".into())));
                return Ok(match opened {
                    Ok(Some(chunks)) => {
                        let len = chunks.len.unwrap_or(0);
                        record(&ident, 200, len, "cargo: a view of the AVAILABLE set");
                        let mut builder = Response::builder()
                            .status(200)
                            .header("Content-Type", "application/octet-stream")
                            .header("X-Holger-Intake-State", "AVAILABLE");
                        if let Some(n) = chunks.len {
                            builder = builder.header("Content-Length", n);
                        }
                        let body = if method == "HEAD" {
                            Full::new(Bytes::new()).boxed()
                        } else {
                            if let Some(t) = &ticket {
                                t.add_net_out(len);
                            }
                            reply_body(chunks, ticket.clone(), path.clone()).await
                        };
                        builder
                            .body(body)
                            .unwrap_or_else(|_| text(500, "Internal error"))
                    }
                    Ok(None) => {
                        record(&ident, 404, 0, "cargo: nothing AVAILABLE here");
                        cargo_reply(
                            404,
                            &crate::promote::cargo::errors_doc(&format!(
                                "{name}@{version} is not AVAILABLE here"
                            )),
                        )
                    }
                    Err(e) => {
                        record(&ident, e.status(), 0, &e.tagged());
                        log::warn!("cargo read of {path} failed: {e}");
                        cargo_reply(e.status(), &crate::promote::cargo::errors_doc(&e.tagged()))
                    }
                });
            }
            let (ctype, body): (&str, Option<Vec<u8>>) = match route {
                Route::Config => {
                    let base = chain
                        .cargo_base()
                        .map(str::to_string)
                        .unwrap_or_else(|| npm_request_base(&req, &settings, &peer));
                    let gated = settings.read_gate.applies(&settings.auth_config, &repo_key);
                    (
                        "application/json",
                        Some(crate::promote::cargo::config_json(&base, &repo_key, gated)),
                    )
                }
                Route::Index(name) => {
                    let (c2, n2) = (Arc::clone(chain), name.clone());
                    let lines = tokio::task::spawn_blocking(move || c2.cargo_index(&n2))
                        .await
                        .ok()
                        .flatten();
                    ("text/plain", lines.map(String::into_bytes))
                }
                _ => ("text/plain", None),
            };
            return Ok(match body {
                Some(body) => {
                    let len = body.len() as u64;
                    record(&ident, 200, len, "cargo: a view of the AVAILABLE set");
                    if let Some(t) = &ticket {
                        t.add_net_out(len);
                    }
                    let body = if method == "HEAD" { Vec::new() } else { body };
                    Response::builder()
                        .status(200)
                        .header("Content-Type", ctype)
                        .header("Content-Length", len)
                        .header("X-Holger-Intake-State", "AVAILABLE")
                        .body(Full::new(Bytes::from(body)).boxed())
                        .unwrap_or_else(|_| text(500, "Internal error"))
                }
                None => {
                    record(&ident, 404, 0, "cargo: nothing AVAILABLE here");
                    text(
                        404,
                        "not found: nothing of it is AVAILABLE in this Holger's intake chain",
                    )
                }
            });
        }
        // A write: what it is decides who may make it, before a byte of the body is read.
        let refusal = match (method.as_str(), route) {
            ("PUT", Route::Publish) => {
                crate::promote::duties::may_ingest(&settings.auth_config, writer.as_ref())
                    .err()
                    .map(IntakeError::Duty)
            }
            ("DELETE", Route::Yank { .. }) | ("PUT", Route::Unyank { .. }) => {
                crate::promote::cargo::may_yank(&settings.auth_config, writer.as_ref())
                    .err()
                    .map(IntakeError::Duty)
            }
            _ => Some(IntakeError::Cargo(CargoError::Publish(format!(
                "{method} {path} is not a write the cargo door takes (cargo publish, cargo yank)"
            )))),
        };
        if let Some(e) = refusal {
            record(&ident, e.status(), 0, &e.tagged());
            return Ok(refuse_unread(
                req,
                cargo_reply(e.status(), &crate::promote::cargo::errors_doc(&e.tagged())),
            )
            .await);
        }
    }
    // ★ A SCANNED REGISTRY (`crate::promote::oci_push`, lane HOL-OCI-EVIDENCE): a writable
    // `oci` repository of a chain Holger serves only what its pushes brought AVAILABLE; a write
    // needs the Importer duty (refused before its body), a DELETE is refused, and a manifest
    // PUT by tag takes the image into the chain once its body is read (below).
    #[cfg(feature = "intake")]
    let oci_push: Option<Arc<crate::promote::intake::IntakeChain>> = settings
        .intake
        .as_ref()
        .filter(|c| c.scans_pushes_to(&repo_key))
        .cloned();
    #[cfg(feature = "intake")]
    let oci_push_manifest: Option<(String, String)> = match &oci_push {
        Some(_) if !is_read && method == "PUT" => {
            crate::promote::oci_push::rest_of(&path_and_query, &repo_key)
                .and_then(crate::promote::oci_push::manifest_target)
        }
        _ => None,
    };
    #[cfg(not(feature = "intake"))]
    let oci_push_manifest: Option<(String, String)> = None;
    #[cfg(feature = "intake")]
    if let Some(chain) = &oci_push {
        // SEC-REVIEW 2026-11-01 P3: a scanned registry answers only on its OCI door's paths.
        // A path outside `/v2/<repo>/` (`/oci/_blob/<hex>`) missed the view and reached the
        // raw backend, which holds staged and BLOCKED pushes.
        if crate::promote::oci_push::rest_of(&path_and_query, &repo_key).is_none() {
            let e = crate::promote::intake::IntakeError::DoorRefused {
                repo: repo_key.clone(),
                why: format!("a scanned registry answers only on its OCI door, /v2/{repo_key}/…"),
            };
            let status = if is_read { 404 } else { e.status() };
            record(&ident, status, 0, &e.tagged());
            return Ok(refuse_unread(req, text(status, &e.tagged())).await);
        }
        if is_read {
            if let Some(rest) =
                crate::promote::oci_push::rest_of(&path_and_query, &repo_key).map(str::to_string)
            {
                let (c2, b2, attest, repo2) = (
                    Arc::clone(chain),
                    Arc::clone(&backend),
                    settings.attest.clone(),
                    repo_key.clone(),
                );
                // A pusher: a named reader who may write this registry and ingest.
                let pusher = reader.is_some()
                    && authorize_http_write_floored(
                        &settings.auth_config,
                        &settings.read_gate,
                        reader.as_ref(),
                        "PUT",
                        &repo_key,
                    )
                    .is_ok()
                    && crate::promote::duties::may_ingest(&settings.auth_config, reader.as_ref())
                        .is_ok();
                let r = tokio::task::spawn_blocking(move || {
                    c2.oci_push()
                        .map(|p| p.read(&c2, b2.as_ref(), attest.as_deref(), &repo2, &rest, pusher))
                })
                .await
                .ok()
                .flatten();
                if let Some(r) = r {
                    record(&ident, r.status, r.body.len() as u64, &r.note);
                    return Ok(oci_push_reply(r, &method, ticket.as_deref()));
                }
            }
        } else if method == "DELETE" {
            let e = crate::promote::oci_push::delete_refused(&repo_key);
            record(&ident, e.status(), 0, &e.tagged());
            return Ok(refuse_unread(req, text(e.status(), &e.tagged())).await);
        } else if let Err(e) =
            crate::promote::duties::may_ingest(&settings.auth_config, writer.as_ref())
        {
            let e = crate::promote::intake::IntakeError::Duty(e);
            record(&ident, e.status(), 0, &e.tagged());
            return Ok(refuse_unread(req, text(e.status(), &e.tagged())).await);
        }
    }
    // The chain's bundles door (lane HOL-BUNDLES-DOOR): a PUT is a signed Holger bundle,
    // staged, verified in the `verify-bundle` job against the door's trust policy, and only
    // then stored as it came; anything else is refused by name (`holger-bundles-1`). A DELETE
    // keeps the repository's own rule; every other write is refused.
    #[cfg(feature = "intake")]
    if !is_read
        && settings
            .intake
            .as_ref()
            .is_some_and(|c| c.bundles_door() == Some(repo_key.as_str()))
        && method != "DELETE"
    {
        let refuse = |status: u16, why: String| {
            let line = holger_errcode::BUNDLES_REFUSED.tag(why);
            record(&ident, status, 0, &line);
            text(status, &line)
        };
        if method != "PUT" {
            return Ok(refuse_unread(
                req,
                refuse(
                    405,
                    format!("the bundles door '{repo_key}' takes a PUT of a signed Holger bundle"),
                ),
            )
            .await);
        }
        let Some(door) = settings.imports.clone() else {
            return Ok(refuse_unread(
                req,
                refuse(
                    503,
                    "this server has no import door to verify a bundle with".into(),
                ),
            )
            .await);
        };
        let mut staged = match door.stage() {
            Ok(s) => s,
            Err(e) => return Ok(refuse_unread(req, refuse(e.status, e.tagged())).await),
        };
        let mut limited = Limited::new(req.into_body(), settings.max_body_bytes);
        loop {
            match limited.frame().await {
                Some(Ok(frame)) => {
                    if let Ok(chunk) = frame.into_data() {
                        if let Err(e) = staged.write(&chunk) {
                            return Ok(refuse(e.status, e.tagged()));
                        }
                    }
                }
                Some(Err(_)) => {
                    record(&ident, 413, 0, "payload too large");
                    return Ok(text(413, "Payload too large"));
                }
                None => break,
            }
        }
        if let Err(e) = staged.finish() {
            return Ok(refuse(e.status, e.tagged()));
        }
        let actor = ident.clone();
        let from = source.clone();
        let store = Arc::clone(&backend);
        let pq = path_and_query.clone();
        let done = tokio::task::spawn_blocking(move || {
            let stored = door
                .store_verified(&staged.path, store.as_ref(), &pq, &actor, &from)
                .map(|(what, n, (status, headers, body))| (what, n, status, headers, body));
            drop(staged);
            stored
        })
        .await;
        return Ok(match done {
            Ok(Ok((what, n, status, headers, body))) => {
                record(&ident, status, n, &format!("bundle published: {what}"));
                let mut b = Response::builder().status(status);
                for (k, v) in headers {
                    b = b.header(k, v);
                }
                b.body(Full::new(Bytes::from(body)).boxed())
                    .unwrap_or_else(|_| text(500, "Internal error"))
            }
            Ok(Err(e)) => {
                record(&ident, e.status, 0, &e.tagged());
                text(e.status, &e.tagged())
            }
            Err(_) => refuse(500, "the bundle verification task failed".into()),
        });
    }
    // P19 (lane HOL-FIELD-2): a write into a repository outside the chain where the policy
    // requires a scan would be served unscanned, so it is refused by name before its body.
    #[cfg(feature = "intake")]
    if !is_read && intake_role.is_none() && oci_push.is_none() {
        if let Some(refusal) = settings
            .intake
            .as_ref()
            .and_then(|c| c.write_refusal(&repo_key))
        {
            let line = refusal.tagged();
            record(&ident, refusal.status(), 0, &line);
            return Ok(refuse_unread(req, text(refusal.status(), &line)).await);
        }
    }
    #[cfg(feature = "intake")]
    if let Some((chain, role)) = &intake_role {
        use crate::promote::intake::IntakeRepo;
        // The production repository's PEP 503 simple index, over the AVAILABLE
        // set, with each file's `#sha256=` from the intake record: an unmodified
        // `pip install --index-url …/production/simple/` installs from it.
        if is_read && *role == IntakeRepo::Production {
            let sub = path
                .strip_prefix(&format!("/{repo_key}/"))
                .unwrap_or("")
                .to_string();
            if sub == "simple" || sub.starts_with("simple/") {
                let chain = Arc::clone(chain);
                // PEP 691 JSON when the client asks for it by `Accept` (pip does).
                let json = crate::promote::intake::wants_pep691(
                    req.headers().get("accept").and_then(|v| v.to_str().ok()),
                );
                // ★ A Python pull-through source: the project page is pulled into
                // the chain when nothing of it is AVAILABLE ("not yet" until then).
                #[cfg(feature = "jobs")]
                {
                    let (c2, s2) = (Arc::clone(&chain), sub.clone());
                    if let Some(r) = tokio::task::spawn_blocking(move || {
                        crate::pull_intake::door::pip_index(&c2, &s2, json)
                    })
                    .await
                    .unwrap_or(None)
                    {
                        record(&ident, r.status, r.body.len() as u64, &r.note);
                        return Ok(pull_door_reply(r, &method, ticket.as_deref()));
                    }
                }
                let index = tokio::task::spawn_blocking(move || chain.simple_index_as(&sub, json))
                    .await
                    .unwrap_or(None);
                return Ok(match index {
                    Some((ctype, body)) => {
                        let len = body.len() as u64;
                        record(
                            &ident,
                            200,
                            len,
                            "intake: simple index over the AVAILABLE set",
                        );
                        let body = if method == "HEAD" { Bytes::new() } else { body };
                        Response::builder()
                            .status(200)
                            .header("Content-Type", ctype)
                            .header("Content-Length", len)
                            .body(Full::new(body).boxed())
                            .unwrap_or_else(|_| text(500, "Internal error"))
                    }
                    None => {
                        record(
                            &ident,
                            404,
                            0,
                            "intake: no such project among the AVAILABLE set",
                        );
                        text(404, "Not found")
                    }
                });
            }
        }
        // ★ An OCI pull-through source: `/v2/<production>/<source>/<image>/…`.
        #[cfg(feature = "jobs")]
        if is_read && *role == IntakeRepo::Production {
            // With its query: a referrers request may filter by `artifactType` (HOL-REFERRERS).
            if let Some(rest) = path_and_query
                .strip_prefix(&format!("/v2/{repo_key}/"))
                .map(str::to_string)
            {
                let (c2, attest) = (Arc::clone(chain), settings.attest.clone());
                if let Some(r) = tokio::task::spawn_blocking(move || {
                    crate::pull_intake::door::oci(&c2, &rest, attest.as_deref())
                })
                .await
                .unwrap_or(None)
                {
                    record(&ident, r.status, r.body.len() as u64, &r.note);
                    return Ok(pull_door_reply(r, &method, ticket.as_deref()));
                }
            }
        }
        // ★ An npm, Maven or crates pull-through source: `/<production>/<source>/…`.
        #[cfg(feature = "jobs")]
        if is_read && *role == IntakeRepo::Production {
            if let Some(sub) = path
                .strip_prefix(&format!("/{repo_key}/"))
                .map(str::to_string)
            {
                let (c2, base) = (
                    Arc::clone(chain),
                    format!("{}/{repo_key}", npm_request_base(&req, &settings, &peer)),
                );
                // A gated production repository's crates sources say `auth-required`, so cargo
                // sends its token past `config.json` (HOL-DOCFIND b).
                let gated = settings.read_gate.applies(&settings.auth_config, &repo_key);
                if let Some(r) = tokio::task::spawn_blocking(move || {
                    crate::pull_intake::door::remote(&c2, &sub, &base, gated)
                })
                .await
                .unwrap_or(None)
                {
                    record(&ident, r.status, r.body.len() as u64, &r.note);
                    return Ok(pull_door_reply(r, &method, ticket.as_deref()));
                }
            }
        }
        if is_read {
            let id = match role {
                IntakeRepo::Production => backend.coordinate(&path_and_query),
                _ => None,
            };
            #[cfg(feature = "jobs")]
            let pulled_id = id.clone();
            // HOL-PERF-3: streamed from the sealed blob file, verified once per file.
            let served = match id {
                Some(id) => {
                    let chain = Arc::clone(chain);
                    tokio::task::spawn_blocking(move || {
                        chain.serve_stream(&id, STREAM_READ_PIECE_BYTES)
                    })
                    .await
                    .unwrap_or_else(|_| {
                        Err(crate::promote::intake::IntakeError::Store(
                            "dispatch task failed".into(),
                        ))
                    })
                }
                None => Ok(None),
            };
            return Ok(match served {
                Ok(Some(chunks)) => {
                    let len = chunks.len.unwrap_or(0);
                    record(
                        &ident,
                        200,
                        len,
                        "intake: AVAILABLE, served from the sealed store",
                    );
                    let mut builder = Response::builder()
                        .status(200)
                        .header("Content-Type", "application/octet-stream")
                        .header("X-Holger-Intake-State", "AVAILABLE");
                    if let Some(n) = chunks.len {
                        builder = builder.header("Content-Length", n);
                    }
                    let body = if method == "HEAD" {
                        Full::new(Bytes::new()).boxed()
                    } else {
                        if let Some(t) = &ticket {
                            t.add_net_out(len);
                        }
                        reply_body(chunks, ticket.clone(), path.clone()).await
                    };
                    builder
                        .body(body)
                        .unwrap_or_else(|_| text(500, "Internal error"))
                }
                Ok(None) => {
                    // PEP 658/714: `<wheel>.metadata`, the sealed wheel's core metadata.
                    if let Some(wheel) = path_and_query
                        .split('?')
                        .next()
                        .and_then(|p| p.strip_suffix(".metadata"))
                        .filter(|p| p.ends_with(".whl"))
                    {
                        if let Some(wid) = backend.coordinate(wheel) {
                            let c2 = Arc::clone(chain);
                            if let Some((meta, _)) =
                                tokio::task::spawn_blocking(move || c2.core_metadata(&wid))
                                    .await
                                    .unwrap_or(None)
                            {
                                let len = meta.len() as u64;
                                record(&ident, 200, len, "intake: a wheel's core metadata (PEP 658), from the sealed wheel");
                                let body = if method == "HEAD" {
                                    Vec::new()
                                } else {
                                    meta.as_ref().clone()
                                };
                                return Ok(Response::builder()

The file goes on; the console shows all of it.