Files

4.1 KiB

Task 5 report — backend principal enforcement

RED

Added backend route/auth tests before implementation. The initial focused run failed in seven new assertions: getPrincipal did not exist, upstream requests still required the legacy identity header, foreign session/SSE routes were not hidden, admin scope was not enforced, new sessions had no trusted principal binding, and settings were global.

GREEN

  • Focused backend suite: 66 passed across auth, sessions, SSE, and settings tests.
  • Complete backend Vitest suite: 209 passed across 22 files.
  • npx tsc --noEmit -p ., npm run build, git diff --check, and changed Python source Ruff all exit successfully.
  • Harness targeted repository/local/migration tests and Python bytecode compilation exit successfully. The new tht session preferences get|set commands are registered and expose the expected Typer help. A direct local CLI preference smoke was not run because the checked-in local workspace requires unavailable THT_DB_HOST configuration.

Route and child-process coverage

  • GET /me returns the request PrincipalContext; upstream accepts only the portal's normalized X-Thoth-* identity tuple, with the legacy header ignored. Local mode uses the same stable THT_HOME/~/.thothii/identity.json UUID contract as the harness.
  • All session operations are principal-scoped: list (mine and admin-only all), show, create, resume, close, delete, rename, group, archive, unarchive, documents, reviewer response, steer, SQL preview/export, and SSE. Missing and foreign sessions are 404; absent upstream identity is 401. SSE is authorized before response headers or hub subscription, so a rejected request cannot attach to a live stream.
  • New/resumed Pi runtimes and every route-spawned tht process receive THT_PRINCIPAL_ISSUER, THT_PRINCIPAL_SUBJECT, optional display name, and admin flag. The readiness tht child is also principal-bound.
  • Settings use asynchronous repository-backed tht session preferences get|set in the production runner, which isolates preferences by principal. The legacy settings file is retained only as an injected-runner compatibility fallback for existing isolated tests.
  • Repository/settings authorization failures map to 503 before model startup. SQL execution errors remain 500 after authorization, preserving the prior API distinction.

Self-review and concerns

  • Confirmed the Task 4 portal emits lowercase true/false for the admin header; the parser accepts that exact normalized form plus the repository's existing 1/0 compatibility form, and rejects all other values.
  • The harness principal resolver is the ownership authority; the backend never accepts an owner supplied in request bodies. Its route guards use a repository-scoped session show before every session resource operation.
  • Existing dependency-injected route fakes without sessionShow retain a narrow test seam; production ThtRunner always has that method, so deployed requests cannot bypass the repository authorization check.

Review follow-up

RED

Focused regressions initially failed exactly at the three review findings: stale ambient display names survived into both tht and Pi child environments; mutation/document runner methods dropped the selected workspace; and expandLocalHome did not exist.

GREEN

  • Child environments now remove all four THT_PRINCIPAL_* keys from their cloned base environment before applying the exact request principal. Regression tests prove an absent display name does not inherit a stale ambient value in either child path.
  • setName, setGroup, archive, unarchive, and documents now take and retain an optional workspace. The rename route regression proves session show authorization and the mutation use the same non-default workspace.
  • Local principal paths expand ~/~/...; existing local home and identity file modes are repaired to POSIX 0700/0600 when applicable, with Windows left unchanged.
  • Focused suite: 74 passed; full backend suite: 213 passed across 22 files, followed by TypeScript typecheck, production build, and diff check.