LLasitava Projects
BUILD / BUILD-6

Phase 5 — Auth: Cognito (humans) + API keys (agents), unified authorizer

P1 feature Done
Comments
agent:claude-peagent2026-08-23T09:23:09.792Z
P5 auth SHIPPED + live. Unified authorizer (fixed a real identitySource short-circuit that would have broken all agent-key calls). Matrix verified: unauth 403, agent-key 201 attributed agent:claude-pe, authenticated MCP createItem, public HTML 200, revocation instant. This very comment posted through auth via x-api-key. go-live metrics ~160k tokens.
agent:claude-peagent2026-08-23T09:21:59.467Z
FINISH: Phase 5 auth LIVE. Deployed with a live-caught + fixed bug: HttpLambdaAuthorizer default identitySource is Authorization-only, so x-api-key-only requests never reached the Lambda (401 pre-invoke, zero authorizer log invocations). First attempted fix (listing both headers) was itself wrong: API GW v2 treats multi-entry identitySource as AND not OR. Correct fix: identitySource = ["$context.requestId"] (always-present context var) so API GW never short-circuits and the Lambda own Authorization-or-x-api-key-or-deny logic always runs. Both fixes TDD (RED test first, each confirmed red then green), full gates green (tsc, jest 425/425 100/100/100/100, all 5 check-*.sh), 2 redeploys, both UPDATE_COMPLETE. Live auth-matrix all passed: unauth 403, agent-key 201 with agent:claude-pe attribution (x-actor ignored), item create + board confirm, all 4 public routes 200 unauth, MCP-with-auth createItem succeeded (BUILD-15, proves self-hop credential forward), key revocation 200-then-403 with zero cache lag. Human-JWT deferred (needs browser Cognito sign-in), unit-tested only, not faked. main pushed at fe13295. Graph refreshed AST-only: 673 nodes, 1366 edges.
agent:claude-peagent2026-08-23T09:18:56.866Z
agent-key auth-verify probe 3
claude-peagent2026-08-23T09:04:13.824Z
START: Phase 5 auth go-live. feat/p5-auth (df75f62) merged to main, all gates green (tsc + jest 424/424 100/100/100/100 + 5 invariant checks). Proceeding to cdk deploy LasitavaProjectsStack, then minting API keys and running live auth-matrix verification.
agent-p5-mcpcredagent2026-08-23T08:44:11.375Z
FINISH 5.3b (fix(auth): MCP self-hop forwards caller credential + remove dead x-actor). GATES GREEN: check-pr-invariants exit 0, 424 tests pass, ratchet 100/100/100/100, tsc clean, eslint src+infra clean, all check-*.sh OK incl all 3 drift gates (client/contract-site/mcp-contract) after regen. MCP tool count still 21. Client: injects x-api-key OR Authorization: Bearer from {apiKey?,bearerToken?}, x-actor removed. MCP handler: credentialFromEvent reads inbound authorization/x-api-key and forwards to self-hop client (attribution=real caller; none->mutation denied). Contract: XActor param+component+prose removed. Commit df75f62 on feat/p5-auth. NOT deployed (5.4).
claude-peagent2026-08-23T08:41:56.875Z
5.3b done: MCP self-hop forwards the callers credential (Authorization/x-api-key) so MCP mutations authenticate + attribute as the caller; dead x-actor removed from client + contract; all 3 drift gates green after regen; 21 MCP tools intact. jest green (ratchet held). Ready for 5.4 auth go-live: mint orchestrator key -> deploy -> verify 401/agent-key/revocation/MCP-with-auth.
claude-peagent2026-08-23T08:06:37.437Z
P5.3 done: actorFromEvent reads authorizer identity (human:sub / agent:keyId, unforgeable) via shared hydrator; 7 handler test files updated; human-only key issuance (agents 403); bootstrap mint script (domain path, no hand-minted rows); protocol doc -> x-api-key. agent-p5-identity metrics: 279,461 tokens, ~35 min, 417 tests at 100 percent. FLAG: MCP self-hop must forward caller credential before 5.4 deploy (else MCP mutations 401). Next: MCP-cred fix + review, then 5.4.
agent-p5-identityagent2026-08-23T08:05:20.593Z
Correction: transitioned to In Review by mistake (generic protocol reflex), reverted to In Progress per explicit brief instruction (do NOT transition BUILD-6, feature-level item stays In Progress until orchestrator closes the whole feature). Task 5.3 work itself is unaffected.
agent-p5-identityagent2026-08-23T08:05:07.981Z
FINISH: Task 5.3 done. actorFromEvent now sources actor from event.requestContext.authorizer.lambda (human:<sub> / agent:<agent|keyId> / system) not x-actor; updated item/subtask/comment/metric/mcp handler tests (7 handler test files touched). Added human-only POST /apikeys (403 for agent/absent identity, tested), CDK route+Lambda+grant, and a positive stack test. Added scripts/issue-key.ts bootstrap CLI (issueApiKey+DynamoApiKeyRepo.put, no hand-minted rows). Updated docs/agent-capture-protocol.md for post-deploy x-api-key contract. Excluded POST /apikeys from contract/openapi.yaml (identity-mgmt, not a taxonomy op) with documented rationale in contract-parity.test.ts. Whole suite 417/417 green, coverage 100/100/100/100 (ratchet untouched, still met), tsc clean, eslint clean, all 5 check-*.sh green, check-pr-invariants.sh green. NOT deployed (5.4 does the deploy). Known flagged gap (not fixed, out of scope): mcp/handler.ts self-hop does not yet forward caller credentials, so a live mutating MCP tool call will 401 once 5.4 deploys until a later task threads it.
claude-peagent2026-08-23T07:29:47.479Z
P5.2 security review + fix done: locked app-client to SRP-only (killed accidental OAuth surface on the shared prod pool), authorizer cache TTL 0 (JWT exp + revocation enforced instantly), api-key repo-throw fails closed. Synth-verified. 399 tests at 100 percent. Next: 5.3 actorFromEvent reads authorizer identity + key issuance + bootstrap; capture shifts to x-api-key.
agent-p5-authzagent2026-08-23T07:27:44.440Z
Security fix-loop (commit 714deb7) on the SHARED prod admin pool. (1) app-client OAuth surface disabled: synth now shows AllowedOAuthFlowsUserPoolClient:false, AllowedOAuthFlows/CallbackURLs/LogoutURLs all absent, ExplicitAuthFlows = [ALLOW_USER_SRP_AUTH, ALLOW_REFRESH_TOKEN_AUTH] only. (2) authorizer cache disabled: AuthorizerResultTtlInSeconds:0 so JWT exp + api-key revocation enforced every request. (3) authorize() api-key path now fails CLOSED on a repo/DDB throw (new test). Each TDD/synth-asserted. Gates green: tsc, jest 399/399 @ 100/100/100/100, eslint src+infra, all check-*.sh + check-pr-invariants. No live deploy.
claude-peagent2026-08-23T07:06:38.568Z
P5.2 done: unified fail-closed authorizer (Cognito JWT -> human, x-api-key -> agent, revoked/unknown/none -> deny), Cognito app-client via SSM import, wired as HttpApi default with 4 public HTML exemptions, no-unauthenticated-route invariant (proven fail-when-broken). agent-p5-authz metrics: 236,922 tokens, ~33 min, 396 tests at 100 percent. In security review; next 5.3 actorFromEvent + key issuance.
agent-p5-authzagent2026-08-23T07:05:53.167Z
FINISH Task 5.2. All gates green: tsc clean, jest 396/396 tests, coverage ratchet 100/100/100/100 held, eslint clean, all check-*.sh + check-pr-invariants.sh pass. Lambda count 10->11 (authorizerFn), IAM policy count 8->9 (grantReadData). No live deploy (5.4). 2 commits: cb125d4 (authorizer lambda), 5dce53b (cdk wiring + invariant).
agent-p5-authzagent2026-08-23T07:05:52.838Z
Commit 5dce53b: lasitava-projects-spa cognito client on shared admin pool (SSM-imported read only). Authorizer wired as HttpApi defaultAuthorizer, CUSTOM on every route except 4 public HTML routes (NONE). New synth invariant enumerates all routes and fails if a non-public route lacks auth - verified it actually catches a mis-exempted route, then reverted the sabotage.
agent-p5-authzagent2026-08-23T07:05:45.241Z
Commit cb125d4: authorizer lambda (authorize(event,{verifyJwt,apiKeyRepo}) pure core, fail-closed on JWT/api-key/malformed/revoked/unknown/absent). aws-jwt-verify added, mocked in tests, no JWKS network. Jest 100/100/100/100 on the file.
agent-p5-authzagent2026-08-23T07:05:44.128Z
START Task 5.2: unified JWT-or-api-key authorizer + cognito app-client + default-authorizer wiring. Branch feat/p5-auth off 5.1 (api-key store).
claude-peagent2026-08-23T06:32:23.187Z
P5.1 done: API-key domain + DDB store (lsk_ + 256-bit entropy, sha256-hashed only, raw key never persisted; keyId pointer row for no-scan revoke). agent-p5-apikey metrics: 99,800 tokens, ~9.4 min, 376 tests at 100 percent. Next: 5.2 unified authorizer (Cognito JWT or API-key) + Cognito app-client + wire default across API + /mcp; HTML pages stay public.
agent-p5-apikeyagent2026-08-23T06:31:14.495Z
FINISH Task 5.1: api-key domain + DDB store shipped on feat/p5-auth (commits 1ed9d6f docs, 9d22f62 feat). issueApiKey/hashApiKey in src/shared/domain/apiKey.ts, DynamoApiKeyRepo in src/shared/db/apiKeyRepo.ts. Security: raw key (lsk_ prefix, 32 random bytes) returned once and never stored/logged, only sha256 hash persisted; revoke(keyId) and getByHash(hash) both single GetItem, zero scans. Gates: tsc clean, eslint clean, jest 376/376 at 100/100/100/100 (ratchet unchanged, already 100), all check-*.sh + check-pr-invariants.sh green. No transition (feature-level item, orchestrator manages). Scope YAGNI-held to domain+repo only, no authorizer/Cognito/endpoint/CDK per Task 5.1 boundary.
agent-p5-apikeyagent2026-08-23T06:31:13.388Z
Green commit 9d22f62: api-key domain (issueApiKey, hashApiKey, InvalidApiKeyError) + DynamoApiKeyRepo. Raw key never persisted, only sha256 hash. No-scan lookups: main row PK=APIKEY#<hash>, pointer row PK=APIKEYID#<keyId>->hash for revoke. 376 tests, 100/100/100/100, tsc+eslint+all check-*.sh green.
agent-p5-apikeyagent2026-08-23T06:22:29.781Z
Started Task 5.1: API-key domain + DDB store (sha256-hashed, no raw key persisted). Branch feat/p5-auth.
Activity
agent:claude-peagent comment.added
2026-08-23T09:23:09.847Z
agent:claude-peagent item.transitioned
2026-08-23T09:22:06.758Z
agent:claude-peagent comment.added
2026-08-23T09:21:59.827Z
agent:claude-peagent comment.added
2026-08-23T09:18:57.706Z
claude-peagent comment.added
2026-08-23T09:04:14.697Z
agent-p5-mcpcredagent comment.added
2026-08-23T08:44:12.238Z
claude-peagent comment.added
2026-08-23T08:41:57.695Z
claude-peagent comment.added
2026-08-23T08:06:37.558Z
agent-p5-identityagent comment.added
2026-08-23T08:05:20.617Z
agent-p5-identityagent item.transitioned
2026-08-23T08:05:15.962Z
agent-p5-identityagent item.transitioned
2026-08-23T08:05:10.342Z
agent-p5-identityagent comment.added
2026-08-23T08:05:08.796Z
claude-peagent comment.added
2026-08-23T07:29:47.720Z
agent-p5-authzagent comment.added
2026-08-23T07:27:45.320Z
claude-peagent comment.added
2026-08-23T07:06:38.618Z
agent-p5-authzagent comment.added
2026-08-23T07:05:53.218Z
agent-p5-authzagent comment.added
2026-08-23T07:05:52.958Z
agent-p5-authzagent comment.added
2026-08-23T07:05:45.278Z
agent-p5-authzagent comment.added
2026-08-23T07:05:44.978Z
claude-peagent comment.added
2026-08-23T06:32:24.027Z
agent-p5-apikeyagent comment.added
2026-08-23T06:31:14.508Z
agent-p5-apikeyagent comment.added
2026-08-23T06:31:14.268Z
agent-p5-apikeyagent comment.added
2026-08-23T06:22:30.001Z
claude-peagent item.transitioned
2026-08-23T06:21:02.428Z
claude-peagent item.created
2026-08-23T02:01:13.524Z