brand
무료Apply this site's visual identity — colours, type, logo files and fixed brand strings. Use for any page, component, social asset or document that should look like the site.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Handling secrets, keys and credentials for site-os — reading vigyan-secrets.md safely, moving keys into app_secrets, rotating, and responding to an exposure. Use whenever a task touches a key, token, password, .env file, app_secrets, encryption, or the secrets document.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.
The canonical record is vigyan-secrets.md in Nextcloud
(admin/files/YourSite/), section 0 of which is the registry: which key
is which, who issues it, how to reissue it. Procedures live in
docs/SECURITY-OPS.md. Neither is duplicated into this repository.
By heading, or by exact key name. Never a line range.
sudo grep -nE '^#{1,4} ' <file> # headings — safe
sudo grep -n 'RESEND_API_KEY' <file> # one key by name — safe
sudo sed -n '340,360p' <file> # NEVER
On 2026-09-29 a sed range with a length-based redact (>=20 chars) echoed
Nextcloud TOTP backup codes — which are 16 characters — into a session
transcript. Length-based filtering does not work. Neither does "I'll be careful."
When you need to know whether two secrets are the same, fingerprint, never print:
sha256sum <<< "$VALUE" | cut -c1-12 # comparable, reveals nothing
Can the app read it before it can reach the database? Yes → Coolify env. No →
app_secrets.
Boot-critical, never movable: DATABASE_URL, NEXT_PUBLIC_SUPABASE_URL,
NEXT_PUBLIC_SUPABASE_ANON_KEY, SUPABASE_SERVICE_ROLE_KEY,
CONFIG_ENCRYPTION_KEY, ACCOUNT_DELETION_ENCRYPTION_KEY, CRON_SECRET.
CONFIG_ENCRYPTION_KEY decrypts app_secrets, so it can never live inside it.
Everything else — vendor keys, webhook URLs, R2 — belongs in app_secrets and
is changeable without a redeploy.
Use the script. Do not hand-roll the encryption; the format has to match
src/lib/app-secrets.ts byte for byte or the row is silently undecryptable.
node scripts/seed-app-secrets.mjs --dry-run
node scripts/seed-app-secrets.mjs --only RESEND_API_KEY --dry-run
node scripts/seed-app-secrets.mjs --sql-out /tmp/seed.sql # then apply, then shred
It prints key names and fingerprints only, refuses boot-critical keys, refuses keys outside the MANAGED list, verifies every round-trip before emitting SQL, and refuses to print SQL to stdout.
Always compare CONFIG_ENCRYPTION_KEY fingerprints first. The script prints
its own; compare with production's. A mismatch means rows write successfully and
cannot be decrypted there.
Verify after applying by decrypting with production's key, not by trusting
the insert. Format is base64(iv[12] ‖ authTag[16] ‖ ciphertext), optionally
prefixed v<N>:. Note Node puts the auth tag in the middle; Python's AESGCM
expects it appended — reorder as body + tag or you get a spurious InvalidTag.
Rollback is DELETE FROM app_secrets WHERE key = '...' — getSecret() falls
straight back to process.env.
Overlap, always: create the new credential, deploy it, verify, then revoke the old one. Never revoke first.
CONFIG_ENCRYPTION_KEY is special — add CONFIG_ENCRYPTION_KEY_V2, set
CONFIG_ENCRYPTION_KEY_CURRENT=2, keep V1 until no v1 rows remain.
~/.claude/projects/*/*.jsonl; git history is permanent.vigyan-secrets.md under the affected key, with the date.Write credentials to production — treat an exposure of these as urgent:
SUPABASE_SERVICE_ROLE_KEY, MCP_SECRET_KEY, WEBHOOK_SECRET (n8n creates
posts through /api/webhook/blog with it), the GitHub PAT.
mask_email() is a plain SQL string function with no key. Masking is access
control — capabilities plus security_barrier views — and the underlying value
is plaintext. A pg_dump sees the real email. That is why backup encryption
is a separate control and why the age keypair exists.
NEXT_PUBLIC_ — it ships in the browser bundlevigyan-secrets.mdenv.manifest.json names every variable, its tier and purpose (no values).
Values live in the encrypted vault secrets/<env>.sops.env; the age private key
lives only in ~/.config/sops/age/keys.txt (never commit, back up offline).
| Tier | Where the value goes |
|---|---|
bootstrap / public | Platform env, pushed from the vault (pnpm secrets sync coolify|vercel --env prod --apply) |
secret | Admin → Settings → Secrets (encrypted app_secrets); vault copy optional |
config | Admin → Settings (app_config) |
local | Operator shell / local scripts only |
deprecated | Remove everywhere |
Rules for agents:
pnpm secrets check --env prod before any sync; fix "missing required" and
"not in manifest" first. pnpm env:check fails if code reads a name the
manifest does not describe.--apply. Build-time (phase: build)
vars need a redeploy to take effect.env.manifest.json in the same change, with a tier.아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.
로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.
아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.
Apply this site's visual identity — colours, type, logo files and fixed brand strings. Use for any page, component, social asset or document that should look like the site.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use FIRST when someone asks for a new feature or a change to an existing one — before any schema, code or test. Works out what is actually being asked for, whether to build it or integrate a third party (Trustpilot, Stripe, Calendly and the like), where the data lives, who may do what, and what happens when the vendor is down. Produces a decision, then hands to feature-schema.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when a new feature needs a table, column or capability — evolving the schema so the new thing joins the permission, audit and RLS contract instead of sitting outside it. Covers the DDL/DML split, the resource/capability wiring, and the self-verifying migration.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use after building a feature — explore it in a real browser to find what nobody predicted, then turn each finding into a deterministic test that guards it forever. Covers the agentic pass, what to generate vs hand-write, and how to skip honestly when a capability is missing.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Publishing content or deploying site-os — what caches exist, what refreshes them, and how to prove a change is actually live. Use when publishing a post or product, launching a page, deploying, or when someone says a change "isn't showing".
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Audit a page or the whole yoursite site (or a new site) for indexing readiness — cache headers, sitemap, robots, canonical, JSON-LD, internal links — and check the publish pipeline (Cloudflare purge/warm, IndexNow, GSC, Bing). Use before/after publishing content or launching a site.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.