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

nordisk/gunnar-ui

crates/gunnar-ui-server/src/anonymous.rs

//! **The unprivileged reader, driven end to end against a gunnar that enforces
//! visibility.**
//!
//! This module is tests and nothing else. It exists as its own file because
//! what it asserts is not a property of any one handler — it is a property of
//! the *console*, and specifically of the seam between two credentials:
//!
//! ```text
//!   browser (no cookie)   ──▶ require_auth ──▶ api::Reader ──┬─▶ App::gunnar  (ADMIN key)
//!   browser (viewer)      ──▶                                │
//!   browser (operator)    ──▶                                └─▶ App::guest   (no grants)
//! ```
//!
//! Two of those three rows arrive at the guest, and the third at the console's
//! own key. The file was written for the first row alone, and its own warning
//! below turned out to describe the hole in the second: see
//! `a_viewers_session_reads_with_the_guest_key_and_never_the_consoles`.
//!
//! # The failure this is here to catch
//!
//! The console signs every control-plane call with **one** key, and
//! `gunnar-ui-server enroll` gives that key a server-wide `Admin` grant,
//! because the console administers the server. The moment any route is served
//! without a session, that key becomes a confused deputy: the visitor is
//! anonymous, the credential is not, and gunnar answers the credential.
//! `Repos.List` on it returns every private repository on the box.
//!
//! A test that only asserted "the public repository shows up" would be **green
//! on that hole**, because a public repository shows up either way. So every
//! assertion below is about a *private* repository, and about the absence of
//! disclosure rather than the presence of content.
//!
//! # Why the fake gunnar authorises by fingerprint
//!
//! [`FakeGunnar`] reads the `gunnar-authorization` header off each request,
//! pulls the fingerprint out of it, and answers as the real gunnar would for
//! that principal: the console's key sees everything, the guest key sees only
//! `Visibility::Public`. That is what makes these tests able to tell *which key
//! the console used* — which is the actual question, and one that no amount of
//! asserting on status codes against a permissive fake could answer.
//!
//! It is a fake and not the real thing (this crate deliberately does not depend
//! on any gunnar crate; see `tests/contract.rs`), so it proves the console's
//! half and not gunnar's. gunnar's half — that a grantless principal is narrowed
//! to the public subset rather than refused, that the account gate outranks
//! visibility — is proved in `gunnar-cli/tests/public_listing.rs` against the
//! real `AuthTable`.

/// **Gunnar's MCP connector through the console** (TASKS-13, `mcp`): the
/// default build serves none of it; the feature build serves its metadata and
/// answers `/mcp` with the login pointer, past the session gate.
mod mcp;

/// **The rendered file view's own end-to-end tests.** A child module so it can
/// use this one's fake gunnar and console harness without a second copy of
/// either, and its own file so that what it asserts — who gets a typeset page,
/// who gets a PDF, whose choice is remembered — can be read without scrolling
/// through the credential seam above it.
mod rendered_files;

/// **Paid signup, driven the way a browser with no session drives it.** A
/// second child module, for the same reason [`rendered_files`] is one: it needs
/// this module's console harness, and what it asserts — which of these routes a
/// stranger can reach at all, what the pages say, and that a name is settled
/// before any money moves — reads better away from the credential seam above.
///
/// `metered` only, because the routes it drives are: an open build does not
/// contain `auth::signup` at all, which is what
/// `tests/open_build_speaks_no_money.rs` exists to hold it to.
#[cfg(feature = "metered")]
mod paid_signup;

/// **The private-gunnar buy page, driven by a visitor with no session**: the
/// white page, and its three calls straight through to monetize's
/// `EstateOrder` — sizes out, monetize's words and picture back.
#[cfg(feature = "metered")]
mod private_order;
/// **The ONE sign-up page's contract** (owner 2026-10-07): the left half is
/// the front page's, the heading follows the situation, one − / +, the
/// picture, and nothing priced or sized by the page itself.
#[cfg(feature = "metered")]
mod signup_page;

/// **The login page's company field is gunnar's to offer** (round 5.3): the
/// status says `sso_offered` only where an account has an identity provider.
mod sso_offered;

/// **Company sign-in is its own default-off feature** (A34-15): the default build
/// serves none of its doors.
mod sso_switch;

/// **gunnar.rs's public face** (TASKS-12, `public-site`): the default build
/// serves none of it, and the feature build serves it to a visitor through the
/// guest key, naming no private repository.
mod public_site;

/// **GUN-GUEST**: one address scheme, the console's document for everyone, guests
/// read-only, and (public-site) the page's content pre-rendered into it.
mod console_address;

/// **GUN-SEO-GUEST** (owner 2026-10-31): what a crawler reads at the site's www origin is
/// the console's own copy-text form, at one www URL, and nothing private.
#[cfg(feature = "public-site")]
mod seo_guest;

thread_local! {
    /// The relying party the next [`console_waiting`] on this thread builds, as
    /// `(rp_id, origin)`; `None` is `console.example`. GUN-SEO-GUEST sets the shape a live
    /// site has: the bare site as the relying party, `https://www.<site>` as the origin.
    static RELYING_PARTY: std::cell::RefCell<Option<(&'static str, &'static str)>> = const { std::cell::RefCell::new(None) };
}

/// **AIRGAP: forge import is off unless built (`forges`) and switched on (`GUNNAR_UI_FORGES`).**
mod forges_switch;

/// **Nobody sidesteps the throttle** (GUN-GUEST, owner 2026-10-30): every route of the console,
/// guest or signed in, passes the one limiter (`crate::throttle`).
mod throttled;

/// **A repository's owner writes on their own repository** (2026-10-18): the
/// issue, pull request and branch-protection writes, owner / stranger / visitor.
mod repo_owner_writes;

use std::collections::BTreeMap;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex};

use tonic::{Request, Response, Status};

use crate::pb;
use crate::pb::refs_server::{Refs, RefsServer};
use crate::pb::repos_server::{Repos, ReposServer};
use crate::pb::usage_server::{Usage, UsageServer};

/// The console's own principal: the one `enroll` gives a server-wide `Admin`.
const CONSOLE_SEED: [u8; 32] = [7u8; 32];
/// The guest principal: enrolled, holding no grants at all.
const GUEST_SEED: [u8; 32] = [23u8; 32];

const NS: &str = "nordisk";
/// A GiB, for the admin disk view's fixture.
const DISK_GIB: u64 = 1 << 30;
const PUBLIC: &str = "gunnar";
const PRIVATE: &str = "payroll";

/// A blob the private repository contains, and which must never be rendered to
/// a caller with no session. Distinctive so a `contains` assertion over a whole
/// response body is meaningful.
const SECRET_BYTES: &[u8] = b"the-private-blob-nobody-anonymous-may-read";

/// **The namespace's traffic, which is nobody's business but the tenant's.**
///
/// A wire-byte count for one day of [`NS`], picked so no other number in this
/// module or in an HTTP status line can spell it: a `contains` over the whole
/// response body is only evidence if the string it looks for could not have got
/// there any other way. It is the byte total, the millisecond stamp and the
/// day key that a leaked `Usage.Activity` answer would carry.
const SECRET_BYTES_MOVED: u64 = 748_912_336_571;
/// The day the traffic above happened on: midnight UTC, and a distinctive one.
const SECRET_DAY_MS: i64 = 20_694 * 86_400_000;
/// When the namespace was last pushed to. The single most operationally
/// interesting number on the whole activity answer, and the one a competitor
/// reading it would want most: it says whether the tenant is still alive.
const SECRET_LAST_PUSH_MS: i64 = SECRET_DAY_MS + 41_237_000;

/// The public repository's README, and the heading a rendered one must name.
///
/// Distinctive so that "the README was served" is a `contains` a test can make
/// against a whole response body, and so that the same string appearing under
/// the PRIVATE repository's refusal would be unmistakable.
const README_HEADING: &str = "The Public Repository";
const README_MARKDOWN: &str =
    "# The Public Repository\n\nA line of prose, and [the guide](docs/guide.pdf).\n";

/// The object id the tree below points README.md at.
///
/// Both repositories are `HashKind::Sha256` in this fake, so a tree entry holds
/// **32** raw bytes and `git::parse_tree` hex-encodes them back into this. A
/// sha1 fake would read the wrong bytes as a name and the wrong name as an id,
/// which is the exact failure `crate::git` warns about.
const README_OID: &str = "aa00000000000000000000000000000000000000000000000000000000000011";

/// A third public repository, whose README is too big to typeset.
///
/// `MAX_SVG_BYTES` is 4 MiB and a typeset page costs about 105 bytes per
/// character, so this is the size at which the SVG grade gives way to the
/// sanitised-HTML one — the failure grade that is otherwise unreachable
/// through the router, because `readme::emit` cannot produce markup the
/// typesetter refuses.
const OVERSIZE: &str = "encyclopaedia";

/// The object id the oversize repository's tree points README.md at.
const HUGE_OID: &str = "bb00000000000000000000000000000000000000000000000000000000000022";

/// A README past the size a browser is handed a page for.
fn huge_readme() -> Vec<u8> {
    let mut out = String::from("# An Encyclopaedia\n\n");
    // 60 KB of prose, which typesets to roughly 6 MB of glyph paths.
    for _ in 0..1_100 {
        out.push_str("lorem ipsum dolor sit amet consectetur adipiscing elit\n\n");
    }
    out.into_bytes()
}

/// The blob oid of the tree's `guide.pdf`, which is a **Git LFS pointer** and
/// not a PDF — the shape gunnar's own `docs/gunnar-fast-setup.pdf` has.
const POINTER_OID: &str = "cc00000000000000000000000000000000000000000000000000000000000033";

/// The sha256 that pointer names: the key the LFS store holds the file under.
const LFS_OID: &str = "dd00000000000000000000000000000000000000000000000000000000000044";

/// The file itself, which lives only in the LFS store. A real PDF header, so a
/// test asserting "the PDF was served" is asserting about the file and not
/// about a string that could have come from anywhere.
const LFS_BODY: &[u8] = b"%PDF-1.7\nthe burned guide, whole\n%%EOF\n";

fn pointer_blob() -> Vec<u8> {
    format!(
        "version https://git-lfs.github.com/spec/v1\noid sha256:{LFS_OID}\nsize {}\n",
        LFS_BODY.len()
    )
    .into_bytes()
}

/// A tree holding `README.md` and the LFS-backed `guide.pdf`, encoded the way
/// gunnar hands one back: the undecorated payload, with no `"tree <n>\0"`
/// header and no zlib frame. Entries are in git's own order, which is why
/// `README.md` comes first.
fn readme_tree(first: u8, last: u8) -> Vec<u8> {
    let mut tree = Vec::new();
    tree.extend_from_slice(b"100644 README.md\0");
    let mut oid = [0u8; 32];
    oid[0] = first;
    oid[31] = last;
    tree.extend_from_slice(&oid);
    tree.extend_from_slice(b"100644 guide.pdf\0");
    let mut pointer = [0u8; 32];
    pointer[0] = 0xcc;
    pointer[31] = 0x33;
    tree.extend_from_slice(&pointer);
    tree
}

/// GUN-GUEST's `docs/` (see [`FakeGunnar::with_docs`]): its tree, `docs/v2`'s, and the files.
const DOCS_TREE_OID: &str = "d000000000000000000000000000000000000000000000000000000000000001";
const DOCS_V2_OID: &str = "d000000000000000000000000000000000000000000000000000000000000002";
const DOCS_README_OID: &str = "d000000000000000000000000000000000000000000000000000000000000003";
const DOCS_APP_OID: &str = "d000000000000000000000000000000000000000000000000000000000000004";
/// The heading `docs/v2/README.md` carries, distinctive for a `contains`.
#[cfg(feature = "public-site")]
const DOCS_HEADING: &str = "The Second Edition Of The Docs";
const DOCS_README: &str = "# The Second Edition Of The Docs\n\nRead [the first](../README.md) too.\n";

/// A hex object id as the 32 raw bytes a sha256 tree entry holds.
fn raw_oid(hex: &str) -> [u8; 32] {
    let mut out = [0u8; 32];
    for (i, b) in out.iter_mut().enumerate() {
        *b = u8::from_str_radix(&hex[2 * i..2 * i + 2], 16).expect("hex");
    }
    out
}

/// The object id `badge.svg` is stored under, in [`badge_tree`].
const BADGE_OID: &str = "5b00000000000000000000000000000000000000000000000000000000000077";

/// A small badge, the shape bestpractices.dev answers.
const BADGE_SVG: &[u8] = b"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"130\" height=\"20\"><text x=\"5\" y=\"14\">openssf best practices</text></svg>";

/// [`readme_tree`] with `badge.svg` between `README.md` and `guide.pdf` (git's order).
fn badge_tree(first: u8, last: u8) -> Vec<u8> {
    let mut tree = Vec::new();
    tree.extend_from_slice(b"100644 README.md\0");
    let mut oid = [0u8; 32];
    oid[0] = first;
    oid[31] = last;
    tree.extend_from_slice(&oid);
    tree.extend_from_slice(b"100644 badge.svg\0");
    let mut badge = [0u8; 32];
    badge[0] = 0x5b;
    badge[31] = 0x77;
    tree.extend_from_slice(&badge);
    tree.extend_from_slice(b"100644 guide.pdf\0");
    let mut pointer = [0u8; 32];
    pointer[0] = 0xcc;
    pointer[31] = 0x33;
    tree.extend_from_slice(&pointer);
    tree
}

// ───────────────────────────────────────────────────────────────────────────
// A gunnar that authorises
// ───────────────────────────────────────────────────────────────────────────

/// What the fake knows about one repository.
#[derive(Clone)]
struct Held {
    visibility: pb::Visibility,
    /// oid -> bytes, the whole object store for this repository.
    objects: BTreeMap<String, Vec<u8>>,
    /// sha256 -> bytes: the LFS store, which is a different store from the
    /// object database and holds the files the tree only points at.
    lfs: BTreeMap<String, Vec<u8>>,
}

/// A file in the public repository with a great many distinct commits — the
/// shape an attacker picks, and the cheapest thing in the world to ask for.
const CROWDED_FILE: &str = "the-file-everybody-has-touched.rs";

/// How many distinct commits that file's lines come from. Well past the
/// console's ceiling, so the ceiling is what the test measures rather than the
/// fixture's size.
const CROWDED_FILE_COMMITS: usize = 500;

/// A tenant who pays for this console, and the private repository in the
/// namespace their own gunnar principal owns.
///
/// gunnar's rule, modelled below: *a principal is intrinsically admin of the
/// namespace named after it* — `control_plane::add_principal` creates the
/// account namespace WITH the principal and rolls the principal back if the
/// namespace is taken, so the two names are one claim. So `vera` reads
/// `vera/ledger` and nobody else does.
const TENANT: &str = "vera";
const TENANT_REPO: &str = "ledger";
/// A second tenant, who is the control: the same role, the same console, and
/// no business whatever with the first one's namespace.
const OTHER_TENANT: &str = "viggo";
/// A blob only [`TENANT`] may read. Distinctive, for the same reason
/// [`SECRET_BYTES`] is.
const LEDGER_BYTES: &[u8] = b"the-ledger-only-vera-paid-for";

/// The fake's issue threads, by (repository, number) (clippy: one name for the shape).
type IssueThreads = Arc<Mutex<BTreeMap<(String, u64), Vec<pb::ForgeEvent>>>>;

/// A gunnar that answers two principals differently, by the same rule the real
/// one uses: `Visibility::Public` is readable with no grant, everything else
/// needs one, and only the console's key has one.
#[derive(Clone)]
struct FakeGunnar {
    repos: Arc<Mutex<BTreeMap<String, Held>>>,
    /// Fingerprints seen, in order. The direct evidence of WHICH key signed a
    /// call — an assertion on this is the only way to prove the console did not
    /// merely get lucky with a permissive answer.
    seen: Arc<Mutex<Vec<String>>>,
    /// How many calls arrived at all. Reads the cache bypass: a request served
    /// out of `Caches::repos` never reaches here.
    calls: Arc<AtomicUsize>,
    /// How many `Admin.VerifyChain` walks one HTTP request cost gunnar. The
    /// amplification factor, counted where it lands.
    verifications: Arc<AtomicUsize>,
    /// Whether this gunnar knows `Refs.ReadLfsObject` at all. `false` is an
    /// OLDER gunnar than the console — the skew the console is deployed under
    /// by design, and the one `tests/contract.rs` exists for.
    serves_lfs: bool,
    /// Whether `Refs.ReadLfsObject` reads RANGES (`offset`/`length`, gunnar
    /// 2026-10-15). `false` is a gunnar from before them: it ignores the two
    /// fields and answers whole-or-refused under its 4 MiB ceiling.
    lfs_ranges: bool,
    /// **gunnar's identity table**: the principals that exist, and which
    /// principal each registered key fingerprint belongs to.
    ///
    /// Without this the console could enrol a per-tenant key and nothing would
    /// be able to tell that it had — every call would still arrive as an
    /// unknown fingerprint and be answered as a stranger, so the test would be
    /// green on a console that never enrolled anything. `Access.AddKey` writes
    /// here and [`FakeGunnar::may_read`] reads it, which is what makes "whose
    /// key signed this, and what may that principal see" one question.
    principals: Arc<Mutex<BTreeMap<String, pb::Principal>>>,
    /// fingerprint -> principal id.
    keys: Arc<Mutex<BTreeMap<String, String>>>,
    /// The credential SCHEME each call arrived under, in the same order as
    /// [`FakeGunnar::seen`].
    schemes: Arc<Mutex<Vec<String>>>,
    /// Whether `Admin.Capacity` / `StorageInfo` / `Health` answer (the admin
    /// disk view). Off by default: the machine test drives an OLDER gunnar
    /// that serves none of them, and must keep doing so.
    admin_disks: bool,
    /// **gunnar's event bus**, for `Events.Watch`: what [`FakeGunnar::emit`]
    /// publishes, every watcher hears — narrowed per watcher the way gunnar's
    /// "mine" scope narrows it.
    bus: tokio::sync::broadcast::Sender<pb::Event>,
    /// Every `Events.Watch`, as `<who> namespaces=[…]`.
    watches: Arc<Mutex<Vec<String>>>,
    /// **Whether any account has an identity provider** — `Sso.Discover`'s
    /// `any_provider` ([`sso_offered`]). Off: a box where nobody configured one.
    sso_providers: Arc<std::sync::atomic::AtomicBool>,
    /// How many `Sso.Discover` calls arrived — what the status's cache saves.
    discovers: Arc<AtomicUsize>,
    /// `Sso.Begin`'s answer: `Ok(redirect_url)` or a refusal's message.
    sso_begin: Arc<Mutex<Result<String, String>>>,
    /// The `client` every `Sso.Begin` named (A34-6).
    sso_clients: Arc<Mutex<Vec<String>>>,
    /// **The forge log's issues** (`Forge.Append` / `ListIssues`), for
    /// [`repo_owner_writes`].
    issues: Arc<Mutex<Vec<pb::IssueState>>>,
    /// Each issue's thread after its opening (`Forge.GetIssue`'s events), by
    /// `(repo, number)`, for the public site's issue pages (PUB-ISSUES).
    issue_threads: IssueThreads,
    /// **gunnar's generic settings** (`Admin.GetSetting` / `SetSetting`), where the console
    /// keeps its administrator's switches (`public-site` and `mcp` builds).
    settings: Arc<Mutex<BTreeMap<String, Vec<u8>>>>,
    /// The one commit's message `Refs.Log` answers (GUN-GUEST: a push changes it).
    subject: Arc<Mutex<String>>,
}

impl FakeGunnar {
    fn new() -> FakeGunnar {
        let mut repos = BTreeMap::new();
        repos.insert(
            format!("{NS}/{PUBLIC}"),
            Held {
                visibility: pb::Visibility::Public,
                objects: BTreeMap::from([
                    ("pub-oid".to_owned(), b"a public blob".to_vec()),
                    // The tree `Refs.Log` below points at, and the README in
                    // it: without these the browse and readme routes could
                    // only ever answer 404 for a repository a visitor CAN see,
                    // and "refused" and "empty" would look the same.
                    ("tree-oid".to_owned(), readme_tree(0xaa, 0x11)),
                    (README_OID.to_owned(), README_MARKDOWN.as_bytes().to_vec()),
                    // The tree's `guide.pdf`: a POINTER, which is all a tree
                    // ever holds for an LFS file.
                    (POINTER_OID.to_owned(), pointer_blob()),
                ]),
                lfs: BTreeMap::from([(LFS_OID.to_owned(), LFS_BODY.to_vec())]),
            },
        );
        repos.insert(
            format!("{NS}/{OVERSIZE}"),
            Held {
                visibility: pb::Visibility::Public,
                objects: BTreeMap::from([
                    ("tree-oid".to_owned(), readme_tree(0xbb, 0x22)),
                    (HUGE_OID.to_owned(), huge_readme()),
                ]),
                lfs: BTreeMap::new(),
            },
        );
        repos.insert(
            format!("{NS}/{PRIVATE}"),
            Held {
                visibility: pb::Visibility::Private,
                objects: BTreeMap::from([
                    ("sec-oid".to_owned(), SECRET_BYTES.to_vec()),
                    ("tree-oid".to_owned(), readme_tree(0xee, 0x55)),
                    (POINTER_OID.to_owned(), pointer_blob()),
                ]),
                // The same pointer, the same sha256, a file nobody anonymous
                // may have: "the console followed a pointer it should not have"
                // has somewhere to show up.
                lfs: BTreeMap::from([(LFS_OID.to_owned(), SECRET_BYTES.to_vec())]),
            },
        );
        // The tenants' own namespaces. Private, so "vera sees her ledger" can
        // only ever be true because gunnar answered HER principal — a public
        // one would be green on the guest key and prove nothing.
        repos.insert(
            format!("{TENANT}/{TENANT_REPO}"),
            Held {
                visibility: pb::Visibility::Private,
                objects: BTreeMap::from([("ledger-oid".to_owned(), LEDGER_BYTES.to_vec())]),
                lfs: BTreeMap::new(),
            },
        );
        repos.insert(
            format!("{OTHER_TENANT}/diary"),
            Held {
                visibility: pb::Visibility::Private,
                objects: BTreeMap::from([("diary-oid".to_owned(), b"viggo's diary".to_vec())]),
                lfs: BTreeMap::new(),
            },
        );
        // Both tenants already have a gunnar principal — the paid signup's
        // account, made before this console was asked anything. The console's
        // own and the guest's are NOT here: they are keys the deployment
        // enrolled, and this fake knows them by seed rather than by table.
        let principals = [TENANT, OTHER_TENANT]
            .into_iter()
            .map(|name| {
                (
                    name.to_owned(),
                    pb::Principal {
                        id: name.to_owned(),
                        name: name.to_owned(),
                        kind: pb::PrincipalKind::User as i32,
                        created_at_unix_ms: 1,
                    },
                )
            })
            .collect();
        FakeGunnar {
            repos: Arc::new(Mutex::new(repos)),
            seen: Arc::new(Mutex::new(Vec::new())),
            calls: Arc::new(AtomicUsize::new(0)),
            verifications: Arc::new(AtomicUsize::new(0)),
            serves_lfs: true,
            lfs_ranges: true,
            principals: Arc::new(Mutex::new(principals)),
            keys: Arc::new(Mutex::new(BTreeMap::new())),
            schemes: Arc::new(Mutex::new(Vec::new())),
            admin_disks: false,
            bus: tokio::sync::broadcast::channel(64).0,
            watches: Arc::new(Mutex::new(Vec::new())),
            sso_providers: Arc::new(std::sync::atomic::AtomicBool::new(false)),
            discovers: Arc::new(AtomicUsize::new(0)),
            sso_begin: Arc::new(Mutex::new(Ok("https://idp.acme.example/authorize?state=s".to_owned()))),
            sso_clients: Arc::new(Mutex::new(Vec::new())),
            issues: Arc::new(Mutex::new(Vec::new())),
            issue_threads: Arc::new(Mutex::new(BTreeMap::new())),
            settings: Arc::new(Mutex::new(BTreeMap::new())),
            subject: Arc::new(Mutex::new("the one commit".to_owned())),
        }
    }

    /// **A `docs/` beside the README** (GUN-GUEST): `docs/v2/README.md` at depth two,
    /// and `docs/app.js` (a file whose name ends like one of the console's assets).
    fn with_docs(self) -> FakeGunnar {
        {
            let mut repos = self.repos.lock().unwrap();
            let held = repos.get_mut(&format!("{NS}/{PUBLIC}")).expect("the public repository");
            let mut root = readme_tree(0xaa, 0x11);
            // git's order: `README.md`, `docs`, `guide.pdf`.
            let at = root.windows(9).position(|w| w == b"100644 gu").expect("guide.pdf");
            let mut docs = b"40000 docs\0".to_vec();
            docs.extend_from_slice(&raw_oid(DOCS_TREE_OID));
            root.splice(at..at, docs);
            held.objects.insert("tree-oid".to_owned(), root);
            let mut docs = b"100644 app.js\0".to_vec();
            docs.extend_from_slice(&raw_oid(DOCS_APP_OID));
            docs.extend_from_slice(b"40000 v2\0");
            docs.extend_from_slice(&raw_oid(DOCS_V2_OID));
            held.objects.insert(DOCS_TREE_OID.to_owned(), docs);
            let mut v2 = b"100644 README.md\0".to_vec();
            v2.extend_from_slice(&raw_oid(DOCS_README_OID));
            held.objects.insert(DOCS_V2_OID.to_owned(), v2);
            held.objects.insert(DOCS_README_OID.to_owned(), DOCS_README.as_bytes().to_vec());
            held.objects.insert(DOCS_APP_OID.to_owned(), b"console.log('the docs script');\n".to_vec());
        }
        self
    }

    /// What gunnar holds under a generic setting's name.
    fn setting(&self, name: &str) -> Option<Vec<u8>> {
        self.settings.lock().unwrap().get(name).cloned()
    }

    /// Publish one ref update on gunnar's bus.
    fn emit(&self, namespace: &str, repo: &str, ref_name: &str, new_oid: &str) {
        let _ = self.bus.send(pb::Event {
            seq: 1,
            at_unix_ms: 1,
            kind: pb::EventKind::RefUpdated as i32,
            payload: Some(pb::event::Payload::RefUpdated(pb::RefUpdated {
                repo: Some(pb::RepoPath {
                    namespace: namespace.to_owned(),
                    repo: repo.to_owned(),
                }),
                ref_name: ref_name.to_owned(),
                new_oid: new_oid.to_owned(),
                ..Default::default()
            })),
        });
    }

    /// gunnar's "mine" for a watcher that named no namespaces: the console's
    /// key hears everything; a principal hears its own account's repositories
    /// (it is inside it); nobody here made their events public, so that is all.
    fn mine(who: &str, event: &pb::Event) -> bool {
        if who == "console" {
            return true;
        }
        match &event.payload {
            Some(pb::event::Payload::RefUpdated(e)) => {
                e.repo.as_ref().is_some_and(|r| r.namespace == who)
            }
            _ => false,
        }
    }

    /// The same gunnar, serving the three reads the admin disk view makes —
    /// to the console's key only, as gunnar gates them (server-wide Read).
    fn with_admin_disks(mut self) -> FakeGunnar {
        self.admin_disks = true;
        self
    }

    /// Server-wide Read, or the refusal gunnar gives without it.
    fn server_read(&self, fingerprint: &str, verb: &str) -> Result<(), Status> {
        if Self::granted(fingerprint) {
            Ok(())
        } else {
            Err(Status::permission_denied(format!("principal has no server read grant ({verb})")))
        }
    }

    /// The same gunnar, one release older: it has an LFS store and no RPC that
    /// reads it.
    fn without_the_lfs_rpc(mut self) -> FakeGunnar {
        self.serves_lfs = false;
        self
    }

    /// A gunnar with `Refs.ReadLfsObject` and no ranged reads: the release
    /// before 2026-10-15.
    fn without_lfs_ranges(mut self) -> FakeGunnar {
        self.lfs_ranges = false;
        self
    }

    /// Put `body` in the public repository's LFS store as the file the tree's
    /// `guide.pdf` pointer names, with a pointer stating its size.
    fn with_the_guide_in_lfs(self, body: Vec<u8>) -> FakeGunnar {
        {
            let mut repos = self.repos.lock().unwrap();
            let held = repos
                .get_mut(&format!("{NS}/{PUBLIC}"))
                .expect("the public repository");
            held.objects.insert(
                POINTER_OID.to_owned(),
                format!(
                    "version https://git-lfs.github.com/spec/v1\noid sha256:{LFS_OID}\nsize {}\n",
                    body.len()
                )
                .into_bytes(),
            );
            held.lfs.insert(LFS_OID.to_owned(), body);
        }
        self
    }

    /// **`badge.svg` in the public and the private repository** (BADGE-7): the
    /// same tree as [`readme_tree`] with an SVG picture beside the README, the
    /// shape `nordisk/ci-status` has for the OpenSSF badges gunnar.rs shows.
    fn with_a_badge(self) -> FakeGunnar {
        {
            let mut repos = self.repos.lock().unwrap();
            for (key, first, last) in [(format!("{NS}/{PUBLIC}"), 0xaa, 0x11), (format!("{NS}/{PRIVATE}"), 0xee, 0x55)] {
                let held = repos.get_mut(&key).expect("the repository");
                held.objects.insert("tree-oid".to_owned(), badge_tree(first, last));
                held.objects.insert(BADGE_OID.to_owned(), BADGE_SVG.to_vec());
            }
        }
        self
    }

    /// The fingerprint that signed this request, from the credential header.
    ///
    /// The console mints a fresh `gunnar-sshsig-v2 <fingerprint> …` per call
    /// (see [`crate::signer`]), so the fingerprint is the second whitespace-
    /// separated field; [`FakeGunnar::admits`] refuses any other scheme. The signature itself is not verified here: this fake is
    /// standing in for gunnar's ACL, not for its cryptography, and
    /// `tests/contract.rs` already pins the credential format against gunnar's
    /// own constants.
    fn who<T>(&self, request: &Request<T>) -> String {
        self.calls.fetch_add(1, Ordering::SeqCst);
        let header = request
            .metadata()
            .get(crate::signer::CREDENTIAL_METADATA_KEY)
            .and_then(|value| value.to_str().ok())
            .unwrap_or_default()
            .to_owned();
        let fingerprint = header
            .split_whitespace()
            .nth(1)
            .unwrap_or("(unsigned)")
            .to_owned();
        // The scheme every call arrived under, kept beside the fingerprint. A
        // credential that names no method can be replayed against a different
        // one, and a key minted per PERSON is the last place that may happen:
        // the whole point of it is that gunnar answers it differently.
        self.schemes.lock().expect("the scheme log").push(
            header
                .split_whitespace()
                .next()
                .unwrap_or("(none)")
                .to_owned(),
        );
        self.seen
            .lock()
            .expect("the fingerprint log")
            .push(fingerprint.clone());
        fingerprint
    }

    /// **The credential let in, as a gunnar started with require_bound lets it
    /// in** (stinky #24): its fingerprint, or the refusal.
    fn admits<T>(&self, request: &Request<T>) -> Result<String, Status> {
        let scheme = request
            .metadata()
            .get(crate::signer::CREDENTIAL_METADATA_KEY)
            .and_then(|value| value.to_str().ok())
            .and_then(|header| header.split_whitespace().next().map(str::to_owned));
        if scheme.is_some_and(|scheme| scheme != crate::signer::CREDENTIAL_SCHEME) {
            self.who(request);
            return Err(Status::unauthenticated("a credential that names no method is refused"));
        }
        Ok(self.who(request))
    }

    /// Does this fingerprint hold a server-wide grant? Only the console's does.
    fn granted(fingerprint: &str) -> bool {
        fingerprint == signer(CONSOLE_SEED).fingerprint()
    }

    /// The principal a registered key belongs to, or `None` for a key this
    /// table never saw — the guest's, or one the console never enrolled.
    fn principal_of_key(&self, fingerprint: &str) -> Option<String> {
        self.keys
            .lock()
            .expect("the key table")
            .get(fingerprint)
            .cloned()
    }

    /// The `SHA256:…` of the key the console enrolled for `principal`, if it
    /// enrolled one.
    ///
    /// The whole point of the tenant tests: an assertion that the fingerprint
    /// on the wire is THIS one is an assertion about which private key the
    /// console reached for, which is the only question worth asking here.
    fn key_of_principal(&self, principal: &str) -> Option<String> {
        self.keys
            .lock()
            .expect("the key table")
            .iter()
            .find(|(_, owner)| owner.as_str() == principal)
            .map(|(fingerprint, _)| fingerprint.clone())
    }

    /// The real `AuthTable::may`, in one line: a grant, or the repository is
    /// public.
    ///
    /// **Plus the account rule**, which is gunnar's and not this fake's
    /// invention: a principal is intrinsically admin of the namespace named
    /// after it (`gunnar_core::AuthTable::owns_account`, and
    /// `control_plane::add_principal` makes the two names one claim by creating
    /// the namespace with the principal). That is what a tenant's own key buys
    /// them, and it is the difference between "this console signs as the
    /// tenant" and "this console signs as somebody with no grants at all".
    ///
    /// `NotFound` and `PermissionDenied` are BOTH answered as
    /// `PermissionDenied` for a caller with no grant, exactly as gunnar does —
    /// telling a stranger apart "does not exist" from "you may not see it"
    /// turns the port into an existence oracle for private repository names.
    fn may_read(&self, fingerprint: &str, path: &pb::RepoPath) -> Result<Held, Status> {
        let key = format!("{}/{}", path.namespace, path.repo);
        let owns_account = self
            .principal_of_key(fingerprint)
            .is_some_and(|principal| principal == path.namespace);
        let repos = self.repos.lock().expect("the catalogue");
        let held = repos.get(&key);
        match held {
            Some(held)
                if Self::granted(fingerprint)
                    || owns_account
                    || held.visibility == pb::Visibility::Public =>
            {
                Ok(held.clone())
            }
            // **The console's own key is told the truth**: a name gunnar does
            // not hold is `NotFound` to a caller whose grant covers it, as the
            // real control plane answers (`get_repo` → "… is not in the
            // catalog"). Only a caller with no grant gets the uniform
            // `PermissionDenied`. Modelled because the console's hidden-name
            // layer (`api::absent`) has to fold BOTH into one answer.
            None if Self::granted(fingerprint) => Err(Status::not_found(format!(
                "repository {key} is not in the catalog"
            ))),
            _ => Err(Status::permission_denied(format!(
                "principal has no read grant on repo:{key}"
            ))),
        }
    }

    /// Does gunnar's catalog hold this namespace? Every namespace a
    /// repository here lives in, and every principal's own account namespace.
    fn namespace_exists(&self, namespace: &str) -> bool {
        self.repos
            .lock()
            .expect("the catalogue")
            .keys()
            .any(|key| key.split_once('/').is_some_and(|(ns, _)| ns == namespace))
            || self
                .principals
                .lock()
                .expect("the principals")
                .contains_key(namespace)
    }

    fn fingerprints(&self) -> Vec<String> {
        self.seen.lock().expect("the fingerprint log").clone()
    }

    fn schemes(&self) -> Vec<String> {
        self.schemes.lock().expect("the scheme log").clone()
    }
}

/// The refusal every unmodelled RPC below returns.
///
/// They refuse rather than answering an empty `Ok`, because a stub that
/// succeeded would make a handler calling the wrong verb look like it worked.
///
/// Written out one method at a time rather than generated by a macro, and not
/// for want of trying: `#[tonic::async_trait]` rewrites each `async fn` into a
/// boxed future, and an attribute macro sees the impl block *before* a
/// function-like macro inside it expands — so macro-generated methods keep a
/// bare `async fn` signature the trait no longer has, and every one of them
/// fails to compile with `lifetimes do not match method in trait`.
fn unmodelled(verb: &'static str) -> Status {
    Status::unimplemented(format!(
        "{verb} is not modelled by the anonymous-access fake"
    ))
}

#[tonic::async_trait]
impl Repos for FakeGunnar {
    // Encrypted repositories (gunnar 2026-10-05): not modelled by this fake.
    async fn set_encrypted(
        &self,
        _: tonic::Request<pb::SetEncryptedRequest>,
    ) -> Result<tonic::Response<pb::SetEncryptedResponse>, tonic::Status> {
        Err(tonic::Status::unimplemented("Repos.SetEncrypted"))
    }
    async fn recipient_keys(
        &self,
        _: tonic::Request<pb::RecipientKeysRequest>,
    ) -> Result<tonic::Response<pb::RecipientKeysResponse>, tonic::Status> {
        Err(tonic::Status::unimplemented("Repos.RecipientKeys"))
    }

    async fn list(
        &self,
        request: Request<pb::ListReposRequest>,
    ) -> Result<Response<pb::ListReposResponse>, Status> {
        let who = self.admits(&request)?;
        // **The narrowing gunnar itself performs** (see
        // `gunnar-cli/tests/public_listing.rs`): a caller with no grant is
        // reduced to what it may read, not refused. Modelled here because it is
        // what the console now depends on.
        let repos = self
            .repos
            .lock()
            .expect("the catalogue")
            .iter()
            .filter(|(_, held)| {
                FakeGunnar::granted(&who) || held.visibility == pb::Visibility::Public
            })
            .map(|(key, held)| {
                let (namespace, repo) = key.split_once('/').expect("ns/name");
                pb::Repo {
                    path: Some(pb::RepoPath {
                        namespace: namespace.to_owned(),
                        repo: repo.to_owned(),
                    }),
                    visibility: held.visibility as i32,
                    hash_kind: pb::HashKind::Sha256 as i32,
                    default_branch: "refs/heads/main".to_owned(),
                    ..Default::default()
                }
            })
            .collect();
        Ok(Response::new(pb::ListReposResponse {
            repos,
            next_page_token: String::new(),
        }))
    }

    async fn get(
        &self,
        request: Request<pb::GetRepoRequest>,
    ) -> Result<Response<pb::GetRepoResponse>, Status> {
        let who = self.admits(&request)?;
        let path = request.into_inner().path.unwrap_or_default();
        let held = self.may_read(&who, &path)?;
        Ok(Response::new(pb::GetRepoResponse {
            repo: Some(pb::Repo {
                path: Some(path),
                visibility: held.visibility as i32,
                hash_kind: pb::HashKind::Sha256 as i32,
                default_branch: "refs/heads/main".to_owned(),
                ..Default::default()
            }),
        }))
    }

    // `ArchiveOut`: the generated default stub answers Unimplemented.

    async fn create_namespace(
        &self,
        _: Request<pb::CreateNamespaceRequest>,
    ) -> Result<Response<pb::CreateNamespaceResponse>, Status> {
        Err(unmodelled("Repos.CreateNamespace"))
    }
    async fn list_namespaces(
        &self,
        _: Request<pb::ListNamespacesRequest>,
    ) -> Result<Response<pb::ListNamespacesResponse>, Status> {
        Err(unmodelled("Repos.ListNamespaces"))
    }
    async fn delete_namespace(
        &self,
        _: Request<pb::DeleteNamespaceRequest>,
    ) -> Result<Response<pb::DeleteNamespaceResponse>, Status> {
        Err(unmodelled("Repos.DeleteNamespace"))
    }
    async fn create(
        &self,
        _: Request<pb::CreateRepoRequest>,
    ) -> Result<Response<pb::CreateRepoResponse>, Status> {
        Err(unmodelled("Repos.Create"))
    }
    async fn delete(
        &self,
        _: Request<pb::DeleteRepoRequest>,
    ) -> Result<Response<pb::DeleteRepoResponse>, Status> {
        Err(unmodelled("Repos.Delete"))
    }
    async fn undelete(
        &self,
        _: Request<pb::UndeleteRepoRequest>,
    ) -> Result<Response<pb::UndeleteRepoResponse>, Status> {
        Err(unmodelled("Repos.Undelete"))
    }
    async fn purge(
        &self,
        _: Request<pb::PurgeRepoRequest>,
    ) -> Result<Response<pb::PurgeRepoResponse>, Status> {
        Err(unmodelled("Repos.Purge"))
    }
    async fn gc(
        &self,
        _: Request<pb::GcRepoRequest>,
    ) -> Result<Response<pb::GcRepoResponse>, Status> {
        Err(unmodelled("Repos.Gc"))
    }
    async fn gc_status(
        &self,
        _: Request<pb::GcStatusRequest>,
    ) -> Result<Response<pb::GcStatusResponse>, Status> {
        Err(unmodelled("Repos.GcStatus"))
    }
    async fn list_deleted(
        &self,
        _: Request<pb::ListDeletedRequest>,
    ) -> Result<Response<pb::ListDeletedResponse>, Status> {
        Err(unmodelled("Repos.ListDeleted"))
    }
    async fn list_orphans(
        &self,
        _: Request<pb::ListOrphansRequest>,
    ) -> Result<Response<pb::ListOrphansResponse>, Status> {
        Err(unmodelled("Repos.ListOrphans"))
    }
    async fn reclaim_orphan(
        &self,
        _: Request<pb::ReclaimOrphanRequest>,
    ) -> Result<Response<pb::ReclaimOrphanResponse>, Status> {
        Err(unmodelled("Repos.ReclaimOrphan"))
    }
    async fn set_default_branch(
        &self,
        _: Request<pb::SetDefaultBranchRequest>,
    ) -> Result<Response<pb::SetDefaultBranchResponse>, Status> {
        Err(unmodelled("Repos.SetDefaultBranch"))
    }
    async fn set_visibility(
        &self,
        _: Request<pb::SetVisibilityRequest>,
    ) -> Result<Response<pb::SetVisibilityResponse>, Status> {
        Err(unmodelled("Repos.SetVisibility"))
    }
}

#[tonic::async_trait]
impl Refs for FakeGunnar {
    async fn list(
        &self,
        request: Request<pb::ListRefsRequest>,
    ) -> Result<Response<pb::ListRefsResponse>, Status> {
        let who = self.admits(&request)?;
        let repo = request.into_inner().repo.unwrap_or_default();
        self.may_read(&who, &repo)?;
        Ok(Response::new(pb::ListRefsResponse {
            refs: vec![pb::RefTarget {
                ref_name: "refs/heads/main".to_owned(),
                oid: "commit-oid".to_owned(),
                ..Default::default()
            }],
            ..Default::default()
        }))
    }

    async fn get(
        &self,
        request: Request<pb::GetRefRequest>,
    ) -> Result<Response<pb::GetRefResponse>, Status> {
        let who = self.admits(&request)?;
        let repo = request.into_inner().repo.unwrap_or_default();
        self.may_read(&who, &repo)?;
        Ok(Response::new(pb::GetRefResponse {
            ref_target: Some(pb::RefTarget {
                ref_name: "HEAD".to_owned(),
                oid: "commit-oid".to_owned(),
                ..Default::default()
            }),
        }))
    }

    async fn log(
        &self,
        request: Request<pb::LogRequest>,
    ) -> Result<Response<pb::LogResponse>, Status> {
        let who = self.admits(&request)?;
        let repo = request.into_inner().repo.unwrap_or_default();
        self.may_read(&who, &repo)?;
        Ok(Response::new(pb::LogResponse {
            commits: vec![pb::Commit {
                oid: "commit-oid".to_owned(),
                message: self.subject.lock().expect("the subject").clone(),
                tree_oid: "tree-oid".to_owned(),
                ..Default::default()
            }],
            ..Default::default()
        }))
    }

    async fn read_object(
        &self,
        request: Request<pb::ReadObjectRequest>,
    ) -> Result<Response<pb::ReadObjectResponse>, Status> {
        let who = self.admits(&request)?;
        let inner = request.into_inner();
        let repo = inner.repo.unwrap_or_default();
        let held = self.may_read(&who, &repo)?;
        let data = held
            .objects
            .get(&inner.oid)
            .cloned()
            .ok_or_else(|| Status::not_found("no such object"))?;
        Ok(Response::new(pb::ReadObjectResponse {
            oid: inner.oid,
            size: data.len() as u64,
            data,
            ..Default::default()
        }))
    }

    /// The LFS store, keyed by the sha256 a pointer names — authorised through
    /// the same `may_read` every other read goes through, because that is the
    /// claim worth testing: an LFS object is as private as the repository that
    /// points at it, and the console must not have found a way around that.
    async fn read_lfs_object(
        &self,
        request: Request<pb::ReadLfsObjectRequest>,
    ) -> Result<Response<pb::ReadLfsObjectResponse>, Status> {
        if !self.serves_lfs {
            return Err(unmodelled("Refs.ReadLfsObject"));
        }
        let who = self.admits(&request)?;
        let inner = request.into_inner();
        let repo = inner.repo.unwrap_or_default();
        let held = self.may_read(&who, &repo)?;
        let data = held
            .lfs
            .get(&inner.oid)
            .cloned()
            .ok_or_else(|| Status::not_found("no such LFS object"))?;
        // gunnar's rules: a 4 MiB ceiling per answer, lowered by `max_bytes`;
        // whole-or-refused without a range; with one (and a gunnar that reads
        // them) the ceiling bounds the range and an offset past the end is
        // refused.
        const CEILING: u64 = 4 * 1024 * 1024;
        let ceiling = match inner.max_bytes {
            0 => CEILING,
            n => n.min(CEILING),
        };
        let size = data.len() as u64;
        if self.lfs_ranges && (inner.offset != 0 || inner.length != 0) {
            let (offset, length) = (inner.offset, inner.length);
            if offset > size || (offset == size && size > 0) {
                return Err(Status::invalid_argument(format!(
                    "offset {offset} is past the end of LFS object {}, which is {size} bytes",
                    inner.oid
                )));
            }
            if length > ceiling {
                return Err(Status::resource_exhausted(format!(
                    "a range of {length} bytes is over the {ceiling}-byte ceiling for this request"
                )));
            }
            let want = if length == 0 { ceiling } else { length }.min(size - offset);
            let range = data[offset as usize..(offset + want) as usize].to_vec();
            return Ok(Response::new(pb::ReadLfsObjectResponse {
                oid: inner.oid,
                size,
                data: range,
                offset,
            }));
        }
        if size > ceiling {
            return Err(Status::resource_exhausted(format!(
                "LFS object {} is {size} bytes, over the {ceiling}-byte ceiling for this request",
                inner.oid
            )));
        }
        Ok(Response::new(pb::ReadLfsObjectResponse {
            oid: inner.oid,
            size,
            data,
            offset: 0,
        }))
    }

    async fn diff(
        &self,
        _: Request<pb::DiffRequest>,
    ) -> Result<Response<pb::DiffResponse>, Status> {
        Err(unmodelled("Refs.Diff"))
    }
    /// **A file whose lines come from as many distinct commits as the caller
    /// asked for.**
    ///
    /// Modelled rather than refused because the amplification GUI-025 is about
    /// is counted in DISTINCT COMMITS, and the file is chosen by whoever makes
    /// the request — so the fake has to be able to produce the expensive shape
    /// on demand, exactly as a long-lived real file does.
    async fn blame(
        &self,
        request: Request<pb::BlameRequest>,
    ) -> Result<Response<pb::BlameResponse>, Status> {
        let who = self.admits(&request)?;
        let asked = request.into_inner();
        self.may_read(&who, &asked.repo.unwrap_or_default())?;
        let commits = if asked.path == CROWDED_FILE {
            CROWDED_FILE_COMMITS
        } else {
            3
        };
        let lines = (0..commits)
            .map(|i| pb::BlameLine {
                commit: format!("{i:040x}"),
                author: "alice".to_owned(),
                line: format!("line {i}").into_bytes(),
            })
            .collect();
        Ok(Response::new(pb::BlameResponse { lines }))
    }
    async fn search(
        &self,
        _: Request<pb::SearchRequest>,
    ) -> Result<Response<pb::SearchResponse>, Status> {
        Err(unmodelled("Refs.Search"))
    }
}

/// **A gunnar that verifies a chain, and counts how often it was asked to.**
///
/// `Admin.VerifyChain` is a walk of history with its own budget on gunnar's
/// side, and the blame route calls it once per distinct commit in a file the
/// CALLER names. Only `verify_chain` is modelled: what the counter is for is
/// the amplification factor of one HTTP request, and every other verb here
/// would be a different question.
#[tonic::async_trait]
impl crate::pb::admin_server::Admin for FakeGunnar {
    async fn verify_chain(
        &self,
        request: Request<pb::VerifyChainRequest>,
    ) -> Result<Response<pb::VerifyChainResponse>, Status> {
        let who = self.admits(&request)?;
        self.verifications.fetch_add(1, Ordering::SeqCst);
        let asked = request.into_inner();
        self.may_read(&who, &asked.repo.unwrap_or_default())?;
        Ok(Response::new(pb::VerifyChainResponse {
            links: vec![pb::ChainLink {
                id: "signature".to_owned(),
                verdict: pb::ChainLinkVerdict::ChainLinkProven as i32,
                detail: "signed by alice".to_owned(),
            }],
            ..Default::default()
        }))
    }

    async fn health(
        &self,
        request: Request<pb::HealthRequest>,
    ) -> Result<Response<pb::HealthResponse>, Status> {
        if !self.admin_disks {
            return Err(unmodelled("Admin.Health"));
        }
        let who = self.admits(&request)?;
        self.server_read(&who, "Admin.Health")?;
        Ok(Response::new(pb::HealthResponse {
            serving: true,
            twins: vec![pb::TwinHeartbeat {
                principal: "twin".to_owned(),
                address: "10.13.8.122:40000".to_owned(),
                disk_total_bytes: DISK_GIB * 400,
                disk_used_bytes: DISK_GIB * 100,
                fill_permille: 250,
                state: "ok".to_owned(),
                ..Default::default()
            }],
            ..Default::default()
        }))
    }
    async fn stats(
        &self,
        _: Request<pb::StatsRequest>,
    ) -> Result<Response<pb::StatsResponse>, Status> {
        Err(unmodelled("Admin.Stats"))
    }
    async fn storage_info(
        &self,
        request: Request<pb::StorageInfoRequest>,
    ) -> Result<Response<pb::StorageInfoResponse>, Status> {
        if !self.admin_disks {
            return Err(unmodelled("Admin.StorageInfo"));
        }
        let who = self.admits(&request)?;
        self.server_read(&who, "Admin.StorageInfo")?;
        Ok(Response::new(pb::StorageInfoResponse {
            total_explode_bytes: DISK_GIB * 20,
            total_explode_budget_bytes: DISK_GIB * 40,
            ..Default::default()
        }))
    }
    async fn capacity(
        &self,
        request: Request<pb::CapacityRequest>,
    ) -> Result<Response<pb::CapacityResponse>, Status> {
        if !self.admin_disks {
            return Err(unmodelled("Admin.Capacity"));
        }
        let who = self.admits(&request)?;
        self.server_read(&who, "Admin.Capacity")?;
        // The disk report only when asked, as gunnar answers it.
        let disks = request.into_inner().disks.then(|| pb::DiskSnapshot {
            measured_at_unix_ms: 1_790_000_000_000,
            mounts: vec![
                pb::DiskMount {
                    source: "/dev/vda2".to_owned(),
                    mount_point: "/".to_owned(),
                    fs_type: "ext4".to_owned(),
                    labels: vec!["system".to_owned()],
                    measured: true,
                    total_bytes: DISK_GIB * 10,
                    free_bytes: DISK_GIB * 6,
                    available_bytes: DISK_GIB * 6,
                    used_bytes: DISK_GIB * 4,
                    ..Default::default()
                },
                pb::DiskMount {
                    source: "/dev/md0".to_owned(),
                    mount_point: "/data".to_owned(),
                    fs_type: "xfs".to_owned(),
                    labels: vec!["data".to_owned()],
                    measured: true,
                    total_bytes: DISK_GIB * 300,
                    free_bytes: DISK_GIB * 200,
                    available_bytes: DISK_GIB * 200,
                    used_bytes: DISK_GIB * 100,
                    floor_bytes: DISK_GIB * 15,
                    servable_bytes: DISK_GIB * 185,
                    ..Default::default()
                },
            ],
            devices: vec![
                pb::BlockDevice {
                    name: "md0".to_owned(),
                    size_bytes: DISK_GIB * 300,
                    members: vec!["vdb1".to_owned(), "vdc1".to_owned()],
                    raid_level: "raid0".to_owned(),
                    ..Default::default()
                },
                pb::BlockDevice {
                    name: "vdb".to_owned(),
                    size_bytes: DISK_GIB * 151,
                    partitions: vec![pb::BlockPartition { name: "vdb1".to_owned(), size_bytes: DISK_GIB * 150 }],
                    ..Default::default()
                },
                pb::BlockDevice {
                    name: "vdc".to_owned(),
                    size_bytes: DISK_GIB * 151,
                    partitions: vec![pb::BlockPartition { name: "vdc1".to_owned(), size_bytes: DISK_GIB * 150 }],
                    ..Default::default()
                },
            ],
            ..Default::default()
        });
        Ok(Response::new(pb::CapacityResponse {
            root: "/data".to_owned(),
            total_bytes: DISK_GIB * 300,
            free_bytes: DISK_GIB * 200,
            floor_bytes: DISK_GIB * 15,
            servable_bytes: DISK_GIB * 185,
            data_set: "2×150G raid0 xfs".to_owned(),
            disks,
            ..Default::default()
        }))
    }
    async fn grow_start(
        &self,
        _: Request<pb::GrowStartRequest>,
    ) -> Result<Response<pb::GrowStatusResponse>, Status> {
        Err(unmodelled("Admin.GrowStart"))
    }
    async fn grow_status(
        &self,
        _: Request<pb::GrowStatusRequest>,
    ) -> Result<Response<pb::GrowStatusResponse>, Status> {
        Err(unmodelled("Admin.GrowStatus"))
    }
    async fn grow_resume(
        &self,
        _: Request<pb::GrowResumeRequest>,
    ) -> Result<Response<pb::GrowStatusResponse>, Status> {
        Err(unmodelled("Admin.GrowResume"))
    }
    async fn get_setting(
        &self,
        request: Request<pb::GetSettingRequest>,
    ) -> Result<Response<pb::GetSettingResponse>, Status> {
        // Not counted in `seen` or `calls`: the console asks its switches once at start, and
        // the tests that count a visitor's calls must not see that ask.
        let value = self.setting(&request.into_inner().name);
        Ok(Response::new(pb::GetSettingResponse { present: value.is_some(), value: value.unwrap_or_default() }))
    }
    async fn set_setting(
        &self,
        request: Request<pb::SetSettingRequest>,
    ) -> Result<Response<pb::SetSettingResponse>, Status> {
        let pb::SetSettingRequest { name, value } = request.into_inner();
        let previous = self.settings.lock().unwrap().insert(name, value);
        Ok(Response::new(pb::SetSettingResponse { had: previous.is_some(), previous: previous.unwrap_or_default() }))
    }
}

/// **A gunnar that counts a namespace's traffic, and guards it with the same
/// grant it guards everything else with.**
///
/// `Usage.Read` and `Usage.Activity` both take `Read` **on the namespace**, so
/// a principal with no grant gets `PermissionDenied` from both — modelled here
/// exactly as [`FakeGunnar::may_read`] models the repository rule, and for the
/// same reason: a permissive fake could not tell which key the console used.
///
/// The point of serving these at all is that the numbers must be *reachable*.
/// A fake that refused the RPC outright would make the anonymous test below
/// green against a console that happily proxied the route — the body would be
/// an error either way. So there is a real, distinctive ledger behind it, and
/// what is asserted is that not one digit of it reaches a visitor.
#[tonic::async_trait]
impl Usage for FakeGunnar {
    async fn read(
        &self,
        request: Request<pb::ReadUsageRequest>,
    ) -> Result<Response<pb::ReadUsageResponse>, Status> {
        let who = self.admits(&request)?;
        let namespace = request.into_inner().namespace;
        if !FakeGunnar::granted(&who) {
            return Err(Status::permission_denied(format!(
                "principal has no read grant on namespace:{namespace}"
            )));
        }
        if !self.namespace_exists(&namespace) {
            return Err(Status::not_found(format!(
                "namespace {namespace} is not in the catalog"
            )));
        }
        Ok(Response::new(pb::ReadUsageResponse {
            usage: Some(pb::NamespaceUsage {
                namespace,
                bytes_in_today: SECRET_BYTES_MOVED,
                last_push_unix_ms: SECRET_LAST_PUSH_MS,
                ..Default::default()
            }),
            allowance: Some(pb::Allowance::default()),
            ..Default::default()
        }))
    }

    async fn read_all(
        &self,
        _: Request<pb::ReadAllUsageRequest>,
    ) -> Result<Response<pb::ReadAllUsageResponse>, Status> {
        Err(unmodelled("Usage.ReadAll"))
    }

    async fn activity(
        &self,
        request: Request<pb::ActivityRequest>,
    ) -> Result<Response<pb::ActivityResponse>, Status> {
        let who = self.admits(&request)?;
        let namespace = request.into_inner().namespace;
        if !FakeGunnar::granted(&who) {
            return Err(Status::permission_denied(format!(
                "principal has no read grant on namespace:{namespace}"
            )));
        }
        if !self.namespace_exists(&namespace) {
            return Err(Status::not_found(format!(
                "namespace {namespace} is not in the catalog"
            )));
        }
        Ok(Response::new(pb::ActivityResponse {
            days: vec![pb::DayActivity {
                day_unix_ms: SECRET_DAY_MS,
                bytes_in: SECRET_BYTES_MOVED,
                bytes_out: SECRET_BYTES_MOVED,
                pushes: 1,
                fetches: 1,
                last_push_unix_ms: SECRET_LAST_PUSH_MS,
                ..Default::default()
            }],
            retained_days: 400,
        }))
    }

    async fn admit_plan(
        &self,
        request: Request<pb::AdmitPlanRequest>,
    ) -> Result<Response<pb::AdmitPlanResponse>, Status> {
        let who = self.admits(&request)?;
        let namespace = request.into_inner().namespace;
        if !FakeGunnar::granted(&who) {
            return Err(Status::permission_denied(format!(
                "principal has no read grant on namespace:{namespace}"
            )));
        }
        Ok(Response::new(pb::AdmitPlanResponse {
            policy: "usage-share".into(),
            window_days: 30,
            used_bytes: SECRET_BYTES_MOVED,
            ..Default::default()
        }))
    }
}

/// **gunnar's identity table, as much of it as a tenant credential needs.**
///
/// Four verbs are modelled and the rest refuse. `AddKey` is the one that
/// matters: it is how the console enrols the key it has minted for a tenant,
/// and the row it writes is what [`FakeGunnar::may_read`] later consults to
/// decide what that key may see. A fake that accepted `AddKey` and remembered
/// nothing would answer every tenant read as a stranger's, and the test would
/// be green on a console that had enrolled nothing at all.
///
/// `AddPrincipal` creates the account namespace with the principal the way
/// gunnar's own `control_plane::add_principal` does — and refuses when the name
/// is taken, which is the case the console has to survive rather than paper
/// over.
#[tonic::async_trait]
impl crate::pb::events_server::Events for FakeGunnar {
    async fn watch(
        &self,
        request: Request<pb::WatchRequest>,
    ) -> Result<Response<tonic::codegen::BoxStream<pb::Event>>, Status> {
        let fingerprint = self.admits(&request)?;
        let who = if Self::granted(&fingerprint) {
            "console".to_owned()
        } else {
            self.principal_of_key(&fingerprint)
                .unwrap_or_else(|| "guest".to_owned())
        };
        self.watches.lock().expect("the watch log").push(format!(
            "{who} namespaces={:?}",
            request.get_ref().namespaces
        ));
        let mut rx = self.bus.subscribe();
        let stream = async_stream::stream! {
            loop {
                match rx.recv().await {
                    Ok(event) if FakeGunnar::mine(&who, &event) => yield Ok(event),
                    Ok(_) | Err(tokio::sync::broadcast::error::RecvError::Lagged(_)) => continue,
                    Err(tokio::sync::broadcast::error::RecvError::Closed) => break,
                }
            }
        };
        Ok(Response::new(Box::pin(stream)))
    }
}

#[tonic::async_trait]
impl crate::pb::access_server::Access for FakeGunnar {
    /// gunnar's `Access.Check`, as this fake decides: the console's key holds
    /// everything, a principal everything in its own account, and anybody a
    /// READ of a public repository.
    async fn check(
        &self,
        request: Request<pb::CheckRequest>,
    ) -> Result<Response<pb::CheckResponse>, Status> {
        let who = self.admits(&request)?;
        let asked = request.into_inner();
        let owns = Self::granted(&who)
            || self.principal_of_key(&who).is_some_and(|p| p == asked.namespace);
        let public_read = asked.level == pb::GrantLevel::Read as i32
            && self
                .repos
                .lock()
                .expect("the catalogue")
                .get(&format!("{}/{}", asked.namespace, asked.repo))
                .is_some_and(|h| h.visibility == pb::Visibility::Public);
        let allowed = owns || public_read;
        Ok(Response::new(pb::CheckResponse {
            allowed,
            reason: if allowed { String::new() } else { format!("principal holds no grant on {}", asked.namespace) },
        }))
    }

    async fn add_principal(
        &self,
        request: Request<pb::AddPrincipalRequest>,
    ) -> Result<Response<pb::AddPrincipalResponse>, Status> {
        self.admits(&request)?;
        let asked = request.into_inner();
        let mut principals = self.principals.lock().expect("the identity table");
        if principals.contains_key(&asked.name) {
            return Err(Status::already_exists(format!(
                "a principal named {:?} already exists",
                asked.name
            )));
        }
        // gunnar's ids are the name (`Principal::new(name, name, …)`), which is
        // a fact this console has to live with and one the report says out
        // loud: pinning an id pins the row that was seen, not an identity that
        // survives a delete and a recreate under the same name.
        let principal = pb::Principal {
            id: asked.name.clone(),
            name: asked.name.clone(),
            kind: asked.kind,
            created_at_unix_ms: 2,
        };
        principals.insert(asked.name, principal.clone());
        Ok(Response::new(pb::AddPrincipalResponse {
            principal: Some(principal),
        }))
    }

    async fn list_principals(
        &self,
        request: Request<pb::ListPrincipalsRequest>,
    ) -> Result<Response<pb::ListPrincipalsResponse>, Status> {
        self.admits(&request)?;
        Ok(Response::new(pb::ListPrincipalsResponse {
            principals: self
                .principals
                .lock()
                .expect("the identity table")
                .values()
                .cloned()
                .collect(),
            next_page_token: String::new(),
            ..Default::default()
        }))
    }

    /// Nobody here holds a passkey yet (thin layer L: passkeys are gunnar's).
    async fn list_credentials(
        &self,
        request: Request<pb::ListCredentialsRequest>,
    ) -> Result<Response<pb::ListCredentialsResponse>, Status> {
        self.admits(&request)?;
        Ok(Response::new(pb::ListCredentialsResponse {
            credentials: Vec::new(),
        }))
    }

    async fn add_key(
        &self,
        request: Request<pb::AddKeyRequest>,
    ) -> Result<Response<pb::AddKeyResponse>, Status> {
        self.admits(&request)?;
        let asked = request.into_inner();
        if !self
            .principals
            .lock()
            .expect("the identity table")
            .contains_key(&asked.principal_id)
        {
            return Err(Status::not_found(format!(
                "no principal {:?} to register a key against",
                asked.principal_id
            )));
        }
        // The fingerprint is gunnar's to derive from the key, never the
        // caller's to choose — the same rule `api::account` states.
        let parsed = ssh_key::PublicKey::from_openssh(&asked.openssh_public_key)
            .map_err(|e| Status::invalid_argument(format!("not an OpenSSH public key: {e}")))?;
        let fingerprint = parsed.fingerprint(ssh_key::HashAlg::Sha256).to_string();
        self.keys
            .lock()
            .expect("the key table")
            .insert(fingerprint.clone(), asked.principal_id.clone());
        Ok(Response::new(pb::AddKeyResponse {
            key: Some(pb::PublicKey {
                fingerprint,
                algo: "ssh-ed25519".to_owned(),
                principal_id: asked.principal_id,
                comment: asked.comment,
                added_at_unix_ms: 3,
                last_used_unix_ms: None,
                expires_at_unix_ms: asked.expires_at_unix_ms,
            }),
        }))
    }

    async fn revoke_key(
        &self,
        request: Request<pb::RevokeKeyRequest>,
    ) -> Result<Response<pb::RevokeKeyResponse>, Status> {
        self.admits(&request)?;
        let asked = request.into_inner();
        self.keys
            .lock()
            .expect("the key table")
            .remove(&asked.fingerprint);
        Ok(Response::new(pb::RevokeKeyResponse {}))
    }

    async fn list_keys(
        &self,
        request: Request<pb::ListKeysRequest>,
    ) -> Result<Response<pb::ListKeysResponse>, Status> {
        self.admits(&request)?;
        let asked = request.into_inner();
        Ok(Response::new(pb::ListKeysResponse {
            keys: self
                .keys
                .lock()
                .expect("the key table")
                .iter()
                .filter(|(_, owner)| owner.as_str() == asked.principal_id)
                .map(|(fingerprint, owner)| pb::PublicKey {
                    fingerprint: fingerprint.clone(),
                    algo: "ssh-ed25519".to_owned(),
                    principal_id: owner.clone(),
                    comment: String::new(),
                    added_at_unix_ms: 3,
                    last_used_unix_ms: None,
                    expires_at_unix_ms: None,
                })
                .collect(),
        }))
    }

    async fn rename_principal(
        &self,
        _: Request<pb::RenamePrincipalRequest>,
    ) -> Result<Response<pb::RenamePrincipalResponse>, Status> {
        Err(unmodelled("Access.RenamePrincipal"))
    }
    async fn remove_principal(
        &self,
        _: Request<pb::RemovePrincipalRequest>,
    ) -> Result<Response<pb::RemovePrincipalResponse>, Status> {
        Err(unmodelled("Access.RemovePrincipal"))
    }
    async fn grant(
        &self,
        _: Request<pb::GrantRequest>,
    ) -> Result<Response<pb::GrantResponse>, Status> {
        Err(unmodelled("Access.Grant"))
    }
    async fn revoke(
        &self,
        _: Request<pb::RevokeRequest>,
    ) -> Result<Response<pb::RevokeResponse>, Status> {
        Err(unmodelled("Access.Revoke"))
    }
    async fn list_grants(
        &self,
        _: Request<pb::ListGrantsRequest>,
    ) -> Result<Response<pb::ListGrantsResponse>, Status> {
        Err(unmodelled("Access.ListGrants"))
    }
    async fn add_group_member(
        &self,
        _: Request<pb::AddGroupMemberRequest>,
    ) -> Result<Response<pb::AddGroupMemberResponse>, Status> {
        Err(unmodelled("Access.AddGroupMember"))
    }
    async fn remove_group_member(
        &self,
        _: Request<pb::RemoveGroupMemberRequest>,
    ) -> Result<Response<pb::RemoveGroupMemberResponse>, Status> {
        Err(unmodelled("Access.RemoveGroupMember"))
    }
    async fn list_group_members(
        &self,
        _: Request<pb::ListGroupMembersRequest>,
    ) -> Result<Response<pb::ListGroupMembersResponse>, Status> {
        Err(unmodelled("Access.ListGroupMembers"))
    }
    async fn list_group_membership_events(
        &self,
        _: Request<pb::ListGroupMembershipEventsRequest>,
    ) -> Result<Response<pb::ListGroupMembershipEventsResponse>, Status> {
        Err(unmodelled("Access.ListGroupMembershipEvents"))
    }
}

// ───────────────────────────────────────────────────────────────────────────
// The console under test
// ───────────────────────────────────────────────────────────────────────────

/// ★ **The fake answers a method-blind credential as gunnar does with
/// require_bound on** (stinky #24, on since 5.3.3): a v1 header is refused, so
/// a console that regressed to sending one is red here instead of green on a
/// fake that never looked; the v2 header the console sends is let in.
#[test]
fn the_fake_refuses_a_method_blind_credential() {
    let fake = FakeGunnar::new();
    let console = signer(CONSOLE_SEED);
    let with = |header: String| {
        let mut request = Request::new(());
        request.metadata_mut().insert(crate::signer::CREDENTIAL_METADATA_KEY, header.parse().expect("an ascii header"));
        request
    };
    let v1 = console.credential(1_700_000_000_000, "nonce-0123456789ab").expect("signs");
    let refused = fake.admits(&with(v1)).expect_err("a method-blind credential is refused");
    assert_eq!(refused.code(), tonic::Code::Unauthenticated, "{refused:?}");
    let v2 = console.credential_for(1_700_000_000_000, "nonce-0123456789ab", "Repos.List").expect("signs");
    assert_eq!(fake.admits(&with(v2)).expect("a bound credential is let in"), console.fingerprint());
}

fn signer(seed: [u8; 32]) -> crate::signer::Signer {
    crate::signer::Signer::new(ssh_key::PrivateKey::from(
        ssh_key::private::Ed25519Keypair::from_seed(&seed),
    ))
    .expect("a fixed seed makes a signer")
}

/// A console pointed at [`FakeGunnar`], in the posture that matters.
///
/// `admin_token: Some(_)` is **load-bearing**, and is the trap this harness
/// exists to avoid. With neither a passkey nor an admin token configured,
/// `require_auth` takes THE ONE BYPASS and runs every request unauthenticated —
/// which, on a console holding a server-wide admin grant, means every request
/// runs as admin. A test written in that posture would show a private
/// repository being served anonymously and would be *right to*, proving
/// nothing about the guest identity at all.
///
/// `guest` is a parameter because half of what is asserted here is what happens
/// when there is no guest identity: the anonymous surface must not exist, and
/// must not fall back to the console's key.
///
/// The passkey subsystem is returned beside the router so a test can mint a
/// REAL session cookie for it ([`signed_in`]). That is what extends this
/// harness past the anonymous path the module doc warns about: a session minted
/// here goes through `require_auth`, the role floor and `api::Reader` exactly as
/// a browser's does, and the fingerprint log says which key the console reached
/// for on the other side.
///
/// The event hub comes back too, so a test can put a line on the live feed and
/// watch who is shown it.
async fn console(
    fake: FakeGunnar,
    with_guest: bool,
) -> (
    axum::Router,
    Arc<crate::auth::Webauthn>,
    crate::sse::EventHub,
) {
    console_with(fake, with_guest.then_some(GUEST_SEED), None).await
}

/// The same console, with the guest identity's KEY chosen by the caller.
///
/// One test needs a guest key that is not grantless: the deployment mistake
/// `auth::routes::public_repos` has always warned about is pointing
/// `GUNNAR_UI_GUEST_IDENTITY` at a key that holds a grant — the console's own,
/// copied because it was to hand. Every other caller wants [`console`].
/// `monetize` is the third credential and it is `None` for every fixture here
/// but one lane: [`paid_signup`] needs it, because the routes it drives are
/// registered only on a console that HAS it (`App::signup_offered`), and a
/// harness that could not hand one over could only ever assert their absence.
/// It arrives as an address rather than a `Monetize`, so the caller owns the
/// fake server and its call log.
// An open build has no third credential to take, so the parameter is unused
// there — the same shape `App::monetize` itself has.
#[cfg_attr(not(feature = "metered"), allow(unused_variables))]
async fn console_with(
    fake: FakeGunnar,
    guest_seed: Option<[u8; 32]>,
    monetize_addr: Option<String>,
) -> (
    axum::Router,
    Arc<crate::auth::Webauthn>,
    crate::sse::EventHub,
) {
    console_provided_by(fake, guest_seed, monetize_addr, None, None).await
}

/// [`console_with`], its monetize handle told whose shop its purchases are:
/// `Some(site)` is a SOLD (provided) Gunnar (one shop, 2026-10-07); `product`
/// the product id its config names (G15; `None`: unset).
#[cfg_attr(not(feature = "metered"), allow(unused_variables))]
async fn console_provided_by(
    fake: FakeGunnar,
    guest_seed: Option<[u8; 32]>,
    monetize_addr: Option<String>,
    provider: Option<&str>,
    product: Option<&str>,
) -> (
    axum::Router,
    Arc<crate::auth::Webauthn>,
    crate::sse::EventHub,
) {
    console_waiting(fake, guest_seed, monetize_addr, provider, product, None, None).await
}

/// How long a fixture's monetize is waited on; `None` is the handle's own
/// default. Nothing to wait on in the open build.
#[cfg(feature = "metered")]
type Waits = Option<crate::monetize::Deadlines>;
#[cfg(not(feature = "metered"))]
type Waits = Option<std::convert::Infallible>;

/// [`console_provided_by`] (`product` as there), its monetize waited on for `deadlines` — THIS
/// console's, and no other's (stinky #21).
#[cfg_attr(not(feature = "metered"), allow(unused_variables))]
async fn console_waiting(
    fake: FakeGunnar,
    guest_seed: Option<[u8; 32]>,
    monetize_addr: Option<String>,
    provider: Option<&str>,
    product: Option<&str>,
    deadlines: Waits,
    ui_dir: Option<std::path::PathBuf>,
) -> (
    axum::Router,
    Arc<crate::auth::Webauthn>,
    crate::sse::EventHub,
) {
    let listener = tokio::net::TcpListener::bind("127.0.0.1:0")
        .await
        .expect("a loopback port");
    let addr = listener.local_addr().expect("its address");
    let serving = fake.clone();
    tokio::spawn(async move {
        tonic::transport::Server::builder()
            .add_service(ReposServer::new(serving.clone()))
            .add_service(RefsServer::new(serving.clone()))
            .add_service(crate::pb::admin_server::AdminServer::new(serving.clone()))
            .add_service(crate::pb::access_server::AccessServer::new(serving.clone()))
            .add_service(crate::pb::events_server::EventsServer::new(serving.clone()))
            .add_service(crate::pb::sso_server::SsoServer::new(serving.clone()))
            .add_service(crate::pb::forge_server::ForgeServer::new(serving.clone()))
            .add_service(crate::pb::pull_requests_server::PullRequestsServer::new(serving.clone()))
            .add_service(crate::pb::policy_server::PolicyServer::new(serving.clone()))
            .add_service(UsageServer::new(serving))
            .serve_with_incoming(tokio_stream::wrappers::TcpListenerStream::new(listener))
            .await
    });

    let endpoint = format!("http://{addr}");
    let gunnar = crate::grpc::Gunnar::connect_lazy(&endpoint, Arc::new(signer(CONSOLE_SEED)))
        .expect("a lazy channel");
    let guest = guest_seed.map(|seed| {
        crate::grpc::Gunnar::connect_lazy(&endpoint, Arc::new(signer(seed)))
            .expect("a lazy guest channel")
    });
    let store = crate::state::StateStore::open(
        tempfile::Builder::new()
            .suffix(".redb")
            .tempfile()
            .expect("a temp file")
            .into_temp_path()
            .keep()
            .expect("keep the path"),
    )
    .expect("a state store");

    // A real passkey subsystem, so `require_auth` runs the role ladder and a
    // session cookie can be minted for it. It does NOT retire the break-glass
    // token below — that happens only once an ADMIN passkey exists, and the
    // sessions minted here are a viewer's and an operator's.
    let rp = RELYING_PARTY.with(|r| r.borrow_mut().take()).unwrap_or(("console.example", "https://console.example"));
    let webauthn = Arc::new(
        crate::auth::Webauthn::new(
            crate::auth::RelyingParty {
                rp_id: rp.0.to_owned(),
                origin: rp.1.to_owned(),
                rp_name: "gunnar".to_owned(),
            },
            store.clone(),
        )
        .expect("a passkey subsystem"),
    );

    let feed = crate::sse::EventHub::detached();
    let router = crate::serve::router_around(Arc::new(crate::app::App {
        webauthn: Some(webauthn.clone()),
        // The metered build has a third credential. Every fixture here has none
        // but the paid-signup lane's, whose routes do not exist without it.
        #[cfg(feature = "metered")]
        monetize: monetize_addr.map(|addr| {
            let m = crate::monetize::Monetize::connect_lazy(&addr, crate::auth::signup::tests::BEARER, "gunnar")
                .expect("a lazy monetize channel");
            let m = match deadlines {
                Some(deadlines) => m.with_deadlines(deadlines),
                None => m,
            };
            let m = if provider.is_some() { m.with_provider(provider) } else { m };
            match product {
                Some(id) => m.with_product(id).expect("a product id"),
                None => m,
            }
        }),
        // See the doc comment: without this the whole suite is vacuous.
        admin_token: Some("break-glass".to_owned()),
        // Detached from gunnar's stream and published into by hand: what the
        // feed test asserts is who is SHOWN a line, not where it came from.
        events: feed.clone(),
        gunnar,
        twin: None,
        guest,
        reviewers: Arc::new(crate::reviewer::ReviewerKeys::new(
            endpoint.clone(),
            store.clone(),
        )),
        tenants: Arc::new(crate::tenant::TenantKeys::new(endpoint, store.clone())),
        forges: Default::default(),
        imports: Default::default(),
        forge_apps: Default::default(),
        ui_dir,
        caches: crate::api::Caches::default(),
        objects: Default::default(),
        // A real store, so the README route in this harness takes the same
        // cached path a live console does — and so that the second read of a
        // public README is asserted to cost no second walk of the tree.
        readmes: Arc::new(crate::readme::Cache::new(Some(store))),
    }), throttled::FRONT.with(|f| f.borrow_mut().take()));
    (router, webauthn, feed)
}

/// **The guests' pages open** where a switch holds them (GUN-GUEST): a `public-site` build
/// shows a visitor only `/` while its public site is off, so a test of the guest's pages
/// turns it on first, as an administrator would. Nothing to do in any other build.
#[cfg_attr(not(feature = "public-site"), allow(unused_variables))]
async fn guests_on(app: &axum::Router, passkeys: &crate::auth::Webauthn) {
    #[cfg(feature = "public-site")]
    {
        use tower::ServiceExt;
        let admin = passkeys.make_session("root", crate::role::Role::Admin, true);
        let put = http::Request::put("/api/public-site")
            .header(http::header::COOKIE, format!("{}={admin}", crate::auth::SESSION_COOKIE))
            .header(http::header::CONTENT_TYPE, "application/json")
            .header(http::header::ORIGIN, passkeys.origin())
            .body(axum::body::Body::from("{\"on\":true}"))
            .expect("a request");
        assert_eq!(app.clone().oneshot(put).await.expect("an answer").status(), http::StatusCode::OK);
    }
}

/// A request with **no credential of any kind**: no cookie, no bearer token.
/// This is the visitor.
async fn anon(app: &axum::Router, uri: &str) -> (http::StatusCode, String) {
    send(app, http::Method::GET, uri, None).await
}

/// The same request signed by the console's break-glass admin token, for the
/// "and an operator still sees it" half of each assertion.
async fn admin(app: &axum::Router, uri: &str) -> (http::StatusCode, String) {
    send(app, http::Method::GET, uri, Some("break-glass")).await
}

async fn send(
    app: &axum::Router,
    method: http::Method,
    uri: &str,
    token: Option<&str>,
) -> (http::StatusCode, String) {
    use tower::ServiceExt;
    let mut request = http::Request::builder().method(method).uri(uri);
    if let Some(token) = token {
        request = request.header(http::header::AUTHORIZATION, format!("Bearer {token}"));
    }
    let response = app
        .clone()
        .oneshot(request.body(axum::body::Body::empty()).expect("a request"))
        .await
        .expect("the console answers");
    let status = response.status();
    let body = axum::body::to_bytes(response.into_body(), 1 << 20)
        .await
        .expect("a readable body");
    (status, String::from_utf8_lossy(&body).into_owned())
}

/// **The same request, carrying a REAL session cookie for a person of `role`.**
///
/// Minted by the console's own passkey subsystem and presented as a browser
/// presents it, so the request crosses `require_auth`, `role_floor` and
/// `api::Reader` by the production path. Nothing here inserts a `Caller` by
/// hand: a test that did would prove the handler works once the gate has
/// already been passed, which is the assertion nobody needs.
async fn signed_in(
    app: &axum::Router,
    keys: &crate::auth::Webauthn,
    user: &str,
    role: crate::role::Role,
    uri: &str,
) -> (http::StatusCode, String) {
    use tower::ServiceExt;
    let cookie = keys.make_session(user, role, true);
    let request = http::Request::builder()
        .method(http::Method::GET)
        .uri(uri)
        .header(
            http::header::COOKIE,
            format!("{}={cookie}", crate::auth::SESSION_COOKIE),
        )
        .body(axum::body::Body::empty())
        .expect("a request");
    let response = app
        .clone()
        .oneshot(request)
        .await
        .expect("the console answers");
    let status = response.status();
    let body = axum::body::to_bytes(response.into_body(), 1 << 20)
        .await
        .expect("a readable body");
    (status, String::from_utf8_lossy(&body).into_owned())
}

/// Every read a visitor is allowed to attempt, against ONE repository.
///
/// A list rather than a test each, because what is being asserted is a property
/// of the whole surface: *no route on it leaks a private repository*. Adding a
/// route to `is_anonymous_read` and not to this list is the mistake worth
/// catching, and `the_anonymous_surface_is_exactly_this_list` below is what
/// catches it.
fn read_routes(namespace: &str, name: &str) -> Vec<String> {
    let base = format!("/api/repos/{namespace}/{name}");
    vec![
        base.clone(),
        format!("{base}/refs"),
        format!("{base}/head"),
        format!("{base}/log"),
        // History's picker and its "all branches" view (2026-10-18): the same
        // route, so the same rule — public repositories only.
        format!("{base}/log?ref=refs/heads/main"),
        format!("{base}/log?all=1"),
        format!("{base}/browse?rev=&path="),
        format!("{base}/object?oid=sec-oid"),
        format!("{base}/readme"),
        format!("{base}/raw?path=README.md"),
    ]
}

// ───────────────────────────────────────────────────────────────────────────
// The tests
// ───────────────────────────────────────────────────────────────────────────

/// ★ **RUNTIME LOGS (2026-09-30): the front's access line names WHO called.**
/// The front's :443 wraps this console in an access log (gunnar-front
/// web/serve.rs); the caller is decided by `require_auth`, so the answer
/// carries it as [`crate::auth::middleware::AccessPrincipal`] — a passkey
/// session's user, `admin-token` for the break-glass bearer — and nothing
/// when there is no caller (the front says `anonymous`). Never the bearer
/// itself. Asked of the router, not of `require_auth`'s source (stinky #22).
#[tokio::test]
async fn the_answer_names_the_caller_for_the_fronts_access_line() {
    use tower::ServiceExt;
    let (app, keys, _) = console(FakeGunnar::new(), true).await;
    let named = |credential: Option<(http::HeaderName, String)>| {
        let app = app.clone();
        async move {
            let mut request = http::Request::builder().uri("/api/repos");
            if let Some((name, value)) = credential {
                request = request.header(name, value);
            }
            let answer = app.oneshot(request.body(axum::body::Body::empty()).expect("a request")).await.expect("the console answers");
            (answer.status(), answer.extensions().get::<crate::auth::middleware::AccessPrincipal>().map(|p| p.0.clone()))
        }
    };
    let (status, who) = named(Some((http::header::AUTHORIZATION, "Bearer break-glass".to_owned()))).await;
    assert_eq!((status, who.as_deref()), (http::StatusCode::OK, Some("admin-token")));
    let cookie = keys.make_session("olle", crate::role::Role::Viewer, true);
    let (status, who) = named(Some((http::header::COOKIE, format!("{}={cookie}", crate::auth::SESSION_COOKIE)))).await;
    assert_eq!((status, who.as_deref()), (http::StatusCode::OK, Some("olle")));
    let (_, who) = named(None).await;
    assert_eq!(who, None, "a visitor with no credential is named by nobody here");
}

/// **The whole point, in one assertion: a private repository is not named on
/// the page served to people who are not logged in.**
#[tokio::test]
async fn the_login_page_lists_public_repositories_and_no_others() {
    let fake = FakeGunnar::new();
    let (app, _passkeys, _feed) = console(fake.clone(), true).await;

    let (status, body) = anon(&app, "/login/repos").await;

    assert_eq!(status, http::StatusCode::OK, "{body}");
    assert!(
        body.contains(&format!("{NS}/{PUBLIC}")),
        "the public repository must be listed: {body}"
    );
    assert!(
        !body.contains(PRIVATE),
        "a PRIVATE repository was named on the login page: {body}"
    );
    // …and it was the guest key that asked. Without this the test above is
    // green on a console that used its admin key against a gunnar that happened
    // to be asked a question with a harmless answer.
    let guest_fingerprint = signer(GUEST_SEED).fingerprint().to_owned();
    assert_eq!(
        fake.fingerprints(),
        vec![guest_fingerprint],
        "the login page must be served by the GUEST key, never the console's"
    );
}

/// **The direct read, not merely the absence from a listing.** Knowing the path
/// of a private repository must buy a stranger nothing.
#[tokio::test]
async fn a_private_repository_is_refused_on_every_anonymous_read_route() {
    let (app, _passkeys, _feed) = console(FakeGunnar::new(), true).await;

    for route in read_routes(NS, PRIVATE) {
        let (status, body) = anon(&app, &route).await;
        // 404, not 403, and the one body `api::absent` answers for a name that
        // is not there: a private repository must be indistinguishable from
        // none (see `an_unknown_namespace_is_404_and_a_private_one_is_the_same_404`).
        assert_eq!(
            status,
            http::StatusCode::NOT_FOUND,
            "{route} answered {status} instead of refusing: {body}"
        );
        assert_eq!(body, crate::api::absent::body().to_string(), "{route}");
        assert!(
            !body.contains(std::str::from_utf8(SECRET_BYTES).expect("utf8")),
            "{route} leaked the private repository's contents: {body}"
        );
    }
}

/// The same routes on a PUBLIC repository are served — otherwise the test above
/// would pass on a console that refused everything, which is not the feature.
#[tokio::test]
async fn a_public_repository_is_readable_with_no_session() {
    let fake = FakeGunnar::new();
    let (app, _passkeys, _feed) = console(fake.clone(), true).await;

    for route in read_routes(NS, PUBLIC) {
        let (status, body) = anon(&app, &route).await;
        // `object?oid=sec-oid` names an object this repository does not hold,
        // so it is a 404 here rather than a 200 — which is exactly right, and
        // is a different answer from the 403 the private repository gives.
        assert!(
            status == http::StatusCode::OK || status == http::StatusCode::NOT_FOUND,
            "{route} was refused for a PUBLIC repository: {status} {body}"
        );
    }

    // Every call reached gunnar as the guest, and not one as the console.
    let guest = signer(GUEST_SEED).fingerprint().to_owned();
    let console_key = signer(CONSOLE_SEED).fingerprint().to_owned();
    let seen = fake.fingerprints();
    assert!(!seen.is_empty(), "no call reached gunnar at all");
    assert!(
        seen.iter().all(|f| *f == guest),
        "an anonymous read used a key other than the guest's: {seen:?} (the console's is \
         {console_key})"
    );
}

/// **The catalogue an anonymous visitor gets is the narrowed one, and it does
/// not come out of the shared cache.**
///
/// The cache is the subtle half. `Caches::repos` holds one value for the whole
/// server with no key for who asked; a guest reading it would be handed the
/// admin's answer without a gRPC call being made at all. So this warms it as
/// the admin first — which is the ordering that would actually happen on a
/// live console, where an operator is logged in somewhere — and then asserts
/// the visitor still gets the narrow answer.
#[tokio::test]
async fn an_anonymous_catalogue_never_comes_out_of_the_admin_cache() {
    let fake = FakeGunnar::new();
    let (app, _passkeys, _feed) = console(fake.clone(), true).await;

    let (status, admin_body) = admin(&app, "/api/repos").await;
    assert_eq!(status, http::StatusCode::OK, "{admin_body}");
    assert!(
        admin_body.contains(PRIVATE),
        "an admin must still see private repositories: {admin_body}"
    );

    let (status, anon_body) = anon(&app, "/api/repos").await;
    assert_eq!(status, http::StatusCode::OK, "{anon_body}");
    assert!(
        anon_body.contains(PUBLIC),
        "the public repository must be listed: {anon_body}"
    );
    assert!(
        !anon_body.contains(PRIVATE),
        "the visitor was served the ADMIN's cached catalogue: {anon_body}"
    );
}

/// ★ **A logged-in VIEWER reads with the guest key, and never with the
/// console's.**
///
/// The hole this module's own doc warned about, one step up from the anonymous
/// path: `api::Reader` used to hand `App::gunnar` — the server-wide admin key —
/// to *any* request that carried a `Caller`, whatever its role, and every GET
/// is floored at `Role::Viewer` whichever namespace the path names. So the
/// lowest rung the console mints, the one a paid signup hands out, read every
/// private repository on the box.
///
/// Seen red before the fix, on this harness: the six private read routes
/// answered **200** to `viewer-vera`, the body carried `SECRET_BYTES`, and the
/// fingerprint log showed the CONSOLE's key. Asserted the way the anonymous
/// tests are — on which key reached gunnar, not on the status code — because a
/// permissive fake would answer a viewer the same either way.
///
/// The operator at the end is the control that keeps the rest honest: this must
/// be a narrowing of the tenant role, not a console that refuses everybody.
///
/// Since the tenant credential, this is the case where the console cannot name
/// the caller at gunnar: `viewer-vera`'s passkey is bound to no principal, so
/// there is no credential that would be hers and the guest is the honest
/// answer. A BOUND viewer is
/// `a_tenants_read_is_signed_by_their_own_key_and_shows_them_their_own_repo`,
/// and the two together are the whole of what `api::Reader` decides.
#[tokio::test]
async fn a_viewers_session_reads_with_the_guest_key_and_never_the_consoles() {
    use crate::role::Role;

    let fake = FakeGunnar::new();
    let (app, keys, _feed) = console(fake.clone(), true).await;
    let console_key = signer(CONSOLE_SEED).fingerprint().to_owned();
    let guest = signer(GUEST_SEED).fingerprint().to_owned();

    // Warm the shared catalogue cache as an admin first, which is the ordering
    // a live console really has — somebody is logged in somewhere — and which
    // is what makes the `/api/repos` assertion below about the cache as well as
    // about the channel.
    let (status, body) = admin(&app, "/api/repos").await;
    assert_eq!(status, http::StatusCode::OK, "{body}");
    assert!(body.contains(PRIVATE), "an admin still sees it all: {body}");

    let before = fake.fingerprints().len();
    for route in read_routes(NS, PRIVATE) {
        let (status, body) = signed_in(&app, &keys, "viewer-vera", Role::Viewer, &route).await;
        assert_eq!(
            status,
            http::StatusCode::NOT_FOUND,
            "{route} answered a VIEWER {status} about a private repository: {body}"
        );
        assert!(
            !body.contains(std::str::from_utf8(SECRET_BYTES).expect("utf8")),
            "{route} leaked the private repository to a viewer: {body}"
        );
    }

    let (status, body) = signed_in(&app, &keys, "viewer-vera", Role::Viewer, "/api/repos").await;
    assert_eq!(status, http::StatusCode::OK, "{body}");
    assert!(body.contains(PUBLIC), "{body}");
    assert!(
        !body.contains(PRIVATE),
        "the viewer was served the ADMIN's cached catalogue: {body}"
    );

    let seen: Vec<String> = fake.fingerprints().split_off(before);
    assert!(!seen.is_empty(), "no call reached gunnar at all");
    assert!(
        seen.iter().all(|f| *f == guest),
        "a viewer's read was signed with a key other than the guest's: {seen:?} (the console's \
         is {console_key})"
    );

    // The control. An operator asks for the same private repository and gets
    // it, with the console's key — so the refusals above are a narrowing of the
    // tenant role and not a console that has stopped answering.
    let (status, body) = signed_in(
        &app,
        &keys,
        "operator-olof",
        Role::Operator,
        &format!("/api/repos/{NS}/{PRIVATE}"),
    )
    .await;
    assert_eq!(
        status,
        http::StatusCode::OK,
        "an operator must still read a private repository: {body}"
    );
    assert!(
        fake.fingerprints().contains(&console_key),
        "the operator's read did not use the console's key"
    );
}

/// ★ **A tenant's read is signed by the TENANT's own key — not the guest's, not
/// the console's — and shows that tenant their own private repository.**
///
/// The consequence of the commit above, and the reason it could not ship on its
/// own: answering a viewer with the grantless guest key stopped the leak and
/// took the paying tenant's own repositories with it. A console that cannot
/// show somebody what they are paying for is not a fixed console.
///
/// So the third credential. The console mints an ed25519 key per console user,
/// enrols it on THAT person's gunnar principal with `Access.AddKey` — which is
/// what its server-wide Admin is for — and signs that session's reads with it.
/// gunnar then applies the tenant's own grants, on gunnar's side of the wire,
/// where a mistake in this crate cannot reach them.
///
/// Every assertion here is about WHICH KEY signed, because that is the only
/// question a permissive fake cannot answer by accident:
///
/// * `vera` reads `vera/ledger` — **private** — and the fingerprint log for
///   that request holds her key and no other. Not the guest's, which would see
///   nothing; not the console's, which would see everything and is the hole
///   this whole branch exists to close.
/// * `viggo`, the same role on the same console, is refused the same
///   repository. The refusal is gunnar's: it is answering a different
///   principal, and the fingerprint proves the console asked as him.
/// * `vera` is still refused `nordisk/payroll`, which is nobody's account
///   namespace but the console's business. A tenant credential that read the
///   whole box would be the old hole wearing a new key.
///
/// Red before the tenant credential: `vera`'s read of her own ledger was
/// answered 403 — the guest key, signed by a principal with no grants — and
/// `fake.key_of_principal("vera")` was `None`, because the console had never
/// enrolled anything for her.
#[tokio::test]
async fn a_tenants_read_is_signed_by_their_own_key_and_shows_them_their_own_repo() {
    use crate::role::Role;

    let fake = FakeGunnar::new();
    let (app, keys, _feed) = console(fake.clone(), true).await;
    let guest = signer(GUEST_SEED).fingerprint().to_owned();
    let console_key = signer(CONSOLE_SEED).fingerprint().to_owned();
    // Bound, which is what registration does now: the passkey carries the id
    // of the principal it acts for, and nothing resolves a name afterwards.
    keys.plant_bound_credential_for_tests(TENANT, Role::Viewer, TENANT);
    keys.plant_bound_credential_for_tests(OTHER_TENANT, Role::Viewer, OTHER_TENANT);

    let before = fake.fingerprints().len();
    let (status, body) = signed_in(
        &app,
        &keys,
        TENANT,
        Role::Viewer,
        &format!("/api/repos/{TENANT}/{TENANT_REPO}"),
    )
    .await;
    assert_eq!(
        status,
        http::StatusCode::OK,
        "a paying tenant was refused their own private repository: {body}"
    );

    let tenant_key = fake
        .key_of_principal(TENANT)
        .expect("the console never enrolled a key for the tenant at all");
    assert_ne!(tenant_key, guest, "the tenant's key IS the guest's");
    assert_ne!(tenant_key, console_key, "the tenant's key IS the console's");

    let seen: Vec<String> = fake.fingerprints().split_off(before);
    assert!(!seen.is_empty(), "no call reached gunnar at all");
    assert!(
        seen.iter().all(|f| *f == tenant_key || *f == console_key),
        "a tenant's read was signed by a key that is neither theirs nor the \
         console's administration of it: {seen:?}"
    );
    assert!(
        !seen.contains(&guest),
        "a tenant's read was signed by the grantless guest, which is what left \
         them unable to see what they pay for: {seen:?}"
    );
    // **And it is signed the way every other credential this console makes is.**
    // A per-person key is the last place a method-blind credential may survive:
    // it is the one gunnar answers differently, so a credential of its that
    // named no method could be replayed from one RPC onto another.
    assert!(
        fake.schemes()
            .iter()
            .all(|scheme| scheme == crate::signer::CREDENTIAL_SCHEME),
        "a call arrived under a credential scheme that is not the method-bound one: {:?}",
        fake.schemes()
    );
    // The console's admin key may appear here and only for one reason: the
    // enrolment itself. It must never be what a repository was READ with.
    let read_calls: Vec<&String> = seen.iter().filter(|f| **f == console_key).collect();
    assert!(
        read_calls.len() <= 3,
        "the console's admin key signed {} calls for one tenant read; it is \
         supposed to sign the provisioning and nothing else: {seen:?}",
        read_calls.len()
    );

    // The other tenant, same role, same console, same repository.
    let before = fake.fingerprints().len();
    let (status, body) = signed_in(
        &app,
        &keys,
        OTHER_TENANT,
        Role::Viewer,
        &format!("/api/repos/{TENANT}/{TENANT_REPO}"),
    )
    .await;
    assert_eq!(
        status,
        http::StatusCode::NOT_FOUND,
        "one tenant read another tenant's private repository: {body}"
    );
    assert!(
        !body.contains(std::str::from_utf8(LEDGER_BYTES).expect("utf8")),
        "the ledger leaked to the wrong tenant: {body}"
    );
    let other_key = fake
        .key_of_principal(OTHER_TENANT)
        .expect("the console never enrolled a key for the other tenant");
    assert_ne!(
        other_key, tenant_key,
        "both tenants were signed with ONE key, so the refusal above was luck"
    );
    let seen: Vec<String> = fake.fingerprints().split_off(before);
    assert!(
        seen.contains(&other_key),
        "the refused read was not signed as the tenant it was refused for: {seen:?}"
    );

    // And a tenant credential is not a console credential: the namespace that
    // belongs to neither of them is still closed.
    let (status, body) = signed_in(
        &app,
        &keys,
        TENANT,
        Role::Viewer,
        &format!("/api/repos/{NS}/{PRIVATE}"),
    )
    .await;
    assert_eq!(
        status,
        http::StatusCode::NOT_FOUND,
        "a tenant key read a private repository outside their own namespace: {body}"
    );
    assert!(
        !body.contains(std::str::from_utf8(SECRET_BYTES).expect("utf8")),
        "a tenant key leaked the server's private repository: {body}"
    );
}

/// ★ **A passkey bound to a gunnar principal keeps acting for THAT principal,
/// whatever the console user happens to be called.**
///
/// GUI-001's durable half. The binding session -> principal was
/// `.find(|p| p.name == user)` — a string comparison against a name the
/// registrant chose, redone on every call — so whichever principal came to hold
/// that name became the identity the session acted for, at any later time, with
/// gunnar unable to object because the caller was the console and the console
/// is Admin.
///
/// Here the console user is called `vera`, gunnar holds a principal called
/// `vera`, and the two are **not** the same identity: the passkey was pinned at
/// registration to `viggo`. A console that still resolved by name would read
/// `vera/ledger` and this test would say so. What it must do instead is read
/// `viggo/diary` — the principal it was bound to — and be refused the namespace
/// whose name it shares.
///
/// Red before `StoredCred::principal_id`: there was no pin to disagree with,
/// `vera` read `vera/ledger`, and the first assertion below failed with a 200.
#[tokio::test]
async fn a_passkey_acts_for_the_principal_it_was_bound_to_and_not_for_its_namesake() {
    use crate::role::Role;

    let fake = FakeGunnar::new();
    let (app, keys, _feed) = console(fake.clone(), true).await;
    keys.plant_bound_credential_for_tests(TENANT, Role::Viewer, OTHER_TENANT);

    let (status, body) = signed_in(
        &app,
        &keys,
        TENANT,
        Role::Viewer,
        &format!("/api/repos/{TENANT}/{TENANT_REPO}"),
    )
    .await;
    assert_eq!(
        status,
        http::StatusCode::NOT_FOUND,
        "a session acted for the principal that merely SHARES its name: {body}"
    );
    assert!(
        !body.contains(std::str::from_utf8(LEDGER_BYTES).expect("utf8")),
        "the namesake's ledger was served: {body}"
    );

    let (status, body) = signed_in(
        &app,
        &keys,
        TENANT,
        Role::Viewer,
        &format!("/api/repos/{OTHER_TENANT}/diary"),
    )
    .await;
    assert_eq!(
        status,
        http::StatusCode::OK,
        "a session did not act for the principal it was BOUND to: {body}"
    );
    // And the key that read it is enrolled on the bound principal, which is
    // what makes the 200 above evidence rather than a coincidence.
    assert!(
        fake.key_of_principal(OTHER_TENANT).is_some(),
        "nothing was enrolled on the bound principal"
    );
    assert!(
        fake.key_of_principal(TENANT).is_none(),
        "the console enrolled a key on the namesake principal after all"
    );
}

/// ★ **The live feed shows a viewer the repositories they may see, and not the
/// whole server's.**
///
/// The pump holds one unfiltered subscription on the console's admin key — the
/// comment beside it says so: *"Everything, unfiltered: the console filters in
/// the browser."* Filtering in the browser is not a permission check; the bytes
/// were already on the wire. `<namespace>/<repo>` alone tells a viewer which
/// private repositories exist and when each tenant last pushed, and the
/// summaries carry principal ids, pull-request titles and ref names.
///
/// Red before the per-subscriber narrowing: the viewer's stream carried the
/// PRIVATE repository's line verbatim, `payroll` and all. Red again before
/// 2026-10-02: an OPERATOR's stream carried it too (the console's own key, so
/// nothing was narrowed). The admin at the end is the control — narrowing a
/// feed until it says nothing would pass the first assertion and break the
/// console. The backlog and the live tail go through the same `may_see`, and
/// `the_backlog_a_non_admin_is_handed_is_narrowed_too` holds the first.
#[tokio::test]
async fn the_live_feed_shows_a_viewer_only_what_that_viewer_may_read() {
    use crate::role::Role;

    let fake = FakeGunnar::new();
    let (app, keys, feed) = console(fake.clone(), true).await;
    let line = |repo: &str, summary: &str| crate::sse::FeedItem {
        seq: 1,
        at_unix_ms: 1,
        kind: "ref_updated".to_owned(),
        repo: Some(format!("{NS}/{repo}")),
        summary: summary.to_owned(),
        dropped: None,
    };

    // The private line goes out FIRST, so "the public one arrived" cannot be
    // green while the private one is still queued ahead of it.
    let private = "refs/heads/salaries moved to 0123456789";
    let public = "refs/heads/main moved to abcdef0123";

    // **Only an administrator's feed is the whole server's** (owner,
    // 2026-10-02: the Overview's "latest events" showed pushes to private
    // repositories to people who cannot read them). An operator is narrowed
    // like a viewer — to what THEIR OWN credential reads — and the admin at the
    // end is the control.
    // Since the owner's final navigation (2026-10-02, "no feed reachable by a
    // non-admin may carry another account's events"), a session below admin
    // is not told even about ANOTHER account's PUBLIC repository: `nordisk` is
    // none of these three people's account. Their own account's lines are
    // `an_accounts_feed_carries_its_own_repositories_and_no_other_accounts`.
    for (user, role, may_see_private) in [
        ("viewer-vera", Role::Viewer, false),
        ("operator-olof", Role::Operator, false),
        ("admin-astrid", Role::Admin, true),
    ] {
        let heard = feed_lines(&app, &keys, user, role, || {
            // The administrator's feed is the console's shared pump; everybody
            // else's is their own `Events.Watch` at gunnar. Both carry the
            // same two pushes.
            feed.publish(line(PRIVATE, private));
            feed.publish(line(PUBLIC, public));
            fake.emit(NS, PRIVATE, "refs/heads/salaries", "0123456789abcdef");
            fake.emit(NS, PUBLIC, "refs/heads/main", "abcdef0123456789");
        })
        .await;

        assert!(heard.contains("connected"), "{user}'s feed never opened: {heard:?}");
        assert_eq!(
            heard.contains(public),
            may_see_private,
            "{user}'s feed and another account's PUBLIC repository: {heard:?}"
        );
        assert_eq!(
            heard.contains(private),
            may_see_private,
            "{user}'s feed carried {PRIVATE}: {heard:?}"
        );
        assert_eq!(
            heard.contains(PRIVATE),
            may_see_private,
            "{user}'s feed named a repository they may not read: {heard:?}"
        );
    }
    // ★ **Below the administrator, the feed is asked of gunnar as the person**
    // (thin layer, owner 2026-10-04) — here the guest's key, as these two
    // sessions are bound to no principal — with no namespaces named, so gunnar's
    // "mine" decides. Never one console-keyed stream filtered here.
    let watches = fake.watches.lock().expect("the watch log").clone();
    assert_eq!(
        watches,
        vec!["guest namespaces=[]".to_owned(), "guest namespaces=[]".to_owned()],
        "who asked gunnar for a feed: {watches:?}"
    );
}

/// ★ **The console's backlog is the administrator's** (owner, 2026-10-02; thin
/// layer 2026-10-04). A non-admin connecting AFTER a push to a private
/// repository is not handed the console's shared backlog at all — their recent
/// history is gunnar's replay of their OWN watch; the admin is handed it.
#[tokio::test]
async fn the_backlog_a_non_admin_is_handed_is_narrowed_too() {
    use crate::role::Role;

    let fake = FakeGunnar::new();
    let (app, keys, feed) = console(fake.clone(), true).await;
    let line = |repo: &str, summary: &str| crate::sse::FeedItem {
        seq: 1,
        at_unix_ms: 1,
        kind: "ref_updated".to_owned(),
        repo: Some(format!("{NS}/{repo}")),
        summary: summary.to_owned(),
        dropped: None,
    };
    let private = "refs/heads/bonus moved to 9876543210";
    let public = "refs/heads/docs moved to fedcba9876";
    // Published BEFORE anybody connects: this is the backlog.
    feed.publish(line(PRIVATE, private));
    feed.publish(line(PUBLIC, public));
    for (user, role, may_see_private) in [
        ("viewer-vera", Role::Viewer, false),
        ("operator-olof", Role::Operator, false),
        ("admin-astrid", Role::Admin, true),
    ] {
        let heard = feed_lines(&app, &keys, user, role, || {}).await;
        assert!(heard.contains("connected"), "{user}'s feed never opened: {heard:?}");
        assert_eq!(heard.contains(public), may_see_private, "{user}'s backlog and another account's public repository: {heard:?}");
        assert_eq!(heard.contains(private) || heard.contains(PRIVATE), may_see_private, "{user}'s backlog: {heard:?}");
    }
}

/// ★ **An account's feed carries its own repositories and no other
/// account's** — and since 2026-10-04 that is gunnar's answer to vera's own
/// `Events.Watch` (owner, 2026-10-02, the final navigation: events by context —
/// a repository's on its Activity tab, the account's under You, the whole
/// server's only under Administration → Overview). vera, bound to her own
/// principal, hears `vera/ledger` and neither `nordisk/gunnar` (another
/// account's PUBLIC repository) nor `nordisk/payroll`; `?repo=` narrows any
/// feed to one repository, and never widens a non-admin's; the admin hears
/// everything, and is the control.
#[tokio::test]
async fn an_accounts_feed_carries_its_own_repositories_and_no_other_accounts() {
    use crate::role::Role;

    let fake = FakeGunnar::new();
    let (app, keys, feed) = console(fake.clone(), true).await;
    keys.plant_bound_credential_for_tests(TENANT, Role::Viewer, TENANT);
    let line = |path: String, summary: &str| crate::sse::FeedItem {
        seq: 1,
        at_unix_ms: 1,
        kind: "ref_updated".to_owned(),
        repo: Some(path),
        summary: summary.to_owned(),
        dropped: None,
    };
    let own = "refs/heads/main moved to 1111111111";
    let others_public = "refs/heads/main moved to 2222222222";
    let others_private = "refs/heads/main moved to 3333333333";
    feed.publish(line(format!("{NS}/{PUBLIC}"), others_public));
    feed.publish(line(format!("{NS}/{PRIVATE}"), others_private));
    feed.publish(line(format!("{TENANT}/{TENANT_REPO}"), own));
    // What gunnar's bus carries while vera watches: the same three pushes.
    let pushes = || {
        fake.emit(NS, PUBLIC, "refs/heads/main", "2222222222ffff");
        fake.emit(NS, PRIVATE, "refs/heads/main", "3333333333ffff");
        fake.emit(TENANT, TENANT_REPO, "refs/heads/main", "1111111111ffff");
    };

    let mine = feed_lines_at(&app, &keys, TENANT, Role::Viewer, "/api/events", own, pushes).await;
    assert!(mine.contains(own), "vera was not told about her own repository: {mine:?}");
    assert!(!mine.contains(others_public) && !mine.contains(&format!("{NS}/{PUBLIC}")), "vera was told about another account's public repository: {mine:?}");
    assert!(!mine.contains(others_private), "vera was told about another account's private repository: {mine:?}");
    // ★ Asked of gunnar with HER OWN key and no namespaces: gunnar's "mine".
    let her = fake.key_of_principal(TENANT).expect("the console enrolled vera's key");
    assert!(!her.is_empty());
    assert_eq!(
        fake.watches.lock().expect("the watch log").clone(),
        vec![format!("{TENANT} namespaces=[]")],
        "vera's feed was not her own watch"
    );

    let tab = feed_lines_at(&app, &keys, TENANT, Role::Viewer, &format!("/api/events?repo={TENANT}/{TENANT_REPO}"), own, pushes).await;
    assert!(tab.contains(own), "her repository's Activity tab is empty: {tab:?}");
    let wider = feed_lines_at(&app, &keys, TENANT, Role::Viewer, &format!("/api/events?repo={NS}/{PUBLIC}"), others_public, pushes).await;
    assert!(!wider.contains(others_public), "?repo= widened a non-admin's feed to another account: {wider:?}");

    let all = feed_lines_at(&app, &keys, "admin-astrid", Role::Admin, "/api/events", own, || {}).await;
    assert!(all.contains(own) && all.contains(others_public) && all.contains(others_private), "the admin's feed is not the whole server's: {all:?}");
    let one = feed_lines_at(&app, &keys, "admin-astrid", Role::Admin, &format!("/api/events?repo={NS}/{PRIVATE}"), others_private, || {}).await;
    assert!(one.contains(others_private) && !one.contains(own) && !one.contains(others_public), "?repo= did not narrow the admin's feed to one repository: {one:?}");
}

/// ★ **One session cannot hold the console's whole fan-out open.**
///
/// Every live feed pins a `broadcast::Receiver`, and a receiver that is not
/// read holds its place in a ring of `FANOUT_CAPACITY` items until it is
/// dropped. Nothing counted them: not per session and not in total, so one
/// logged-in viewer with a loop that opens `/api/events` and never reads it
/// could hold as many as they liked, and every one of them made the fan-out a
/// little slower for everybody else.
///
/// The cap is per SESSION, which is the half this asserts: the ninth feed for
/// one cookie is refused with a 429 that says to close a tab, a DIFFERENT
/// session is admitted at the same moment — so this is a bucket and not a
/// global ceiling wearing one — and closing one connection gives the place
/// back rather than burning it.
///
/// Red before the census: the ninth, the ninetieth and the nine-hundredth were
/// all 200, and `live_feeds()` did not exist to count them.
#[tokio::test]
async fn one_session_may_not_hold_the_whole_fan_out_open() {
    use crate::role::Role;

    let fake = FakeGunnar::new();
    let (app, keys, feed) = console(fake.clone(), true).await;
    let cap = crate::sse::PER_SESSION_FEEDS;

    // Held, not dropped: a response whose body is still alive is a connection
    // that is still open, which is exactly what the census counts.
    let mine = keys.make_session("operator-olof", Role::Operator, true);
    let mut open = Vec::new();
    for nth in 1..=cap {
        let response = feed_response(&app, &mine).await;
        assert_eq!(
            response.status(),
            http::StatusCode::OK,
            "feed {nth} of {cap} was refused before the cap was reached"
        );
        open.push(response);
    }
    assert_eq!(feed.live_feeds(), cap, "the census did not count them");

    let refused = feed_response(&app, &mine).await;
    assert_eq!(
        refused.status(),
        http::StatusCode::TOO_MANY_REQUESTS,
        "a session opened feed {} of {cap}",
        cap + 1
    );
    assert_eq!(
        refused
            .headers()
            .get(http::header::RETRY_AFTER)
            .and_then(|v| v.to_str().ok()),
        Some("5"),
        "a refusal that clears on its own must say so, or a client reads it as never"
    );

    // A different session, at the same moment: the cap is a bucket per session
    // and not one ceiling for the console.
    let theirs = keys.make_session("viewer-vera", Role::Viewer, true);
    let other = feed_response(&app, &theirs).await;
    assert_eq!(
        other.status(),
        http::StatusCode::OK,
        "one session's tabs refused another session's first feed"
    );
    drop(other);

    // And a place given back is a place usable again.
    open.pop();
    // The guard is dropped with the response body, which happens on the task
    // that owns it; one yield is enough for that to have run.
    tokio::task::yield_now().await;
    let again = feed_response(&app, &mine).await;
    assert_eq!(
        again.status(),
        http::StatusCode::OK,
        "closing a feed did not give its place back"
    );
}

/// One `GET /api/events` as the holder of `cookie`, response not consumed.
async fn feed_response(app: &axum::Router, cookie: &str) -> http::Response<axum::body::Body> {
    use tower::ServiceExt;
    let request = http::Request::get("/api/events")
        .header(
            http::header::COOKIE,
            format!("{}={cookie}", crate::auth::SESSION_COOKIE),
        )
        .body(axum::body::Body::empty())
        .expect("a request");
    app.clone()
        .oneshot(request)
        .await
        .expect("the console answers")
}

/// Open the feed as `user`, publish with `emit`, and return what the stream
/// actually sent.
///
/// The subscription is taken when the handler runs, which is before this
/// returns, so items published afterwards are in the channel rather than lost.
/// Reading stops at the first quiet moment: an SSE stream never ends on its
/// own, and the thing being asserted is what did NOT arrive.
async fn feed_lines(
    app: &axum::Router,
    keys: &crate::auth::Webauthn,
    user: &str,
    role: crate::role::Role,
    emit: impl FnOnce(),
) -> String {
    feed_lines_at(app, keys, user, role, "/api/events", "abcdef0123", emit).await
}

/// [`feed_lines`] at any feed address (`/api/events?repo=…`), reading until
/// `until` has been heard or the stream goes quiet.
async fn feed_lines_at(
    app: &axum::Router,
    keys: &crate::auth::Webauthn,
    user: &str,
    role: crate::role::Role,
    uri: &str,
    until: &str,
    emit: impl FnOnce(),
) -> String {
    use futures_util::StreamExt as _;
    use tower::ServiceExt;

    let cookie = keys.make_session(user, role, true);
    let request = http::Request::get(uri)
        .header(
            http::header::COOKIE,
            format!("{}={cookie}", crate::auth::SESSION_COOKIE),
        )
        .body(axum::body::Body::empty())
        .expect("a request");
    let response = app
        .clone()
        .oneshot(request)
        .await
        .expect("the console answers");
    assert_eq!(
        response.status(),
        http::StatusCode::OK,
        "the feed refused {user}"
    );

    emit();

    let mut body = response.into_body().into_data_stream();
    let mut heard = String::new();
    // Generous on purpose, and it costs nothing to be: the loop below leaves as
    // soon as the last line this session is entitled to has arrived, so the
    // wait is only ever paid by a stream that is genuinely missing something.
    // At 750ms it was paid by a BUSY MACHINE instead — the viewer's narrowing
    // costs one `Repos.List` round trip before the first event can be judged,
    // and under load that alone outran the budget about one run in five, with
    // the failure reading "shown nothing at all".
    while let Ok(Some(Ok(chunk))) =
        tokio::time::timeout(std::time::Duration::from_secs(10), body.next()).await
    {
        heard.push_str(&String::from_utf8_lossy(&chunk));
        // Both lines have been published by now, so the moment the last one
        // this session is entitled to has arrived there is nothing more to wait
        // for.
        if heard.contains(until) {
            break;
        }
    }
    heard
}

/// ★ **One anonymous GET cannot be turned into an unbounded number of walks of
/// gunnar's history.**
///
/// `blame` is on `is_anonymous_read`, and it folded `Refs.Blame` with one
/// `Admin.VerifyChain` per DISTINCT commit in the file. The bound was the
/// sentence "a file has few distinct commits" — an assumption about other
/// people's repositories, in a comment, on a route that needs no session. The
/// file is the caller's to choose, so the factor was theirs to choose: one
/// cheap GET against the longest-lived file in a public repository, and gunnar
/// walks its history N times, each walk with its own budget.
///
/// Red before the ceiling: this request made 500 `Admin.VerifyChain` calls, one
/// per commit in the fixture, and would have made a million for a file with a
/// million. The second half is the control that keeps the first honest — an
/// ordinary file is still fully verified and not marked truncated, so this is a
/// ceiling rather than a console that stopped proving anything.
#[tokio::test]
async fn an_anonymous_blame_cannot_be_amplified_into_unbounded_backend_calls() {
    let fake = FakeGunnar::new();
    let (app, _passkeys, _feed) = console(fake.clone(), true).await;
    let ceiling = crate::api::blame::MAX_VERIFIED_COMMITS;

    let (status, body) = anon(
        &app,
        &format!("/api/repos/{NS}/{PUBLIC}/blame?path={CROWDED_FILE}"),
    )
    .await;

    assert_eq!(status, http::StatusCode::OK, "{body}");
    let walks = fake.verifications.load(Ordering::SeqCst);
    assert!(
        walks <= ceiling,
        "one anonymous GET cost gunnar {walks} VerifyChain walks for a file with \
         {CROWDED_FILE_COMMITS} distinct commits"
    );
    assert!(
        body.contains("\"truncated\":true"),
        "an answer that stopped short must say so: {}",
        &body[body.len().saturating_sub(200)..]
    );
    // …and the count it reports is the number of walks it really made. Not
    // pinned to the ceiling: the clock is the other half of the bound, and on a
    // loaded machine the five-second budget can be what stops the loop. Either
    // way the answer says how much of it was proven.
    assert!(walks > 0, "nothing was verified at all");
    assert!(
        body.contains(&format!("\"verified\":{walks}")),
        "the answer must say how much of it was proven: {}",
        &body[body.len().saturating_sub(200)..]
    );
    // Every line is still attributed and served; the ceiling costs the proof,
    // not the blame.
    assert!(
        body.contains("line 0") && body.contains("line 499"),
        "{body}"
    );

    // The control: an ordinary file is verified all the way through.
    let before = fake.verifications.load(Ordering::SeqCst);
    let (status, body) = anon(
        &app,
        &format!("/api/repos/{NS}/{PUBLIC}/blame?path=small.rs"),
    )
    .await;
    assert_eq!(status, http::StatusCode::OK, "{body}");
    assert_eq!(fake.verifications.load(Ordering::SeqCst) - before, 3);
    assert!(body.contains("\"truncated\":false"), "{body}");
    assert!(body.contains("\"signature\":\"proven\""), "{body}");
}

/// ★ **A misconfigured guest key does not turn `/api/repos` into a public index
/// of every private repository on the box.**
///
/// `auth::routes::public_repos` has filtered the login page's list on
/// visibility since the guest identity existed, with a comment saying why: one
/// `==` against a deployment mistake, where somebody points
/// `GUNNAR_UI_GUEST_IDENTITY` at a key that holds a grant — the console's own,
/// copied because it was to hand. gunnar then answers correctly for the
/// principal it was asked about, which is everything.
///
/// `/api/repos` is the same list, on the same credential, to the same visitor,
/// and it carried no such filter. This drives the mistake: the guest channel is
/// signed with the CONSOLE's key, so the fake gunnar hands back the whole
/// catalogue, and the console must still print only what is public.
///
/// Red before: the visitor's `/api/repos` named `payroll`. The fingerprint
/// assertion is what keeps the test honest — it proves gunnar really did answer
/// the wide list, rather than the fixture quietly doing the filtering.
#[tokio::test]
async fn a_guest_key_that_was_given_a_grant_still_lists_only_public_repositories() {
    let fake = FakeGunnar::new();
    // THE MISTAKE: the guest identity is the console's own admin key.
    let (app, _passkeys, _feed) = console_with(fake.clone(), Some(CONSOLE_SEED), None).await;

    let (status, body) = anon(&app, "/api/repos").await;

    assert_eq!(status, http::StatusCode::OK, "{body}");
    assert!(
        body.contains(PUBLIC),
        "the public repository is still listed"
    );
    assert!(
        !body.contains(PRIVATE),
        "a misconfigured guest key made /api/repos a public index of private \
         repositories: {body}"
    );
    // And gunnar really was asked as the console, so the row was there to be
    // printed and this console chose not to.
    assert_eq!(
        fake.fingerprints(),
        vec![signer(CONSOLE_SEED).fingerprint().to_owned()],
        "the fixture did not exercise the misconfiguration at all"
    );

    // The login page's own list has always had this wall; asserted here beside
    // the new one so the two cannot drift apart.
    let (status, body) = anon(&app, "/login/repos").await;
    assert_eq!(status, http::StatusCode::OK, "{body}");
    assert!(!body.contains(PRIVATE), "{body}");
}

/// **With no guest identity there is no anonymous surface**, and in particular
/// no fallback to the console's key.
///
/// The fallback is the whole hazard: a console that answered anonymous traffic
/// with its own credential "because the guest key was missing" would fail open
/// on a misconfiguration, which is the failure mode that never gets noticed
/// because everything looks like it is working.
#[tokio::test]
async fn without_a_guest_identity_nothing_is_served_anonymously() {
    let fake = FakeGunnar::new();
    let (app, _passkeys, _feed) = console(fake.clone(), false).await;

    let (status, body) = anon(&app, "/login/repos").await;
    assert_eq!(status, http::StatusCode::OK, "{body}");
    assert_eq!(
        body.trim(),
        "[]",
        "with no guest identity the login page must list nothing: {body}"
    );

    for route in read_routes(NS, PUBLIC) {
        let (status, body) = anon(&app, &route).await;
        assert_eq!(
            status,
            http::StatusCode::UNAUTHORIZED,
            "{route} was served without a guest identity: {status} {body}"
        );
    }

    assert!(
        fake.fingerprints().is_empty(),
        "a call reached gunnar for an anonymous request with no guest identity: {:?}",
        fake.fingerprints()
    );
}

/// **Mutations stay shut.** The read allow-list is method-scoped, so this is a
/// property of one `matches!` — which is exactly why it is worth pinning: the
/// day somebody widens that match, this is what says so.
#[tokio::test]
async fn a_visitor_cannot_write_anything() {
    let (app, _passkeys, _feed) = console(FakeGunnar::new(), true).await;

    let attempts = [
        (http::Method::POST, "/api/repos".to_owned()),
        (http::Method::PATCH, format!("/api/repos/{NS}/{PUBLIC}")),
        (http::Method::DELETE, format!("/api/repos/{NS}/{PUBLIC}")),
        (http::Method::POST, format!("/api/repos/{NS}/{PUBLIC}/gc")),
        (
            http::Method::POST,
            format!("/api/repos/{NS}/{PUBLIC}/issues"),
        ),
        (http::Method::POST, "/api/grants".to_owned()),
        (http::Method::POST, "/api/principals".to_owned()),
        // **The one mutating surface a VIEWER may reach**, and a visitor is
        // not a viewer. `/api/account/**` is floored at `Role::Viewer` so a
        // tenant can add their own key (`api::account`), and the floor is
        // reached only by a request that HAS a role — a caller with no session
        // has none. Listed here so that lowering the floor cannot be mistaken
        // for opening the door.
        (http::Method::POST, "/api/account/keys".to_owned()),
        (
            http::Method::DELETE,
            "/api/account/keys?fingerprint=SHA256:x".to_owned(),
        ),
    ];
    for (method, uri) in attempts {
        let (status, body) = send(&app, method.clone(), &uri, None).await;
        assert_eq!(
            status,
            http::StatusCode::UNAUTHORIZED,
            "{method} {uri} was not refused: {status} {body}"
        );
    }
}

/// **The operator's surface is still the operator's.** A read route that is not
/// on the anonymous allow-list must refuse a visitor even though it is a `GET`
/// on a repository they can otherwise see.
#[tokio::test]
async fn the_operator_surface_is_not_widened_by_the_anonymous_one() {
    let (app, _passkeys, _feed) = console(FakeGunnar::new(), true).await;

    let gated = [
        "/api/repos/deleted".to_owned(),
        "/api/orphans".to_owned(),
        "/api/namespaces".to_owned(),
        "/api/storage".to_owned(),
        // The box's own disks: device paths, disk serials, the ISO hash and
        // the kernel command line. An ADMIN read behind a session, and
        // therefore doubly not a visitor's.
        "/api/machine".to_owned(),
        "/api/stats".to_owned(),
        "/api/principals".to_owned(),
        "/api/keys".to_owned(),
        // Reading your own keys still needs a session to be the OWNER of.
        "/api/account/keys".to_owned(),
        "/api/grants".to_owned(),
        "/api/accounts/gates".to_owned(),
        // **A namespace's own meters and its own traffic.** Both take `Read`
        // on the namespace at gunnar, and this console's key holds it
        // server-wide — so the gate that keeps a stranger out of them is this
        // list and nothing else.
        // `an_anonymous_visitor_cannot_read_a_namespaces_activity` below is the
        // same refusal asserted on the BODY rather than on the status.
        format!("/api/namespaces/{NS}/usage"),
        format!("/api/namespaces/{NS}/activity"),
        // On a repository the visitor CAN see: it is the leaf that is gated,
        // not the repository.
        format!("/api/repos/{NS}/{PUBLIC}/gc"),
        format!("/api/repos/{NS}/{PUBLIC}/protection"),
        format!("/api/repos/{NS}/{PUBLIC}/gates"),
        format!("/api/repos/{NS}/{PUBLIC}/ref-names"),
        format!("/api/repos/{NS}/{PUBLIC}/pulls"),
    ];
    for route in gated {
        let (status, body) = anon(&app, &route).await;
        assert_eq!(
            status,
            http::StatusCode::UNAUTHORIZED,
            "{route} is not an anonymous route but answered {status}: {body}"
        );
    }
}

/// The console's own document routes: a visitor may reach the repository pages
/// and is still sent to the login page for the operator's dashboard.
///
/// Asserted on the REDIRECT rather than on the body, because with `ui_dir:
/// None` there is no bundle to serve — what is being tested is the middleware's
/// decision, and a 404 from the missing fallback is that decision saying "I
/// would have served you".
#[tokio::test]
async fn the_repository_pages_are_reachable_and_the_dashboard_is_not() {
    let (app, passkeys, _feed) = console(FakeGunnar::new(), true).await;
    guests_on(&app, &passkeys).await;

    for page in ["/repos", &format!("/{NS}/{PUBLIC}"), &format!("/repo/{NS}/{PUBLIC}")] {
        let (status, _) = anon(&app, page).await;
        assert_ne!(
            status,
            http::StatusCode::SEE_OTHER,
            "{page} redirected a visitor to the login page"
        );
        assert_ne!(
            status,
            http::StatusCode::TEMPORARY_REDIRECT,
            "{page} redirected a visitor to the login page"
        );
        assert_ne!(
            status,
            http::StatusCode::UNAUTHORIZED,
            "{page} refused a visitor"
        );
    }

    for page in [
        "/",
        "/access",
        "/storage",
        // The machine's disks. An admin page, and a visitor is not even a
        // viewer.
        "/machine",
        "/usage",
        "/events",
        "/account",
    ]
    // `/` is the PUBLIC HOME in a `public-site` build (TASKS-12 S-1), the
    // server-rendered page `anonymous::public_site` holds; never the dashboard.
    .into_iter()
    .filter(|page| !(crate::PUBLIC_SITE && *page == "/"))
    {
        let (status, _) = anon(&app, page).await;
        assert_eq!(
            status,
            http::StatusCode::UNAUTHORIZED,
            "{page} is an operator page and must not be served to a visitor"
        );
    }
}

/// ★ **The machine's disks are the administrator's, and an older gunnar is not
/// a failure box.**
///
/// Two properties of one route, together, because they are the two ways the
/// Machine page can be got wrong:
///
/// * a **viewer** is refused with a 403 that names both roles. The box's
///   device paths, disk serials, ISO hash and kernel command line are not a
///   tenant's business, and the gate is `role_floor`'s one admin READ — a
///   client-side `is_admin()` in the console is a courtesy, never a boundary;
/// * an **admin** on a gunnar that does not serve `Admin.StorageInfo` gets a
///   **200** carrying gunnar's own refusal in `unanswered`, not a 501. The
///   page still has three layers to draw and a sentence to draw about the
///   server. `FakeGunnar` answers `Unimplemented` for every Admin verb, so
///   this is exactly that case.
///
/// The machine now rides on `Admin.StorageInfo`'s `reality` field rather than
/// on an `Admin.Machine` RPC that gunnar never served, which means the OTHER
/// "cannot answer" — a gunnar that serves the call and predates field 10 —
/// arrives as `Ok` with the field absent and cannot be produced by refusing a
/// verb. `api::machine`'s own tests cover that half; this one covers the
/// refusal half end to end, through the role gate.
#[tokio::test]
async fn the_machine_page_is_an_admins_and_an_older_gunnar_answers_it_in_words() {
    let (app, passkeys, _feed) = console(FakeGunnar::new(), true).await;

    let (status, body) = signed_in(
        &app,
        &passkeys,
        "viewer-vera",
        crate::role::Role::Viewer,
        "/api/machine",
    )
    .await;
    assert_eq!(
        status,
        http::StatusCode::FORBIDDEN,
        "a viewer read the machine's disks: {body}"
    );
    assert!(
        body.contains("admin"),
        "the refusal does not name the role it needs: {body}"
    );

    let (status, body) = signed_in(
        &app,
        &passkeys,
        "alice",
        crate::role::Role::Admin,
        "/api/machine",
    )
    .await;
    assert_eq!(status, http::StatusCode::OK, "{body}");
    let answer: serde_json::Value = serde_json::from_str(&body).expect("the machine, as JSON");
    assert!(
        answer["unanswered"]
            .as_str()
            .is_some_and(|words| words.contains("Admin.StorageInfo")),
        "an older gunnar's refusal did not reach the page in words: {body}"
    );
    // And nothing was invented to fill the hole.
    assert!(answer["record"].is_null(), "{body}");
    assert_eq!(
        answer["filesystems"].as_array().map(Vec::len),
        Some(0),
        "{body}"
    );
    assert!(answer["placement"].is_null(), "{body}");

    // A visitor, for completeness: refused before the role is ever consulted.
    let (status, _) = anon(&app, "/api/machine").await;
    assert_eq!(status, http::StatusCode::UNAUTHORIZED);
}

/// ★ **A visitor cannot read a namespace's ACTIVITY — asserted on the body, not
/// on the status code.**
///
/// `Usage.Activity` answers what a tenant pushed and fetched, day by day, and
/// when they were last seen. It takes `Read` **on the namespace** at gunnar —
/// and this console signs with a key that holds `Read` on every namespace on
/// the box. So gunnar would answer it. The only thing between a stranger and
/// another tenant's traffic is the console's own allow-list, which is exactly
/// the confused-deputy shape this module exists for, and exactly the shape a
/// new route is most likely to be added into by accident: `/usage` was already
/// gated, `/activity` sits beside it, and copying the route registration
/// without thinking about the gate is a one-line mistake.
///
/// Asserted three ways, because a 401 alone proves the least of them:
///
///  * **no digit of the ledger is in the body** — not the byte total, not the
///    day key, not the last-push stamp, and not the `days` array itself;
///  * **no call reached gunnar at all**, so the console did not fetch the
///    answer and then decide to withhold it. A refusal after the read has
///    already happened is a refusal that a logging change can undo;
///  * **an operator still gets the numbers**, so this is not green because the
///    route is broken for everybody. That control is the half that makes the
///    other two mean something: without it, deleting the handler would pass.
#[tokio::test]
async fn an_anonymous_visitor_cannot_read_a_namespaces_activity() {
    let fake = FakeGunnar::new();
    let (app, _passkeys, _feed) = console(fake.clone(), true).await;

    let route = format!("/api/namespaces/{NS}/activity");
    let before = fake.calls.load(Ordering::SeqCst);
    let (status, body) = anon(&app, &route).await;

    assert_eq!(
        status,
        http::StatusCode::UNAUTHORIZED,
        "{route} answered {status} to a visitor: {body}"
    );
    // The disclosure, looked for as it would be written on the wire.
    for secret in [
        SECRET_BYTES_MOVED.to_string(),
        SECRET_DAY_MS.to_string(),
        SECRET_LAST_PUSH_MS.to_string(),
    ] {
        assert!(
            !body.contains(&secret),
            "the visitor was handed {NS}'s traffic ({secret}): {body}"
        );
    }
    assert!(
        !body.contains("days") && !body.contains("retained_days"),
        "the visitor was handed a day series: {body}"
    );
    assert_eq!(
        fake.calls.load(Ordering::SeqCst),
        before,
        "the console asked gunnar for {NS}'s activity on behalf of a visitor and then \
         withheld the answer; the read must not happen at all"
    );

    // The control. An operator asks the same question and gets the numbers —
    // so the three assertions above are about the gate and not about a route
    // that answers nobody.
    let (status, body) = admin(&app, &route).await;
    assert_eq!(status, http::StatusCode::OK, "{body}");
    assert!(
        body.contains(&SECRET_BYTES_MOVED.to_string()),
        "an operator must still be able to read the namespace's activity: {body}"
    );
    assert!(
        body.contains(&SECRET_LAST_PUSH_MS.to_string()),
        "…including when it was last pushed to: {body}"
    );

    // And the same for the glance on `/usage`, which carries `bytes_in_today`
    // and `last_push_unix_ms` — the same facts in a smaller shape, behind the
    // same gate, and worth pinning here rather than trusting the neighbouring
    // route's test to cover a different module's decision.
    let usage = format!("/api/namespaces/{NS}/usage");
    let (status, body) = anon(&app, &usage).await;
    assert_eq!(status, http::StatusCode::UNAUTHORIZED, "{usage}: {body}");
    assert!(
        !body.contains(&SECRET_BYTES_MOVED.to_string())
            && !body.contains(&SECRET_LAST_PUSH_MS.to_string()),
        "the visitor was handed {NS}'s meters: {body}"
    );

    // And the admission plan, which carries the same window's byte total.
    let admit = format!("/api/namespaces/{NS}/admit");
    let before = fake.calls.load(Ordering::SeqCst);
    let (status, body) = anon(&app, &admit).await;
    assert_eq!(status, http::StatusCode::UNAUTHORIZED, "{admit}: {body}");
    assert!(
        !body.contains(&SECRET_BYTES_MOVED.to_string()) && !body.contains("used_bytes"),
        "the visitor was handed {NS}'s admission plan: {body}"
    );
    assert_eq!(fake.calls.load(Ordering::SeqCst), before, "{admit} reached gunnar for a visitor");
}

/// **The allow-list, pinned by shape.** A unit test over the predicate itself,
/// because the integration tests above can only ever cover the routes somebody
/// remembered to list.
#[test]
fn the_anonymous_read_predicate_admits_only_named_leaves() {
    use crate::auth::middleware::is_anonymous_read;
    use http::Method;

    let get = Method::GET;
    assert!(is_anonymous_read(&get, "/api/repos"));
    assert!(is_anonymous_read(&get, "/api/repos/ns/name"));
    for leaf in [
        "refs", "head", "log", "browse", "diff", "blame", "search", "object", "chain", "readme",
        "raw",
    ] {
        assert!(
            is_anonymous_read(&get, &format!("/api/repos/ns/name/{leaf}")),
            "{leaf} should be readable"
        );
    }

    // The leaves that are the operator's.
    for leaf in [
        "gc",
        "protection",
        "gates",
        "ref-names",
        "pulls",
        "undelete",
    ] {
        assert!(
            !is_anonymous_read(&get, &format!("/api/repos/ns/name/{leaf}")),
            "{leaf} must NOT be anonymous"
        );
    }

    // GUN-GUEST (owner 2026-10-30): a public repository's issues are a guest's to read, the
    // list and one issue (gunnar takes Read for both), never a write under them.
    assert!(is_anonymous_read(&get, "/api/repos/ns/name/issues"));
    assert!(is_anonymous_read(&get, "/api/repos/ns/name/issues/3"));
    assert!(!is_anonymous_read(&get, "/api/repos/ns/name/issues/3/comment"));

    // `/api/repos/deleted` is the whole server's tombstones, and it has the
    // shape of a namespace. A prefix match would have admitted it.
    assert!(!is_anonymous_read(&get, "/api/repos/deleted"));
    // **A namespace's meters and its traffic are never anonymous.** They have
    // the same three-segment shape the repository leaves have — `/api/x/y/z` —
    // so a predicate written by counting segments rather than by naming the
    // prefix would let them through, and this console's key can read every
    // namespace on the box.
    assert!(!is_anonymous_read(&get, "/api/namespaces/ns/usage"));
    assert!(!is_anonymous_read(&get, "/api/namespaces/ns/activity"));
    assert!(!is_anonymous_read(&get, "/api/namespaces/ns/admit"));
    // Nothing deeper than one leaf.
    assert!(!is_anonymous_read(&get, "/api/repos/ns/name/pulls/1/merge"));
    assert!(!is_anonymous_read(&get, "/api/repos/ns/name/log/extra"));
    // Empty segments cannot stand in for a repository.
    assert!(!is_anonymous_read(&get, "/api/repos//name"));
    assert!(!is_anonymous_read(&get, "/api/repos/ns/"));
    // Not a read.
    for method in [Method::POST, Method::PATCH, Method::PUT, Method::DELETE] {
        assert!(!is_anonymous_read(&method, "/api/repos"));
        assert!(!is_anonymous_read(&method, "/api/repos/ns/name/browse"));
    }
}

/// The document allow-list, same treatment: the repository pages and `/<ns>`
/// (owner, 2026-10-03), and none of the console's own surfaces.
#[test]
fn the_anonymous_page_predicate_admits_only_the_repository_and_namespace_pages() {
    use crate::auth::middleware::is_anonymous_page;
    use http::Method;

    let get = Method::GET;
    assert!(is_anonymous_page(&get, "/repos"));
    assert!(is_anonymous_page(&get, "/repo/ns/name"));
    assert!(is_anonymous_page(&get, "/repo/ns/name/files"));

    for page in [
        "/",
        "/access",
        "/storage",
        // The machine's disks. An admin page, and a visitor is not even a
        // viewer.
        "/machine",
        "/usage",
        "/events",
        "/account",
        "/admin",
        "/overview",
        "/account/storage",
        "/admin/storage",
        "/login",
        "/api",
        "/health",
        "/favicon.ico",
    ] {
        assert!(!is_anonymous_page(&get, page), "{page} must not be public");
    }
    // `/<ns>`: ONE segment that is not a console route — the page that shows a
    // visitor a private namespace's public repositories, and "does not exist"
    // for the rest (the data is `/api/namespaces/{ns}/page`, asked as the
    // guest). `/repository-settings` is a namespace name by that rule, which is
    // harmless: it is the same `index.html`, and the namespace answers 404.
    assert!(is_anonymous_page(&get, "/acme"));
    assert!(is_anonymous_page(&get, "/repository-settings"));
    // GUN-GUEST: `/{ns}/{name}` IS a repository's address now (the same `index.html`, and a
    // missing repository answers as missing); a leaf the console has no page for is not one.
    assert!(is_anonymous_page(&get, "/repository-settings/x"));
    assert!(!is_anonymous_page(&get, "/repository-settings/x/y"));
    assert!(!is_anonymous_page(&Method::POST, "/repo/ns/name"));
    assert!(!is_anonymous_page(&Method::POST, "/acme"));
}

/// ★ **The CLI page is the console's own and open to a visitor** (E4, 2026-10-11): `/cli`
/// renders what the front serves under `/download/` (the signed `gunnar` CLI), which a
/// person needs before any encrypted flow, logged in or not — and it is not a namespace.
#[test]
fn the_cli_page_is_a_console_route_a_visitor_may_open() {
    use crate::auth::middleware::{is_anonymous_page, is_namespace_page};
    use http::Method;

    assert!(crate::serve::CONSOLE_ROUTES.contains(&"/cli"));
    assert!(!is_namespace_page("/cli"));
    assert!(is_anonymous_page(&Method::GET, "/cli"));
    assert!(!is_anonymous_page(&Method::POST, "/cli"));
    assert!(!is_anonymous_page(&Method::GET, "/cli/x"));
}

/// **The README route, both ways round and in both shapes.**
///
/// The public repository's README is rendered for somebody with no session, by
/// the GUEST key, in each of the two grades; the private one's is refused at
/// the same place every other read of it is. All of it in one test because the
/// interesting claim is the pair — "it is served" alone would be green on a
/// console that served everything.
#[tokio::test]
async fn a_public_readme_is_rendered_for_a_visitor_and_a_private_one_is_refused() {
    let fake = FakeGunnar::new();
    let (app, _passkeys, _feed) = console(fake.clone(), true).await;

    // ── the default grade: the typeset page, words and all ───────────────
    let (status, body) = anon(&app, &format!("/api/repos/{NS}/{PUBLIC}/readme")).await;
    assert_eq!(status, http::StatusCode::OK, "{body}");
    assert!(
        body.contains("\"kind\":\"svg\""),
        "the typeset page is the default grade: {}",
        &body[..body.len().min(400)]
    );
    assert!(
        body.contains(&format!("{NS}/{PUBLIC} README.md")),
        "the page is named after the repository and file it came from"
    );
    // **The heading text IS in the SVG, and that is what let the typeset grade
    // become the default.** It used to be asserted absent — `typst-svg` draws
    // every glyph as a path and nothing in the markup spelled the words — and
    // that absence was the whole reason this console led with the html grade.
    // docbook 0.1.2's text layer puts the characters back over the glyphs, so
    // the assertion is inverted rather than deleted.
    assert!(
        body.contains(README_HEADING),
        "the heading must be SELECTABLE TEXT in the typeset page's layer: {}",
        &body[..body.len().min(400)]
    );
    assert!(
        body.contains("README.md"),
        "the answer names where it was found"
    );
    assert!(!body.contains("<script"), "{body}");

    // ── the plain grade: real elements, a thirtieth of the bytes ─────────
    let (status, body) = anon(&app, &format!("/api/repos/{NS}/{PUBLIC}/readme?as=html")).await;
    assert_eq!(status, http::StatusCode::OK, "{body}");
    assert!(
        body.contains("\"kind\":\"html\""),
        "?as=html must serve the plain grade: {}",
        &body[..body.len().min(400)]
    );
    assert!(
        body.contains(README_HEADING),
        "the heading must be selectable text in the html grade too: {body}"
    );
    assert!(!body.contains("<script"), "{body}");

    // ── and the private one, in both shapes ──────────────────────────────
    for query in ["", "?as=html"] {
        let (status, body) = anon(&app, &format!("/api/repos/{NS}/{PRIVATE}/readme{query}")).await;
        assert_eq!(status, http::StatusCode::NOT_FOUND, "{query}: {body}");
        assert!(!body.contains(README_HEADING), "{body}");
        assert!(
            !body.contains(std::str::from_utf8(SECRET_BYTES).expect("utf8")),
            "{body}"
        );
    }

    // Every one of those calls went out as the guest, not as the console.
    let guest = signer(GUEST_SEED).fingerprint().to_owned();
    let seen = fake.fingerprints();
    assert!(!seen.is_empty(), "no call reached gunnar at all");
    assert!(
        seen.iter().all(|f| *f == guest),
        "the README route used a key other than the guest's: {seen:?}"
    );
}

/// **A README's relative link lands on the file, in both shapes.**
///
/// Measured on gunnar.rs 2026-09-11: the gunnar README's link to its own PDF
/// was written for the tree (`docs/…pdf`) and resolved against the console's
/// `/repo/{ns}/{name}` route, a page that is not a directory of anything. Both
/// grades must hand the browser the raw route instead, and the typeset one must
/// carry it in the link layer that sits above the text.
#[tokio::test]
async fn a_readme_link_to_a_file_in_the_tree_points_at_the_raw_route() {
    let (app, _passkeys, _feed) = console(FakeGunnar::new(), true).await;
    let raw = format!("/api/repos/{NS}/{PUBLIC}/raw?path=docs/guide.pdf");

    for query in ["", "?as=html"] {
        let (status, body) = anon(&app, &format!("/api/repos/{NS}/{PUBLIC}/readme{query}")).await;
        assert_eq!(status, http::StatusCode::OK, "{query}: {body}");
        assert!(
            body.contains(&raw),
            "{query}: the link was not rewritten: {body}"
        );
        assert!(
            !body.contains("href=\\\"docs/guide.pdf"),
            "{query}: a link still points at the tree path: {body}"
        );
    }
    let (_, body) = anon(&app, &format!("/api/repos/{NS}/{PUBLIC}/readme")).await;
    assert!(
        body.contains("class=\\\"link-layer\\\""),
        "the typeset page must lift the link above its text layer"
    );
    let (_, body) = anon(&app, &format!("/api/repos/{NS}/{PUBLIC}/readme?as=html")).await;
    assert!(
        body.contains("external"),
        "the router must not claim a click on a README link: {body}"
    );
}

/// **The raw route, both ways round.** A stranger gets a public repository's
/// file as the file — with the type decided by the console, not the file — and
/// the private repository's is refused, by gunnar, against the guest.
#[tokio::test]
async fn a_public_file_is_served_raw_to_a_visitor_and_a_private_one_is_refused() {
    use tower::ServiceExt;

    let fake = FakeGunnar::new();
    let (app, _passkeys, _feed) = console(fake.clone(), true).await;
    let get = |uri: String| {
        let app = app.clone();
        async move {
            let request = http::Request::get(uri)
                .body(axum::body::Body::empty())
                .expect("a request");
            let response = app.oneshot(request).await.expect("the console answers");
            let (parts, body) = response.into_parts();
            let body = axum::body::to_bytes(body, 1 << 20).await.expect("a body");
            (parts, body)
        }
    };

    let (parts, body) = get(format!("/api/repos/{NS}/{PUBLIC}/raw?path=README.md")).await;
    assert_eq!(
        parts.status,
        http::StatusCode::OK,
        "{}",
        String::from_utf8_lossy(&body)
    );
    assert_eq!(&body[..], README_MARKDOWN.as_bytes());
    let header = |name: http::HeaderName| {
        parts
            .headers
            .get(&name)
            .and_then(|v| v.to_str().ok())
            .unwrap_or_default()
            .to_owned()
    };
    // ★ GUN-LANDING (coordinator 2026-10-30): a Markdown or text file is read as text,
    // `text/plain; charset=utf-8`, shown inline — in a sandbox, never sniffed, and under the
    // route's own policy, not the console's. (It was a download, application/octet-stream.)
    assert_eq!(
        header(http::header::CONTENT_TYPE),
        "text/plain; charset=utf-8"
    );
    assert!(header(http::header::CONTENT_DISPOSITION).starts_with("inline;"));
    assert!(header(http::header::CONTENT_DISPOSITION).contains("README%2Emd"));
    assert_eq!(
        header(http::HeaderName::from_static("x-content-type-options")),
        "nosniff"
    );
    let policy = header(http::header::CONTENT_SECURITY_POLICY);
    assert!(policy.contains("sandbox"), "{policy}");
    assert!(
        !policy.contains("script-src"),
        "the console's policy overwrote the route's: {policy}"
    );

    let (parts, body) = get(format!("/api/repos/{NS}/{PUBLIC}/raw?path=")).await;
    assert_eq!(
        parts.status,
        http::StatusCode::BAD_REQUEST,
        "a directory is not a file"
    );
    let _ = body;

    let (parts, body) = get(format!("/api/repos/{NS}/{PRIVATE}/raw?path=README.md")).await;
    assert_eq!(parts.status, http::StatusCode::NOT_FOUND);
    assert!(!body.windows(SECRET_BYTES.len()).any(|w| w == SECRET_BYTES));

    let guest = signer(GUEST_SEED).fingerprint().to_owned();
    assert!(
        fake.fingerprints().iter().all(|f| *f == guest),
        "the raw route used a key other than the guest's"
    );
}

/// ★ **An SVG picture in a PUBLIC repository is served as a picture** (BADGE-7):
/// `image/svg+xml`, inline, under a policy with no script and `sandbox`, never
/// sniffed — so gunnar.rs's README can draw the OpenSSF badge from its own origin
/// (`img-src 'self'`) and no visitor's browser asks bestpractices.dev for it. It
/// is a picture because the repository is public, not because the reader is a
/// guest: the administrator reading the same public file gets the same picture.
/// The same file in a PRIVATE repository stays a download, read by whoever may
/// read it: it would be a document on the console's origin with that reader's
/// session beside it.
#[tokio::test]
async fn an_svg_in_a_public_repository_is_a_picture_and_in_a_private_one_a_download() {
    use tower::ServiceExt;

    let fake = FakeGunnar::new().with_a_badge();
    let (app, _passkeys, _feed) = console(fake.clone(), true).await;
    let get = |uri: String, token: Option<&'static str>| {
        let app = app.clone();
        async move {
            let mut request = http::Request::get(uri);
            if let Some(token) = token {
                request = request.header(http::header::AUTHORIZATION, format!("Bearer {token}"));
            }
            let response = app
                .oneshot(request.body(axum::body::Body::empty()).expect("a request"))
                .await
                .expect("the console answers");
            let (parts, body) = response.into_parts();
            let body = axum::body::to_bytes(body, 1 << 20).await.expect("a body");
            (parts, body)
        }
    };
    let h = |parts: &http::response::Parts, name: http::HeaderName| {
        parts.headers.get(&name).and_then(|v| v.to_str().ok()).unwrap_or_default().to_owned()
    };

    for token in [None, Some("break-glass")] {
        let (parts, body) = get(format!("/api/repos/{NS}/{PUBLIC}/raw?path=badge.svg"), token).await;
        assert_eq!(parts.status, http::StatusCode::OK, "{token:?}: {}", String::from_utf8_lossy(&body));
        assert_eq!(&body[..], BADGE_SVG);
        assert_eq!(h(&parts, http::header::CONTENT_TYPE), "image/svg+xml", "{token:?}");
        assert!(h(&parts, http::header::CONTENT_DISPOSITION).starts_with("inline;"), "{token:?}");
        assert_eq!(h(&parts, http::HeaderName::from_static("x-content-type-options")), "nosniff");
        let policy = h(&parts, http::header::CONTENT_SECURITY_POLICY);
        assert!(policy.contains("sandbox"), "{policy}");
        assert!(policy.contains("default-src 'none'"), "{policy}");
        assert!(!policy.contains("script-src"), "no script, and not the console's policy: {policy}");
    }

    // The private repository's identical file, read by the administrator: a download.
    let (parts, body) = get(format!("/api/repos/{NS}/{PRIVATE}/raw?path=badge.svg"), Some("break-glass")).await;
    assert_eq!(parts.status, http::StatusCode::OK, "{}", String::from_utf8_lossy(&body));
    assert_eq!(h(&parts, http::header::CONTENT_TYPE), "application/octet-stream");
    assert!(h(&parts, http::header::CONTENT_DISPOSITION).starts_with("attachment;"));
    assert!(h(&parts, http::header::CONTENT_SECURITY_POLICY).contains("sandbox"));

    // And a stranger does not get it at all.
    let (parts, _) = get(format!("/api/repos/{NS}/{PRIVATE}/raw?path=badge.svg"), None).await;
    assert_eq!(parts.status, http::StatusCode::NOT_FOUND);
}

/// **A file kept in Git LFS is served as the file, not as its pointer.**
///
/// The tree holds 131 bytes of pointer text for `guide.pdf`, which is the shape
/// gunnar's own `docs/gunnar-fast-setup.pdf` has. Before `Refs.ReadLfsObject`
/// the console had nothing else to serve: the pointer would have gone out as
/// `application/pdf` and the browser would have called the repository's PDF
/// broken. Red before that RPC (the body was the pointer text), green now.
///
/// The private half is the claim that matters: the same pointer, the same
/// sha256, a repository the visitor may not read — and following a pointer must
/// not be a way around that.
#[tokio::test]
async fn a_file_in_git_lfs_is_served_as_the_file_and_not_as_its_pointer() {
    use tower::ServiceExt;

    let fake = FakeGunnar::new();
    let (app, _passkeys, _feed) = console(fake.clone(), true).await;
    let get = |uri: String| {
        let app = app.clone();
        async move {
            let request = http::Request::get(uri)
                .body(axum::body::Body::empty())
                .expect("a request");
            let response = app.oneshot(request).await.expect("the console answers");
            let (parts, body) = response.into_parts();
            let body = axum::body::to_bytes(body, 1 << 20).await.expect("a body");
            (parts, body)
        }
    };

    let (parts, body) = get(format!("/api/repos/{NS}/{PUBLIC}/raw?path=guide.pdf")).await;
    assert_eq!(
        parts.status,
        http::StatusCode::OK,
        "{}",
        String::from_utf8_lossy(&body)
    );
    assert_eq!(&body[..], LFS_BODY, "the LFS object, whole");
    assert!(
        !body.starts_with(b"version https://git-lfs"),
        "the pointer was served as if it were the file"
    );
    assert_eq!(
        parts
            .headers
            .get(http::header::CONTENT_TYPE)
            .and_then(|v| v.to_str().ok()),
        Some("application/pdf")
    );

    // The private repository's identical pointer names an object this visitor
    // may not have, and the refusal comes from gunnar, against the guest.
    let (parts, body) = get(format!("/api/repos/{NS}/{PRIVATE}/raw?path=guide.pdf")).await;
    assert_eq!(parts.status, http::StatusCode::NOT_FOUND);
    assert!(
        !body.windows(SECRET_BYTES.len()).any(|w| w == SECRET_BYTES),
        "the private repository's LFS object reached a stranger"
    );

    let guest = signer(GUEST_SEED).fingerprint().to_owned();
    assert!(
        fake.fingerprints().iter().all(|f| *f == guest),
        "the LFS read used a key other than the guest's"
    );
}

/// **Against an older gunnar, the answer says what is wrong, not which method
/// is missing.**
///
/// The console and the appliance are deployed on their own timetables — that
/// skew is what `tests/contract.rs` is for — so a console that knows
/// `Refs.ReadLfsObject` will meet a gunnar that does not. tonic answers an
/// unknown method `Unimplemented`, which would reach a visitor as a bare 501
/// naming a gRPC method. The file is in LFS, this server cannot serve it, and
/// `git lfs pull` can: that is what the reader needs.
#[tokio::test]
async fn an_older_gunnar_answers_the_lfs_link_with_a_reason_not_a_method_name() {
    use tower::ServiceExt;

    let (app, _passkeys, _feed) = console(FakeGunnar::new().without_the_lfs_rpc(), true).await;
    let request = http::Request::get(format!("/api/repos/{NS}/{PUBLIC}/raw?path=guide.pdf"))
        .body(axum::body::Body::empty())
        .expect("a request");
    let response = app.oneshot(request).await.expect("the console answers");
    let (parts, body) = response.into_parts();
    let body = axum::body::to_bytes(body, 1 << 20).await.expect("a body");
    let body = String::from_utf8_lossy(&body).into_owned();

    assert_eq!(parts.status, http::StatusCode::BAD_REQUEST, "{body}");
    assert!(body.contains("Git LFS"), "{body}");
    assert!(body.contains("git lfs pull"), "{body}");
    assert!(body.contains(LFS_OID), "the object is named: {body}");
    assert!(
        !body.starts_with("version https://git-lfs"),
        "the pointer must never be the body"
    );
}

/// A body that is not a run of one byte, so a lost or repeated range shows.
fn six_megabytes() -> Vec<u8> {
    (0..6_000_000u32)
        .map(|i| (i % 251) as u8 ^ (i >> 16) as u8)
        .collect()
}

/// `GET …/raw?path=guide.pdf` on the public repository, against `fake`.
async fn raw_guide(fake: FakeGunnar) -> (http::response::Parts, Vec<u8>) {
    use tower::ServiceExt;
    let (app, _passkeys, _feed) = console(fake, true).await;
    let request = http::Request::get(format!("/api/repos/{NS}/{PUBLIC}/raw?path=guide.pdf"))
        .body(axum::body::Body::empty())
        .expect("a request");
    let response = app.oneshot(request).await.expect("the console answers");
    let (parts, body) = response.into_parts();
    let body = axum::body::to_bytes(body, 64 << 20).await.expect("a body");
    (parts, body.to_vec())
}

fn header(parts: &http::response::Parts, name: http::HeaderName) -> Option<&str> {
    parts.headers.get(name).and_then(|v| v.to_str().ok())
}

/// ★ **An LFS file larger than one gunnar answer is streamed whole,
/// byte-exact** (the owner's 6 MB README picture, 2026-10-15): range after
/// range of at most 4 MiB, under the file's own type and a `Content-Length` of
/// the whole.
#[tokio::test]
async fn an_lfs_file_past_one_gunnar_answer_is_streamed_whole() {
    let body = six_megabytes();
    let fake = FakeGunnar::new().with_the_guide_in_lfs(body.clone());

    let (parts, got) = raw_guide(fake).await;

    let head = String::from_utf8_lossy(&got[..got.len().min(300)]).into_owned();
    assert_eq!(parts.status, http::StatusCode::OK, "{head}");
    assert_eq!(header(&parts, http::header::CONTENT_TYPE), Some("application/pdf"));
    assert_eq!(header(&parts, http::header::CONTENT_LENGTH), Some("6000000"));
    assert_eq!(got.len(), body.len());
    assert!(got == body, "the streamed file is the stored file, byte for byte");
}

/// ★ **Against a gunnar from before ranged reads, the same file is refused in
/// words, not JSON** — what the browser got as `{"code":"resourceexhausted",…}`
/// on 2026-10-15.
#[tokio::test]
async fn against_an_older_gunnar_a_large_lfs_file_is_refused_in_words() {
    let fake = FakeGunnar::new()
        .without_lfs_ranges()
        .with_the_guide_in_lfs(six_megabytes());

    let (parts, body) = raw_guide(fake).await;
    let body = String::from_utf8_lossy(&body).into_owned();

    assert_eq!(parts.status, http::StatusCode::PAYLOAD_TOO_LARGE, "{body}");
    assert_eq!(
        header(&parts, http::header::CONTENT_TYPE),
        Some("text/plain; charset=utf-8")
    );
    assert_eq!(
        body,
        "guide.pdf is 5.7 MB, kept in Git LFS, and this console hands a browser files of up to \
         4 MB. Clone the repository and run `git lfs pull` to get it.\n"
    );
}

/// ★ **The file view of an LFS file describes the FILE, not its pointer**
/// (owner 2026-10-15, gunnar.rs mikronova/modgunn `docs/idiot_guide.pdf` read
/// "131 B · Plain Text · version https://git-lfs…"): the size is the file's,
/// it says it is in LFS and how to show it, and no line of the pointer is
/// served as the file's content.
#[tokio::test]
async fn the_file_view_of_an_lfs_file_is_the_file_and_not_its_pointer() {
    use tower::ServiceExt;

    let (app, _passkeys, _feed) = console(FakeGunnar::new(), true).await;
    let request = http::Request::get(format!("/api/repos/{NS}/{PUBLIC}/browse?path=guide.pdf"))
        .body(axum::body::Body::empty())
        .expect("a request");
    let response = app.oneshot(request).await.expect("the console answers");
    let (parts, body) = response.into_parts();
    let body = axum::body::to_bytes(body, 1 << 20).await.expect("a body");
    let body = String::from_utf8_lossy(&body).into_owned();
    assert_eq!(parts.status, http::StatusCode::OK, "{body}");
    let found: serde_json::Value = serde_json::from_str(&body).expect("json");

    assert_eq!(found["size"], serde_json::json!(LFS_BODY.len()), "the file's size, not the pointer's: {body}");
    assert_eq!(found["lfs"]["shown"], "pdf", "{body}");
    assert_eq!(found["lfs"]["sha256"], LFS_OID, "{body}");
    assert_eq!(found["lines"], serde_json::json!([]), "the pointer served as lines: {body}");
    assert!(found["lfs"]["pointer"].as_str().unwrap_or("").starts_with("version https://git-lfs"), "{body}");
}

/// **The second reader does not pay for the typesetting.**
///
/// The counter is gunnar's, not the cache's: a warm answer makes no
/// `Refs.ReadObject` call at all, because the whole tree walk is behind the
/// cache. That is the property worth pinning — a cache that saved the compile
/// and still walked the tree would spend a credential per page view.
#[tokio::test]
async fn a_second_reader_of_the_same_readme_costs_gunnar_nothing() {
    let fake = FakeGunnar::new();
    let (app, _passkeys, _feed) = console(fake.clone(), true).await;
    let route = format!("/api/repos/{NS}/{PUBLIC}/readme");

    let (status, _) = anon(&app, &route).await;
    assert_eq!(status, http::StatusCode::OK);
    let after_first = fake.fingerprints().len();

    let (status, body) = anon(&app, &route).await;
    assert_eq!(status, http::StatusCode::OK, "{body}");
    let after_second = fake.fingerprints().len();

    assert!(
        body.contains("\"kind\":\"svg\""),
        "the warm answer is the same answer"
    );
    // Get, resolve and read the tree still happen — the oid is the cache key
    // and it has to be learned. Reading the BLOB and typesetting it do not.
    assert!(
        after_second - after_first < after_first,
        "the second read cost {} calls against the first read's {after_first}; \
         the cache is not being hit",
        after_second - after_first
    );
}

/// **The last grade, through the router.**
///
/// A README that typesets to more than a browser should be handed comes back as
/// the HTML grade with the reason in `warning`, and NOT as a 500 — the console
/// is not entitled to fall over on somebody else's file. The DEFAULT request is
/// what reaches it, which is what makes the limit matter: `?as=html` has no size
/// limit to cross, because its cost is linear in the text rather than in the
/// glyphs, and a visitor asking for nothing in particular now asks for the
/// typeset page.
///
/// Size is also the only way to reach it at all. docbook writes every run of a
/// README's text as a typst string literal, so no README can produce markup the
/// typesetter refuses.
#[tokio::test]
async fn a_readme_too_large_to_typeset_falls_back_to_the_html_grade() {
    let (app, _passkeys, _feed) = console(FakeGunnar::new(), true).await;

    let (status, body) = anon(&app, &format!("/api/repos/{NS}/{OVERSIZE}/readme")).await;

    assert_eq!(status, http::StatusCode::OK, "a big README is not an error");
    assert!(
        body.contains("\"kind\":\"html\""),
        "the fallback grade must be html: {}",
        &body[..body.len().min(400)]
    );
    assert!(
        body.contains("over the"),
        "the warning must say why it is not typeset: {}",
        &body[..body.len().min(600)]
    );
    assert!(
        body.contains("An Encyclopaedia"),
        "the reader still gets the README"
    );
    assert!(!body.contains("<script"), "the fallback is sanitised");
}

/// **The twin's heartbeat is an operator's read, and restoring from the twin
/// an administrator's act** — through the role gate, end to end.
#[tokio::test]
async fn the_twin_panel_is_an_operators_and_the_restore_an_admins() {
    let (app, passkeys, _feed) = console(FakeGunnar::new(), true).await;

    let (status, body) = signed_in(&app, &passkeys, "viewer-vera", crate::role::Role::Viewer, "/api/twin").await;
    assert_eq!(status, http::StatusCode::FORBIDDEN, "a viewer read the twin's heartbeat: {body}");

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