diff --git a/.gitignore b/.gitignore index 9223a34..4c46f41 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,16 @@ dist # Credentials *.credentials.json +*.credentials.* +**/*credentials*.json +credentials.* +**/credentials.* +**/*service-account*.json +**/*service_account*.json +*.pem +*.key +*.p12 +*.pfx # Logs / caches *.log @@ -24,10 +34,12 @@ coverage .vscode # Local infra volumes -infra/data +infra/data/ infra/.env # Embedded demo / local DB -.keyring-pglite -.keyring-pglite-demo -.keyring-pglite-* +.keyring-pglite*/ +**/.keyring-pglite*/ +*.sqlite +*.sqlite3 +*.db diff --git a/.prettierignore b/.prettierignore index fee6e0b..76f2e0f 100644 --- a/.prettierignore +++ b/.prettierignore @@ -2,3 +2,8 @@ dist node_modules pnpm-lock.yaml *.credentials.json +infra/data +infra/data/** +.keyring-pglite* +*.sqlite* +*.db diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6ce0a00..1c18767 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,37 +1,35 @@ # Contributing -All work goes through pull requests. Do not push directly to `main`. +Keyring changes are reviewed through pull requests. Do not push directly to `main`. -## Getting started +## Start here -1. Install Node 20+ and [pnpm](https://pnpm.io/). -2. Copy `.env.example` to `.env` and fill in local values (never commit real secrets). -3. Start infra (includes Keyring Postgres on `:5432`): `cd infra && cp .env.example .env && docker compose up -d` -4. From the repo root: +Install Node 20 or newer and pnpm 9 or newer. ```bash pnpm install -pnpm db:migrate -pnpm seed:test-org -pnpm build -pnpm test +pnpm demo ``` -## Development +The demo needs no credentials. For server work that uses Postgres, copy `.env.example` to `.env`, start the database from `infra`, and run the migrations. + +## Before opening a pull request + +Run the checks from the repository root: ```bash -pnpm dev +pnpm lint +pnpm typecheck +pnpm test +pnpm audit:secrets ``` -Runs the API server and the web app together. +Keep each change focused. Add a regression test when fixing a bug. Update the relevant documentation when behavior or configuration changes. Do not include generated build output or local database files. -## Before opening a PR +## Secrets -- `pnpm lint` -- `pnpm typecheck` -- `pnpm test` -- Keep commits focused; prefer small PRs. +Never commit `.env`, credential files, provider keys, access tokens, or service account JSON. The only env file intended for the repository is `.env.example`, and it must contain placeholders only. -## Secrets +## Pull requests -Never commit `.env`, `.env.*` (except `.env.example`), or any `*.credentials.json` files. +Describe the user-visible change, the safety impact, and the checks you ran. Call out any live provider behavior that was not tested. Keep commits and review comments factual and specific. diff --git a/README.md b/README.md index 3fa4d5b..98128cc 100644 --- a/README.md +++ b/README.md @@ -2,126 +2,100 @@ Every company can list its employees. None of them can list what those employees can still access. -Keyring is access governance on [TrueForge](https://trueforge.dev): inventory grants across systems, reconcile identities, queue approvals, execute revokes, and keep an append-only audit ledger. +## The problem -## Judge path (verbatim) +When someone leaves a company, their access is spread across many systems. A manager may remove a GitHub collaborator but miss a personal Google Drive share, an old Slack role, or an automation key. Checklists fail because they depend on one person remembering every system and every kind of access. The result is wasted review time, unnecessary risk, broken automation, and no reliable record of what was checked. -Requires **Node 20+** and **pnpm 9+**. No Docker, no API keys, no Postgres install. +## What Keyring does -```bash -pnpm install -pnpm demo -``` +Keyring collects access grants from connected systems into one review queue. It links usernames, work emails, personal emails, keys, and directory records without guessing when the evidence is weak. It treats AI agents as first class principals, recording their runtime, purpose, reachable tools, owner, and declaration status. It proposes an action for each grant and keeps protected resources in a separate human approval path. After approval, it can run the action and records the decision, result, and verification data in an append only ledger. -(`pnpm demo` builds once if needed.) Open **http://127.0.0.1:5173**, start a scan for **Ada Lovelace**. The UI runs in **replay** mode from `fixtures/recordings/ada-lovelace.json` against embedded **PGlite**. Execution stays **dry-run** by default. +Read [`docs/AGENT-IDENTITY.md`](docs/AGENT-IDENTITY.md) for the agent identity +model, evidence sources, risk treatment, and OWASP and NIST mapping. -Optional checks (still no credentials): +## Approval queue -```bash -pnpm test -pnpm audit:secrets -``` +The queue keeps the important facts visible before anyone decides. -## The problem +```mermaid +sequenceDiagram + participant S as Scan activity + participant U as Unattributed findings + participant A as Attributed findings + participant Q as Approval queue + participant O as Operator + S->>U: Show first + U->>A: Continue review + A->>Q: Show evidence and action + O->>Q: Approve, hold, or reject + Q->>O: Keep protected CI card for named decision +``` -Offboarding and access reviews fail because entitlements are scattered: GitHub collaborators, Drive shares to personal Gmail, deploy keys that look orphaned, stale Notion admins. HR can list people; nobody can list what those people can still touch. +## Quickstart -## What the harness does vs what we do +Requirements are Node 20 or newer and pnpm 9 or newer. The demo needs no API keys, Docker, Postgres, or cloud account. -| TrueForge (harness) | Keyring (product) | -| --- | --- | -| Agent loop, model calls, MCP tool invocation | Grant model, identity reconciliation | -| MCP auth / deferred tools / approvals mid-turn | Approval queue UI for access decisions | -| Sandbox, subagents, session persistence | Append-only governance audit ledger | -| | Policy (`keyring.yml`), spend cap, record/replay, execute dry-run | +```bash +pnpm install && pnpm demo +``` -Details: [`docs/HARNESS.md`](docs/HARNESS.md). +Open http://127.0.0.1:5173 and select **Run guided demo**, or start a scan for **Ada Lovelace**. The demo uses the checked in recording at `fixtures/recordings/ada-lovelace.json`, embedded PGlite, replay events, and dry run execution. The guided demo pauses at the protected CI card until you select **Continue**. Use **Stop** to discard an aborted demo take and start again. ## Architecture -``` - ┌─────────────────┐ - Operator UI ────►│ apps/web │ - (approve/exec) └────────┬────────┘ - │ HTTP / SSE - ┌────────▼────────┐ - │ packages/server │ scans · cards · execute · audit - │ MCP /mcp/scan │ /mcp/mutate (read vs write) - └────────┬────────┘ - ┌─────────────────┼─────────────────┐ - ▼ ▼ ▼ - packages/core connectors TrueForge - grants · policy GitHub/Google agent + MCP - reconcile · audit FixtureConnector (optional live) - │ - ▼ - Postgres or PGlite (demo) — append-only audit_records +```mermaid +sequenceDiagram + participant T as TrueForge agent + participant S as Five system subagents + participant B as TrueForge sandbox + participant H as Harness approvals and sessions + participant K as Keyring API + participant C as Keyring core + participant Q as Approval queue + participant L as Audit ledger + T->>S: Start one subagent per system + T->>B: Run identity reconciliation + T->>H: Persist session and gate sensitive tools + S->>K: Return compact grants + B->>K: Return reconciliation + K->>C: Build grants and apply policy + C->>Q: Persist ApprovalCards + Q->>L: Record decisions and results ``` -## Setup +TrueForge owns the agent loop, model calls, subagents, sandbox, MCP routing, harness approvals, and session persistence. Keyring owns grant semantics, identity reconciliation rules, policy, connectors, the HTTP API, the approval queue, execution policy, and the audit ledger. -### Offline demo (default for judges) +## How Keyring uses TrueForge -```bash -pnpm install && pnpm demo -``` +The agent asks TrueForge for the connected systems and starts one subagent per system. Each subagent inventories access through a read only MCP server and returns a compact grant list. Keyring combines those grants and runs identity reconciliation in the TrueForge sandbox when one is available. The result becomes ApprovalCards in the Keyring queue. Any irreversible or protected action requires a harness approval before the mutate tool can run. TrueForge sessions retain turns and events, so a reconnect can resume the same work instead of starting a second turn. -Uses `KEYRING_DEMO=1` → embedded PGlite at `.keyring-pglite-demo`, `KEYRING_SCAN_DRIVER=replay`, `KEYRING_EXECUTE_DRY_RUN=1`. - -### Live / full stack - -1. Copy env templates: root `.env.example`, `infra/.env.example` → `infra/.env` -2. Start Postgres (or TrueForge stack): `cd infra && docker compose up keyring-db -d` (or full stack) -3. `export DATABASE_URL=postgresql://keyring:keyring@localhost:5432/keyring` -4. `pnpm db:migrate` -5. Optional model keys in env only: `OPENAI_API_KEY` / `ANTHROPIC_API_KEY` — never commit -6. `pnpm --filter @keyring/server start` and `pnpm --filter @keyring/web dev` -7. Register agent: `pnpm register:agent` (TrueForge up) +## Safety guarantees -## Policy file (`keyring.yml`) +- Dry run is the default. `KEYRING_EXECUTE_DRY_RUN=1` walks the execution path without calling mutating provider APIs. +- The scan path is read only. Inventory uses read credentials and the scan MCP server. Mutations use the separate mutate MCP server after approval. +- The audit ledger is append only. A database trigger rejects updates and deletes, and the hash chain can be verified with `pnpm verify:audit`. +- Protected resources cannot be bulk approved. Policy can identify service accounts, protected resources, staleness rules, and optional auto approval. +- A hard spend cap stops model work cleanly. The default is `$0.50`, controlled by `KEYRING_HARD_CAP_USD`. +- Credentials stay in environment variables or the harness configuration. They are not stored in the agent manifest, recordings, or committed fixtures. -Checked into the **customer’s** repo. Declares protected resources, known service accounts, staleness, and optional auto-approve (off by default). See [`docs/POLICY.md`](docs/POLICY.md). +## Development and testing -```yaml -service_accounts: - - id: ci-payments-cdn - display_name: "GitHub Actions — payments CDN publish" - owner: "platform@keyring-test.example" - key_ids: - - AKIA_KEYRING_CI_ORPHAN_LOOKALIKE - resource_ids: - - keyring-test/payments +Install dependencies, then run: -protected: - - resource: "keyring-test/payments" - system: github - reason: "Prod payments CDN — always individual approval (never bulk)" +```bash +pnpm lint +pnpm typecheck +pnpm test ``` -## Safety guarantees - -- **Dry-run default** — `KEYRING_EXECUTE_DRY_RUN=1`. Clones cannot revoke by accident. Pass `dryRun:false` only when intentional ([`docs/EXECUTE.md`](docs/EXECUTE.md)). -- **Read-only scan path** — inventory uses `/mcp/scan` and read credentials; mutates only via `/mcp/mutate` after approval. -- **Append-only ledger** — `audit_records` rejects UPDATE/DELETE at the DB; hash chain verifiable with `pnpm verify:audit`. -- **Hard spend cap** — default `$0.50` (`KEYRING_HARD_CAP_USD`); scan stops cleanly as `cost_capped`. -- **Secrets** — API keys only in env; `pnpm audit:secrets` scans the tree (and git history when `.git` exists). - -## UI error states +The suite uses local fixtures and embedded test databases. It does not require provider credentials. Use `pnpm audit:secrets` before sharing a branch. See [`CONTRIBUTING.md`](CONTRIBUTING.md) for the pull request workflow. -| Condition | Message | Recovery | -| --- | --- | --- | -| Connector auth failure | Clear auth error from MCP | Re-authorize connector in TrueForge, retry | -| Rate limit | 429 / quota | Wait / lower rate, retry; or use replay | -| Partial scan | Some systems failed | Use successful grants; fix connector; re-scan | -| Spend cap | Cap reached, no further model calls | Raise cap or use `pnpm demo` | -| Execution failure | Per-card failure + undo hint when restorable | Check credentials / dry-run; retry cards | +More detail is available in [`docs/HARNESS.md`](docs/HARNESS.md), [`docs/API.md`](docs/API.md), [`docs/CONNECTORS.md`](docs/CONNECTORS.md), [`docs/IDENTITY.md`](docs/IDENTITY.md), [`docs/AGENT-IDENTITY.md`](docs/AGENT-IDENTITY.md), [`docs/POLICY.md`](docs/POLICY.md), [`docs/EXECUTE.md`](docs/EXECUTE.md), [`docs/COSTS.md`](docs/COSTS.md), [`docs/UI.md`](docs/UI.md), [`docs/AGENT.md`](docs/AGENT.md), and [`docs/TEST_ORG.md`](docs/TEST_ORG.md). -## More docs +## Limitations -- [`docs/HARNESS.md`](docs/HARNESS.md) · [`docs/POLICY.md`](docs/POLICY.md) · [`docs/COSTS.md`](docs/COSTS.md) -- [`docs/UI.md`](docs/UI.md) · [`docs/API.md`](docs/API.md) · [`docs/EXECUTE.md`](docs/EXECUTE.md) -- [`docs/AGENT.md`](docs/AGENT.md) · [`docs/IDENTITY.md`](docs/IDENTITY.md) · [`docs/CONNECTORS.md`](docs/CONNECTORS.md) · [`docs/TEST_ORG.md`](docs/TEST_ORG.md) +The default demo is replay based. It verifies the UI, API, decision path, dry run execution, streamed results, and ledger hash verification without making provider calls. The TrueForge driver has been exercised against the local harness and the Keyring MCP endpoints, including the five system fan out, reconciliation, and card persistence. Live GitHub and Google Workspace provider operations remain opt in and require credentials, a configured MCP server, and a throwaway test organization. The repository does not claim that every live provider response or live mutation path has been verified. -## AI-assistance disclosure +## AI assistance disclosure -This project was developed with assistance from **Cursor** (AI coding agent). Humans directed product decisions, safety defaults, and review; Cursor was used for implementation, refactoring, tests, and documentation drafting as required by the competition rules. +This project was developed with assistance from Cursor, an AI coding agent. Humans directed the product decisions, safety defaults, tests, review, and final verification. Cursor assisted with implementation, refactoring, testing, and documentation drafting, as permitted by the hackathon rules. diff --git a/apps/web/src/App.tsx b/apps/web/src/App.tsx index b28bb3a..0815c7d 100644 --- a/apps/web/src/App.tsx +++ b/apps/web/src/App.tsx @@ -2,6 +2,7 @@ import { AgentActivity } from "./components/AgentActivity.js"; import { ApprovalQueue } from "./components/ApprovalQueue.js"; import { ErrorBanner } from "./components/ErrorBanner.js"; import { GuidedDemoPanel } from "./components/GuidedDemoPanel.js"; +import { GuidedDemoStatusStrip } from "./components/GuidedDemoStatusStrip.js"; import { useScanSession } from "./hooks/useScanSession.js"; import { useGuidedDemo } from "./hooks/useGuidedDemo.js"; import { classifyClientError, recoveryFor, type ProductErrorKind } from "./lib/errors.js"; @@ -108,6 +109,12 @@ export function App() { onStop={guided.stop} /> ) : null} + {demoMode && guided.state.phase !== "idle" ? ( + + ) : null}