npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

arcanum-seal

v1.0.1

Published

Encrypted secrets for teams that ship fast. No servers, no accounts, no cloud — just git.

Readme

ArcanumSeal 🔐

Encrypted secrets for teams that ship fast.

ArcanumSeal is an open-source CLI tool that solves one problem: developers share API keys, passwords, and tokens over Slack, email, and Notion because there is no simple encrypted alternative. ArcanumSeal fixes this.

seal push  →  encrypts .env  →  safe to commit to git
seal pull  →  decrypts blob  →  .env available locally
seal exec  →  decrypts blob  →  injects into process (never touches disk)

No servers. No accounts. No cloud. Git is the sync mechanism.


Why ArcanumSeal?

| Problem | ArcanumSeal | |---|---| | Secrets shared over Slack/email | Encrypted blobs committed to git | | .env files accidentally committed | .gitignore updated automatically | | New dev needs secrets → DM the admin | seal grant re-encrypts for them | | Dev leaves → rotate everything manually | seal revoke re-encrypts in one command | | CI needs secrets → store in plaintext | seal pull --key /tmp/key in pipeline | | "Was this secret leaked?" | seal scan --git checks entire history |


Install

npm install -g arcanumSeal

Requirements: Node.js 22+. That's it.

Verify:

seal --version   # 1.0.0
seal help        # all commands

Node.js 22+ required. Check with node --version.


Quick Start (Solo Developer)

1. Generate your keypair

seal keygen
✓ Keypair generated and saved.

Your public key:
CUlyjQI/M3FeBQlzWTBzdK76WDkwtczywmDfSQIbyDQ=

  Private key → ~/.arcanumSeal/master.key  (never share this)
  Public key  → ~/.arcanumSeal/master.pub  (safe to share)

Your private key never leaves your machine. The public key is safe to share with anyone.


2. Initialize your project

cd my-project
seal init
  Project name detected: my-project

✓ ArcanumSeal initialized for project: my-project

  Created: .arcanumSeal/config.json
  Created: .arcanumSeal/team.json
  Updated: .gitignore  (ArcanumSeal entries appended)

Next steps:
  1. seal keygen                        — generate your personal keypair
  2. seal push --env development        — encrypt your .env.development
  3. git add .arcanumSeal/ && git push  — commit encrypted secrets

Your .gitignore is automatically updated:

# ArcanumSeal
.env
.env.*
!.env.example
.arcanumSeal/master.key    ← private key blocked
# .arcanumSeal/*.enc.json  ← encrypted blobs are NOT blocked (safe to commit)

3. Encrypt your secrets

# Given .env.production contains:
# DB_HOST=prod-db.example.com
# DB_PASS=hunter2
# API_KEY=sk-prod-abc123

seal push --env production
✓ Secrets pushed to .arcanumSeal/production.enc.json

  3 secrets added

  Next: commit the encrypted store to git:
    git add .arcanumSeal/ && git commit -m "chore: update secrets"

The encrypted file is safe to commit. It contains no plaintext:

{
  "version": 1,
  "environment": "production",
  "secrets": {
    "DB_HOST": {
      "encrypted": {
        "ciphertext": "base64...",
        "nonce": "base64...",
        "ephemeralPublicKey": "base64..."
      },
      "recipients": {
        "<riya-pubkey>": { "ciphertext": "...", "nonce": "...", "ephemeralPublicKey": "..." },
        "<arjun-pubkey>": { "ciphertext": "...", "nonce": "...", "ephemeralPublicKey": "..." }
      },
      "version": 1
    }
  }
}

Each team member gets their own independently encrypted copy of every secret value. No two ciphertexts are the same.


4. Decrypt secrets back

seal pull --env production
✓ 3 secrets synced to .env.production

Or write to a custom path:

seal pull --env production --out .env

5. Run your app with secrets (never writes to disk)

seal exec --env production -- node server.js

Secrets are decrypted in memory only and injected as process.env. No .env file is written. Works with any runtime:

seal exec --env production -- python manage.py runserver
seal exec --env production -- ruby app.rb
seal exec --env production -- docker-compose up

Exit codes are mirrored exactly:

seal exec --env production -- node failing-script.js
echo $?   # → 1  (same as the child process)

Team Workflow

Adding a new developer

New developer (Arjun):

# Step 1: Generate keypair
seal keygen

# Step 2: Print public key to share with admin
seal request-access --to [email protected]
Your public key:

bY2W660AN/FqsQlycQbtKMltG3hW0F/IsM4FUTxN5zg=

  Send this key to [email protected] and ask them to run:

  seal grant <your-email> --key bY2W660AN/FqsQlycQbtKMltG3hW0F/IsM4FUTxN5zg=

Admin (Riya):

seal grant [email protected] --key bY2W660AN/FqsQlycQbtKMltG3hW0F/IsM4FUTxN5zg=
  Re-encrypting secrets for [email protected]...

✓ Access granted to [email protected]

  Added to:    .arcanumSeal/team.json
  Environments: all
  Re-encrypted: 2 environments

  Next: commit and push so the new member can pull:
    git add .arcanumSeal/ && git commit -m "chore: grant access to [email protected]" && git push

seal grant re-encrypts every secret for all current team members in a single pass — existing members retain access and the new member is added atomically.

Arjun (after git pull):

git pull
seal pull --env production   # ✓ works immediately

No Slack DM. No plaintext secrets shared. No infrastructure required.


Revoking access when someone leaves

seal revoke [email protected]
  Re-encrypting secrets without [email protected]'s key...

✓ Access revoked for [email protected]

  Removed from: .arcanumSeal/team.json
  Re-encrypted: 2 environments

⚠ Commit and push IMMEDIATELY to prevent further access:
  git add .arcanumSeal/ && git commit -m "chore: revoke access for [email protected]" && git push

seal revoke re-encrypts every secret for all remaining team members in a single pass — their access is preserved while the revoked member's key is permanently excluded.

After you push, Arjun's local copies are permanently undecryptable.


View team members

seal team list
Team members (2)

  EMAIL                ROLE      ENVIRONMENTS  ADDED       ADDED BY
  -------------------  --------  ------------  ----------  -------------------
  [email protected]     admin ★   *             2026-01-01  [email protected]
  [email protected]     member    *             2026-02-15  [email protected]

Promote or demote a member

# Promote a member to admin (e.g. after key recovery or role change)
seal team promote [email protected]

# Demote an admin back to member
seal team demote [email protected]
  • seal team promote and seal team demote are the only way to change roles — team.json should never be edited manually.
  • Demoting the last admin is blocked — there must always be at least one admin.
  • Both actions are recorded in the audit log (PROMOTE / DEMOTE).

Developer Day-to-Day Workflow

This section covers the exact steps a developer takes during normal feature work — adding new secrets, changing existing values, and keeping the team in sync.


The Golden Rule

Never edit .enc.json files directly.
Always edit your .env.<environment> file, then run seal push. ArcanumSeal is the only thing that touches the encrypted store.


Workflow 1 — Adding a Brand New Secret Variable

You're building a new feature that needs a Twilio API key. Here's the complete flow:

Step 1 — Add the variable to your local .env

# Open your local .env.development (not committed — gitignored)
echo 'TWILIO_AUTH_TOKEN=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' >> .env.development

Or edit it in your editor. Your .env.development now looks like:

DB_HOST=localhost
DB_PASS=devpassword
API_KEY=sk-dev-test123
TWILIO_AUTH_TOKEN=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx   ← new

Step 2 — Push the updated secrets

seal push --env development
✓ Secrets pushed to .arcanumSeal/development.enc.json

  1 secret added
  3 secrets updated
  Encrypted for 3 recipients

ArcanumSeal re-encrypts all secrets (not just the new one) for every team member in a single pass.

Step 3 — Also add it to staging and production

# Add the real values for each environment
echo 'TWILIO_AUTH_TOKEN=ACyyyy_staging_token' >> .env.staging
echo 'TWILIO_AUTH_TOKEN=ACzzzz_prod_token' >> .env.production

seal push --env staging
seal push --env production

Step 4 — Update .env.example so teammates know the variable exists

echo 'TWILIO_AUTH_TOKEN=your-twilio-auth-token' >> .env.example

Step 5 — Commit and push

git add .arcanumSeal/ .env.example
git commit -m "feat: add TWILIO_AUTH_TOKEN secret for SMS feature"
git push

Step 6 — Teammates pull and get the new secret automatically

# On any teammate's machine
git pull
seal pull --env development   # .env.development now contains TWILIO_AUTH_TOKEN

Or if they use seal exec, it's available immediately with no extra steps:

seal exec --env development -- npm run dev
# process.env.TWILIO_AUTH_TOKEN is available inside the process

Workflow 2 — Changing an Existing Secret Value

You need to update the database password because it was rotated by your DBA.

Option A — Update via .env file + seal push (recommended for bulk changes)

Use this when you're changing multiple secrets at once, or when you already have the new values in your .env file.

# Edit .env.production — change DB_PASS to the new value
nano .env.production
# DB_PASS=old-password  →  DB_PASS=new-dba-rotated-password

seal push --env production
✓ Secrets pushed to .arcanumSeal/production.enc.json

  4 secrets updated
  Encrypted for 3 recipients
git add .arcanumSeal/
git commit -m "chore: update DB_PASS to new DBA-rotated value"
git push

Option B — seal rotate (recommended for a single secret, with hidden input)

Use this when you're changing one secret and want the value hidden from your terminal history and screen.

seal rotate DB_PASS --env production
New value for DB_PASS: ********

✓ DB_PASS rotated successfully
  Environment: production
  Version:     2 → 3
  Updated by:  [email protected]

seal rotate re-encrypts the new value for all team members in one step — no need to run seal push afterward.

git add .arcanumSeal/
git commit -m "chore: rotate DB_PASS"
git push

When to use which:

  • seal push — you have a new .env file from your DBA / DevOps, or you're changing many secrets at once
  • seal rotate — you're changing one secret interactively and want the value hidden from your screen and shell history

Workflow 3 — Removing a Secret Variable

A feature was deprecated and LEGACY_PAYMENT_KEY is no longer needed.

Step 1 — Remove it from your .env file

# Edit .env.production and delete the LEGACY_PAYMENT_KEY line
nano .env.production
# Before
DB_HOST=prod-db.example.com
DB_PASS=secret
LEGACY_PAYMENT_KEY=pk_live_old123   ← delete this line
API_KEY=sk-prod-abc

# After
DB_HOST=prod-db.example.com
DB_PASS=secret
API_KEY=sk-prod-abc

Step 2 — Push — ArcanumSeal detects the removal

seal push --env production
✓ Secrets pushed to .arcanumSeal/production.enc.json

  3 secrets updated
  1 secret removed

The key is removed from the encrypted store. Teammates will no longer receive it on their next seal pull.

Step 3 — Also remove from .env.example

# Remove the LEGACY_PAYMENT_KEY line from .env.example
nano .env.example

git add .arcanumSeal/ .env.example
git commit -m "chore: remove deprecated LEGACY_PAYMENT_KEY"
git push

Workflow 4 — Pulling the Latest Secrets (After a Teammate Pushed Changes)

A teammate added a new secret or rotated a value. You need to sync.

git pull                          # get the updated .enc.json
seal pull --env development       # decrypt to your local .env.development
✓ 5 secrets synced to .env.development

If you use seal exec instead of seal pull, you don't need to do anything — the latest secrets are always decrypted fresh on every run:

seal exec --env development -- npm run dev   # always uses the latest encrypted store

Workflow 5 — Working Across Multiple Environments

A typical day might involve switching between environments:

# Morning: local development
seal exec --env development -- npm run dev

# Afternoon: test against staging
seal pull --env staging
npm run test:integration

# Deploy to production
seal validate --env production --keys DB_HOST,DB_PASS,API_KEY
seal exec --env production -- npm run deploy

Or check what's in each environment without decrypting:

seal history --env production    # see recent pushes and rotations
seal rotation-report             # check if any secrets are overdue for rotation

Workflow 6 — Checking What Changed (Before Pulling)

Before pulling and decrypting, you can inspect what changed between two pushes:

seal history --env production
History for production  (4 events)

  TIMESTAMP            ACTION  USER              SECRET    DETAILS
  -------------------  ------  ----------------  --------  -------
  2026-03-12 10:15:00  ROTATE  [email protected]  DB_PASS   —
  2026-03-11 14:22:31  PUSH    [email protected]  —         —
  2026-03-10 09:00:00  PUSH    [email protected] —         —

Diff two specific pushes to see exactly what changed:

seal diff p3 p4 --env production
Diff: push p3 → p4  (production)

  ↻ Changed (1):
  SECRET   VERSION  FINGERPRINT  VALUE
  -------  -------  -----------  ---------------------------
  DB_PASS  v2 → v3  63ef416a     (value changed — not shown)

  — Unchanged: 4 secrets

Workflow 7 — Onboarding Yourself to an Existing Project

You just joined a team that already uses ArcanumSeal.

# 1. Clone the repo (encrypted stores are already in git)
git clone [email protected]:company/project.git
cd project

# 2. Install ArcanumSeal
npm install -g arcanumSeal

# 3. Generate your personal keypair (one-time setup)
seal keygen

# 4. Share your public key with an admin
seal request-access --to [email protected]
Your public key:

bY2W660AN/FqsQlycQbtKMltG3hW0F/IsM4FUTxN5zg=

  Send this key to [email protected] and ask them to run:
  seal grant [email protected] --key bY2W660AN/FqsQlycQbtKMltG3hW0F/IsM4FUTxN5zg=
# 5. After the admin grants access and pushes — pull the latest
git pull
seal pull --env development

# 6. Start working
seal exec --env development -- npm run dev

Quick Reference — Which Command to Use When

| Situation | Command | |-----------|---------| | Added a new variable to .env | seal push --env <env> | | Changed multiple values in .env | seal push --env <env> | | Changed one secret (hidden input) | seal rotate <KEY> --env <env> | | Removed a variable from .env | seal push --env <env> (removal is automatic) | | Teammate pushed new secrets | git pull then seal pull --env <env> | | Run app with latest secrets | seal exec --env <env> -- <command> | | Check what changed recently | seal history --env <env> | | Compare two versions | seal diff p1 p2 --env <env> | | Check rotation health | seal rotation-report | | Verify all required secrets exist | seal validate --env <env> --keys A,B,C |


Common Mistakes to Avoid

| ❌ Don't | ✅ Do Instead | |----------|--------------| | Edit .arcanumSeal/*.enc.json directly | Edit .env.<env> then seal push | | Commit .env.* files | They are gitignored — use seal push | | Share secrets over Slack/email | Use seal grant to give access | | Use --value flag for seal rotate | Use SEAL_ROTATE_VALUE=... seal rotate or interactive prompt | | Forget to git push after seal push | Always commit .arcanumSeal/ after any push/rotate/grant/revoke | | Assume revoke alone cuts off access | After seal revoke, rotate all secret values too |


Secret Rotation

Rotate a single secret

seal rotate DB_PASS --env production
New value for DB_PASS: ********

✓ DB_PASS rotated successfully
  Environment: production
  Version:     3 → 4
  Updated by:  [email protected]

Check rotation health

seal rotation-report
Environment: production

  SECRET      LAST ROTATED  VERSION  BY                STATUS
  ----------  ------------  -------  ----------------  ----------
  DB_HOST     0d ago        v2       [email protected]  ✓ HEALTHY
  DB_PASS     0d ago        v4       [email protected]  ✓ HEALTHY
  API_KEY     95d ago       v1       [email protected]  ⚠ DUE SOON
  STRIPE_KEY  200d ago      v1       [email protected]  ✗ OVERDUE

Summary
  ✓ Healthy:   2
  ⚠ Due soon:  1  (rotate within 90 days)
  ✗ Overdue:   1  (rotate immediately!)

Suggested rotation commands:
  seal rotate STRIPE_KEY --env production

Audit Log

View all activity

seal audit
Audit log  (21 entries)

  TIMESTAMP            USER              ACTION  ENVIRONMENT  SECRET
  -------------------  ----------------  ------  -----------  -------
  2026-03-11 15:43:07  [email protected]  ROTATE  production   DB_PASS
  2026-03-11 14:22:31  [email protected]  PUSH    production   —
  2026-03-11 13:10:05  [email protected] PULL    production   —

Filter the log

seal audit --user arjun          # only Arjun's entries
seal audit --env production      # only production
seal audit --action ROTATE       # only rotations
seal audit --since 7d            # last 7 days
seal audit --from 2026-01-01 --to 2026-03-31   # date range

Export for compliance (SOC2, etc.)

seal audit --since 90d --export audit-report.json
✓ Audit log exported to audit-report.json
  21 entries written
  Format: JSON array, timestamps ISO 8601

Leak Detection

Scan git history

seal scan --git
  Scanning git history for 5 secret values...

✓ Clean — no secrets found in git history (47 commits scanned)

If a leak is found:

✗ Found 1 leaked secret in git history!

  SECRET   ENVIRONMENT  LOCATION
  -------  -----------  ------------------------------------------
  DB_PASS  production   commit a3f8b21c — config/database.js:12

Rotate these secrets immediately:
  seal rotate DB_PASS --env production

Scan working files (pre-commit hook)

seal scan --files

Use as a pre-commit hook to block accidental commits:

# .git/hooks/pre-commit
#!/bin/sh
seal scan --files

Version History & Diffing

View history for an environment

seal history --env production
History for production  (3 events)

  TIMESTAMP            ACTION  USER              SECRET   DETAILS
  -------------------  ------  ----------------  -------  -------
  2026-03-11 15:43:07  ROTATE  [email protected]  DB_PASS  —
  2026-03-11 10:24:12  PUSH    [email protected]  —        —
  2026-03-10 09:00:00  PUSH    [email protected]  —        —

Current state

  SECRET      VERSION  LAST UPDATED         BY                FINGERPRINT
  ----------  -------  -------------------  ----------------  -----------
  DB_HOST     v2       2026-03-11 10:24:12  [email protected]  4953d00c
  DB_PASS     v4       2026-03-11 15:43:07  [email protected]  63ef416a
  API_KEY     v2       2026-03-11 10:24:12  [email protected]  664e0f99

Diff two versions

seal diff p1 p4 --env production
Diff: push p1 → p4  (production)

  ↻ Rotated (1):
  SECRET  VERSION  FINGERPRINT  VALUE
  ------  -------  -----------  ---------------------------
  DB_PASS v1 → v4  63ef416a     (value changed — not shown)

  — Unchanged: 2 secrets

  Note: plaintext values are never shown in diff output.

Integrating ArcanumSeal Into Your Project

This section walks through complete, real-world integration scenarios from scratch — from a solo developer to a full team with CI/CD.


Scenario A — Solo Developer (Node.js / Express)

Goal: Encrypt your .env.production so it's safe to commit, and run your app without ever writing secrets to disk.

Step 1 — Install and generate your keypair

npm install -g arcanumSeal
seal keygen
✓ Keypair generated and saved.

Your public key:
CUlyjQI/M3FeBQlzWTBzdK76WDkwtczywmDfSQIbyDQ=

  Private key → ~/.arcanumSeal/master.key  (never share this)
  Public key  → ~/.arcanumSeal/master.pub  (safe to share)

Step 2 — Initialize ArcanumSeal in your project

cd my-express-app
seal init
✓ ArcanumSeal initialized for project: my-express-app

  Created: .arcanumSeal/config.json
  Created: .arcanumSeal/team.json
  Updated: .gitignore

Your .gitignore now contains:

# ArcanumSeal
.env
.env.*
!.env.example
.arcanumSeal/master.key
.arcanumSeal/audit.log
.arcanumSeal/*.tmp

Step 3 — Create your .env.production

cat > .env.production << 'EOF'
DB_HOST=prod-db.example.com
DB_PORT=5432
DB_PASS=super-secret-password
API_KEY=sk-prod-abc123xyz
STRIPE_SECRET=sk_live_abc123
EOF

Step 4 — Encrypt and commit

seal push --env production
✓ Secrets pushed to .arcanumSeal/production.enc.json

  5 secrets added
  Encrypted for 1 recipient
git add .arcanumSeal/
git commit -m "chore: add encrypted production secrets"
git push

Your .env.production is never committed (blocked by .gitignore). Only the encrypted blob is in git.

Step 5 — Run your app with secrets injected (no disk write)

# Instead of: node server.js  (which requires a .env file)
seal exec --env production -- node server.js

Secrets are decrypted in memory and injected as process.env. Your server.js reads them normally:

// server.js — no changes needed
const db = new Pool({
  host: process.env.DB_HOST,
  password: process.env.DB_PASS,
})

Step 6 — Add an .env.example for documentation

cat > .env.example << 'EOF'
DB_HOST=your-db-host
DB_PORT=5432
DB_PASS=your-db-password
API_KEY=your-api-key
STRIPE_SECRET=sk_live_...
EOF

git add .env.example
git commit -m "docs: add .env.example"

Scenario B — Team of Developers (Full Workflow)

Goal: Admin Riya sets up secrets, grants access to new developer Arjun, and later revokes access when Arjun leaves.

Step 1 — Admin (Riya) sets up the project

# Riya already has a keypair from seal keygen
cd team-project
seal init
seal push --env production
seal push --env staging

git add .arcanumSeal/
git commit -m "chore: initialize ArcanumSeal with encrypted secrets"
git push

Step 2 — New developer (Arjun) joins

On Arjun's machine:

git clone [email protected]:company/team-project.git
cd team-project
npm install -g arcanumSeal
seal keygen
seal request-access --to [email protected]
Your public key:

bY2W660AN/FqsQlycQbtKMltG3hW0F/IsM4FUTxN5zg=

  Send this key to [email protected] and ask them to run:
  seal grant [email protected] --key bY2W660AN/FqsQlycQbtKMltG3hW0F/IsM4FUTxN5zg=

Arjun sends this public key to Riya (Slack, email — it's safe to share).

Step 3 — Admin (Riya) grants access

seal grant [email protected] --key bY2W660AN/FqsQlycQbtKMltG3hW0F/IsM4FUTxN5zg=
  Re-encrypting secrets for [email protected]...

✓ Access granted to [email protected]

  Added to:    .arcanumSeal/team.json
  Environments: all
  Re-encrypted: 2 environments
git add .arcanumSeal/
git commit -m "chore: grant access to [email protected]"
git push

Step 4 — Arjun pulls and starts working

git pull
seal pull --env staging       # writes .env.staging locally
seal exec --env production -- npm start   # injects production secrets in memory

Step 5 — Rotate a secret (e.g., after a suspected leak)

seal rotate DB_PASS --env production
New value for DB_PASS: ********

✓ DB_PASS rotated successfully
  Environment: production
  Version:     1 → 2
  Updated by:  [email protected]

For CI rotation, use the env var form to avoid exposing the value in process arguments:

SEAL_ROTATE_VALUE=new-super-secret seal rotate DB_PASS --env production
git add .arcanumSeal/
git commit -m "chore: rotate DB_PASS"
git push

All team members automatically get the new value on their next seal pull or seal exec.

Step 6 — Arjun leaves the company

seal revoke [email protected]
✓ Access revoked for [email protected]

  Re-encrypted: 2 environments

⚠ IMPORTANT: Re-encryption alone does NOT invalidate existing local copies.
  You MUST rotate all secret values to fully cut off access:
  seal rotate <KEY> --env <env>  (repeat for every secret in every environment)
# Rotate every secret to fully cut off access
seal rotate DB_PASS --env production
seal rotate API_KEY --env production
seal rotate STRIPE_SECRET --env production
# ... repeat for all secrets

git add .arcanumSeal/
git commit -m "chore: revoke access for [email protected] and rotate all secrets"
git push

Scenario C — Python / Django Project

ArcanumSeal is language-agnostic. Here's a Django integration:

Setup

pip install --user arcanumSeal   # or: npm install -g arcanumSeal
seal keygen
seal init

Create .env.production

cat > .env.production << 'EOF'
DJANGO_SECRET_KEY=your-50-char-secret-key-here
DATABASE_URL=postgres://user:pass@prod-db:5432/mydb
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
REDIS_URL=redis://prod-redis:6379/0
ALLOWED_HOSTS=myapp.com,www.myapp.com
EOF

seal push --env production

Run Django with secrets injected

# Development
seal exec --env development -- python manage.py runserver

# Run migrations
seal exec --env production -- python manage.py migrate

# Collect static files
seal exec --env production -- python manage.py collectstatic --noinput

# Django shell with production secrets
seal exec --env production -- python manage.py shell

settings.py — no changes needed

# settings.py
import os

SECRET_KEY = os.environ['DJANGO_SECRET_KEY']
DATABASES = {'default': dj_database_url.parse(os.environ['DATABASE_URL'])}
AWS_ACCESS_KEY_ID = os.environ['AWS_ACCESS_KEY_ID']

Scenario D — Docker / Docker Compose

Option 1 — Inject secrets into a container at runtime

# Pull secrets to a temp file, run container, then delete
seal pull --env production --out /tmp/.env.prod
docker run --env-file /tmp/.env.prod myapp:latest
rm /tmp/.env.prod

Option 2 — Use seal exec to wrap docker-compose

# Secrets are injected into docker-compose's environment
seal exec --env production -- docker-compose up

Your docker-compose.yml reads from the environment:

# docker-compose.yml
services:
  app:
    image: myapp:latest
    environment:
      - DB_HOST=${DB_HOST}
      - DB_PASS=${DB_PASS}
      - API_KEY=${API_KEY}

Option 3 — Build-time secrets (multi-stage Dockerfile)

# Dockerfile
FROM node:22-alpine AS builder
# Build stage — no secrets needed

FROM node:22-alpine AS runtime
# Secrets are injected at runtime via seal exec, not baked into the image
COPY --from=builder /app /app
CMD ["node", "server.js"]
# Run with secrets injected
seal exec --env production -- docker run myapp:latest

Scenario E — Monorepo (Multiple Services)

Each service has its own ArcanumSeal store. Use --env to namespace by service:

# Initialize once at the monorepo root
seal init

# Push secrets per service
seal push --env api-production
seal push --env worker-production
seal push --env frontend-production

# Run each service with its own secrets
seal exec --env api-production -- node services/api/server.js
seal exec --env worker-production -- node services/worker/index.js

File structure:

monorepo/
├── .arcanumSeal/
│     ├── config.json
│     ├── team.json
│     ├── api-production.enc.json
│     ├── worker-production.enc.json
│     └── frontend-production.enc.json
├── services/
│     ├── api/
│     ├── worker/
│     └── frontend/
└── .gitignore

Scenario F — Pre-commit Hook (Leak Prevention)

Automatically scan for leaked secrets before every commit:

# .git/hooks/pre-commit
#!/bin/sh
set -e

echo "ArcanumSeal: scanning for leaked secrets..."
seal scan --files

if [ $? -ne 0 ]; then
  echo ""
  echo "✗ Commit blocked — secret values found in working files."
  echo "  Remove the secrets and run: seal push --env <env>"
  exit 1
fi
chmod +x .git/hooks/pre-commit

Or with Husky:

npm install --save-dev husky
npx husky init
echo "seal scan --files" > .husky/pre-commit

Scenario G — Environment-Specific Configs (dev / staging / prod)

# Create separate .env files per environment
cat > .env.development << 'EOF'
DB_HOST=localhost
DB_PASS=devpassword
API_KEY=sk-dev-test123
EOF

cat > .env.staging << 'EOF'
DB_HOST=staging-db.example.com
DB_PASS=staging-secret
API_KEY=sk-staging-abc456
EOF

cat > .env.production << 'EOF'
DB_HOST=prod-db.example.com
DB_PASS=ultra-secret-prod-pass
API_KEY=sk-prod-xyz789
EOF

# Encrypt all three
seal push --env development
seal push --env staging
seal push --env production

# Commit all encrypted stores
git add .arcanumSeal/
git commit -m "chore: encrypt all environment secrets"

Switch environments:

# Local development
seal exec --env development -- npm run dev

# Integration tests against staging
seal exec --env staging -- npm test

# Production deployment
seal exec --env production -- npm run deploy

Scenario H — Validate Secrets Before Deployment

Use seal validate as a deployment gate — it exits with code 1 if any required secrets are missing, blocking the deployment:

# package.json
{
  "scripts": {
    "predeploy": "seal validate --env production --keys DB_HOST,DB_PASS,API_KEY,STRIPE_SECRET",
    "deploy": "node scripts/deploy.js"
  }
}
npm run deploy
# predeploy runs first:
# ✓ All 4 required secrets present for environment: production
# Then deploy runs

If a secret is missing:

✗ Validation failed for environment: production

  Missing secrets (1):
    ✗ STRIPE_SECRET

  Present secrets (3):
  Run: seal push --env production  to add missing secrets

The deploy is blocked with exit code 1.


CI/CD Integration

GitHub Actions

# .github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install ArcanumSeal
        run: npm install -g arcanumSeal

      - name: Write CI private key
        run: |
          mkdir -p ~/.arcanumSeal
          echo "${{ secrets.ARCANUMSEAL_KEY }}" > ~/.arcanumSeal/master.key
          chmod 600 ~/.arcanumSeal/master.key

      - name: Validate secrets present
        run: seal validate --env production

      - name: Pull secrets and deploy
        run: seal exec --env production -- npm run deploy
        # OR: seal pull --env production && npm run deploy

Setup:

  1. Run seal keygen locally to generate a CI keypair
  2. Run seal grant [email protected] --key <ci-public-key> to grant CI access (The person running seal init is automatically registered as admin in team.json)
  3. Store the CI private key as a GitHub Actions secret named ARCANUMSEAL_KEY
  4. Commit and push the re-encrypted blobs

Validate secrets in CI

# Fails with exit code 1 if any secrets are missing — blocks deployment
seal validate --env production

# Validate specific required keys
seal validate --env production --keys DB_HOST,DB_PASS,API_KEY,STRIPE_KEY

How It Works

ArcanumSeal uses NaCl box encryption (X25519 key exchange + XSalsa20-Poly1305 AEAD) via the audited tweetnacl library.

Encrypting a secret:

  1. Generate a one-time ephemeral X25519 keypair
  2. Generate a random 24-byte nonce
  3. Encrypt with nacl.box(plaintext, nonce, recipientPublicKey, ephemeralPrivateKey)
  4. Store { ciphertext, nonce, ephemeralPublicKey } — discard ephemeral private key
  5. Each secret has its own unique ephemeral keypair

Decrypting a secret:

  1. Load your private key from ~/.arcanumSeal/master.key
  2. Call nacl.box.open(ciphertext, nonce, ephemeralPublicKey, yourPrivateKey)
  3. Returns plaintext bytes → UTF-8 string

Multi-recipient encryption:

When you seal push, every secret is encrypted independently for each team member using their own ephemeral keypair. The store holds a recipients map (publicKey → EncryptedSecret) alongside the primary encrypted field. When you seal pull, ArcanumSeal looks up your public key in the recipients map first, then falls back to the primary field.

This means:

  • seal grant re-encrypts once for all members simultaneously — no second pass needed
  • seal revoke rebuilds the recipients map without the revoked key — one atomic operation
  • Each member's ciphertext is independent — compromising one does not affect others

Why this design:

  • Compromising one secret does not compromise others (unique ephemeral keys per recipient)
  • The git repository never sees plaintext
  • Standard, audited cryptography — not custom
  • Backward-compatible: stores without a recipients map still decrypt via the primary field

File Structure

your-project/
├── .arcanumSeal/
│     ├── config.json          ← project config       (commit ✓)
│     ├── team.json            ← team public keys      (commit ✓)
│     ├── production.enc.json  ← encrypted secrets     (commit ✓)
│     ├── staging.enc.json     ← encrypted secrets     (commit ✓)
│     └── audit.log            ← local audit log       (do NOT commit — gitignored)
└── .gitignore                 ← updated automatically

~/.arcanumSeal/
    ├── master.key   ← YOUR private key  (NEVER commit — chmod 600)
    └── master.pub   ← YOUR public key   (safe to share)

Command Reference

| Command | Description | |---|---| | seal init | Initialize ArcanumSeal in the current project | | seal keygen | Generate your personal X25519 keypair | | seal push --env <env> | Encrypt .env.<env> and store it | | seal pull --env <env> | Decrypt secrets to .env.<env> | | seal exec --env <env> -- <cmd> | Run command with secrets injected (no disk write) | | seal grant <email> --key <key> | Grant a team member access | | seal revoke <email> | Revoke a team member's access | | seal request-access --to <email> | Print your public key for an admin | | seal team list | List all team members and their access | | seal team promote <email> | Promote a member to admin role | | seal team demote <email> | Demote an admin to member role | | seal rotate <KEY> --env <env> | Rotate a single secret to a new value | | seal rotation-report | Show rotation health for all secrets | | seal audit | View the full audit log | | seal audit --export <file> | Export audit log as JSON | | seal history --env <env> | Show push/rotation history | | seal diff <p1> <p2> --env <env> | Compare two push snapshots (no plaintext shown) | | seal scan --git | Scan git history for leaked secrets | | seal scan --files | Scan working files for secret values | | seal validate --env <env> | Validate all expected secrets are present |


Security

  • Algorithm: NaCl box — X25519 key exchange + XSalsa20-Poly1305 AEAD
  • Library: tweetnacl — audited, zero dependencies, 3.2kb
  • Private key: Never leaves your machine. Stored at ~/.arcanumSeal/master.key with chmod 600
  • Ephemeral keys: Each secret encrypted with a unique one-time keypair
  • No plaintext: Only encrypted blobs are ever written to disk or committed to git
  • No network: Fully offline. Zero HTTP requests at runtime
  • Audit trail: Every push, pull, grant, revoke, and rotation is logged locally

See docs/SECURITY.md for the full security model.

CI secret rotation: Use the SEAL_ROTATE_VALUE environment variable instead of --value to avoid exposing secrets in process argument lists (ps aux):

SEAL_ROTATE_VALUE=newvalue seal rotate DB_PASS --env production

Tech Stack

| | | |---|---| | Language | TypeScript (strict mode) | | Runtime | Node.js 22+ | | Module | ESM (import/export) | | Encryption | tweetnacl ^1.0.3 | | Encoding | tweetnacl-util ^0.15.1 | | CLI parser | Built from scratch (no commander/yargs) | | Terminal output | Built from scratch (no chalk) | | Prompts | Built from scratch (no inquirer) | | .env parser | Built from scratch (no dotenv) | | Tests | Vitest — 100+ tests, 9 test files |

Total production dependencies: 2 (tweetnacl + tweetnacl-util)


Development

git clone https://github.com/your-org/arcanumSeal
cd arcanumSeal
npm install

# Run in dev mode
npm run dev -- keygen

# Run tests
npm test

# Run tests in watch mode
npm run test:watch

# Type check
npm run lint

# Build
npm run build

License

MIT — see LICENSE