本文へ移動
cccskills
無料GitHub で公開

secrets-ops

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.

インストール方法を見る

含まれるファイル(1)

  • SKILL.md5.8 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Secrets operations

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.

Rule 1 — how to read the secrets file

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

Rule 2 — where a key belongs

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.

Moving keys into app_secrets

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.

Rotation

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.

If a value is exposed

  1. Rotate first, investigate second. Everything is cheap to rotate except the age backup private key, which cannot be rotated at all for existing backups.
  2. Scrub what you can and say plainly what you cannot. Transcripts are at ~/.claude/projects/*/*.jsonl; git history is permanent.
  3. Record it in 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.

What this codebase does NOT encrypt

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.

Never

  • Paste a value into a chat, a commit, or a terminal that logs
  • Put anything sensitive behind NEXT_PUBLIC_ — it ships in the browser bundle
  • Copy a broad-scoped credential onto a server that only needs a narrow one
  • Write key documentation into this repo; it goes in vigyan-secrets.md

Bootstrap values: vault → platform (SOPS + age, 2026-10-02)

env.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).

TierWhere the value goes
bootstrap / publicPlatform env, pushed from the vault (pnpm secrets sync coolify|vercel --env prod --apply)
secretAdmin → Settings → Secrets (encrypted app_secrets); vault copy optional
configAdmin → Settings (app_config)
localOperator shell / local scripts only
deprecatedRemove everywhere

Rules for agents:

  • Never print, echo or log a value. The tool prints names, counts and plans only.
  • 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.
  • Platform syncs are dry runs unless --apply. Build-time (phase: build) vars need a redeploy to take effect.
  • New variable = add it to env.manifest.json in the same change, with a tier.
  • Prove a pushed value works by behaviour (the integration answers), not by reading it back.
  • Moving hosts (Coolify → Vercel → AWS) changes only the bootstrap tier, ~7 vars.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

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.

日本語の概要は準備中です。原文の説明を表示しています。

aryannema/vigyan-site-os22026年10月2日 更新

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.

日本語の概要は準備中です。原文の説明を表示しています。

aryannema/vigyan-site-os22026年10月2日 更新

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.

日本語の概要は準備中です。原文の説明を表示しています。

aryannema/vigyan-site-os22026年10月2日 更新

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.

日本語の概要は準備中です。原文の説明を表示しています。

aryannema/vigyan-site-os22026年10月2日 更新

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".

日本語の概要は準備中です。原文の説明を表示しています。

aryannema/vigyan-site-os22026年10月2日 更新

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.

日本語の概要は準備中です。原文の説明を表示しています。

aryannema/vigyan-site-os22026年10月2日 更新

aryannema のスキルをすべて見る

このスキルの問題を報告する