Skip to main content
← Back to list
01Issue
BugShippedSwamp CLIPublic
Assigneesstack72

Relationships

#1871 serve: workflow tags never reach grant CEL conditions — tag-conditioned grants always deny

Opened by stack72 · 8/27/2026· Shipped 8/27/2026

Summary

Grants with a CEL condition on tags.* (e.g. --when 'tags.env == "staging"') never match during real serve enforcement, because handleWorkflowRun builds the authorization resource context with only the workflow name — the workflow definition tags are never loaded into the condition context. Conditions over missing variables fail closed, so a tag-conditioned allow grant silently denies everything.

The rest of the product implies this should work:

  • the CEL grant environment registers tags (map) for the workflow kind (also collective; model kind registers modelType/tags/collective; data kind ns/tags/owner — none of which enforcement provides either)
  • swamp access grant create --when 'tags.env == "staging"' validates and accepts the condition
  • swamp access check --subject ... --field tags.env=staging reports ALLOW for the same subject/action/resource

Steps to reproduce

Repo with a workflow whose definition has tags: {env: staging} (name tagged-workflow, one shell-echo step), serve in token mode (--admins user:stack72):

swamp access grant create --subject user:member --allow run --on "workflow:*" --when 'tags.env == "staging"'
swamp serve --auth-mode token --admins user:stack72 ...
swamp access token mint member-tok --principal user:member
swamp workflow run tagged-workflow --server <url> --token member-tok.<secret>

Actual

Error: Server reported unauthorized: Access denied: user:member does not have 'run' on workflow:tagged-workflow

Expected

The run succeeds: the workflow carries tags: {env: staging}, so the condition is true. (swamp access check --subject user:member --action run --on workflow:tagged-workflow --field tags.env=staging agrees and prints ALLOW.)

Root cause pointer

src/serve/handlers/workflow_handlers.ts handleWorkflowRun (~L149-155):

authorizeOrReject(socket, requestId, principal, "run", {
  kind: "workflow",
  name: payload.workflowIdOrName,
  fields: { name: payload.workflowIdOrName },
}, ctx)

fields should include the workflow definition tags (and collective where known) — likely by resolving the workflow before authorization, or enriching the context in authorizeOrReject per resource kind. Same pattern applies to the other handlers that pass fields: {} or name-only while the CEL environment advertises richer variables (model tags/modelType, data ns/tags/owner).

Impact

Attribute-based access control via CEL is effectively unusable on serve: any operator following the documented example (--when 'tags.env == "staging"') locks the subject out entirely, and access check tells them it works. Discovered implementing the grants UAT suite (swamp-uat GRANTS-TEST-PLAN.md Phase 2); pinned there as a characterization test to flip when fixed.

Environment

swamp 20260826.235928.0-sha.da5373d1, source at commit b2433052; serve token mode, filesystem datastore, macOS.

02Bog Flow
OPENTRIAGEDIN PROGRESSSHIPPED+ 1 MOREASSIGNED+ 2 MOREREVIEW+ 13 MOREPR_MERGED+ 2 MORESESSION_SUMMARIZED

Shipped

8/27/2026, 7:01:17 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
stack72 assigned stack728/27/2026, 5:19:39 PM

Sign in to post a ripple.