CI/CD & containers
The pattern for every automated environment is the same: provide a service token and either
run your command with secrets injected or export them. No passphrase is involved.
Store the token in your platform's secret store as SEEKRIT_TOKEN. The token is bound to one
application environment, so seekrit run/export need no --app/--env flags — it resolves its
own org, app, environment, and composed groups.
GitHub Actions
The seekritdev/github-action action resolves your
secrets, decrypts them on the runner, and injects them into the job — every later step sees them
as environment variables. Store the token as an encrypted Actions
secret named SEEKRIT_TOKEN.
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: seekritdev/github-action@v1
with:
token: ${{ secrets.SEEKRIT_TOKEN }}
- run: ./deploy.sh # $DATABASE_URL, $API_KEY, … are set and masked
Every value is masked in the logs (::add-mask::) and decryption happens entirely on the runner —
the API only ever returns ciphertext. Handy inputs: with (compose a group at a specific
environment, like the CLI's --with), prefix, include/exclude, and set-outputs to expose
values as step outputs instead of environment variables. See the
action's README for the full list.
Prefer injecting into the job environment (the default) over step outputs — masked environment variables are a smaller surface than run-scoped outputs.
Want to wrap a single command instead of exporting to the whole job? Install the CLI and use
seekrit run — the same pattern as every other CI system:
jobs:
deploy:
runs-on: ubuntu-latest
env:
SEEKRIT_TOKEN: ${{ secrets.SEEKRIT_TOKEN }}
steps:
- uses: actions/checkout@v4
- run: npm install -g @seekrit/cli
- run: seekrit run -- ./deploy.sh # secrets injected into the process
A config per pull request
Preview deploys usually need almost the shared config — with one or two values
of their own (a database branch URL, a preview hostname). A
branch config gives each PR exactly that: it inherits
everything from dev and stores only the difference, then deletes itself.
SEEKRIT_BRANCH is read by seekrit run, seekrit export, and seekrit-run,
so setting it once at the job level is enough. The token stays bound to dev —
naming a branch of its own environment needs no new token and no new grants.
jobs:
preview:
runs-on: ubuntu-latest
env:
SEEKRIT_TOKEN: ${{ secrets.SEEKRIT_TOKEN }} # bound to api/dev
SEEKRIT_BRANCH: pr-${{ github.event.number }}
steps:
- uses: actions/checkout@v4
- run: npm install -g @seekrit/cli
- run: seekrit branch create "$SEEKRIT_BRANCH" --app api --from dev --ttl 3d
- run: seekrit secrets set DATABASE_URL "$NEON_BRANCH_URL" --app api --env dev --branch "$SEEKRIT_BRANCH"
- run: seekrit run -- ./deploy-preview.sh
teardown:
if: github.event.action == 'closed'
runs-on: ubuntu-latest
env:
SEEKRIT_TOKEN: ${{ secrets.SEEKRIT_TOKEN }}
steps:
- run: npm install -g @seekrit/cli
- run: seekrit branch delete "pr-${{ github.event.number }}" --app api
branch create is idempotent-friendly in practice — re-running the workflow on a
new commit hits an existing-slug conflict, which you can ignore. The --ttl is
the backstop for when teardown never runs: a cancelled workflow, a force-push, a
dead runner. Nothing is left holding credentials.
Docker
Prefer injecting secrets at runtime, not baking them into an image. In
containers the best fit is seekrit-run — a tiny static
binary with no Node/OpenSSL/CA dependency, so it works in distroless,
alpine, and scratch images. Copy it out of the published seekritdev/run
image and make it the entrypoint:
FROM seekritdev/run:latest AS seekrit
FROM gcr.io/distroless/static
COPY --from=seekrit /seekrit-run /usr/local/bin/seekrit-run
ENTRYPOINT ["seekrit-run", "--"]
CMD ["./start-server"]
The seekrit-run guide also has a
Docker-Hub-free variant that downloads the binary from run.seekrit.dev and
verifies its checksum.
docker run --rm \
-e SEEKRIT_TOKEN="$SEEKRIT_TOKEN" \
your-image ./start-server
If Node is already in your image you can use the CLI instead — same behavior.
The CLI ships as seekritdev/cli,
or install it and wrap your command:
# entrypoint.sh
#!/bin/sh
exec seekrit run -- "$@"
If you must materialize a file (for tools that read .env), write it inside the container at
startup and keep it out of any image layer:
seekrit export --format dotenv > /run/secrets.env
Never seekrit export into a build stage that gets committed to an image layer. Fetch secrets
at container start, into a tmpfs or process environment.
Kubernetes
Store the token in a Kubernetes Secret and reference it as an environment variable; run your app through the CLI:
env:
- name: SEEKRIT_TOKEN
valueFrom:
secretKeyRef:
name: seekrit-token
key: token
command: ["seekrit", "run", "--"]
args: ["./start-server"]
Prefer a declarative sync into native Kubernetes Secret objects — so pods
consume secrets without any seekrit tooling in the image — with the
External Secrets Operator. One helm install, then
you write only ExternalSecret resources.
AI agent sandboxes
Ephemeral environments — like the throwaway sandboxes an AI coding agent spins up — are a natural fit: create a short-lived environment, grant a scoped token, and let the agent's process read secrets through the CLI without ever seeing long-lived credentials. Revoke the token when the sandbox is torn down.
A dedicated agent-proxy that swaps tokenized placeholders for real credentials on outbound requests (so an agent never sees secret values at all) is on the roadmap. The grant/wrap model already supports it — a proxy is just another principal.