Skip to content

service-template-894: Add protected users.revoke capability - #72

Merged
vladmesh merged 1 commit into
mainfrom
pipeline/service-template-894
Aug 31, 2026
Merged

vladmesh merged 1 commit into
mainfrom
pipeline/service-template-894

Conversation

@vladmesh

Copy link
Copy Markdown
Owner

Card: service-template-894 — Add protected users.revoke capability
Branch: pipeline/service-template-894 → main

What the card asks for

Goal

Give newly generated backend+Telegram-bot services a protected, typed users.revoke(channel, external_id) capability so the orchestrator can end a temporary QA grant by making the same stored User.status gate inactive.

Context

  • service-template-893 is merged on the default tree 29417d16043981de449bead3e7fb3953b7455ce3. It provides protected POST /users/grant, public GET /users/access, User/UserChannel, and User.status as the sole Telegram admission gate.
  • codegen-orchestrator-1232 deliberately preserved its temporary QA environment-slot protocol because the template had no expiry/revoke semantic. Its durable TemporaryAccessGrant reconciler already owns TTL, retries, release of QA, and proof that access has been removed. A later codegen card will change that reconciler to call this capability; it must not invent a permanent QA grant or emulate expiry in the template.
  • The backend's grant security boundary is services/backend/src/app/grant_capability.py: one generated-secret USERS_GRANT_CAPABILITY is presented only as X-Grant-Capability. It currently protects only /users/grant and must protect every privileged users write endpoint without exposing the header in OpenAPI or helper commands.
  • The current repository/controller/spec paths are template/shared/spec/models.yaml, template/services/backend/spec/users.yaml, src/app/repositories/user.py, src/controllers/users.py, generated seeds, migrations, backend tests, tg_bot admission tests, contract docs, and Copier coverage.

Acceptance criteria

  • Add a typed users.revoke(channel, external_id) contract and protected POST /users/revoke route. It accepts an explicit identity shape, returns the existing typed UserAccess result, and uses the same single generated USERS_GRANT_CAPABILITY header contract as grant. The header/value remains absent from generated OpenAPI examples, user-facing commands, events, diagnostics, and logs.
  • revoke never creates or activates an identity. For an existing identity it idempotently changes that identity's User.status to inactive and returns the resulting inactive access state; repeats return the same inactive state. An unknown identity fails closed without creating a row. A subsequent users.grant reactivates it through the existing sole activation path.
  • Telegram admission remains derived solely from User.status: after a successful revoke, that Telegram identity is denied before any application handler; no expiry field, environment allow-list, owner literal, channel-specific fallback, or second admission gate is introduced.
  • The middleware authenticates both grant and revoke before any database write, including missing, wrong, duplicate, and malformed header cases. GET /users/access remains the read-only resolution contract and does not accept or expose the capability.
  • Follow the repository spec-first workflow: regenerate and commit every affected shipped schema, protocol/router, OpenAPI, TypeScript, event artifact if applicable, and a migration only if the final model change actually requires one. A fresh Copier output must be importable before setup and describe grant, revoke, and access rather than obsolete user CRUD.
  • Add focused regressions for authenticated and rejected revoke, idempotent inactive result, unknown no-write behavior, grant-after-revoke reactivation, and bot denial after revoke. Update living backend/template contract documentation and the unreleased changelog.
  • Run the repository canonical broad check once on the final content tree and report the candidate SHA. Dispatcher exact-SHA validation remains authoritative. Do not run a Stand/mega E2E or rotate credentials.

Out of scope

  • Changing codegen_orchestrator's TemporaryAccessGrant model, scheduler/reconciler, deploy worker, QA handoff, or environment-slot cleanup. Those consume this merged capability in the next card.
  • Adding autonomous expiry scheduling, a new secret/capability, end-user au

… (truncated; the full text is on the card)

What the worker reports

Delivered candidate 89436d602b322212387aa7fd4dbcc9192fbdb483 (Add user revoke capability).

  • Added typed UserRevoke, protected POST /users/revoke, generated protocol/router/OpenAPI/TypeScript artifacts, and idempotent no-create deactivation through the existing User.status gate. Grant remains the sole activation path.
  • Extended the existing single X-Grant-Capability middleware boundary to authenticate both privileged writes before handling invalid, duplicate, missing, wrong, or malformed headers. /users/access remains read-only and undocumented capability-free.
  • Added backend regressions for rejected/authenticated revoke, idempotence, unknown no-write, reactivation, and generated bot coverage proving a revoked Telegram identity is stopped before handlers. Updated the template/backend contract docs and Unreleased changelog. No migration was needed because the ORM model is unchanged.
  • Fresh backend+tg_bot Copier render compiled before setup; after setup, backend tests passed (22) and bot tests passed (23). make lint-template, spec validation, and framework mirror sync passed.
  • Worker-local broad receipt for the exact committed content: python -m pytest tests/unit tests/tooling tests/copier -m not slow; 286 passed, 13 deselected, exit 0, 168.001s. Receipt state/checks/broad-a00b157112b08b9b.json, content tree 5a7046dc38a1b8119d28dcc39b011aa90517457b, imported from this workspace. This is worker-local evidence; dispatcher exact-SHA validation remains authoritative.

Workspace is clean. TASK.md was not modified or committed.


Opened by the secretary CI gate so that the pull_request workflow runs. Title and body are built from the card and the worker's done report.

@vladmesh
vladmesh merged commit edf54df into main Aug 31, 2026
3 checks passed
@vladmesh
vladmesh deleted the pipeline/service-template-894 branch August 31, 2026 14:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant