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

nordisk/gunnar

crates/gunnar-grpc/tests/machine_enrolment.rs

//! **A machine asks; an admin approves with a fresh step-up; gunnar decides**
//! (2026-10-05: the ops kit's console credential without the owner's copied
//! session cookie — "WHY THIS WAY?? SOLVE IT", and an outside review called
//! the cookie hand-over an account-takeover pattern).
//!
//! The kit makes its own P-256 key, answers a creation ceremony with it and
//! asks for a role under a machine name (`kit-*`). The request is PENDING and
//! changes nothing until a PERSON who is a server admin approves it with a
//! fresh, user-verified assertion of their own passkey — verified here, by
//! gunnar — or the installer's break-glass token approves it while the
//! operator's first invite is pending (a fresh box). The touch is the identity
//! core's (IDENTITY-HOST): the approver's own core session, stepped up — the
//! call carries no assertion of its own. Then gunnar makes the
//! MACHINE principal, grants it the role and stores the credential, never on a
//! person. Requests expire, can be refused, and every step is audited.
//!
//! Every assertion is a real ES256 signature over the bytes a browser (or
//! the kit) sends; every refusal is also asserted on what did NOT happen.

mod machine_enrolment_common;

use gunnar_grpc::ControlPlane as _;
use gunnar_grpc::Identity as _;
use gunnar_proto::access_server::Access as _;
use gunnar_proto::*;
use machine_enrolment_common::*;
use tonic::Code;

/// ★ **A request is PENDING and changes nothing**: a code for the eye, an id
/// to poll with, listed to a server admin — and no principal, no grant, no
/// credential until somebody approves it.
#[tokio::test]
async fn a_request_is_pending_and_enrols_nothing_until_approved() {
    let h = Harness::new();
    let kit = Authenticator::new(9, b"kit-dwarf-key");
    let asked = h.ask(&kit, "kit-dwarf", GrantLevel::Admin).await;
    assert_eq!(state(&asked), MachineEnrolmentState::Pending);
    assert_eq!(asked.machine, "kit-dwarf");
    assert_eq!(asked.label, "installer kit on dwarf");
    assert_eq!(asked.server_level, GrantLevel::Admin as i32);
    assert_eq!(asked.request_id.len(), 32, "{asked:?}");
    let code = asked.code.as_bytes();
    assert!(
        code.len() == 7
            && code[3] == b'-'
            && code[..3].iter().all(u8::is_ascii_uppercase)
            && code[4..].iter().all(u8::is_ascii_digit),
        "a code is ABC-123: {:?}",
        asked.code
    );
    assert!(asked.key_fingerprint.starts_with("SHA256:"), "{asked:?}");
    assert!(
        asked.expires_at_unix_ms > now_ms() + 14 * 60_000,
        "fifteen minutes: {asked:?}"
    );

    let listed = h
        .access()
        .list_machine_enrolments(Harness::authed(&h.kim, ListMachineEnrolmentsRequest {}))
        .await
        .expect("a server admin lists the pending requests")
        .into_inner()
        .requests;
    assert_eq!(listed.len(), 1);
    assert_eq!(
        (listed[0].request_id.as_str(), listed[0].code.as_str()),
        (asked.request_id.as_str(), asked.code.as_str())
    );
    assert_eq!(
        state(&h.status(&asked.request_id).await),
        MachineEnrolmentState::Pending
    );
    h.nothing_for("kit-dwarf", &kit);

    // A login with the pending credential is a stranger's.
    let refused = kit
        .login(&h.identity, 1)
        .expect_err("a pending credential logs nobody in");
    assert_eq!(refused.code, nornir_identity::Code::Ceremony, "{refused:?}");
}

/// ★ **An approval is a fresh step-up of the approver's own core session.**
/// No session at all (a signed key), a session that did not step up, or an
/// approval for another code: each refused, and nothing lands. (The touch
/// itself — user verification, a challenge the core issued, the approver's
/// own passkey — is the core's step-up, held by its conformance suite.)
#[tokio::test]
async fn approve_without_a_fresh_step_up_is_refused_and_enrols_nothing() {
    let h = Harness::new();
    let kit = Authenticator::new(9, b"kit-dwarf-key");
    let asked = h.ask(&kit, "kit-dwarf", GrantLevel::Admin).await;

    let none = h
        .approve(&h.kim, &asked, None)
        .await
        .expect_err("no step-up");
    assert_eq!(none.code(), Code::PermissionDenied, "{none:?}");
    assert!(
        none.message().contains("[stepup]"),
        "the refusal names the step-up: {none:?}"
    );

    // kim's core session, logged in without user verification: no step-up.
    let c = h.identity.login_start(&relay()).unwrap();
    let challenge = gunnar_grpc::webauthn::from_b64url(&c.challenge).unwrap();
    let plain = h
        .identity
        .login_finish(h.kim_key.assert(&c.id, &challenge, UP, 1))
        .expect("kim logs in with a plain touch");
    assert!(!plain.session.stepped_up);
    let refused = h
        .approve_with_session(&plain.token, &asked)
        .await
        .expect_err("a session that did not step up");
    assert_eq!(refused.code(), Code::PermissionDenied, "{refused:?}");
    assert!(refused.message().contains("[stepup]"), "{refused:?}");

    let mut wrong = asked.clone();
    wrong.code = "ZZZ-999".into();
    let refused = h
        .approve(&h.kim, &wrong, Some(h.kims_step_up().await))
        .await
        .expect_err("another code");
    assert_eq!(refused.code(), Code::FailedPrecondition, "{refused:?}");

    h.nothing_for("kit-dwarf", &kit);
    assert_eq!(
        state(&h.status(&asked.request_id).await),
        MachineEnrolmentState::Pending,
        "still waiting"
    );

    // kim's user-verified login is a step-up: through the real gate it approves.
    let fresh = kim_login(&h, 2);
    h.approve_with_session(&fresh, &asked)
        .await
        .expect("kim's stepped-up session approves");
}

/// kim's user-verified login through the core: her session token.
fn kim_login(h: &Harness, counter: u32) -> String {
    h.kim_key
        .login(&h.identity, counter)
        .expect("kim logs in")
        .token
}

/// ★ **Approved, the credential is a MACHINE's**: gunnar makes `kit-dwarf`
/// (kind MACHINE), grants it server Admin, stores the credential there and
/// nowhere else — kim's own credential set is untouched — and the kit then
/// logs in as its machine, with its own key.
#[tokio::test]
async fn an_approval_makes_the_machine_and_its_credential_and_the_kit_logs_in_as_it() {
    let h = Harness::new();
    let kit = Authenticator::new(9, b"kit-dwarf-key");
    let asked = h.ask(&kit, "kit-dwarf", GrantLevel::Admin).await;
    let kims_before = h.plane.credentials(Some("kim")).expect("read").len();

    let approved = h
        .approve(&h.kim, &asked, Some(h.kims_step_up().await))
        .await
        .expect("kim approves with a fresh step-up");
    let principal = approved.principal.expect("the machine");
    assert_eq!(
        (principal.id.as_str(), principal.kind),
        ("kit-dwarf", PrincipalKind::Machine as i32)
    );
    let credential = approved.credential.expect("the credential");
    assert_eq!(
        (
            credential.principal_id.as_str(),
            credential.credential_id.as_slice()
        ),
        ("kit-dwarf", kit.id.as_slice())
    );
    assert_eq!(credential.label, "installer kit on dwarf");
    let request = approved.request.expect("the request");
    assert_eq!(state(&request), MachineEnrolmentState::Approved);
    assert_eq!(request.decided_by, "kim");

    assert_eq!(
        h.plane.credentials(Some("kim")).expect("read").len(),
        kims_before,
        "kim's own set is untouched"
    );
    assert!(
        h.plane
            .may(
                "kit-dwarf",
                &gunnar_grpc::auth::Access::Server,
                GrantLevel::Admin
            )
            .expect("ask"),
        "the machine holds server Admin"
    );
    assert_eq!(
        state(&h.status(&asked.request_id).await),
        MachineEnrolmentState::Approved
    );
    let listed = h
        .access()
        .list_machine_enrolments(Harness::authed(&h.kim, ListMachineEnrolmentsRequest {}))
        .await
        .expect("listed")
        .into_inner()
        .requests;
    assert!(
        listed.is_empty(),
        "an approved request is pending no more: {listed:?}"
    );

    let login = kit
        .login(&h.identity, 1)
        .expect("the kit logs in with its own key through the core");
    assert_eq!(login.session.user_id, "kit-dwarf");
    let as_kit = h
        .gate_session(&login.token)
        .expect("the session authenticates");
    assert_eq!(as_kit.principal_id, "kit-dwarf");
    let who = h
        .access()
        .who_am_i(Harness::authed(&as_kit, WhoAmIRequest {}))
        .await
        .expect("who am I")
        .into_inner();
    assert_eq!(
        who.server_level,
        GrantLevel::Admin as i32,
        "the kit's whoami: admin"
    );

    // Approved once: a second approval finds nothing pending.
    let again = h
        .approve(&h.kim, &asked, Some(h.kims_step_up().await))
        .await
        .expect_err("approved already");
    assert_eq!(again.code(), Code::FailedPrecondition, "{again:?}");

    // An operator's request is a server Write, on its own machine.
    let ops = Authenticator::new(10, b"kit-ops-key");
    let asked = h.ask(&ops, "kit-ops", GrantLevel::Write).await;
    h.approve(&h.kim, &asked, Some(h.kims_step_up().await))
        .await
        .expect("approved");
    assert!(h
        .plane
        .may(
            "kit-ops",
            &gunnar_grpc::auth::Access::Server,
            GrantLevel::Write
        )
        .expect("ask"));
    assert!(
        !h.plane
            .may(
                "kit-ops",
                &gunnar_grpc::auth::Access::Server,
                GrantLevel::Admin
            )
            .expect("ask"),
        "an operator is not an admin"
    );
}

/// **A request expires**: after its time nobody approves it, and its machine
/// reads `expired`.
#[tokio::test]
async fn a_request_expires_and_is_approved_by_nobody() {
    let h = Harness::with_ttl(300);
    let kit = Authenticator::new(9, b"kit-dwarf-key");
    let asked = h.ask(&kit, "kit-dwarf", GrantLevel::Admin).await;
    std::thread::sleep(std::time::Duration::from_millis(400));
    assert_eq!(
        state(&h.status(&asked.request_id).await),
        MachineEnrolmentState::Expired
    );
    let late = h
        .approve(&h.kim, &asked, Some(h.kims_step_up().await))
        .await
        .expect_err("expired");
    assert_eq!(late.code(), Code::FailedPrecondition, "{late:?}");
    assert!(late.message().contains("expired"), "{late:?}");
    h.nothing_for("kit-dwarf", &kit);
}

/// **A refused request enrols nothing**, and is approved by nobody after.
#[tokio::test]
async fn a_refused_request_enrols_nothing() {
    let h = Harness::new();
    let kit = Authenticator::new(9, b"kit-dwarf-key");
    let asked = h.ask(&kit, "kit-dwarf", GrantLevel::Admin).await;
    let refused = h
        .access()
        .refuse_machine_enrolment(Harness::authed(
            &h.kim,
            RefuseMachineEnrolmentRequest {
                request_id: asked.request_id.clone(),
            },
        ))
        .await
        .expect("kim refuses")
        .into_inner()
        .request
        .expect("the request");
    assert_eq!(
        (state(&refused), refused.decided_by.as_str()),
        (MachineEnrolmentState::Refused, "kim")
    );
    assert_eq!(
        state(&h.status(&asked.request_id).await),
        MachineEnrolmentState::Refused
    );
    let late = h
        .approve(&h.kim, &asked, Some(h.kims_step_up().await))
        .await
        .expect_err("refused");
    assert_eq!(late.code(), Code::FailedPrecondition, "{late:?}");
    h.nothing_for("kit-dwarf", &kit);
}

/// ★ **Only a PERSON who is a server admin approves.** lee — a person with a
/// passkey and a perfect step-up, but no admin — is refused at every verb an
/// admin has; and a machine that holds Admin (an approved kit, stepping up
/// with its own key file) never approves another: the human is the point.
#[tokio::test]
async fn a_non_admin_and_a_machine_never_approve() {
    let h = Harness::new();
    let kit = Authenticator::new(9, b"kit-dwarf-key");
    let asked = h.ask(&kit, "kit-dwarf", GrantLevel::Admin).await;

    let lees = h
        .lee_key
        .login(&h.identity, 1)
        .expect("lee logs in, user-verified")
        .token;
    let refused = h
        .approve_with_session(&lees, &asked)
        .await
        .expect_err("lee is no admin");
    assert_eq!(refused.code(), Code::PermissionDenied, "{refused:?}");
    let refused = h
        .access()
        .list_machine_enrolments(Harness::authed(&h.lee, ListMachineEnrolmentsRequest {}))
        .await
        .expect_err("lee lists nothing");
    assert_eq!(refused.code(), Code::PermissionDenied, "{refused:?}");
    let refused = h
        .access()
        .refuse_machine_enrolment(Harness::authed(
            &h.lee,
            RefuseMachineEnrolmentRequest {
                request_id: asked.request_id.clone(),
            },
        ))
        .await
        .expect_err("lee refuses nothing");
    assert_eq!(refused.code(), Code::PermissionDenied, "{refused:?}");
    // And asking is the relay's: lee cannot ask on a machine's behalf.
    let refused = h
        .ask_as(
            &h.lee,
            &Authenticator::new(11, b"other"),
            "kit-other",
            GrantLevel::Admin,
        )
        .await
        .expect_err("lee is no relay");
    assert_eq!(refused.code(), Code::PermissionDenied, "{refused:?}");
    h.nothing_for("kit-dwarf", &kit);

    // kim approves the first kit; the kit, an admin machine, tries the next.
    h.approve(&h.kim, &asked, Some(h.kims_step_up().await))
        .await
        .expect("approved");
    let kits = kit.login(&h.identity, 1).expect("the kit logs in").token;
    let second = Authenticator::new(12, b"kit-second-key");
    let next = h.ask(&second, "kit-second", GrantLevel::Admin).await;
    let refused = h
        .approve_with_session(&kits, &next)
        .await
        .expect_err("a machine never approves");
    assert_eq!(refused.code(), Code::PermissionDenied, "{refused:?}");
    assert!(refused.message().contains("person"), "{refused:?}");
    h.nothing_for("kit-second", &second);
}

/// ★ **On a fresh box the OWNER registers first — with the break-glass
/// token, his first invite — and then approves the kit** (2026-10-05, the
/// stage-L constraint: the token IS the owner's first invite, and an invite
/// never makes an admin, so a kit that spent it would leave the owner no way
/// to admin). Before he holds a passkey nothing approves the kit's request —
/// not the token, which no approval carries — and his first invite stays
/// pending; he registers with it; it is spent; his step-up approves the kit.
#[tokio::test]
async fn the_owner_registers_first_with_the_token_then_approves_the_kit() {
    let h = Harness::new();
    let operator = h
        .plane
        .claim_operator("rickard")
        .expect("the operator")
        .principal;
    let hash = gunnar_grpc::webauthn::sha256_hex(TOKEN.as_bytes());
    h.plane
        .operator_bootstrap_invite(
            &operator.id,
            &hash,
            now_ms(),
            gunnar_grpc::seam::OPERATOR_INVITE_TTL_MS,
        )
        .expect("the first invite is recorded");
    let first_invite_pending = |h: &Harness| h.plane.first_invite().expect("read").is_some();

    // A kit asks on the fresh box: nothing approves it without a person's touch.
    let kit = Authenticator::new(9, b"kit-fresh-key");
    let asked = h.ask(&kit, "kit-fresh", GrantLevel::Admin).await;
    // The console's own key (what the break-glass bearer acts with) is no
    // person: the token approves nothing, it is the owner's first invite.
    let refused = h
        .approve(&h.console, &asked, None)
        .await
        .expect_err("no person, no approval");
    assert_eq!(refused.code(), Code::PermissionDenied, "{refused:?}");
    assert!(
        refused.message().contains("not a person"),
        "the refusal says why the token is no approval: {refused:?}"
    );
    h.nothing_for("kit-fresh", &kit);
    assert!(
        first_invite_pending(&h),
        "the owner's first invite is untouched"
    );

    // The owner registers his YubiKey with the token — his first invite —
    // through the core, which reads the token's hash as a fed invite onto him.
    let mut yubikey = nornir_identity::test_host::SoftPasskey::new(20);
    let c = h
        .identity
        .redeem_start(TOKEN, "", &relay())
        .expect("the token opens his ceremony");
    assert_eq!(c.user_id, operator.id, "onto the operator");
    let owner = h
        .identity
        .redeem_finish(yubikey.register(&c, ORIGIN))
        .expect("the token registers the owner's first passkey");
    assert_eq!(owner.session.user_id, operator.id);
    assert!(
        !first_invite_pending(&h),
        "the first invite was redeemed by the OWNER"
    );
    assert_eq!(
        h.plane
            .operator_bootstrap_invite(
                &operator.id,
                &hash,
                now_ms(),
                gunnar_grpc::seam::OPERATOR_INVITE_TTL_MS
            )
            .expect("asked"),
        gunnar_grpc::BootstrapInvite::Spent
    );

    // He logs in, user-verified, and approves the kit from that session.
    let c = h.identity.login_start(&relay()).unwrap();
    let session = h
        .identity
        .login_finish(yubikey.login(&c, ORIGIN, true))
        .expect("the owner logs in")
        .token;
    let approved = h
        .approve_with_session(&session, &asked)
        .await
        .expect("the owner approves the kit");
    assert_eq!(
        approved.request.map(|r| r.decided_by),
        Some(operator.id.clone())
    );
    assert_eq!(
        approved.principal.map(|p| (p.id, p.kind)),
        Some(("kit-fresh".to_owned(), PrincipalKind::Machine as i32))
    );
    let held: Vec<Vec<u8>> = h
        .plane
        .credentials(Some(&operator.id))
        .expect("read")
        .into_iter()
        .map(|c| c.credential_id)
        .collect();
    assert_eq!(
        held,
        vec![yubikey.id.clone()],
        "the owner's set holds his key only"
    );
}

/// **A request is checked like a registration**: a machine name (never a
/// person's or a console's), ADMIN, WRITE or READ, a creation ceremony over a
/// challenge gunnar issued, at the relay's origin. And an invite still never
/// makes an admin, nor lands on a machine: the approval is the one door.
#[tokio::test]
async fn a_request_is_checked_and_the_approval_is_the_only_door() {
    let h = Harness::new();
    let kit = Authenticator::new(9, b"kit-dwarf-key");
    for (machine, level) in [
        ("rickard", GrantLevel::Admin),
        ("console-x", GrantLevel::Admin),
        ("kit-", GrantLevel::Admin),
        ("kit-Dwarf", GrantLevel::Admin),
    ] {
        let refused = h
            .ask_as(&h.console, &kit, machine, level)
            .await
            .expect_err(machine);
        assert_eq!(
            refused.code(),
            Code::InvalidArgument,
            "{machine} {level:?}: {refused:?}"
        );
    }
    // READ and no role at all are asked for now (2026-10-18: no role is the
    // lowest, READ — `a_request_that_names_no_role_asks_the_lowest_…`); a
    // level gunnar does not know is still refused.
    let unknown = h
        .ask_level(&kit, "kit-dwarf", 99)
        .await
        .expect_err("an unknown level");
    assert_eq!(unknown.code(), Code::InvalidArgument, "{unknown:?}");
    let base = |challenge: Vec<u8>, kind: &str, origin: &str| RequestMachineEnrolmentRequest {
        machine: "kit-dwarf".into(),
        label: "kit".into(),
        server_level: GrantLevel::Admin as i32,
        credential_id: kit.id.clone(),
        public_key: kit.public(),
        client_data_json: created(&challenge, kind, origin),
        rp_id: RP_ID.into(),
        origin: ORIGIN.into(),
        sign_count: 0,
        attestation_object: gunnar_grpc::webauthn::attestation_none(
            RP_ID,
            &kit.id,
            &kit.public(),
            0,
        ),
    };
    for (what, body) in [
        (
            "a login, not a creation",
            base(h.challenge().await, "webauthn.get", ORIGIN),
        ),
        (
            "another origin",
            base(
                h.challenge().await,
                "webauthn.create",
                "https://evil.example",
            ),
        ),
        (
            "a challenge gunnar never issued",
            base(vec![3; 32], "webauthn.create", ORIGIN),
        ),
        // Stinky row 13 (2026-10-10): the relayed key must be the attested one.
        (
            "no attestation object",
            RequestMachineEnrolmentRequest {
                attestation_object: Vec::new(),
                ..base(h.challenge().await, "webauthn.create", ORIGIN)
            },
        ),
        (
            "an attestation naming another key",
            RequestMachineEnrolmentRequest {
                attestation_object: gunnar_grpc::webauthn::attestation_none(
                    RP_ID,
                    &kit.id,
                    &Authenticator::new(66, b"x").public(),
                    0,
                ),
                ..base(h.challenge().await, "webauthn.create", ORIGIN)
            },
        ),
    ] {
        let refused = h
            .access()
            .request_machine_enrolment(Harness::authed(&h.console, body))
            .await
            .expect_err(what);
        assert_eq!(
            refused.code(),
            Code::PermissionDenied,
            "{what}: {refused:?}"
        );
    }
    assert!(h
        .access()
        .list_machine_enrolments(Harness::authed(&h.kim, ListMachineEnrolmentsRequest {}))
        .await
        .expect("listed")
        .into_inner()
        .requests
        .is_empty());

    // A person may not carry a machine's name.
    let refused = h
        .access()
        .add_principal(Harness::authed(
            &h.kim,
            AddPrincipalRequest {
                name: "kit-dwarf".into(),
                kind: PrincipalKind::User as i32,
                id: String::new(),
            },
        ))
        .await
        .expect_err("`kit-*` is a machine's");
    assert_eq!(refused.code(), Code::InvalidArgument, "{refused:?}");

    // Approved, the machine holds its credential; the other doors stay shut.
    let asked = h.ask(&kit, "kit-dwarf", GrantLevel::Admin).await;
    h.approve(&h.kim, &asked, Some(h.kims_step_up().await))
        .await
        .expect("approved");
    // An invite never makes an admin (the core's rule: `Code::InviteWouldBeAdmin`,
    // `invites.rs`); a passkey lands on a machine only by approval:
    let other = Authenticator::new(13, b"sneaked-in");
    let refused = h
        .access()
        .add_credential(Harness::authed(
            &h.kim,
            AddCredentialRequest {
                principal_id: "kit-dwarf".into(),
                credential_id: other.id.clone(),
                public_key: other.public(),
                label: "x".into(),
                sign_count: 0,
            },
        ))
        .await
        .expect_err("no credential lands on a machine but by approval");
    assert_eq!(refused.code(), Code::FailedPrecondition, "{refused:?}");
}

/// **An admin lists the kit's credential and revokes it**; its sessions end
/// and the kit no longer logs in.
#[tokio::test]
async fn an_admin_lists_and_revokes_the_kits_credential() {
    let h = Harness::new();
    let kit = Authenticator::new(9, b"kit-dwarf-key");
    let asked = h.ask(&kit, "kit-dwarf", GrantLevel::Admin).await;
    h.approve(&h.kim, &asked, Some(h.kims_step_up().await))
        .await
        .expect("approved");
    let session = kit.login(&h.identity, 1).expect("the kit logs in").token;
    let listed = h
        .access()
        .list_credentials(Harness::authed(
            &h.kim,
            ListCredentialsRequest {
                principal_id: String::new(),
            },
        ))
        .await
        .expect("kim lists every credential")
        .into_inner()
        .credentials;
    let row = listed
        .iter()
        .find(|c| c.credential_id == kit.id)
        .expect("the kit's credential is listed");
    assert_eq!(
        (row.principal_id.as_str(), row.label.as_str()),
        ("kit-dwarf", "installer kit on dwarf")
    );
    h.access()
        .revoke_credential(Harness::authed(
            &h.kim,
            RevokeCredentialRequest {
                credential_id: kit.id.clone(),
            },
        ))
        .await
        .expect("kim revokes it");
    assert!(
        h.gate_session(&session).is_err(),
        "the kit's session ended with its credential"
    );
    kit.login(&h.identity, 2)
        .expect_err("revoked: the kit logs in no more");
}

/// ★ **A request that names no role asks for the LOWEST, and the admin grants
/// more on approval** (owner order 2026-10-18). `/auth/machine/enrol` is a
/// door anybody can knock on; what a knock asks for by default must be the
/// least a machine can hold — a server READ — never Admin. The approving
/// admin, touching their own key, decides what the machine becomes: the role
/// asked, or the one they give.
#[tokio::test]
async fn a_request_that_names_no_role_asks_the_lowest_and_the_admin_grants_more() {
    let h = Harness::new();
    let kit = Authenticator::new(9, b"kit-quiet-key");
    let asked = h.ask(&kit, "kit-quiet", GrantLevel::Unspecified).await;
    assert_eq!(
        asked.server_level,
        GrantLevel::Read as i32,
        "no role asked is the lowest: {asked:?}"
    );
    h.approve(&h.kim, &asked, Some(h.kims_step_up().await))
        .await
        .expect("approved as asked");
    let server = gunnar_grpc::auth::Access::Server;
    assert!(
        h.plane
            .may("kit-quiet", &server, GrantLevel::Read)
            .expect("ask"),
        "the machine reads"
    );
    assert!(
        !h.plane
            .may("kit-quiet", &server, GrantLevel::Write)
            .expect("ask"),
        "and nothing more"
    );

    // The admin gives more than was asked, on the approval itself.
    let ops = Authenticator::new(10, b"kit-raised-key");
    let asked = h.ask(&ops, "kit-raised", GrantLevel::Read).await;
    h.approve_at(
        &h.kim,
        &asked,
        Some(h.kims_step_up().await),
        GrantLevel::Write,
    )
    .await
    .expect("the admin grants Write");
    assert!(
        h.plane
            .may("kit-raised", &server, GrantLevel::Write)
            .expect("ask"),
        "granted Write on approval"
    );
    assert!(
        !h.plane
            .may("kit-raised", &server, GrantLevel::Admin)
            .expect("ask"),
        "not Admin"
    );
}