Sync to Bunnyshell
Bunnyshell interpolates variables while it builds an environment, and hands the result to the containers it starts. A binding writes one of two collections: an environment's variables, or a project's — the latter reaching environments that do not exist yet.
| At a glance | |
|---|---|
| What seekrit writes | An environment's variables, or a project's |
| Addressed by | A Bunnyshell environment ID or project ID |
| Connection carries | The token alone — both IDs are globally unique |
| Token permission | A token whose user can change variables in the organization |
| Takes effect | Next deployment of the environment |
| Value visibility | Hidden in the dashboard when marked secret (the default); encrypted at rest either way |
New to sync? Read Third-party sync first — the decryption grant, name mapping, deletions, and failure handling are the same on every destination.
1. Create an access token
Bunnyshell issues one at environments.bunnyshell.com/access-token — the same
token bns configure saves. It carries its user's access to every organization
they belong to, so the least-privilege setup is a machine user in only the
organization it syncs.
There is no second half to state. A Bunnyshell connection carries nothing beyond the provider: both variable collections name their parent by a globally unique ID, so the token plus the destination is the whole address.
printf '%s' "$BUNNYSHELL_TOKEN" \
| seekrit sync connect --name acme-bunnyshell --provider bunnyshell
2. Bind an environment
A binding writes one of two scopes. --bunnyshell-environment names an
environment, whose variables every component in it inherits:
seekrit sync verify acme-bunnyshell --provider bunnyshell \
--bunnyshell-environment env-9f3a2b
seekrit sync enable --connection acme-bunnyshell --provider bunnyshell \
--bunnyshell-environment env-9f3a2b \
--app storefront --env production --acknowledge-decryption
--project names a project instead, and is the one that reaches an environment
which does not exist yet — every environment created in the project from then
on inherits its variables, which is how you seed the ephemeral environments a
webhook will spin up per branch or per pull request:
seekrit sync enable --connection acme-bunnyshell --provider bunnyshell \
--project prj-4c8d1e \
--app storefront --env preview --acknowledge-decryption
Pass one or the other, never both. Get either ID from bns environments list /
bns projects list, or from the dashboard URL.
A project binding's blast radius is the project, not one environment. Every environment created in it afterwards inherits these values, and there may be many. An existing environment is not touched — it keeps whatever it already has, and an environment-scoped value always beats the project's, so a project binding does not fight an environment binding pointed at the same name.
Values are marked secret. Bunnyshell's isSecret hides a value in the
dashboard and keeps it encrypted inside an exported environment definition.
seekrit sets it by default.
It is a weaker guarantee than Netlify's flag of the same name: Bunnyshell
encrypts every variable with an organization key whether or not the flag is
set, so this is about who can read it, not whether it is stored in the clear.
The flag is only sent when seekrit creates a variable — an update never
mentions it, so one you deliberately un-secreted stays that way. Pass
--no-bunnyshell-secret to create dashboard-visible variables instead.
How a push behaves
- There is no bulk write and no upsert here. A run pages through the collection to find which names already exist, then creates or updates each one individually. That makes Bunnyshell the destination where the per-run budget (400 requests) binds hardest.
- A write is skipped when nothing would change. Bunnyshell's listing discloses current values, and seekrit uses that for exactly one thing — skipping a redundant write. Those values are never stored, logged, or audited.
- Every variable's parent is re-checked before it is touched. Bunnyshell IDs
are opaque strings with no documented format, so seekrit cannot validate them
by shape the way it validates a Netlify site ID. Instead the connector confirms
each listed variable really belongs to this binding's environment or project
before editing it — a filter that failed to bite cannot turn into an edit of a
neighbouring environment's variables. A create names its parent in the request
body as a required relation, so an unresolvable ID is a
422naming the field, not a write that lands somewhere broader. - A truncated listing fails the run loudly rather than making a deletion look already done.
- A value Bunnyshell echoes back in an error is scrubbed before the reason is stored on the run row.
Bunnyshell interpolates variables while it builds, so a pushed value reaches the workload on the environment's next deployment. seekrit starts none: a secret rotation should not restart someone's environment as a side effect.
Name rules
Bunnyshell will not accept every name seekrit will. Variable names take
letters, numbers, underscores, dashes, and dots, cannot begin with a digit,
cannot begin with BNS_, which Bunnyshell reserves for the variables it
injects itself, and must be at least 3 characters and at most 255. A
name that breaks one of those is reported as a failure against that name alone;
the rest of the environment still pushes. Watch for the length floor and the
leading digit if you use a --prefix.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
401 or 403, whole run stopped | The token was revoked, or its user can't change variables in that organization | Mint a new token from a user with the right role |
422 naming environment or project | The ID doesn't resolve | Check it against bns environments list / bns projects list. A create names its parent as a required relation, so this fails safely rather than writing elsewhere |
| Both scope flags rejected | --bunnyshell-environment and --project were both passed | A binding writes one collection; pass one |
| A new environment didn't get the values | It was created before the project binding, or the binding is environment-scoped | Project variables are inherited at creation only. Bind the project, and existing environments keep what they have |
| A value looks wrong in an environment | An environment-scoped value shadows the project's | That is Bunnyshell's precedence. Remove the environment-level one |
| A variable is visible in the dashboard | It already existed when seekrit first wrote it — the secret flag is only sent at creation | Delete it in Bunnyshell and let the next sync recreate it |
| One name failed, rest landed | The mapped name is under 3 characters, starts with a digit, or begins BNS_ | Fix the prefix or rename |
| Run reported partial on a big environment | The 400-request budget, which binds hard here | Nothing to do — the engine re-runs immediately until it drains |
See also
- Third-party sync — the shared model, naming and filtering, deletions
- Branch configs — per-PR environments that pair with ephemeral Bunnyshell environments
- CLI reference — every
seekrit syncflag