You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(security): ADR-0090 D5/D9 suggested-audience-binding surface + confirm/dismiss API (#2746)
* feat(security): queryable suggested-audience-binding surface + confirm/dismiss API (ADR-0090 D5/D9)
A package permission set declaring isDefault: true is an install-time
SUGGESTION to bind the set to the builtin everyone position — never
auto-bound. Until now the flag was only read at bootstrap as the
fallback-set name; after an install there was no way to see or act on
the suggestion (framework#2696 remaining item).
plugin-security:
- new sys_audience_binding_suggestion system object (read-only data API,
unique per package × set × anchor)
- convergent reconciler syncAudienceBindingSuggestions reading declared
stack metadata AND installed package manifests (a runtime
POST /api/v1/packages install is visible immediately); prunes pending
rows on uninstall, marks out-of-band bindings confirmed (observed);
runs at boot, after a permission publish, and on every list call
- security service gains listAudienceBindingSuggestions /
confirmAudienceBindingSuggestion / dismissAudienceBindingSuggestion,
all pre-gated on tenant-level admin (anchors stay tenant-level, D12);
confirm inserts sys_position_permission_set WITH the caller's
execution context so the D5/D9 anchor gate and D12 delegated-admin
gate enforce the write; not-yet-materialized sets are seeded through
the provenance-checked upsert (ADR-0086 D4)
runtime:
- GET /api/v1/security/suggested-bindings?status=&packageId=
- POST /api/v1/security/suggested-bindings/:id/confirm
- POST /api/v1/security/suggested-bindings/:id/dismiss
(401 unauthenticated; 403/404/409 from typed service errors; 503
without plugin-security)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DP13MuGwFWLcVxVtuA7rgq
* docs(permissions): document the suggested-audience-binding surface (ADR-0090 D5)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DP13MuGwFWLcVxVtuA7rgq
* fix(runtime): drop redundant slash-trim regex on request path (CodeQL polynomial-redos)
split('/')+filter(Boolean) already discards empty segments; the
^\/+|\/+$ regex over request-controlled input was flagged by CodeQL
as polynomial backtracking.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DP13MuGwFWLcVxVtuA7rgq
* feat(rest): serve /security/suggested-bindings on the RestServer surface (ADR-0090 D5/D9)
The hono dev/production stack serves /api/v1 through @objectstack/rest,
not the runtime HttpDispatcher, so the suggested-bindings routes must be
registered there too (same pattern as sharing rules: a security service
provider injected by rest-api-plugin, resolveExecCtx + enforceAuth per
request, 501 when plugin-security is absent, typed 403/404/409 mapping).
Verified end-to-end against a fresh showcase run: anonymous list → 401;
admin list → the showcase's second isDefault set (showcase_member_default)
appears as a pending suggestion; confirm → 200 with the binding row
created by the caller (not system) in sys_position_permission_set;
re-confirm → 409.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DP13MuGwFWLcVxVtuA7rgq
---------
Co-authored-by: Claude <noreply@anthropic.com>
description: 'Admin who confirmed/dismissed. Empty on a confirmed row means the binding was observed (e.g. bound at boot or by hand), not confirmed through the prompt.',
86
+
}),
87
+
88
+
resolved_at: Field.datetime({
89
+
label: 'Resolved At',
90
+
required: false,
91
+
description: 'When the suggestion left the pending state.',
0 commit comments