feat(v1.1.9): QueueService trait + Postgres impl + Services bundle wiring

- shared/services.rs: Services::new gains queue: Arc<dyn QueueService>
  positionally after users (mirrors v1.1.8's append of users).
  with_noop_services adds NoopQueueService.
- manager-core/queue_service.rs: QueueServiceImpl wraps QueueRepo with
  script-as-gate authz on AppQueueEnqueue. enqueue clamps max_attempts
  to [1,20] and delay_ms to [0, 86_400_000ms]. depth/depth_pending are
  read-only — no authz check (scripts in the app can see their own
  queue depths). cx.principal threads through as enqueued_by_principal
  (forensic only).
- manager-core/authz.rs: AppQueueEnqueue(AppId) capability — script:write
  scope, granted to editor+ (same trust shape as AppPubsubPublish).
- picloud/lib.rs: wires PostgresQueueRepo + QueueServiceImpl into
  Services::new alongside the existing v1.1.7+ services.
- 11 sdk test binaries + manager-core/realtime_authority.rs updated to
  pass NoopQueueService to Services::new.

Unit tests cover empty queue_name reject, max_attempts clamping
(0/21 → invalid), delay_ms negative-reject, anonymous principal skips
authz, depth/depth_pending pass-through.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-06-06 19:30:34 +02:00
parent f6c7ab6f7c
commit 73e19ca626
15 changed files with 371 additions and 2 deletions

View File

@@ -89,6 +89,12 @@ pub enum Capability {
/// (v1.1.5). Maps to `script:write` on API keys (a publish is a
/// write that fans out to subscribers). Granted to `editor`+.
AppPubsubPublish(AppId),
/// Enqueue a message onto this app's queue from a script (v1.1.9).
/// Maps to `script:write` on API keys (an enqueue is a write that
/// fans out to the registered consumer). Granted to `editor`+.
/// `depth` / `depth_pending` are read-only inspection and don't gate
/// — scripts in the app can always see their own queue depths.
AppQueueEnqueue(AppId),
/// Read a decrypted secret from this app's secrets store (v1.1.7).
/// Same trust shape as KV/docs/files read — granted to `viewer`+,
/// maps to `script:read` on API keys. Honors the seven-scope
@@ -156,6 +162,7 @@ impl Capability {
| Self::AppFilesRead(id)
| Self::AppFilesWrite(id)
| Self::AppPubsubPublish(id)
| Self::AppQueueEnqueue(id)
| Self::AppSecretsRead(id)
| Self::AppSecretsWrite(id)
| Self::AppEmailSend(id)
@@ -191,6 +198,7 @@ impl Capability {
| Self::AppHttpRequest(_)
| Self::AppFilesWrite(_)
| Self::AppPubsubPublish(_)
| Self::AppQueueEnqueue(_)
| Self::AppSecretsWrite(_)
| Self::AppEmailSend(_)
| Self::AppUsersWrite(_)
@@ -358,6 +366,7 @@ const fn role_satisfies(role: AppRole, cap: Capability) -> bool {
| Capability::AppHttpRequest(_)
| Capability::AppFilesWrite(_)
| Capability::AppPubsubPublish(_)
| Capability::AppQueueEnqueue(_)
| Capability::AppSecretsWrite(_)
| Capability::AppEmailSend(_)
| Capability::AppUsersWrite(_)