A command-line tool for Google Secret Manager, with a manifest in the repo.
A manifest in the repo says which secrets each environment has, and one short command sets, reads, pulls or pushes them. The values stay in Secret Manager.
$ npm install -g @osroc-labs/storehouse
storehouse needs Node 24 or later. It signs in to Google the way
gcloud does, so if gcloud auth login works, storehouse
works.
What's set where
storehouse status shows what's set where, and exits non-zero
when a required secret is missing. It never reads a value.
$ storehouse status
dev stage purpose
AUTH_SECRET set 10d ago set 10d ago Signs session cookies.
SMS_SID set 2d ago missing The SMS account that texts sign-in codes.
SEED_TOKEN set 7d ago - A sandbox token, for the seed script.
prod is protected and not shown. Name it to include it: storehouse status dev stage prod
Quickstart
In a project where you can create secrets (a scratch one is best for a first try):
-
Write
storehouse.jsonat the root of your repo:storehouse.json { "$schema": "https://cdn.jsdelivr.net/npm/@osroc-labs/storehouse/schema.json", "project": "my-gcp-project", "name": "myapp-{env}-{key}", "envs": { "dev": {}, "prod": { "protected": true } }, "secrets": { "API_KEY": { "purpose": "Calls the payments API.", "required": true } } } storehouse checkchecks it, with no Google access.-
storehouse statusshowsAPI_KEYmissing in dev, and exits 4 because it's required. -
storehouse set dev API_KEYasks for the value (hidden) and stores it asmyapp-dev-API_KEY. Piping works too:printf %s "$VALUE" | storehouse set dev API_KEY. -
storehouse statusshows it set.storehouse history devshows when. -
storehouse pull devwrites.env.dev(0600) for local development, and adds it to.gitignoreif git doesn't already ignore it.
storehouse never writes to the manifest: a new secret is a decision for a commit. Pushes go to Cloudflare Workers, GitHub Actions, Vercel and Fly, always with values on stdin, never in a command's arguments.
Commands
The env is always the first word after the command, and a key is always a
manifest key, never a Secret Manager name. Every command takes
--help.
-
- Command
-
storehouse status [env…] - What it does
- Show which secrets are set in each env, and when they changed.
- Options
-
--jsonprint JSON instead of a table
-
- Command
-
storehouse set <env> <KEY> - What it does
- Store a value for a secret.
-
- Command
-
storehouse get <env> <KEY> - What it does
- Print a secret's latest value.
- Options
-
--out <path>write the value to a file (0600) instead of stdout -
--forceoverwrite a file that exists
-
- Command
-
storehouse history <env> [KEY] - What it does
- List versions and when each was added, for one secret or a whole env.
- Options
-
--jsonprint JSON instead of a table -
--limit <n>show at most n versions (default 20; 0 for all)
-
- Command
-
storehouse check - What it does
- Check storehouse.json, with no Google access.
- Options
-
--jsonprint JSON instead of a table
-
- Command
-
storehouse auth - What it does
- Show which Google credentials storehouse uses.
- Options
-
--jsonprint JSON instead of a table
-
- Command
-
storehouse pull <env> - What it does
- Write an env's secrets to its dotenv file.
- Options
-
--dry-runsay what would happen; read no values and change nothing -
--forceoverwrite a file that exists
-
- Command
-
storehouse push <env> [KEY…] - What it does
- Send an env's secrets to where they run.
- Options
-
--dry-runsay what would happen; read no values and change nothing
Protected environments
An env with "protected": true, such as prod, is for people
only:
- Any command that names it needs a terminal on stdin and stdout, and the env's name typed at a prompt. Every check that can fail without Google runs first, so a typo never costs a prompt.
-
It refuses outright when a coding agent's environment variable is set:
CLAUDECODE,CODEX_SANDBOX,CURSOR_AGENT,GEMINI_CLIand others. No flag or variable turns that off. -
statuswith no env leaves protected envs out, so it never needs the prompt. Name one to include it.
It's a second line, not the first. An agent with a shell and your Google
login can always call gcloud itself. The first line is your
own guard, a hook that inspects the commands an agent runs, and
storehouse exports what that guard needs:
protectedInvocation.
Exit codes
| Code | Meaning |
|---|---|
| 0 | Done. |
| 1 | Failed: Google, a file, a CLI. The message says why and what to do. |
| 2 | A mistake on the command line: an unknown command, option, env or key. |
| 3 |
storehouse.json is missing or has problems. storehouse check lists them.
|
| 4 |
A required secret is missing (status, pull, push), or the secret asked for isn't set (get, history).
|
| 5 | Refused by a protected env, or stopped at a prompt with Ctrl-C. |
Why
Secret Manager is a good place to keep secrets, and gcloud secrets
is a hard way to work with them. Every command needs the full secret name,
the project and --data-file=-. Nothing shows what's set in
which environment. storehouse keeps Secret Manager as the one source of
truth.
| Instead of | Why storehouse |
|---|---|
gcloud secrets
|
Short commands by key and environment, a status table, pulls and pushes. |
| fnox, secretspec, varlock |
Built for Secret Manager alone, with its own login (gcloud) or application default credentials, a manifest it never rewrites, and no exec that hands a command your production secrets.
|
| Doppler, Infisical, 1Password | They replace Secret Manager. storehouse works with the secrets, IAM and audit logs you already have. |