invoke_service::resolve and enqueue_async performed no authz check — no AppInvoke capability existed. Same-app isolation was preserved (cross-app guards work), but within one app an anonymous public-HTTP script could trigger any other script (e.g. an admin-only worker that hits secrets/files/external HTTP). Worse: invoke_async runs the callee with principal: None, so the callee could hold capabilities the original public caller shouldn't. - Add Capability::AppInvoke(AppId). app_id() / scope_for_capability (script:write) / role_satisfies (editor+) are all updated. - InvokeServiceImpl gains an optional `authz: Option<Arc<dyn AuthzRepo>>` + a `with_authz` builder. When set, resolve() runs script_gate on AppInvoke before doing the cross-app id check. - picloud/src/lib.rs wires it: `InvokeServiceImpl::new(...).with_authz(...)`. - Anonymous callers (cx.principal == None) continue to skip the check via script_gate, preserving the public-HTTP convention. Existing 5 invoke_service unit tests still pass (the tests use the authz-less constructor, so the gate is a no-op there). AUDIT.md anchor: F-S-012. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
32 KiB
32 KiB