Skip to content

fix: meta-critic tiers 1-3 — security, architecture, tests#39

Open
AlexU-A wants to merge 2 commits intomainfrom
fix/meta-critic-tiers-1-3
Open

fix: meta-critic tiers 1-3 — security, architecture, tests#39
AlexU-A wants to merge 2 commits intomainfrom
fix/meta-critic-tiers-1-3

Conversation

@AlexU-A
Copy link
Copy Markdown
Contributor

@AlexU-A AlexU-A commented Mar 20, 2026

Summary

Addresses 16 findings from a 13-lane parallel meta-critic review of the entire repository, covering the top 3 priority tiers.

Tier 1 — Real Bugs (5 fixes)

  • SearchService interface mismatch — removed duplicate interface in retriever.ts, eliminated as unknown as unsafe casts in production init path
  • Inngest empty registry — replaced static empty registry with lazy proxy singleton (inngest/registry.ts) that delegates to the real registry once pipeline module initializes
  • content_search uses LIKE — wired SearchService FTS into the MCP tool handler with graceful LIKE fallback
  • verify_branch always returns match:true — now reads expected branch from StateStore snapshot
  • (Python score_against fix in separate PR for _private/joyus-profile-engine)

Tier 2 — Pre-Deploy Blockers (5 fixes)

  • Weak encryption — replaced CryptoJS passphrase-mode AES with Node native crypto AES-256-GCM (random IV + auth tag). Fail-closed in production when key missing.
  • Pipeline routes unauthenticated — added requireBearerToken middleware to /api route mount
  • Tenant spoofinggetTenantId() no longer trusts x-tenant-id header; derives from authenticated session/user only
  • Session secret — fail-closed in production when SESSION_SECRET not set
  • Env validation — new src/config.ts with Zod-based validation at startup

Tier 3 — Pre-Users (6 fixes)

  • CSRF — disconnect route changed from GET to POST; SameSite=lax on session cookie
  • XSSescapeHtml() applied to all user values in scheduler HTML templates
  • CSP — enabled Content Security Policy via helmet
  • Rate limitingexpress-rate-limit on auth (20/15min) and API (100/15min) routes
  • Entitlement cache — wired periodic 5-minute cleanup interval with unref()
  • Auth tests — 55 new tests for auth/routes.ts and auth/verify.ts (was 0% coverage)

Governance & Documentation (bundled)

  • Constitution v1.7 — added §5.4 "MCP Architecture": four-server domain boundary, mandatory domain prefixing, Tool Search-optimized description guidelines, no MCP for internal integrations, per-agent MCP isolation pattern
  • Spec 010 backfill — added research.md and requirements checklist documenting the completed Inngest evaluation spike
  • Spec 011 task files — WP01–WP04 task breakdowns with completion status
  • .gitignore — allowlisted 011 task files

Files Changed

  • 30 files changed, +1,648 / -112 lines
  • 12 new files: src/config.ts, src/inngest/registry.ts, tests/auth/routes.test.ts, tests/auth/verify.test.ts, kitty-specs/010-inngest-evaluation/research.md, kitty-specs/010-inngest-evaluation/research/research.md, kitty-specs/010-inngest-evaluation/checklists/requirements.md, kitty-specs/011-inngest-migration/tasks/WP01-port-remaining-pipelines.md, kitty-specs/011-inngest-migration/tasks/WP02-update-routes.md, kitty-specs/011-inngest-migration/tasks/WP03-delete-custom-plumbing.md, kitty-specs/011-inngest-migration/tasks/WP04-integration-tests.md
  • New dependency: express-rate-limit
  • crypto-js is now unused and can be removed in a follow-up

Test plan

  • npx tsc --noEmit — 0 errors
  • npx vitest run (mcp-server) — 420 passed, 0 failed
  • npx vitest run (state) — 433 passed, 2 pre-existing flaky failures (git collector env issue)
  • Python profile engine — 555 passed (separate repo)
  • Manual: verify scheduler UI renders correctly with escaped HTML
  • Manual: verify disconnect button works as POST form
  • Manual: confirm rate limiting headers appear on API responses

🤖 Generated with Claude Code

…fixes, and test coverage

Tier 1 (bugs):
- Fix SearchService interface mismatch — remove duplicate interface, eliminate unsafe casts
- Fix Inngest empty registry — lazy proxy singleton populated during pipeline init
- Wire SearchService FTS into content_search MCP tool (replaces LIKE fallback)
- Fix verify_branch to read expected branch from state store instead of hard-coded null

Tier 2 (pre-deploy):
- Replace CryptoJS AES (weak passphrase KDF) with Node native AES-256-GCM
- Fail-closed encryption when TOKEN_ENCRYPTION_KEY missing in production
- Add bearer token auth middleware to pipeline API routes
- Fix tenant spoofing — derive tenant from authenticated user, not x-tenant-id header
- Session secret fail-closed in production
- Add Zod-based env var validation at startup (new src/config.ts)

Tier 3 (pre-users):
- CSRF: change disconnect from GET to POST, add SameSite=lax cookie
- XSS: escape all user values in scheduler HTML templates
- Enable Content Security Policy via helmet
- Add rate limiting (express-rate-limit) to auth and API routes
- Wire periodic entitlement cache cleanup (5min interval)
- Add 55 auth route tests (routes.test.ts + verify.test.ts) — was 0% coverage

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: fd7d2e1083a4
- Add Feature 010 requirements checklist and research doc (ART-003)
- Add Feature 011 WP01-04 task prompt files and gitignore exceptions (REF-001)
- Sync .kittify/memory/constitution.md with spec/constitution.md (CONST-002)

Governance check: 0 P0 failures (was 6)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 340ab52d5259
@grndlvl grndlvl self-requested a review March 21, 2026 13:15
Copy link
Copy Markdown
Member

@grndlvl grndlvl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Requested Changes

MCP Token Display Hardening

The MCP bearer token (generateMcpToken) is currently displayed in full on the dashboard every time. Needs:

  1. Show once — Display the full token only immediately after user creation (use a session flash). On subsequent dashboard visits, show only the first 8 characters masked (e.g., a1b2c3d4...). Remove the "Copy" button when masked.

  2. Regenerate endpoint — Add a POST /auth/regenerate-token route that generates a new MCP token, replaces the old one in the DB, and flashes the new token for one-time display. Include a confirmation step or button on the dashboard.

@grndlvl grndlvl assigned AlexU-A and unassigned grndlvl Mar 21, 2026
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