The workflow prepares the environment, and Sluiceway never wraps or hooks the tool
Decision record 0013
Many repos never run their IaC tool directly. A script or task runner of their own resolves secrets from a secret manager, sets the state backend and then calls the tool. Sluiceway calls the tool itself (0001), so it has to fit next to that tooling without learning what it does. The rule: everything the tool needs is put into the job’s environment by workflow steps that run before Sluiceway, and Sluiceway passes that environment on. There is no configurable command wrapper and there are no hooks before or after a stack, in v1.
A command wrapper was rejected (for example command: ["op", "run", "--", "pulumi"]). It resolves every secret again for every preview, which on a repo with dozens of stacks is slow and runs into secret manager rate limits. It makes “which command does Sluiceway run” a user setting, so the version check, the exit code handling and the process group kill of 0012 would all have to survive arbitrary wrappers. Its security gain is small: the action is pinned code in the user’s own runner, in the same job as the token that unlocks the secrets. Hooks per stack were rejected because nothing needed them. The first real user’s wrapper was read line by line: what it does around each call is resolve one env file, select the stack and pass fixed flags. Cluster access, which looked like a per-stack step, turned out to live inside the programs as a stack reference. Both a wrapper and hooks can be added later without breaking anything.
Consequences
- The tool’s child process inherits the whole environment of the job, unchanged. There is no allowlist, no
envkey insluiceway.yamland no environment per stack. Programs may read any variable, so Sluiceway cannot know the names. A stack that needs its own value gets it through its own variable name or its stack config. - One exception: every
INPUT_*variable is removed from the child’s environment. GitHub hands an action its inputs that way, the GitHub token among them, and a stack program or one of its dependencies must never get the token that can edit the dashboard. - Sluiceway sets only what makes the tool behave in CI, such as
PULUMI_SKIP_UPDATE_CHECK. It never sets or defaults a backend URL, a passphrase or a credential. When one is missing, the tool’s own error becomes the stack’s preview failure, and when every preview fails the job goes red (0012). - Sluiceway never sees a secret as a secret, so it cannot mask by value. Masking belongs to the step that loads the secrets (
::add-mask::). The rules for what Sluiceway itself prints are decided separately and are a second net, not the guarantee. - The example workflow has a visible place for “load your credentials here” in the jobs that run the tool. The docs get one page on credentials and existing tooling: the pattern first, then short recipes (cloud OIDC, GitHub secrets, a secret manager). No secret manager, cluster or cloud is named in Sluiceway’s code or config.
- Setup stays the user’s job, as in 0001 and 0012: install the tool, install dependencies, load the environment. One scan job means it is paid once per scan.