Repository navigation
spec: v0.1.25.14 — dual-auth on 6 tenant-scoped webhook endpoints (Stage 3) - #40
Merged
Merged
Conversation
Stage 3 of the admin-on-behalf-of rollout. Adds AdminKeyAuth alongside
ApiKeyAuth on the tenant-scoped /v1/webhooks/* endpoints that are
meaningful for admin incident response. Matches the pattern from
v0.1.25.13 (budgets/policies) and the 2026-04-13 reservations revision
in cycles-protocol-v0.
Dual-auth added to:
- GET /v1/webhooks listTenantWebhooks
- GET /v1/webhooks/{subscription_id} getTenantWebhook
- PATCH /v1/webhooks/{subscription_id} updateTenantWebhook
- DELETE /v1/webhooks/{subscription_id} deleteTenantWebhook
- POST /v1/webhooks/{subscription_id}/test testTenantWebhook
- GET /v1/webhooks/{subscription_id}/deliveries listTenantWebhookDeliveries
Intentionally NOT dual-auth:
- POST /v1/webhooks (createTenantWebhook) — URL / secret / event choices
are tenant policy; admin creating on a tenant's behalf obscures
provenance.
- POST /v1/webhooks/{id}/replay — already admin-only at
/v1/admin/webhooks/{id}/replay; tenant self-service replay remains
tenant-key-only (bulk re-delivery is a capacity decision owed to the
tenant).
Semantics:
- listTenantWebhooks gains `tenant` query param: REQUIRED under
AdminKeyAuth (filter), MUST NOT be set under ApiKeyAuth. Same
single-param dual-semantic pattern as listBudgets / listPolicies /
listReservations.
- Per-subscription endpoints resolve the owning tenant from the
subscription record under AdminKeyAuth. 404 preserved across both
auth types for consistency.
- Admin-driven PATCH/DELETE MUST record actor_type=admin_on_behalf_of
in the shared audit store. Callers SHOULD populate a structured
reason (e.g., [WEBHOOK_PAUSE], [WEBHOOK_FORCE_DELETE]) for
grep-ability.
Backward compatibility: purely additive. Existing ApiKeyAuth callers
see no behavior change. No schemas modified.
Gates: spectral lint clean (0 errors; pre-existing warnings unchanged).
Merged artifact (merged/cycles-openapi-admin-merged.yaml) regenerated.
2 of 4 tasks
amavashev
added a commit
that referenced
this pull request
Apr 14, 2026
README header listed 'Governance base: v0.1.25.8'. After PR #40 (Stage 3 webhooks dual-auth) the governance-admin spec is at editorial revision v0.1.25.14. The semantic_base is frozen at 0.1.25.9 per the PR #41 versioning model. Updated to 'v0.1.25.14 (semantic_base 0.1.25.9)' — surfaces both values so readers see the latest feature revision AND understand wire-compatibility is tied to the 0.1.25.9 baseline.
amavashev
added a commit
that referenced
this pull request
Apr 14, 2026
…ard-compat) Additive spec extension reserving the contract for tenant-role introspect. No server implementation required in this revision; no downstream repos touched. Purely forward-compatibility stake so future multi-role clients don't re-litigate the capability shape or drift across implementations. Changes (all additive, zero wire impact on existing admin callers): 1. Security block on GET /v1/auth/introspect gains ApiKeyAuth alongside existing AdminKeyAuth. Same dual-auth pattern used for budgets/policies (#36), reservations (#37), and webhooks (#40). 2. AuthIntrospectResponse schema gains three fields, populated only when auth_type=tenant: - tenant_id (REQUIRED under tenant auth; MUST be absent under admin) - scope_filter (OPTIONAL; non-empty when key has scope restrictions) - auth_type enum gains value "tenant" alongside existing "admin" 3. Also surfaces the optional manage_* / view_reservations capability flags that servers have been returning for several releases (pre- existing wire behavior, now formally documented in the schema). 4. NORMATIVE capability-derivation table added to the capabilities schema description. Servers MUST derive the capabilities map from a tenant key's permissions per the published rules. Guarantees any future server or client produces identical capability maps from identical permission sets. Admin-plane views (view_tenants, view_api_keys, view_audit, view_overview) only fire on admin:* permissions, so default tenant keys cannot accidentally access admin-only pages. 5. Scope-filtered keys documented as NOT altering the capability map — filters constrain which records are visible at each endpoint, not whether a page is accessible. Enforcement stays server-side. Non-goals (explicit to prevent scope creep when implementation lands): - No tenant-scoped /v1/admin/overview (admin-only). - No tenant-scoped /v1/admin/audit/logs (admin-only). - No admin-on-behalf-of introspect of a specific tenant key. Version: editorial 0.1.25.14 -> 0.1.25.15. semantic_base unchanged at 0.1.25.9 (no wire-breaking change). cycles-spec-index.yaml editorial pin bumped to match. Gates: - spectral lint: 0 errors (64 pre-existing warnings unchanged) - merge_specs.py: idempotent (rerun produces no further diff) - yaml.safe_load parses cleanly - ApiKeyAuth count: +1 (41 total, was 40) Implementation impact: none required. Compliant servers continue returning admin-only introspect until they explicitly extend to ApiKeyAuth. Rollout is opt-in; this revision just reserves the shape.
5 of 6 tasks
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.
Summary
Stage 3 of the admin-on-behalf-of rollout. Adds
AdminKeyAuthalongsideApiKeyAuthon the 6 tenant-scoped/v1/webhooks/*endpoints that matter for admin incident response. Mirrors the pattern from #36 (v0.1.25.13 budgets/policies) and #37 (reservations).Motivating use case — a tenant's webhook endpoint is flapping (auto-disabled, or spamming a shared downstream). Ops gets paged, needs to pause / force-delete / inspect deliveries without waiting for the tenant to rotate keys. Admin already owns
/v1/admin/webhooks/*for admin-provisioned subscriptions; this closes the gap for tenant-provisioned ones.Dual-auth added (6)
/v1/webhookslistTenantWebhooks—tenantquery REQUIRED under admin/v1/webhooks/{id}getTenantWebhook/v1/webhooks/{id}updateTenantWebhook(pause/resume)/v1/webhooks/{id}deleteTenantWebhook(force-remove)/v1/webhooks/{id}/testtestTenantWebhook/v1/webhooks/{id}/deliverieslistTenantWebhookDeliveriesIntentionally NOT dual-auth
POST /v1/webhooks(create) — URL / signing secret / event choice are tenant policy; admin creating on a tenant's behalf obscures provenance.POST /v1/webhooks/{id}/replay— already admin-only at/v1/admin/webhooks/{id}/replay; tenant self-service replay remains tenant-key-only (bulk re-delivery is a capacity decision owed to the tenant).Semantic rules
listTenantWebhooks— newtenantquery param. REQUIRED underAdminKeyAuth, MUST NOT be set underApiKeyAuth. Omitting under admin →400 INVALID_REQUESTwith the same message as listBudgets / listPolicies / listReservations.actor_type=admin_on_behalf_ofin the shared audit store so the governance audit-query surface surfaces them. Callers SHOULD populate a structured reason in request metadata (e.g.,[WEBHOOK_PAUSE] INC-1234,[WEBHOOK_FORCE_DELETE] abuse-report-42).Backward compatibility
Purely additive. No schemas modified. Existing
ApiKeyAuthcallers see no behavior change. Newtenantquery param is validation-only underApiKeyAuthand MAY be omitted.Downstream chain
cycles-server-admin— AuthInterceptor allowlist + controller branching + audit tag on the 6 endpoints (runtime plane not involved; webhooks live on admin)cycles-dashboard— flip the 6 existing webhook wrappers to sendX-Admin-API-Keyagainst/v1/webhooks/*; extendWebhooksViewwith tenant filter under admin authTest plan
spectral lint cycles-governance-admin-v0.1.25.yaml --fail-severity=error→ 0 errorspython scripts/merge_specs.py→ merged artifact regenerated