Repository navigation
Conversation
Implements Auth → Test-mode Users → Lifetime, specified on 2026-10-20.
- Migration 0005_test_user_expiry: users.expires_at and
expired_processed_at, backfilled to created_at + 30 days for existing
test Users; check constraints, the sweep index, and test_user_expired /
user.expired in the device-reason and audit-action checks.
- Creation (signup and POST /v1/users) defaults test Users to 24 hours and
range-checks a requested expires_at; live Users reject it (live_user).
- Expired Users' platform tokens are rejected per request; sign-in,
refresh, MFA verify, app tokens, and oauth/token return
403 test_user_expired. Access, app-token, and session lifetimes are
capped at expires_at, and access resolution treats expiry like
suspension.
- PATCH /v1/users/{id} expires_at (users.manage only); extending a swept
User fires access.granted (test_user_extended).
- The entitlement-sweep job now also expires test Users exactly once:
sessions and devices revoked, access.revoked, user.expired webhook and
audit event.
- Expired Users aren't covered members of a test-mode subscription.
- openapi.yaml 1.0.0-draft.4, regenerated routes and MCP tools, docs,
Changelog, and plan-remaining.md updated.
Closes #30
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 22, 2026
Brings in the Substratal-Version header and root paths (#37), the plan-job secret fix (#59), and the versioning docs (#63). - Conflicts: plan-remaining.md keeps this branch's removal of the now-built section; Auth -> Lifetime keeps this branch's wording with root paths and anchors; the Changelog puts this branch's entry above main's two 2026-10-21 entries - openapi.yaml 1.0.0-draft.5 (main took draft.4 for the header change) - test_user_expiry_test.go: root paths; tools.json regenerated Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
terraform plan (production)This is exactly what merging will change in AWS. Plan |
… 0009 - Migration 0005_test_user_expiry → 0009_test_user_expiry: 0008_scim_tokens reached production first, and migrations are numbered in the order they ship. The backfill test now migrates through 0008 first. - Its audit action check is now the full set (SCIM's organization.scim_token_* and audit.exported included), so whichever order the open PRs merge in, no action is dropped. - openapi.yaml 1.0.0-draft.6 (SCIM took draft.5); Changelog entry stacked above SCIM's; tools.json regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adron
added a commit
that referenced
this pull request
Oct 22, 2026
…o 0010 - Migration 0006_self_registered_apps → 0010_self_registered_apps: 0008_scim_tokens reached production first, and #58's expiry migration is now 0009. - openapi.yaml 1.0.0-draft.7 (assuming #58 merges first as draft.6); Changelog entry stacked above SCIM's. - plan-remaining.md: both the SCIM and the self-service Phase 3 bullets are gone, since both are built. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adron
added a commit
that referenced
this pull request
Oct 22, 2026
- Migration 0007_audit_exports → 0011_audit_exports: 0008_scim_tokens reached production first; #58 and #60 are now 0009 and 0010. Its audit action check is the full set, SCIM's actions included. - openapi.yaml 1.0.0-draft.8 (after #58 draft.6 and #60 draft.7), 123 operations; Changelog, OpenAPI index, roadmap, schema, action catalog, ids, and plan-remaining.md merged with SCIM's additions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
terraform plan (production)This is exactly what merging will change in AWS. Plan |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #30.
Builds Auth → Test-mode Users → Lifetime, which was specified on 2026-10-20 and was the only specified API behavior with no code. It follows the build steps that were in
plan-remaining.md, in order. That section is now removed.What changed
0009_test_user_expiryusers.expires_atandusers.expired_processed_at.created_at + 30 days, so nothing changes for them.test_user_expiredto thedevices.inactive_reasoncheck anduser.expiredto theaudit_events.actioncheck.sessions.revoked_reasonhas no check constraint, so it needed nothing.POST /usersdefault test Users to 24 hours. A requestedexpires_atis range-checked (≥ 15 min, ≤ created_at + 30 days). A live User sending one getslive_user.401 session_revoked.oauth/tokenreturn403 test_user_expired.allowed: falseat once.exp, the app tokenexp,expires_in, and the session'sabsolute_expires_atare all capped atexpires_at.PATCH /users/{id}expires_at:users.manageonly; anyone else gets403 status_change_forbidden. Extending a User the sweep has already processed firesaccess.granted(test_user_extended). Writesuser.updated.entitlement-sweepjob also runsExpireTestUsers. For each expired User it revokes sessions and devices, then firesaccess.revoked(test_user_expired), theuser.expiredwebhook, and theuser.expiredaudit event (actorsystem). It does this exactly once per User.1.0.0-draft.6, with regenerated routes and MCP tools:403declared ontoken/refreshandmfa/verify.mfa/verifyalready returnedaccount_suspendedwithout declaring it.Spec clarifications (recorded in the Changelog)
details.fields, not in a separatedetails.reason.access.granted, since noaccess.revokedwent out for them either.Tests
internal/core/test_user_expiry_test.go:live_useron create and signup, and a chosen lifetime being kept.expcapping on refresh and app tokens.access.granted.0008with a test User and a live User, then migrated to0009.The harness has no fake clock, so the tests move
expires_atdirectly in the database.testenvgainsDatabaseThroughandMigrateRestfor migration tests.make checkpasses locally on this branch: gen-check, the full integration and contract suite including the Quickstart, Lambda builds, and terraform fmt. golangci-lint isn't installed locally; CI runs it.Notes
0009rewrites every test-modeusersrow (the backfill) and validates the new checks. That's cheap at today's volumes.Update (2026-10-22): rebased on the current API
main: header versioning (Move the API version from the URL to a Substratal-Version header #37, Spell out how API versioning works across the docs #63) and SCIM (Add SCIM 2.0 provisioning for Organizations #62). Every path is at the host root withSubstratal-Version: 1, and this description now uses root paths.0005_test_user_expiry→0009_test_user_expiry.0008_scim_tokensreached production first, and migrations are numbered in the order they ship. Its audit action check is now the full set, including SCIM'sorganization.scim_token_*and the other open PRs' actions, so no merge order can drop an action.info.versionis1.0.0-draft.6. SCIM tookdraft.5; the open PRs are numbered Build test-mode User expiry (expires_at) #58 →draft.6, Open POST /applications to self-service registration #60 →draft.7, Add Audit Event exports (POST/GET /audit-exports) #61 →draft.8, assuming they merge in that order.🤖 Generated with Claude Code