Skip to content

feat(secrets): per-execution environment scoping for secret resolution (ADR-0031 Phase 3, PR A) - #83

Merged
gustavobertoi merged 1 commit into
mainfrom
feat/environments-per-execution-scope
Jun 3, 2026
Merged

feat(secrets): per-execution environment scoping for secret resolution (ADR-0031 Phase 3, PR A)#83
gustavobertoi merged 1 commit into
mainfrom
feat/environments-per-execution-scope

Conversation

@gustavobertoi

Copy link
Copy Markdown
Collaborator

What & why

ADR-0031 Phase 3, deliverable 1 of 4 (PR A — threading core). Makes environment a
per-execution scoping dimension instead of a single server-wide config string baked into
the secret resolver at DI time. This unblocks per-context LLM keys, credentials, and external
backends, all of which scope by environment.

Changes

  • Per-workflow scoped resolver: workflow.New gains an environment field + getter; the
    WorkflowHandler builds a secrets.NewResolver(store, env) per workflow. New executions take
    the environment from the trigger (default FUSE_ENVIRONMENT); replay reads it from the
    reconstructed workflow
    so resolution is deterministic across restart/recovery/retry. The
    process-wide resolver DI provider is removed.
  • Threading: environment flows trigger → TriggerWorkflowMessageworkflow_sup spawn →
    instance supervisor → WorkflowHandlerInitArgs. Sub-workflows inherit the parent's
    environment. TriggerWorkflowRequest/Response gain an optional environment; fuse workflow
    gains -e/--environment.
  • Persistence: migration 000009 adds workflows.environment (NOT NULL DEFAULT 'default'
    backfill + index); postgres Get reads it, Save writes it and excludes it from the
    ON CONFLICT DO UPDATE
    so state-change saves can't clobber it. Memory backend unchanged.

Tests

make lint clean, make build ok, make test 638→ passing incl. new TestNewStoresEnvironment
and a functional contract subtest asserting Save/Get preserves environment (memory + postgres).

🤖 Generated with Claude Code

…n (ADR-0031 Phase 3)

Make "environment" a per-execution scoping dimension instead of a single
server-wide config string baked into the secret resolver at DI time.

- workflow.New gains an environment field + getter; the WorkflowHandler builds
  a per-workflow secrets.Resolver scoped to that environment. New executions
  take the environment from the trigger (default FUSE_ENVIRONMENT); replay reads
  it from the reconstructed workflow so resolution stays deterministic across
  restart/recovery/retry.
- Thread environment trigger -> message -> workflow_sup spawn -> instance
  supervisor -> WorkflowHandlerInitArgs. Sub-workflows inherit the parent's
  environment. TriggerWorkflowRequest/Response gain an optional environment
  field; CLI `fuse workflow` gains -e/--environment.
- Persist environment on the workflows row (migration 000009, NOT NULL DEFAULT
  'default' backfill) and read it back in Get; excluded from the upsert UPDATE
  clause so state-change saves never clobber it.
- Drop the now-orphaned process-wide secret resolver DI provider.

Tests: unit coverage for New/Environment(); functional contract subtest asserts
Save/Get preserves environment (memory + postgres). Strict environments registry
and trigger validation follow in a separate PR.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant