DataTalksClub / DataTalksClub/website
Enable development owner login, Studio access, and management API token issuance
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 0
- Forks
- 0
- PR merge metrics
- No merged PRs in 30d
Description
Outcome
On https://web.dtcdev.click, the owner can authenticate with one development-only local owner identity, use Django admin at /admin/ and the distinct custom Studio at /studio/, and issue a scoped, expiring, revocable Bearer token for a development automation service principal. Runtime Studio and /api/v1/admin/ expose credential list/create/rotate/revoke through the existing hashed APICredential services. The first automation token can call the implemented /api/v1/admin/health; the UI and API do not claim unavailable domain actions.
This is a rapid development vertical slice. It does not weaken or decide the production OIDC, MFA, break-glass, or final high-risk policy owned by #20/#28/#32/#33/#61.
Authority and current facts
_docs/specs/06-studio-and-admin-api.md: distinct management adapters, explicit permissions, Bearer tokens, one-time secrets, lifecycle, parity, audit, and private caching._docs/specs/07-security-privacy-operations.md: protected staff/session/API credentials, CSRF, redaction, and deny-by-default authorization._docs/specs/10-verification-strategy.md: staff denial and API-token one-time-display browser coverage.- Exact reviewed baseline:
872fd8a9145a0e29de8890e9ea3e9d8df8c63cfd. - Closed #86 provides explicit Studio roles/permissions, revocable
StaffSession, audit, and private Studio middleware. Closed #87 providesAPIPrincipal, password-style hashedAPICredential, Bearer authentication, scope/permission checks, rate limits, idempotency, concurrency, OpenAPI/parity, and test-only credential lifecycle adapters/services. Closed #100 preserves one durable website account model. - Current deployed reality is intentionally empty of production-origin users, tokens, sessions, SocialApps, and SocialAccounts; the login page therefore reports no configured providers. The owner's production password/account cannot work in this development database unless a separately approved exact identity is loaded. This issue does not load it.
Canonical management surfaces
/admin/remains Django admin for low-level model administration. Do not rename, replace, or style it as Studio./studio/remains the custom management product over capability-registered application services./api/v1/admin/remains the JSON automation API over the same services and permissions.- Safe
GET/HEADrequests to/adminreturn one permanent redirect directly to/admin/;/studiodoes the same to/studio/. Preserve the query string, produce no redirect chain, and do not redirect unsafe methods. - Anonymous
/admin/follows Django admin's own login flow. Anonymous/studio/redirects once to/accounts/login/?next=%2Fstudio%2F; authenticated but unauthorized requests return403, not a misleading login loop.
Scope
Development owner bootstrap and login
Implement one secret-safe bootstrap interface for an authorized operator. The preferred application contract is an idempotent bootstrap_development_owner management command/service that:
- refuses unless
DTC_ENVIRONMENT=development; test code may exercise the underlying service only with explicit test settings; - accepts exactly one operator-confirmed owner email and a new development password via a non-echoing interactive channel, never a command-line argument, URL, committed file, issue comment, CI input/output, application log, or persisted bootstrap record;
- creates exactly one
accounts.CustomUserwhen absent, or resets only that same normalized identity after explicit reset confirmation; a conflicting existing identity or second owner attempt fails closed; - sets active/staff/superuser for Django admin, assigns the code-owned
site_admingroup for explicit Studio authority, and creates/updates the owner's linked humanAPIPrincipalwith only the credential-management and health permissions registered by this issue; - creates/updates one named development automation service principal with only
core.access_studioinitially and no plaintext credential; the owner issues its first token in Studio; - on reset, revokes the owner's existing
StaffSessionrows and owner-human API credentials before accepting a new login; it does not silently revoke or recreate the separately visible service credential; - prints only a fixed success/failure category and safe counts—never email, password, token, digest, session key, database value, or provider material.
Document the exact authorized execution handoff without embedding a secret. If the deployed interactive execution mechanism is still under operational/AWS audit, engineering must still deliver and test this command/service interface; the operator invocation is [HUMAN] and must not broaden CI/deployer AWS permissions or block the code deployment.
On development only, /accounts/login/ adds a CSRF-protected local email/password form using the durable account backend. It uses generic invalid-credential responses and bounded throttling, preserves only a validated same-host next, rotates the Django session on success, and creates the existing revocable StaffSession for active staff. Production/local-test behavior does not silently enable routine local staff passwords.
Explicit Studio authority
is_staff/is_superuserpermits Django admin as Django intends, but neither bypasses Studio authorization.- Studio requires active staff, an unrevoked
StaffSession, and explicitsite_adminpermissions checked on every request. - Logout, owner disablement, role removal, session revocation, and owner password reset deny Studio on the next request.
- The
site_adminrole gains one explicit credential-management permission; lower roles receive none.
Runtime credential workflows
Register non-test capabilities and readable CMP-based, line-broken Django templates for:
| Action | Studio | Admin API |
|---|---|---|
| List safe credential metadata | GET /studio/access/api-credentials/ |
GET /api/v1/admin/credentials |
| Create for an allowed service principal | POST /studio/access/api-credentials/ |
POST /api/v1/admin/credentials |
| Rotate | POST /studio/access/api-credentials/<uuid>/rotate/ |
POST /api/v1/admin/credentials/<uuid>/rotate |
| Revoke | POST /studio/access/api-credentials/<uuid>/revoke/ |
POST /api/v1/admin/credentials/<uuid>/revoke |
All adapters call shared management_auth query/command services through the capability registry; no adapter writes models directly. Target querysets are limited to active service principals the actor may manage. Missing, malformed, out-of-scope, human, and unauthorized targets do not leak object existence.
Create allows a safe name, an expiry within the existing 90-day maximum (default 30 days), and one or more non-test capability scopes that the target principal currently possesses. For this slice the development automation principal is entitled only to studio.home.read, so its first token can call GET /api/v1/admin/health. No wildcard, future implicit scope, or unimplemented action is shown. Future registered capabilities become selectable only after their owning issue grants the service principal permission and the owner explicitly issues a new scoped credential.
List responses contain only safe metadata: credential UUID, name, principal label/UUID, prefix, scopes, expiry, state, approximate last-used time, created time, and revision. They never expose the token, secret digest, password material, authorization header, or a recovery action.
Create and rotate reveal the raw token exactly once in the immediate successful response. Refresh, back navigation, idempotent replay, later GET/list, audit, database, logs, errors, OpenAPI examples, test artifacts, and screenshots cannot recover it. A create/rotate replay returns the existing safe result as secret_unavailable_on_replay without a token. Rotation preserves approved scopes, defaults to zero overlap, permits only an explicitly requested overlap up to the existing one-hour maximum, and marks the predecessor unusable after that bound. Revocation is immediate and safely idempotent.
Studio mutations require CSRF and explicit confirmation. Admin API create/rotate/revoke require Bearer authentication, the exact management scope/permission, confirmed: true, and Idempotency-Key; rotate/revoke also require the current revision (If-Match or the existing exact revision convention). Stale writes return 409 without mutation. Use existing bounded JSON, field allowlist, CORS-deny, rate, and safe error conventions.
Every allowed and denied create/rotate/revoke and bootstrap/reset action writes redacted audit evidence with actor, target snapshot, outcome, request/idempotency correlation, scopes, expiry/state, and safe reason. Never audit credentials, passwords, digests, headers, cookies, session keys, email values, or request bodies containing secrets.
Management response policy
Every response and redirect under /admin, /admin/, /studio, /studio/, /api/v1/admin/, and the development owner login flow is Cache-Control: private, no-store and X-Robots-Tag: noindex, nofollow; authenticated responses must not enter a public sitemap. Login, logout, denial, validation, one-time reveal, stale, and error states follow the same policy.
Non-goals
- Importing any production user table, password hash, session, token, reset material, Allauth provider/app/account row, other user's PII, registration/activity data, or a broad production database.
- Configuring a social/OIDC provider or deciding production MFA, break-glass, high-risk freshness/dual approval, production Django-admin availability, or final credential retention; #20/#28/#32/#33/#61 retain those responsibilities.
- Replacing Django admin with Studio, folding Studio into
/admin/, exposing Django admin models through the admin API, or restoring legacyaccounts.Token/plaintext CMP tokens. - Principal/role administration beyond the two bootstrap principals, domain CRUD, content sync, course/event/email actions, wildcard scopes, token recovery, production cutover, or AWS/IAM/Secrets Manager mutation.
- Claiming the development automation token can perform any action not present in the runtime capability registry.
Acceptance criteria
- One authorized development bootstrap creates/resets only the exact owner, assigns Django-admin flags plus explicit
site_admin, creates the human and development service principals, leaks no identity/secret, and refuses production, noninteractive secret input, conflicts, and a second owner. - The owner can use the development login form, receives a fresh revocable
StaffSession, reaches both distinct/admin/and/studio/surfaces, and loses Studio access immediately after logout, reset, disablement, role removal, or session revocation. -
/adminand/studioperform exact one-hop permanent safe-method redirects to their slash routes with query preservation; unsafe methods do not redirect; canonical surfaces remain distinct. - Runtime capability registry, Studio, admin API, OpenAPI, permissions, services, audit, idempotency, concurrency, and results cover list/create/rotate/revoke with no test-only fixture route used at runtime.
- The first service token is scoped only to
studio.home.read, succeeds on/api/v1/admin/health, and is denied on missing scopes, credential-management operations, test-only operations, and unknown domain operations. - Secrets are one-time only and hashed at rest; list/replay/back/refresh/log/audit/error/database/artifact/screenshot checks expose no raw token, password, digest, cookie, or authorization header.
- Expiry (default 30/max 90 days), zero/default and max-one-hour rotation overlap, immediate revocation, owner/principal disablement, permission removal, stale revision, replay, mass assignment, target scoping, throttling, and generic denials behave fail closed.
- CSRF protects every Studio/login mutation; admin API mutations enforce Bearer scope, confirmation, idempotency, revision where applicable, bounded input/rate, and deny-by-default CORS.
- All management/login responses are private/no-store/noindex and templates are CMP-based, readable, indented, line-broken, and non-minified.
- Focused Django/auth/management/OpenAPI/parity tests and core Playwright pass; after independent tester and PM acceptance, normal main deployment proceeds automatically. The operator's real bootstrap invocation/login/token copy is reported separately as
[HUMAN]without secret evidence.
Focused Django and security scenarios
- Exercise bootstrap create, same-owner idempotent run, explicit reset, second/conflicting owner, production refusal, noninteractive refusal, rollback on failure, and output/log/audit secret canaries. Assert exact user/group/principal/session/credential counts and no production identity/provider/token rows.
- POST valid/invalid local login with CSRF, throttling, hostile external
next, duplicate normalized email, inactive/nonstaff/unassigned/superuser-only users, session fixation, logout, reset, revoke, and permission change. Studio never accepts flag-only authority. - Assert exact slashless redirect status/location/query/hop count for GET/HEAD and non-redirect behavior for POST, followed by canonical Django-admin versus Studio auth behavior.
- Through both adapters, create/list/rotate/revoke the service credential; compare status, safe result, database effect, audit action, and permission decisions. Assert one-time token display and password-style digest verification without persisting raw secrets.
- Replay create/rotate/revoke, reuse idempotency keys with changed payloads, race/stale revisions, expire/rotate/revoke/disable/remove permission, malformed IDs, human/out-of-scope targets, unknown/extra fields, invalid scopes/expiry/overlap, and rate exhaustion. Assert no existence leak or partial mutation.
- Call
/api/v1/admin/healthwith the first token, then prove missing/malformed/wrong/expired/revoked/rotated tokens and test-only/unregistered operations fail with the existing safe envelope. Regenerate OpenAPI and parity artifacts with only real runtime routes. - Scan response bodies, redirect locations, database rows, captured logs, audits, idempotency records, templates, OpenAPI, and test artifacts for token/password/digest/header/session/email canaries.
Browser acceptance
At desktop (~1440×900) and mobile (~390×844), using isolated synthetic identities only:
- Visit
/adminand/studio; verify direct slash redirects, distinct branding/purpose, correct login destination, no redirect loop, and private/noindex headers. - Log in through the development owner form with keyboard-only controls; verify safe invalid credentials, preserved local
next, Studio navigation, separate Django admin, responsive layout, visible focus, and logout/back-cache denial. - In Studio list zero credentials, create the health-only automation token, verify the one-time warning/copy affordance without capturing the token, navigate away/back/refresh and confirm it cannot be revealed again.
- Rotate with zero overlap, inspect safe predecessor/successor states, revoke the successor, and verify confirmation/cancel/stale/error/empty states. No secret appears in URL, page title, history, screenshot, or console/network diagnostics.
- Use a separately injected synthetic token in the API client to prove health success then expiry/revocation denial; screenshots contain redacted placeholders only.
Store screenshots only under .tmp/screenshots/issue-107/, inspect each image, and post an independent tester report before PM acceptance.
Dependencies and delivery
Closed #86, #87, and #100 are sufficient implementation prerequisites. #20/#28/#32/#33/#61 are production-policy follow-ups, not blockers for this development-only owner slice. #99's safe review-data boundary is evidence that production identities are absent, not a dependency and not permission to import them.
Follow _docs/PROCESS.md: engineer implements/tests without committing; independent tester verifies and captures safe screenshots; PM accepts; engineer commits; orchestrator locally merges/pushes without a pull request; on-call alone observes CI/deployment. No secret may be used as lifecycle evidence.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with _docs/specs/06-studio-and-admin-api.md, _docs/specs/07-security-privacy-operations.md, and _docs/specs/10-verification-strategy.md, then trace the existing management_auth services, capability registry, Studio routes, and /api/v1/admin/ entry points. Done means the development-only owner flow and distinct admin/Studio surfaces work, credential lifecycle behavior and one-time secret handling meet the acceptance criteria, and the specified denial and browser checks pass.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- django, python
- Domain
- api, authentication, backend, security, testing-qa
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100