Skip to content

feat(auth): control schema, local accounts and sign-in sessions (M2a, #92) - #98

Merged
amar-python merged 1 commit into
mainfrom
feat/m2a-control-schema-local-accounts
Oct 26, 2026
Merged

amar-python merged 1 commit into
mainfrom
feat/m2a-control-schema-local-accounts

Conversation

@amar-python

Copy link
Copy Markdown
Owner

Fixes #92. This is part 1 of 5 of ART Milestone 2 (BR-36; ADR-0003).

What changes

  • Migration 0004_control_schema. Adds a control schema (name set by CONTROL_SCHEMA) with four tables:

    • tenants: the slug is checked as ^[a-z][a-z0-9_]{1,40}$.
    • users.
    • memberships: one role per user per tenant, limited to uploader, reviewer, tenant_admin or auditor.
    • sessions.

    Downgrade drops the schema.

  • api/services/accounts.py.

    • Passwords are hashed with stdlib hashlib.scrypt, so there's no new dependency and it works air-gapped.
    • Session tokens come from secrets.token_urlsafe(32). The token is returned once, and only its SHA-256 is stored.
    • All login failures return the same 401: wrong password, unknown user, unknown tenant, not a member, inactive. Unknown users are still checked against a dummy hash, so a miss takes about as long as a hit.
  • /api/auth endpoints. POST /login (tenant, username, password) returns a token, POST /logout revokes it, and GET /me returns the user, tenant and role.

  • What makes a session invalid. Expiry (SESSION_TTL_HOURS, default 12), logout, deactivating the user, or removing their membership all end a session immediately.

  • require_session dependency. Ready for use, but not yet applied to the data routers. M2b: route every request to its tenant's schema (BR-36) #93 (tenant routing) and M2c: role-based authorisation matrix (BR-36) #94 (role matrix) switch them over. Until then the existing API-key gate is unchanged.

  • scripts/create_tenant_admin.py. Creates a tenant and its first admin. It reads the password from TE_ADMIN_PASSWORD or prompts for it, and requires at least 12 characters.

  • Other changes. CORS now allows the Authorization header. docs/ENV_VARIABLES.md documents the two new settings. The migration tests now use a throwaway control schema, so they never drop the live one.

Evidence

All runs are against local PostgreSQL 16.

Check Result
Local replica of the CI integration job (scripts/test_report.py --strict) 268 passed, 0 failed, 0 skipped (255 on main + 13 new)
Evals p,i,s,e 26/26
tests/test_accounts.py + tests/test_migrations.py 21 passed
Same tests with expiry, revocation and the password check removed from the service 4 fail (as expected)
DB-free pytest 126 passed
scripts/lint.sh clean (new files added to the gate)
CLI creates a tenant and admin, and that admin signs in (200, tenant_admin); a short password is refused

The login endpoint is covered by the existing global rate limit for writes (20 per minute per client). A per-account lockout isn't included; say if you want it.


Generated by Claude Code

…92)

Migration 0004 adds a control schema (name from CONTROL_SCHEMA) with
tenants, users, memberships (the four ADR-0003 roles) and sessions.
Passwords use stdlib scrypt; session tokens are random, returned once
and stored as SHA-256 hashes. POST /api/auth/login, POST /api/auth/logout
and GET /api/auth/me; require_session is ready for the data routers (#93,
#94) but not applied to them yet. scripts/create_tenant_admin.py creates
a tenant and its first admin.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019YPoXzBSj89ZHgw7nfTmbB
@amar-python amar-python added this to the ART extension milestone Oct 26, 2026 — with Claude
@amar-python amar-python added enhancement New feature or request art ART framework extension work labels Oct 26, 2026 — with Claude
@amar-python
amar-python merged commit 2ca4e6e into main Oct 26, 2026
3 checks passed
@amar-python
amar-python deleted the feat/m2a-control-schema-local-accounts branch October 27, 2026 10:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

art ART framework extension work enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

M2a: control schema and local accounts (BR-36)

2 participants