Enforce capability and resource authorization #86

Merged
lost-rob0t merged 46 commits from agent/issue-28-authorization-policy into dev 2026-08-03 01:16:18 +00:00
lost-rob0t commented 2026-07-31 01:48:28 +00:00 (Migrated from github.com)

Runtime policy

  • add a closed default-deny policy protocol receiving principal, action, canonical resource, request metadata, and current quotas
  • use closed capability and resource-scope vocabularies stored in existing credential scopes
  • require explicit tenant, dataset, actor, target, target-namespace, and program grants for dimensioned resources
  • reject unknown capabilities/scopes at credential issuance
  • require explicit request principal, server service context, or deliberately bound trusted internal context
  • emit structured redacted allow/deny audit events

HTTP and embedded boundaries

  • deny unmapped protected HTTP routes
  • enforce capability checks at the HTTP gate and recheck resource policy in embedded document/search/view/target/Rabbit services
  • enforce document read/write/delete/bulk scopes
  • build dataset/tenant clauses into Clouseau queries before execution
  • add tenant-aware search indexing
  • add a tenant+dataset scoped count view and a scoped generic view endpoint
  • fail-close legacy unscoped view endpoints unless the principal has wildcard dataset authority
  • enforce actor, target, namespace, and program scopes for target operations
  • protect lease, force-release, replay, and credential-administration surfaces with elevated capabilities
  • keep lease/replay backends explicit 501 stubs after policy allow; ordinary principals are rejected before backend dispatch

Rabbit provenance

  • re-authorize at the publish boundary from server-captured request/service context
  • attach server-generated decision id, action, tenant, dataset, and actor headers
  • ignore caller-supplied principal and authorization fields

Mandatory acceptance tests

  • read-only principals cannot write, delete, dispatch, or lease
  • cross-tenant and cross-dataset direct lookup, search, view, bulk, and target access is denied or filtered before disclosure
  • bulk denial occurs before any publish side effect
  • actor/target/namespace/program restrictions are all enforced
  • internal calls require explicit principal or deliberately bound trusted context
  • force-release, credential administration, and replay reject ordinary target operators
  • quota exhaustion denies otherwise-valid actions
  • audit and Rabbit provenance contain no bearer or verifier material
  • unknown scopes and unmapped routes deny

Remaining merge gates

  • final-head schema, unit, integration, and authenticated container workflows
  • real container checks with scoped credentials and cross-dataset attempts
  • runtime authorization documentation and route/action matrix
  • manual issue #28 acceptance audit

PR remains draft until every gate passes.

Fixes #28

## Runtime policy - add a closed default-deny policy protocol receiving principal, action, canonical resource, request metadata, and current quotas - use closed capability and resource-scope vocabularies stored in existing credential scopes - require explicit tenant, dataset, actor, target, target-namespace, and program grants for dimensioned resources - reject unknown capabilities/scopes at credential issuance - require explicit request principal, server service context, or deliberately bound trusted internal context - emit structured redacted allow/deny audit events ## HTTP and embedded boundaries - deny unmapped protected HTTP routes - enforce capability checks at the HTTP gate and recheck resource policy in embedded document/search/view/target/Rabbit services - enforce document read/write/delete/bulk scopes - build dataset/tenant clauses into Clouseau queries before execution - add tenant-aware search indexing - add a tenant+dataset scoped count view and a scoped generic view endpoint - fail-close legacy unscoped view endpoints unless the principal has wildcard dataset authority - enforce actor, target, namespace, and program scopes for target operations - protect lease, force-release, replay, and credential-administration surfaces with elevated capabilities - keep lease/replay backends explicit `501` stubs after policy allow; ordinary principals are rejected before backend dispatch ## Rabbit provenance - re-authorize at the publish boundary from server-captured request/service context - attach server-generated decision id, action, tenant, dataset, and actor headers - ignore caller-supplied principal and authorization fields ## Mandatory acceptance tests - read-only principals cannot write, delete, dispatch, or lease - cross-tenant and cross-dataset direct lookup, search, view, bulk, and target access is denied or filtered before disclosure - bulk denial occurs before any publish side effect - actor/target/namespace/program restrictions are all enforced - internal calls require explicit principal or deliberately bound trusted context - force-release, credential administration, and replay reject ordinary target operators - quota exhaustion denies otherwise-valid actions - audit and Rabbit provenance contain no bearer or verifier material - unknown scopes and unmapped routes deny ## Remaining merge gates - final-head schema, unit, integration, and authenticated container workflows - real container checks with scoped credentials and cross-dataset attempts - runtime authorization documentation and route/action matrix - manual issue #28 acceptance audit PR remains draft until every gate passes. Fixes #28
lost-rob0t (Migrated from github.com) reviewed 2026-08-02 12:33:23 +00:00
lost-rob0t (Migrated from github.com) left a comment

CI review: not ready to merge

I reran the failed workflow jobs on the current head (dfa121e). Both the unit job (Test system) and service-backed job (Test with services) fail again after their Nix/container/RabbitMQ/CouchDB setup succeeds, so this is a reproducible branch defect rather than stale CI or service startup.

Blocking defect: make-capability is not visible to the test package

The new helpers in both:

  • t/authorization-policy-test.lisp
  • t/authorization-quota-test.lisp

call make-capability without a package qualifier.

capability is defined with defstruct in source/authorization/policy.lisp, so SBCL creates the constructor star.authorization::make-capability. However, source/authorization/package.lisp exports the structure and accessors but does not export make-capability.

The test package only :uses star.authorization; :use imports external symbols only. Consequently, the unqualified test call resolves as starintel-gserver-tests::make-capability, which has no function definition. The first test using either helper will therefore fail with an undefined-function error. Both CI jobs execute this test system, which explains the shared failure path.

Required fix

Choose one intentional constructor API and update every caller consistently:

  1. Smallest patch: export #:make-capability from star.authorization; or
  2. Cleaner public API: define and export a named constructor such as make-authorization-capability, then update the tests/callers; or
  3. If the constructor is deliberately internal, qualify it as star.authorization::make-capability in white-box tests only.

Option 2 is preferable for a stable public API. Option 1 is acceptable if the generated constructor is intentionally public.

After fixing it, run both exact CI entry points:

nix run .#test
nix run .#testWithServices

Do not skip or remove the new tests to obtain green CI.

Secondary review issue: load-order-dependent HTTP security behavior

source/frontends/http-status-message.lisp introduces another status-msg implementation that includes a trace field and omits correlation_id, while the existing HTTP boundary tests require the opposite. A later ASDF-loaded file currently redefines the function again, so behavior depends on serial load order.

Consolidate status-msg into one canonical implementation that:

  • never exposes stack traces or internal error details;
  • includes correlation_id;
  • preserves the existing boundary-test contract.

The PR also contains other silent function redefinitions in the HTTP integration path. Those should be converted to explicit wrappers/methods or changes to the canonical definitions instead of relying on whichever file loads last.

Merge verdict

Not ready. Keep this draft unmerged until both workflow jobs are green and the duplicate security-sensitive definitions are resolved.

## CI review: not ready to merge I reran the failed workflow jobs on the current head (`dfa121e`). Both the unit job (`Test system`) and service-backed job (`Test with services`) fail again after their Nix/container/RabbitMQ/CouchDB setup succeeds, so this is a reproducible branch defect rather than stale CI or service startup. ### Blocking defect: `make-capability` is not visible to the test package The new helpers in both: - `t/authorization-policy-test.lisp` - `t/authorization-quota-test.lisp` call `make-capability` without a package qualifier. `capability` is defined with `defstruct` in `source/authorization/policy.lisp`, so SBCL creates the constructor `star.authorization::make-capability`. However, `source/authorization/package.lisp` exports the structure and accessors but does **not** export `make-capability`. The test package only `:use`s `star.authorization`; `:use` imports external symbols only. Consequently, the unqualified test call resolves as `starintel-gserver-tests::make-capability`, which has no function definition. The first test using either helper will therefore fail with an undefined-function error. Both CI jobs execute this test system, which explains the shared failure path. ### Required fix Choose one intentional constructor API and update every caller consistently: 1. **Smallest patch:** export `#:make-capability` from `star.authorization`; or 2. **Cleaner public API:** define and export a named constructor such as `make-authorization-capability`, then update the tests/callers; or 3. If the constructor is deliberately internal, qualify it as `star.authorization::make-capability` in white-box tests only. Option 2 is preferable for a stable public API. Option 1 is acceptable if the generated constructor is intentionally public. After fixing it, run both exact CI entry points: ```sh nix run .#test nix run .#testWithServices ``` Do not skip or remove the new tests to obtain green CI. ### Secondary review issue: load-order-dependent HTTP security behavior `source/frontends/http-status-message.lisp` introduces another `status-msg` implementation that includes a `trace` field and omits `correlation_id`, while the existing HTTP boundary tests require the opposite. A later ASDF-loaded file currently redefines the function again, so behavior depends on serial load order. Consolidate `status-msg` into one canonical implementation that: - never exposes stack traces or internal error details; - includes `correlation_id`; - preserves the existing boundary-test contract. The PR also contains other silent function redefinitions in the HTTP integration path. Those should be converted to explicit wrappers/methods or changes to the canonical definitions instead of relying on whichever file loads last. ### Merge verdict **Not ready.** Keep this draft unmerged until both workflow jobs are green and the duplicate security-sensitive definitions are resolved.
Sign in to join this conversation.
No description provided.