Skip to Content
DojOps: AI-powered DevOps automation. Learn more →
TutorialsAdvanced Config Management

Advanced config management

Keep API keys out of plaintext, snapshot your setup before risky changes, and distribute a consistent configuration across your team.

Difficulty: Intermediate Duration: 30 minutes What you’ll build: A team-shareable configuration workflow with an encrypted secrets vault, versioned config snapshots, and a one-command onboarding script for new team members


What you’ll learn

  • Store API keys in an AES-256-GCM encrypted vault and reference them with $secret: syntax
  • Create point-in-time configuration snapshots with SHA-256 integrity verification
  • Restore a previous configuration safely, with automatic pre-restore backup
  • Export your current settings as a shareable JSON file for team onboarding
  • Apply bulk configuration from a file in a single command

Prerequisites

  • DojOps 1.1.6 installed (npm i -g @dojops/cli)
  • A project initialized with dojops init
  • At least one LLM provider API key to practice with

Workshop steps

Step 1: Understand the default storage problem

By default, dojops init stores your API key in ~/.dojops/config.json as plaintext. Open it to see what that looks like:

cat ~/.dojops/config.json
{ "provider": "openai", "providers": { "openai": { "apiKey": "sk-proj-abc123yourrealkey..." } } }

That key is readable by any process that can read your home directory. If you ever cat this file in a screen share, it leaks. The encrypted vault replaces this pattern entirely.


Step 2: Store a secret in the vault

The dojops secrets set command encrypts your key using AES-256-GCM and writes it to .dojops/secrets.json. The original key is never stored anywhere in plaintext after this point.

dojops secrets set OPENAI_API_KEY sk-proj-abc123...
┌ Secret Stored │ Key: OPENAI_API_KEY │ Encryption: AES-256-GCM │ Storage: .dojops/secrets.json └ Encrypted and saved

The encryption key is derived from a random key stored at ~/.dojops/vault-key (or from the DOJOPS_VAULT_KEY env var if set). The secrets file alone is useless without the corresponding key.

Now store your other provider keys if you have them:

dojops secrets set ANTHROPIC_API_KEY sk-ant-api03-... dojops secrets set DEEPSEEK_API_KEY sk-... dojops secrets set GEMINI_API_KEY AIza...

Step 3: Reference secrets in your config

Once a key is in the vault, update your config to reference it by name instead of value. Open ~/.dojops/config.json and change the apiKey fields:

{ "provider": "openai", "providers": { "openai": { "apiKey": "$secret:OPENAI_API_KEY" }, "anthropic": { "apiKey": "$secret:ANTHROPIC_API_KEY" }, "deepseek": { "apiKey": "$secret:DEEPSEEK_API_KEY" } } }

DojOps resolves $secret: references at runtime by looking up the vault. Your config file can now be committed to version control or shared with teammates without exposing any keys.

Verify the resolution works by running a quick provider check:

dojops check provider
✔ Provider: openai ✔ Model: gpt-4o ✔ Connection: OK

If the connection succeeds, the vault lookup is working correctly.


Step 4: Inspect what’s stored

List your vault contents at any time. DojOps shows only the key name and a short prefix of the value — enough to confirm you stored the right key without exposing it.

dojops secrets list
┌ Encrypted Secrets │ OPENAI_API_KEY set (sk-proj-abc...) │ ANTHROPIC_API_KEY set (sk-ant-api0...) │ DEEPSEEK_API_KEY set (sk-...) │ GEMINI_API_KEY set (AIza...) └ 4 secrets stored in .dojops/secrets.json

Step 5: Remove a secret

If you rotate an API key or stop using a provider, remove the old secret:

dojops secrets remove DEEPSEEK_API_KEY
┌ Secret Removed │ Key: DEEPSEEK_API_KEY │ Status: deleted from vault └ 3 secrets remaining

After removal, any config reference pointing to $secret:DEEPSEEK_API_KEY will fail at runtime with a clear error message — which makes broken references easy to catch.


Step 6: Create a configuration snapshot

Before you make any significant change — switching providers, updating model settings, applying team config — take a snapshot. A snapshot is a tar.gz of your entire .dojops/ directory with a SHA-256 checksum to prove integrity.

dojops backup
┌ Backup Created │ Snapshot: backup-2026-03-20-143022.tar.gz │ Location: ~/.dojops/backups/ │ Size: 24 KB │ SHA-256: a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6... │ Contents: │ config.json │ vault.enc │ context.json │ scan-history/ (3 files) │ execution-logs/ (7 files) │ audit-log.jsonl └ Backup verified

The SHA-256 hash is written into the archive metadata. When you restore later, DojOps recomputes it and refuses to restore a corrupted or tampered archive.


Step 7: View all snapshots

dojops backup list
┌ Backups │ backup-2026-03-20-143022 24 KB just now │ backup-2026-03-17-091500 18 KB 3 days ago │ backup-2026-03-10-160000 12 KB 10 days ago └ 3 snapshots (54 KB total) stored in ~/.dojops/backups/

Snapshots accumulate over time. You can keep them indefinitely or prune old ones manually — DojOps doesn’t auto-delete them.


Step 8: Apply a team configuration file

Team configs are JSON files that set provider, model, aliases, and scan defaults. Anyone who applies them gets the same behavior as everyone else on the team, regardless of what they had configured before.

Create team-defaults.json:

{ "provider": "openai", "model": "gpt-4o", "temperature": 0, "fallbackProvider": "anthropic", "aliases": { "fast": "gpt-4o-mini", "smart": "gpt-4o", "review": "claude-sonnet-4-6" }, "thinking": "medium", "scan": { "defaultCategories": ["security", "deps", "iac"], "jsonOutput": true } }

Apply it:

dojops config apply team-defaults.json
┌ Config Applied │ Applied from: team-defaults.json │ Changes: │ provider → openai │ model → gpt-4o │ temperature → 0 │ fallbackProvider → anthropic │ aliases → 3 aliases set (fast, smart, review) │ thinking → medium │ scan.categories → security, deps, iac │ scan.jsonOutput → true └ 8 settings updated

Notice temperature: 0. This is intentional for team configs — zero temperature makes output deterministic, which means two people running the same prompt get equivalent results. Use higher temperatures for exploratory work in personal configs.


Step 9: Restore from a snapshot

Something went wrong after applying the team config. Roll back to your pre-change snapshot:

dojops backup restore backup-2026-03-17-091500
┌ Restore │ Restoring: backup-2026-03-17-091500 │ SHA-256: verified ✓ │ Restored: │ config.json │ vault.enc │ context.json │ scan-history/ (2 files) │ execution-logs/ (5 files) │ audit-log.jsonl │ Current config backed up to: │ backup-2026-03-20-pre-restore.tar.gz └ Restore complete

DojOps automatically creates a backup of your current state before overwriting it. So even if the restoration takes you somewhere wrong, you can restore again from backup-2026-03-20-pre-restore.tar.gz.


Step 10: Build a team onboarding workflow

Put the pieces together into a reproducible onboarding flow. Export your current config as the team standard:

dojops config export > .dojops/team-config.json

Check this file into your repository. It contains no secrets — only model names, aliases, and scan defaults. New team members run:

git clone git@github.com:your-org/your-repo.git cd your-repo dojops init dojops secrets set OPENAI_API_KEY sk-proj-... # their own key dojops config apply .dojops/team-config.json dojops check provider

After those four commands, a new team member has the same model, aliases, and scan settings as everyone else. They bring their own API key; you provide the configuration.


Try it yourself

Challenge 1: Create a second JSON config file called local-dev.json that overrides temperature to 0.7 and model to gpt-4o-mini for local experimentation. Apply it, verify the change, then restore from your snapshot.

Challenge 2: Write a shell script that takes a backup, applies team-defaults.json, runs dojops check provider, and on failure automatically restores the previous backup.

Challenge 3: Add a fourth alias called code mapped to your preferred model for code-heavy tasks. Export the config and check whether the alias survives a config apply round-trip.


Troubleshooting

dojops secrets set fails with “encryption key not found”

The vault encryption key is derived on first use and stored in ~/.dojops/.key. If it’s missing, run dojops init to regenerate it. Don’t delete .key — doing so makes all existing vault entries unreadable.

$secret:OPENAI_API_KEY resolves as the literal string at runtime

The $secret: prefix is case-sensitive. Check your config for $Secret: or $SECRET: typos. Also verify the key was actually stored: dojops secrets list.

Restore fails with “SHA-256 mismatch”

The archive was modified after creation. This is either corruption (disk issue) or tampering. DojOps will not restore a mismatched archive. If you need to recover, check ~/.dojops/backups/ for an older snapshot.

config apply silently ignores some fields

Only known config keys are applied. Unrecognized fields are ignored and logged at the debug level. Run dojops config apply team-defaults.json --verbose to see which keys were accepted and which were skipped.


What you learned

Config management in DojOps is built around three habits: encrypt secrets before they touch disk, snapshot before changes, and share configs as files rather than word-of-mouth. The vault uses AES-256-GCM, the same cipher used by professional password managers. Snapshots are portable and integrity-verified, so you can restore with confidence even weeks later. The config apply pattern gives teams a single source of truth for model behavior without requiring everyone to manually recreate settings. Together, these practices eliminate the two most common config problems: leaked API keys and “works on my machine” model differences.


Next steps