H1a: Tuvens account mapping + one-time-code validation service + external-id migrations - #22
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
tuvens
left a comment
There was a problem hiding this comment.
Coordinator review — REQUEST CHANGES (shared across #22/#24/#25): strip the docs sweep
The core H1a slice (the 7 code files: two CrossApp services, two migrations, services.php, the unit test, README line) reviews WELL against the ratified contract and ruling 1 — member-count-safe account claiming, HMAC timestamp.body signing with env-only secret and timeout, external_* migrations indexed, no Cognito anywhere. That part is approve-ready.
But the PR is +229,913 lines: ~800 lines of slice + ~229k lines of unrelated docs swept from the untracked tree — including a 214,005-line scrape dump (docs/HiEventsDev-Hi.Events-2025-07-22T17-46-34.md), docs/microdocs_generated/**, and docs/.claude/** command files. #24 and #25 carry the identical contamination (shared base commit), which is why #23 (stacked) is the only clean diff.
Required:
- Rewrite the three branches so each slice contains ONLY its code files (the H1 plan's own discipline: docs reviewed individually, never inside slices).
- The scrape dump and generated microdocs should almost certainly not enter git history at all — gitignore or delete; if any docs are genuinely wanted, one separate docs-only PR.
- Re-run your grep gates + suites after the rebase; ping #16 when the wave is clean and I'll re-review same-day.
No findings on the slice code itself — this is purely hygiene, and it matters: a 229k-line diff is unreviewable-by-default and buries your own excellent work.
… external-id migrations (H1a) First hardened slice of the Tuvens integration (#16, #17): - Migrations adding users.external_user_id and accounts.external_account_id (nullable, indexed) for cross-app identity mapping. - SecureCrossAppAuthService (CrossApp namespace): validates a one-time authorization code server-to-server against tuvens-api POST /api/service/hi-events/session/validate, signed with X-Tuvens-Timestamp + X-Tuvens-Signature (HMAC-SHA256 of "timestamp.body"). No token caching (codes are single-use), no TLS-verification bypass, no dev-secret fallback, no mock-user path, no sensitive response logging. Local users are provisioned from the validated identity with a random password and no Cognito round-trips. - CrossAppAccountMappingService: maps a Tuvens organiser onto a hi.events account. An existing account is reused only when it already carries the external id or has no other members; shared accounts are never silently claimed. Fabricated fallback emails and dev magic strings removed. - config/services.php main_backend block (env-only: MAIN_BACKEND_URL, MAIN_BACKEND_SHARED_SECRET, MAIN_BACKEND_TIMEOUT). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RrKvdjja8NtzqRKJnX7sA1
3308dc2 to
057aac4
Compare
|
Rebase done — the wave is clean. All three contaminated PRs were rebased onto current |
tuvens
left a comment
There was a problem hiding this comment.
Coordinator re-review — APPROVED (approval of record)
Rebase verified: exactly the six core files (+806), docs sweep gone from the wave. Slice content matches the previously-reviewed code (ruling-1-safe mapping, HMAC timestamp.body signing env-only, indexed external_* migrations, no Cognito). Merge when ready; #23/#27 retarget to develop after.
* feat(auth): Tuvens account mapping, one-time-code validation service, external-id migrations (H1a) (#22) First hardened slice of the Tuvens integration (#16, #17): - Migrations adding users.external_user_id and accounts.external_account_id (nullable, indexed) for cross-app identity mapping. - SecureCrossAppAuthService (CrossApp namespace): validates a one-time authorization code server-to-server against tuvens-api POST /api/service/hi-events/session/validate, signed with X-Tuvens-Timestamp + X-Tuvens-Signature (HMAC-SHA256 of "timestamp.body"). No token caching (codes are single-use), no TLS-verification bypass, no dev-secret fallback, no mock-user path, no sensitive response logging. Local users are provisioned from the validated identity with a random password and no Cognito round-trips. - CrossAppAccountMappingService: maps a Tuvens organiser onto a hi.events account. An existing account is reused only when it already carries the external id or has no other members; shared accounts are never silently claimed. Fabricated fallback emails and dev magic strings removed. - config/services.php main_backend block (env-only: MAIN_BACKEND_URL, MAIN_BACKEND_SHARED_SECRET, MAIN_BACKEND_TIMEOUT). Claude-Session: https://claude.ai/code/session_01RrKvdjja8NtzqRKJnX7sA1 Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * feat(auth): code-in-body cross-app exchange endpoint (H1b) Second hardened slice of the Tuvens integration (#16, #17): - CrossAppAuthAction reduced to a single exchange: POST /auth/cross-app/validate with {"code"} in the JSON body. The code is read strictly from the body (query-string values are ignored), validated server-to-server via SecureCrossAppAuthService, and exchanged for a hi.events JWT carrying an account_id claim, using the same response shape as regular login. - Removed: mock_session_* bypass, status/accounts/validate-permission endpoints (superseded by the one-time-code seam), token logging, and all query-param token reads. - config/app.php frontend_url is env-only (no localhost fallback). - CrossAppAuthenticationTest rewritten for the new contract (10 tests): exchange success incl. account+organizer provisioning, HMAC-signed upstream request, body-only code reads, mock tokens rejected, shared accounts never claimed, no validation caching. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RrKvdjja8NtzqRKJnX7sA1 * feat(auth): organiser gate and throttle on the cross-app exchange (review follow-up) Coordinator review asks on PR #23: - Defense in depth: refuse any validate response without organiser === true; tuvens-api's mint endpoint is the primary gate, but hi.events won't mint a session without the flag. New test asserts refusal without provisioning. - throttle:10,1 on the public exchange endpoint, with a 429 test. - Tightened code read to json('code') only (dropped the form-post fallback). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RrKvdjja8NtzqRKJnX7sA1 --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
First hardened slice of the Tuvens integration workstream. Closes nothing yet — part of #17, per the architecture brief #16 and the coordinator rulings posted there.
What's in this slice
users.external_user_id,accounts.external_account_id(nullable, indexed).SecureCrossAppAuthService(newCrossAppnamespace): exchanges a one-time authorization code server-to-server with tuvens-api (POST /api/service/hi-events/session/validate,X-Tuvens-Timestamp+X-Tuvens-Signature= HMAC-SHA256 overtimestamp + "." + body). Provisions local users from the validated identity.CrossAppAccountMappingService: maps a Tuvens organiser to a hi.events account and auto-creates an organizer. Per coordinator ruling 1, an existing account is reused only when it already carries the matchingexternal_account_idor has no other members — shared accounts can no longer be silently claimed by a Tuvens login.config/services.php:main_backendblock, env-only.Hardening applied inside the slice (brief item 6)
'dev-secret'HMAC fallback,verify => falseTLS bypass,mock_session_*/mock-user creation, response body/header/token logging, fabricated{name}@example.comemails, dev magic strings, 5-minute validation cache (codes are 60s single-use; caching would enable local replay).Deviation from ruling 5 (improvement, flagged for review)
Ruling 5 permitted committing
findOrCreateUserwith its inline Cognito provisioning intact, at the cost of a "do not deploy before H2" constraint. This slice instead removes the Cognito dependency from the committed service entirely (identity is verified upstream by tuvens-api before a code is minted, so Cognito registration added nothing but risk). Consequence: this slice is deployable on its own, and H2 shrinks to not-committing the remaining dead Cognito files. The prior Cognito-entangled implementation remains preserved in the operator's working-tree backup.Contract note (for the tuvens-api contract doc)
The brief's validate response carries no
account_id; the mapping service keys onaccount_id ?? user_idas the external account identifier. Please confirm indocs/integrations/hi-events-contract.md.Tests
SecureCrossAppAuthServiceTest(8 tests, 16 assertions) — signature correctness, failure/missing-config/missing-fields → null, no caching, user provisioning idempotency. Green locally against Postgres.🤖 Generated with Claude Code
https://claude.ai/code/session_01RrKvdjja8NtzqRKJnX7sA1