feat: 30 workflows to wire relayauth/relayfile permissions into workflow runner#673
Conversation
|
Preview deployed!
This preview will be cleaned up when the PR is merged or closed. |
Wire per-agent permissions through the workflow runner lifecycle:
- AgentPermissions type with access presets, file globs, network, exec
- Permission profiles for reusable named configurations
- Provisioner module: compiler, token factory, seeder, mount, audit
- Dry-run permission resolution and display
- Network permission supports boolean and object {allow, deny} forms
- 6 example workflows demonstrating permission patterns
- Comprehensive docs (MDX + MD mirror)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
333a746 to
960a619
Compare
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
| } | ||
| }; | ||
|
|
||
| // Caller-supplied agent_token overrides auto-registration | ||
| let worker_relay_key = agent_token.or(worker_relay_key); |
There was a problem hiding this comment.
🔴 Fatal Relaycast registration aborts spawn before caller-supplied agent_token can be used
When the broker receives a spawn request with an agent_token, it still unconditionally calls retry_agent_registration at src/main.rs:966. If this returns RegRetryOutcome::Fatal (e.g. the Relaycast SDK client is not initialized, which is common when no RELAY_API_KEY is set), the handler executes continue at line 982, aborting the spawn before the agent_token.or(worker_relay_key) override at line 988 is reached. This means a perfectly valid caller-supplied agent_token is silently ignored, and the spawn fails with a pre-registration error. The SDK's WorkflowRunner now sends agentToken on every spawn when permissions are configured (runner.ts:5753), so any environment without a Relaycast API key will have all permission-enabled workflow spawns fail.
Was this helpful? React with 👍 or 👎 to provide feedback.
| /** JWT token TTL in seconds. Default: 3600 (1 hour). */ | ||
| tokenTtlSeconds?: number; |
There was a problem hiding this comment.
🟡 WorkflowProvisionConfig.tokenTtlSeconds documents default as 3600 but actual default is 7200
The JSDoc comment on tokenTtlSeconds in packages/sdk/src/provisioner/types.ts:33 states Default: 3600 (1 hour), but when the field is omitted, mintAgentToken in packages/sdk/src/provisioner/token.ts:3 uses DEFAULT_WORKFLOW_TOKEN_TTL_SECONDS = 2 * 60 * 60 (7200 seconds / 2 hours). External consumers of the provisionWorkflowAgents() API who rely on the documented default will unknowingly mint tokens that live twice as long as expected. The WorkflowRunner is unaffected because it explicitly passes tokenTtlSeconds: 3600 at runner.ts:1557.
| /** JWT token TTL in seconds. Default: 3600 (1 hour). */ | |
| tokenTtlSeconds?: number; | |
| /** JWT token TTL in seconds. Default: 7200 (2 hours). */ | |
| tokenTtlSeconds?: number; |
Was this helpful? React with 👍 or 👎 to provide feedback.
| errors.push(`${label}.scopes must not contain empty strings`); | ||
| continue; | ||
| } | ||
| if (!/^[^:\s]+:[^:\s]+:[^:\s]+:.+$/u.test(scope)) { |
There was a problem hiding this comment.
🔴 Scope validation regex rejects valid 2-3 segment custom scopes, blocking workflow execution
The scope validation regex at packages/sdk/src/workflows/runner.ts:715 requires exactly 4+ colon-separated segments (/^[^:\s]+:[^:\s]+:[^:\s]+:.+$/u), but the codebase, documentation, and test fixtures all use scopes with fewer segments like relay:custom:deploy (3 segments) and relay:custom (2 segments). These are accepted by the compiler (packages/sdk/src/provisioner/compiler.ts) and baked into JWT tokens without issue, but when a user defines such scopes in their relay.yaml agent permissions, execute() throws Permission validation failed and blocks the entire workflow. The dryRun() path accumulates these as validation errors, marking the report as valid: false.
Affected scopes across the codebase
Compiler test (packages/sdk/src/provisioner/__tests__/compiler.test.ts:259): relay:custom:deploy (3 segments → FAIL)
Workflow runner test (packages/sdk/src/__tests__/workflow-runner.test.ts:1156): relay:custom (2 segments → FAIL)
Documentation example (docs/permissions.md): relay:custom:deploy (3 segments → FAIL)
All of these are passed through to the token factory and work fine at runtime — the validation is the sole gate rejecting them.
Prompt for agents
The scope validation regex at runner.ts:715 is too strict. It requires 4+ colon-separated segments (plane:resource:action:path) but valid scopes across the codebase and documentation use 2 or 3 segments (e.g. relay:custom, relay:custom:deploy, fs:read).
The regex /^[^:\s]+:[^:\s]+:[^:\s]+:.+$/u should be relaxed to accept any scope with at least 2 colon-separated non-empty, non-whitespace segments. For example: /^[^:\s]+:[^:\s]+(:[^:\s]+)*$/u would accept relay:custom, relay:custom:deploy, and relayfile:fs:read:/src/index.ts.
Alternatively, you could simply require a non-empty string with at least one colon and no whitespace: /^[^\s:]+(?::[^\s:]+)+$/u
After fixing, verify the test at workflow-runner.test.ts:1156 (scopes: ['relay:custom']) and the compiler test at compiler.test.ts:259 (scopes: ['relay:custom:deploy']) pass validation correctly.
Was this helpful? React with 👍 or 👎 to provide feedback.
Summary
agent-relay runget proper tokens, scopes, and filesystem enforcementrun-waves.sh) runs all waves with parallelism within each waveArchitecture (6 layers)
AgentPermissionsinterface,permissionsfield onAgentDefinitionrelay oninto reusablepackages/sdk/src/provisioner/agentTokenfield onSpawnPtyInput, broker/api/spawnaccepts tokenWave Breakdown
Key Design Decisions
Running
What exists today
relay onalready does full provisioning (dotfiles → scopes → JWT → ACL seeding)RELAY_AGENT_TOKENenv var propagation viaspawn_wrap_with_token()@relayauth/coreand@relayfile/sdkare installed as dependenciesWhat these workflows build
relay onusesSpawnPtyInput.agentToken→ SDK client → broker API →RELAY_AGENT_TOKENenvpermissions:in relay.yaml, presets from roles, dry-run shows accessTest plan
agent-relay run --dry-run <workflow>🤖 Generated with Claude Code