Skip to content
secrets

@rinci/secrets

Every secrets manager. One command.

Fetch from Infisical, Doppler, Vault, AWS, GCP, Azure, 1Password or Bitwarden, then run anything with the values in its environment. One config, zero dependencies, nothing written to disk.

$ bun add -d @rinci/secrets
Read the docs

Wrap the command you already run.

Sources are read in parallel and merged in order. Every run says where its values came from, how many, and which existing variables it replaced. With -v it lists the names. Never the values.

$ rinci-secrets run -e prod -- bun dev
secrets 42 secrets from infisical 38 (184ms), dotenv 4 (1ms)
secrets overriding 1 existing: NODE_ENV
  ready on http://localhost:3000

Safe by default, readable throughout.

No dependencies sit between your credentials and the network. The request signing, the token exchange and the process spawning are a few hundred lines each, in the repository, with tests.

Credentials stay out of the config

The config says where secrets live. Logins come from the environment or an untracked env file, and a key that looks like a credential is rejected.

Withheld from your app

Your command gets the secrets, not the identity that fetched them. INFISICAL_CLIENT_SECRET and its kind are removed from its environment.

Fails closed

If a source fails, the command does not start. No app booting half-configured against the wrong database.

No shell in between

Arguments reach the program exactly as typed, Windows .cmd shims included. A quote or an & cannot become a second command.

HTTPS, or a private network

Plain HTTP is refused unless the host is local or private, like an in-cluster API reached over WARP or a VPN.

Short-lived by default

Access tokens minted for a run are revoked as soon as the read is done. Values are never written to disk.

secrets.config.json

{
  "$schema": "https://secrets.rin.ci/schema.json",
  "envFiles": [".env.infisical"],
  "sources": [
    {
      "provider": "infisical",
      "domain": "https://infisical.internal",
      "projectId": "your-project-id",
      "environment": "${SECRETS_ENV:-dev}"
    },
    { "provider": "dotenv", "path": ".env.local", "required": false }
  ]
}

package.json

{
  "scripts": {
    "dev": "rinci-secrets run -- bun dev",
    "start": "rinci-secrets run -e prod -- bun start"
  }
}
  1. 01Commit the config. It names projects and paths, never a password.
  2. 02Put the machine identity in .env.infisical, which git ignores.
  3. 03Pick the environment per run with -e. The config reads it as${SECRETS_ENV}.

Replace the script you keep copying between repos.

Start with the provider you use today. Add a second source when you need one; the command stays the same.