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.

Install
$ 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
$ 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):

  1. Write storehouse.json at 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 }
      }
    }
  2. storehouse check checks it, with no Google access.
  3. storehouse status shows API_KEY missing in dev, and exits 4 because it's required.
  4. storehouse set dev API_KEY asks for the value (hidden) and stores it as myapp-dev-API_KEY. Piping works too: printf %s "$VALUE" | storehouse set dev API_KEY.
  5. storehouse status shows it set. storehouse history dev shows when.
  6. storehouse pull dev writes .env.dev (0600) for local development, and adds it to .gitignore if 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.

Protected environments

An env with "protected": true, such as prod, is for people only:

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.