Commit Graph

631 Commits

Author SHA1 Message Date
Jakub Zych
64f9009d3d test(fetchguard): widen streaming-cap ceiling to stop flake under parallel runs
TestFetchTooLargeIsStreaming asserted the server wrote at most 64 KiB, but
the handler keeps flushing 64-byte chunks until the client's close propagates,
which under a loaded full-suite run exceeds that (observed ~80 KiB). The
assertion guards against unbounded buffering toward 8 MiB, so 1 MiB keeps
the intent and removes the flake.
2026-09-23 21:15:43 +02:00
Jakub Zych
7f37311120 docs(08-05): complete consent plan 2026-09-23 21:11:45 +02:00
Jakub Zych
fac9648ac9 feat(08-05): add read-only UI-contract harness for consent and connected apps
check-phase8-ui.mjs encodes 08-UI-SPEC.md's full consent/connected-app
state matrix, accessibility, responsive, and i18n contract as a versioned
32-scenario catalog across 7 categories. --contract-self-test validates
catalog completeness, guarded Nuxt source-file hashes (proving the
harness itself never writes inside vue-fonoteka-app), and that
@playwright/test resolves from the already-installed dependency, all
without booting a browser or service (runs in ~50ms).

--final-gate (running verify:oauth-return-path, verify:oauth-i18n, and
the real Playwright matrix) is scaffolded but refuses to run without
PHASE8_UI_ALLOW_FINAL_GATE=1 and is explicitly 08-10's closing-checkpoint
responsibility, not executed by this plan.
2026-09-23 21:04:34 +02:00
Jakub Zych
a1fa9c6f44 feat(08-05): add wristband consent issue/deny operations
Server.PendingRequest/IssueCode/DenyPending port PHP
OAuthConsentController::pendingFor/OAuthCodeManager::issueCode as
app-agnostic protocol operations (08-CONTEXT.md D-08): every missing,
foreign-owner, used, expired, or already-issued pending row collapses to
the identical ErrPendingNotFound (T-08-CROSS-USER/T-08-REQUEST-LEAK).
IssueCode trusts the caller's already-computed granted scopes/collection
ids and returns the ordered redirect_to URL built through the existing
RFC 3986 encoder.

AuthCodeStore.MarkIssued gains scopes/collectionIDs/expiresAt parameters
(PHP's issueCode overwrites all three, not just code_hash/user_id) and
ClientStore gains MarkConsented, both required for D-08's consented_at
stamping and server-derived grant persistence. Options gains CodeTTL
(600s PHP-parity default) following the established Options-extension
pattern.
2026-09-23 20:59:24 +02:00
Jakub Zych
a459f74897 docs(08-04): complete token-exchange plan 2026-09-23 20:35:49 +02:00
Jakub Zych
4bd3b3db4f feat(08-04): implement atomic PKCE-bound code exchange in wristband
- Server.Token: JSON rejection before ParseForm, body-over-query precedence,
  Basic-over-form client auth, exact invalid_request/unsupported_grant_type/
  invalid_client/invalid_grant bodies, Cache-Control/Pragma on success only
- authenticateClient: public/confidential dispatch, constant-time secret
  compare (T-08-SECRET-TIMING)
- exchangeAuthorizationCode: single WithinTx lock/consume/mint/refresh-create
  covering code/client/redirect/resource/PKCE binding and single-use replay
  (T-08-CODE-REPLAY), sequential and concurrent proofs
- rotateRefreshToken: grant_type=refresh_token dispatches per PHP validity
  but is a deliberate invalid_grant placeholder; full rotation is 08-06
- full token_test.go behavior matrix appended alongside the RED anchor
2026-09-23 20:28:07 +02:00
Jakub Zych
5ca830beef test(08-04): add failing code-exchange RED test in wristband
- Server.Token 501 stub and TestPhase8RedCodeExchange (PHASE8_RED:code-exchange)
- Options gains AccessTokenTTL/RefreshTokenTTL with PHP-parity defaults
2026-09-23 20:25:16 +02:00
Jakub Zych
5dc8c35e06 docs(08-03): record parity test fix and fetchguard flake in deferred items 2026-09-23 20:16:21 +02:00
Jakub Zych
33ab188a2e docs(08-03): complete authorize plan 2026-09-23 20:11:54 +02:00
Jakub Zych
90752beb87 feat(08-03): implement exact authorize validation and pending creation in wristband
- Server.Authorize ports OAuthAuthorizeController::authorize's exact
  validation order: usable client, exact redirect, response_type=code,
  code_challenge_method=S256, challenge length, scope parsing/ceiling
  truncation, resource check, then opaque pending-request creation
- Unknown client/unregistered redirect are local text/plain 400s with no
  Location; every later failure is an ordered RFC3986 redirect with
  error/error_description/iss[/state], built via a dedicated encoder
  (never url.Values.Encode, which sorts keys and space-encodes as '+')
- Options gains Resource and PendingRequestTTL (both PHP-parity defaults)
  so authorize's resource check and 600s pending expiry are configurable
2026-09-23 20:08:37 +02:00
Jakub Zych
787e612ab3 test(08-03): add failing authorize RED test in wristband
- Server.Authorize stub returns 501
- TestPhase8RedAuthorize drives a full valid S256 request and asserts the
  exact 302 /connect success contract; fails with PHASE8_RED:authorize
  against the stub, verified fail-closed via check-phase8-red.sh
2026-09-23 20:01:18 +02:00
Jakub Zych
ae326b0941 docs(08-02): complete persistence and registration plan 2026-09-23 19:54:54 +02:00
Jakub Zych
c0b1e3cfae feat(08-02): implement exact RFC 7591 registration in wristband
- Register validates redirect_uris/grant_types/response_types/auth-method
  in PHP's exact order, strips control characters and caps client_name at
  255 runes, and generates client_id/secret via crypto/rand base64url
- confidential clients return the raw secret once; only its sha256 hex
  persists (constant-time-comparable fixed transform)
- sweep-unconsented, the atomic cap check and the create all run inside one
  wristband.Backend.WithinTx transaction (T-08-DCR-FLOOD)
- 64 KiB body bound via http.MaxBytesReader collapses to the endpoint's
  native invalid_client_metadata body, matching D-21
2026-09-23 19:37:54 +02:00
Jakub Zych
c026b83f41 test(08-02): add failing RFC 7591 registration RED test in wristband
- TestPhase8RedRegistration asserts the exact public-client DCR success
  contract and fails while Server.Register is a 501 stub
- adds the Backend/Tx transaction-scoped store bundle (ClientStore,
  AuthCodeStore, RefreshTokenStore, AccessTokenIssuer) and wristband's own
  in-memory implementation for framework-level tests (D-07)
- adds crypto.go's fixed-transform helpers (random base64url, sha256 hex,
  constant-time compare, S256) and Options/Server seams for the DCR
  lifetimes, cap, sweep age and 64 KiB body bound (D-03/D-21)
2026-09-23 19:37:03 +02:00
Jakub Zych
deee2cc8d7 docs(08-01): complete metadata RED infrastructure plan 2026-09-23 19:20:35 +02:00
Jakub Zych
c578bb58d7 feat(08-01): implement exact RFC 8414 metadata writer in wristband
- Server.Metadata now writes the unwrapped 11-field PHP-parity document
  through a local no-envelope, no-trailing-newline JSON writer with the
  PHP Cache-Control: no-cache, private header (D-06); response types,
  grant types and PKCE method stay fixed protocol constants
- TestPhase8RedMetadata now passes; TestMetadataExactBytes and
  TestMetadataUsesConfiguredOptions cover byte-exact output and the four
  configurable Options fields
2026-09-23 19:10:26 +02:00
Jakub Zych
24d35d85e8 test(08-01): add failing RFC 8414 metadata RED test and fail-closed verifier
- wristband.Server.Metadata is a compiling 501 stub; TestPhase8RedMetadata
  asserts the exact unwrapped PHP metadata document, headers and status and
  fails with the PHASE8_RED:metadata sentinel (D-06)
- scripts/check-phase8-red.sh implements the shared go/shell RED contract
  for the rest of Phase 8: exact selected test/package failure plus sentinel,
  rejecting unrelated fail actions, compile/setup failures, panics,
  malformed JSON, missing/duplicate sentinels and zero selection (D-04/D-18)
2026-09-23 19:09:14 +02:00
Jakub Zych
a59e69211d docs(08): finalize oauth plans after final checker pass 2026-09-23 18:42:49 +02:00
Jakub Zych
2d7ac66605 docs(phase-07): add security threat verification 2026-09-23 18:19:43 +02:00
Jakub Zych
e23cbac240 fix(08): revise oauth plans after checker feedback 2026-09-23 17:46:38 +02:00
Jakub Zych
3c6a505c5f fix(08): revise plans based on checker feedback 2026-09-23 17:13:47 +02:00
Jakub Zych
241af16ba7 docs(08): create OAuth authorization server plans 2026-09-23 13:38:58 +02:00
Jakub Zych
716d0ea40d docs(08): approve UI design contract 2026-09-23 12:53:09 +02:00
Jakub Zych
dd96f59e57 docs(8): revise UI design contract 2026-09-23 12:50:25 +02:00
Jakub Zych
2aafa6f2a2 docs(08): add UI design contract 2026-09-23 12:44:34 +02:00
Jakub Zych
37fbcdc6de docs(phase-08): add validation strategy and resolve research decisions 2026-09-23 12:32:31 +02:00
Jakub Zych
a3a4636c29 docs(08): research OAuth authorization server 2026-09-23 12:14:03 +02:00
Jakub Zych
47b856b1c6 docs(state): record phase 8 context session 2026-09-23 11:37:14 +02:00
Jakub Zych
251ac038e2 docs(08): capture phase context 2026-09-23 11:37:13 +02:00
Jakub Zych
b435304570 docs(phase-7): complete phase execution
Avatar bucket publish closed the last UAT blocker. Phase 7 is 8/8
verified. Next is discuss Phase 8; do not auto-advance.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-23 10:53:42 +02:00
Jakub Zych
e537b67a37 docs(07): verify phase after the avatar bucket gap close
Assembled avatar POST is 200. UAT is 12/12. AUTH-02 through AUTH-04
and I18N-02 are marked complete. Do not auto-advance.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-23 10:52:45 +02:00
Jakub Zych
3a15105a1b docs(state): record 07-08 completion and tracking
All eight Phase 7 plans have summaries. Avatar bucket publish is the
UAT gap close; phase verification still has to run.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-23 10:51:26 +02:00
Jakub Zych
b74484eabc docs(07-08): complete the avatar bucket publish plan
Serve and Handler now publish the uploads bucket; assembled avatar
POST is 200. Record the gap-closure outcome.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-23 10:50:01 +02:00
Jakub Zych
44900f0d16 feat(07-08): publish the uploads bucket on serve
Avatar upload 500s when serve never opens storage.uploads.bucket_url.
Wire OpenBucket + Publish on the CLI boot path so the user plugin can store files.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-23 10:43:47 +02:00
Jakub Zych
33f716ddef docs(07-08): plan avatar bucket publish on serve and Handler 2026-09-23 10:33:19 +02:00
Jakub Zych
ab84becf16 test(07): complete UAT - 11 passed, 1 issues 2026-09-23 10:33:16 +02:00
Jakub Zych
1bd9f9e056 docs(state): record phase 9 context session 2026-09-23 10:24:37 +02:00
Jakub Zych
8268ff780d docs(09): capture phase context 2026-09-23 10:24:22 +02:00
Jakub Zych
d20f99f2e6 docs(07-07): complete the user-api parity gap plan
Record the PHP-does-blacklist finding, the accepted Go 401 after logout,
and the 22-ported corpus so later phases do not revive the harness artifact.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-23 00:01:18 +02:00
Jakub Zych
31634f706f feat(07-07): localize lagoon validation with Laravel-shaped Polish messages
Replay of the user-api corpus needs lagoon::validate.* catalogs and
underscore-to-space attribute names so Go 422 bodies match Winter.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 23:56:58 +02:00
Jakub Zych
dd3cb7ac29 docs(07): record gap-closure planning in state 2026-09-22 20:41:30 +02:00
Jakub Zych
8a1a52915b fix(07): revise 07-07-PLAN.md for checker-found seeding blockers 2026-09-22 20:38:01 +02:00
Jakub Zych
f75e3e84db docs(07): plan gap closure for the pending user-api parity routes 2026-09-22 20:22:45 +02:00
Jakub Zych
d4e9c17816 docs(07): record the phase goal verification
The six plans are in, and three of the four success criteria hold. AUTH-01 stays blocked because the 15 user API routes are still pending against the recorded PHP bodies.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 19:27:27 +02:00
Jakub Zych
9446981ffd docs(07-06): complete the unit coverage plan
The validation contract is signed off and the phase plan count is 6/6. Requirement checkboxes stay open while the user-api routes are still pending.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 19:21:31 +02:00
Jakub Zych
4754377442 feat(07-06): prove mint, refresh, and blacklist under concurrency
A minted token refreshes once, then the old jti is blacklisted. Memory and Postgres blacklists take concurrent Add and IsBlacklisted calls.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 19:20:14 +02:00
Jakub Zych
fa7bdb5f71 docs(07-05): complete the user API parity capture plan
Record that the 15 user routes stay pending until Go matches the PHP bodies, including the HTML 500 on a bad activation code and the still-valid token after logout.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 18:44:05 +02:00
Jakub Zych
7d5d8659ec feat(07-05): allow the second parity test password
Change-password recordings need a distinct new password that the fixture scrubber still accepts.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 18:43:27 +02:00
Jakub Zych
ecfcd23150 docs(07-04): complete the personal token and locale plan
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 18:09:31 +02:00
Jakub Zych
4e56ff98b0 docs(07-03): complete the account management plan
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 16:48:10 +02:00