Skip to content

Agent-side credential store + fetch (agent-owned, real cred worker)#228

Open
joker4002 wants to merge 4 commits into
litentry:mainfrom
joker4002:crossagent/github-litentry-agentkeys-198
Open

Agent-side credential store + fetch (agent-owned, real cred worker)#228
joker4002 wants to merge 4 commits into
litentry:mainfrom
joker4002:crossagent/github-litentry-agentkeys-198

Conversation

@joker4002

Copy link
Copy Markdown

Change:

Objective Evidence:

  • Reviewer-approved commit: ff89313 Add agent-owned credential store and fetch
  • Validation passed before review: cargo fmt --all -- --check; cargo check -p agentkeys-cli --bin agentkeys; cargo test -p agentkeys-backend-client -p agentkeys-mcp-server -p agentkeys-cli --lib; cargo test -p agentkeys-mcp-server --test three_acts --test http_auth; bash -n harness/scripts/sandbox-agent-isolation.sh; bash scripts/check-backend-fixture-drift.sh; git diff --check.
  • Reviewer approval: FINAL_REVIEW APPROVE, no findings, riskLevel=none.

Visual Evidence:

  • Not applicable for this backend/CLI task; reviewer noted no visual evidence artifact was required.

Reviewer:

  • repo-intake.reviewer.workspace_f4bd591d1ae845a5

Risks / Not Covered:

  • No known risks from the reviewer-approved READY_PACKAGE.

joker4002 and others added 2 commits June 8, 2026 10:23
… cred test; runbook sync

- sandbox-agent-isolation.sh: resolve + export AGENTKEYS_SESSION_BEARER BEFORE
  the memory roundtrip, not just cred. Both paths cap-mint AS the agent, so the
  broker's omni_account-vs-operator_omni check fails the FIRST (memory) roundtrip
  when the bearer is absent. Keep an already-set env bearer to avoid regressing
  setups that provide it directly.
- three_acts.rs: add agent_owned_cred_store_rejects_cross_actor_param — the MCP
  per-actor gate (check_actor_param) refuses a cross-actor cred.store and mints
  no cap.
- operator-runbook-harness.md: note the sandbox proof now covers memory + cred.
@hanwencheng hanwencheng changed the title Agent-side credential store and provisioning Agent-side credential store + fetch (agent-owned, real cred worker) Jun 8, 2026
@hanwencheng

Copy link
Copy Markdown
Member

Pushed 3b68304 addressing the review. cargo test -p agentkeys-mcp-server --test three_acts --test http_auth green locally (7 + 6 passed); CI will re-run.

1. Sandbox bearer ordering (the real blocker). sandbox-agent-isolation.sh exported AGENTKEYS_SESSION_BEARER only just before cred store, but the memory roundtrip above it also cap-mints as the agent — the broker validates the bearer's agentkeys.omni_account claim against operator_omni, so a missing bearer fails the memory step first, not cred. Hoisted the resolution + export above both roundtrips, with an already-set-in-env short-circuit so it can't regress a setup that supplies the bearer directly. (The new cred path had only been bash -n'd — never run — so the ordering mattered more.)

2. Negative test. Added agent_owned_cred_store_rejects_cross_actor_param: a cross-actor agentkeys.cred.store is refused by the MCP per-actor gate (check_actor_param) and mints no cap — the per-actor isolation invariant at the cap-authz layer, symmetric with the IAM-layer cross-actor denial already proven in stage-3 steps 4-9.

3. Runbook sync. operator-runbook-harness.md now states the sandbox proof covers memory + credential roundtrips (harness doc-sync rule).

Scope — retitled to drop "provisioning". This PR ships agent-owned store/fetch; the agent-email → service-signup → store provisioning half of #198 is not here. The body says "Source issue" (not "Closes"), so merge won't auto-close #198 — leaving it open for the provisioning follow-up. Note #198 and #199 are duplicates of the same work; worth closing one.

Deliberately not changed: cred store --content <secret> exposes the secret on argv — but that's identical to memory put --content, so it's better addressed for both verbs in a follow-up than diverging cred alone.

…ed tools reach the worker

The MCP server advertised agentkeys.cred.{store,fetch} but built its BackendClient
with cred_url=None, so every real (non-mock) call failed with
NotConfigured("cred_url") before reaching the deployed cred worker (cred.<zone>:9094).
Unit tests missed it because MockBackend bypasses BackendClient.

- config.rs: add cred_url (--cred-url / env AGENTKEYS_CRED_URL), mirroring memory_url.
- main.rs: pass config.cred_url; extract build_http_backend + a unit test asserting
  every worker URL (incl. cred_url) flows from config, so a hardcoded None can't
  silently return — the gap a MockBackend test cannot catch.
- phase1-wire-demo.sh: launch the sandbox MCP with --cred-url $AGENTKEYS_WORKER_CRED_URL.
- setup-mcp-host.sh: add AGENTKEYS_CRED_URL to the hosted MCP env (both modes).
@hanwencheng

Copy link
Copy Markdown
Member

Codex adversarial review follow-up — pushed 15e3edb.

Finding #1 [critical] — FIXED. Confirmed real: the MCP server advertised agentkeys.cred.{store,fetch} but constructed its BackendClient with cred_url = None (stale "no MCP cred tool yet" comment at main.rs:45), and Config had no cred-URL field. Since the CLI/agent cred path is CLI → MCP → BackendClient.cred_storeself.cred()?, every real (non-mock) call would have failed with NotConfigured("cred_url") before reaching the deployed worker (cred.<zone>:9094). MockBackend hid it in tests. Wired through:

  • cred_url added to Config (--cred-url / AGENTKEYS_CRED_URL), mirroring memory_url/audit_url.
  • main.rs now passes config.cred_url; extracted build_http_backend() + a unit test asserting every worker URL flows from config — the regression guard Codex asked for, which a MockBackend-only test can't provide (fails if cred_url is ever hardcoded to None again).
  • Sandbox launcher phase1-wire-demo.sh passes --cred-url $AGENTKEYS_WORKER_CRED_URL (that env var already existed in operator-workstation{,.test}.env + the CI materializer — it was simply never plumbed in); hosted MCP env setup-mcp-host.sh gets AGENTKEYS_CRED_URL (both modes).
  • Local: cargo fmt + clippy --all-targets clean, cargo test -p agentkeys-mcp-server green incl. the new wiring test.

Finding #2 [high] — real but pre-existing & repo-wide; deferring to a follow-up, not this PR. The cred-fetch handler audits only via tracing::info! — but so does the memory MCP tool (memory.rs literally labels that "Audit trail"), and neither the memory nor the cred worker emits a durable audit. So cred faithfully mirrors memory; bolting cred-only durable audit on here would create the very cred-vs-memory asymmetry the per-data-class design avoids. The correct fix is worker-side audit (after cap-verify, before returning plaintext) covering both classes — better as its own issue than scope-creeping this PR. Happy to file it.

The cred_url field doc still framed it as litentry#216 fetch-only ("no cred-fetch
available"); this PR makes it back /v1/cred/{store,fetch} (the protocol.rs
section header was already updated). No code change — comment only.

Verified the rest of the PR carries no dead code: cargo clippy -D warnings across
agentkeys-backend-client + agentkeys-cli + agentkeys-mcp-server is clean (the
Input/Body + Resp/Result type pairs are the deliberate litentry#203 wire/API split that
the memory + config paths also follow, not redundancy).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants