Defense in depth nodejs
Skill jaredwray/agentic/skills/security/defense-in-depth-nodejs
Harden a Node.js repo against supply-chain compromise one PR at a time — pnpm's 7-day dependency cooldown, SHA-pinned actions via actions-up, Socket Firewall on every CI job, zizmor workflow linting, Aikido Safe Chain on Codespaces and Cursor Cloud Agents, staged OIDC npm publishing reviewed in Drydock, check-npmjs.sh to audit npmjs trusted-publishing settings, then a repo admin runs lockdown-repo.sh last (never checked into the target repo; all manual tasks last too) for repo settings (PRs required on main, admin-only tags, approval for outside workflow runs). Keeps a simple public SECURITY.md and tracks progress in DEFENSE_IN_DEPTH.md. Adapts to what the repo is — npm library, website/app, public or private. Use when asked to harden a repo, improve supply-chain security, lock down GitHub settings, validate npmjs publishing settings, or pin and lint CI. Manual, resumable, one item per PR.From its SKILL.md
npx -y skills add jaredwray/agentic --skill defense-in-depth-nodejsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
12.8 KB, as published. Nobody here has run it
Defense in Depth (Node.js)
Operation manual for hardening Node.js repos (Keyv, Cacheable, flat-cache, file-entry-cache, and
similar) against supply-chain compromise. One controllable improvement per PR; status tracked in the
target repo's DEFENSE_IN_DEPTH.md.
When this document is loaded, begin executing immediately. Do not ask the user what to do — start with Workflow Step 1. Only stop where the workflow says to stop (uncommitted changes, CODEOWNERS owners not yet named, status disagrees with reality, applying GitHub settings) or when a decision genuinely requires the user.
One PR at a time. Open a PR for one item, drive its CI to green, then stop and wait. Resume only when the user says
continue,next,next defense PR, or similar.This skill follows the shared
shipping-conventionsloop andpr-conventions; the status-block format and reconciliation rules live insecurity-status-tracking.
Goal and scope
Make compromise require multiple independent failures, and shrink the blast radius of any one failure: no direct pushes or tags, no write token on jobs that only generate files, no long-lived publish credentials, no fresh-off-the-registry dependencies, no unreviewed workflow changes, and no release that a human didn't approve.
Out of scope: signer policy, release-intent, and verification-gate internals
(release-management-nodejs); governance boilerplate (project-templates).
Two files in the target repo
SECURITY.md— simple and public: how to report a vulnerability, plus a short "How this repository is secured" summary that only lists measures actually in place.DEFENSE_IN_DEPTH.md— the tracked checklist (three checkbox states persecurity-status-tracking). The catalog in reference.md defines the universe — do not invent items.
Repo profile
Classify the repo before scaffolding; the profile decides which sections apply. Record it in
DEFENSE_IN_DEPTH.md (Profile: npm library · public).
| Question | Signal | Consequence |
|---|---|---|
| Does it publish to npm? | package.json without "private": true and with a publishable name/exports (workspaces: any published package) | npm library → full catalog. Website/app (site, service, docs, internal tool) → skip § 5 npm publishing; everything else applies. |
| Is the repo private? | gh repo view --json isPrivate | Private → the lockdown script skips private-vulnerability-reporting and fork-PR workflow approval; plan-gated settings (rulesets, secret scanning) tracked only if available — the script reports this; skip § 5 unless it actually publishes; SECURITY.md keeps the email contact only. |
Item priority
Sections in DEFENSE_IN_DEPTH.md, in execution order — pick the first unchecked applicable item
top-to-bottom. lockdown-repo.sh is never checked into a repo. It lives only in this skill;
never copy or commit it into the target. A repo admin runs apply last, after every earlier
applicable item including every (manual) task. --check during audit does not change that.
- § 1 Security docs — scaffold/simplify
SECURITY.md, scaffoldDEFENSE_IN_DEPTH.md. - § 2 CODEOWNERS and cloud bootstrap —
.github/CODEOWNERS(file PR); Aikido Safe Chain on Codespaces and Cursor Cloud Agents (file PR; skip withoutpnpm-lock.yaml). - § 3 Dependencies (pnpm) — 7-day cooldown with no first-party excludes,
trustPolicy: no-downgrade, blocked lifecycle scripts, frozen lockfile. - § 4 GitHub Actions — least-privilege permissions, no CI commit-back, actions-up SHA pinning,
Socket Firewall on every job with
sfw-prefixed installs,check-workflows.yamlzizmor linting, kebab-case workflow and job names (no spaces, so they can be required checks). - § 5 npm publishing (npm libraries only) —
release.yamlstages withpnpm stage publish ./packed/*.tgz --no-git-checks; npmjs.com / Drydock / 2FA settings are(manual). Audit npmjs with./scripts/check-npmjs.sh(never copied into the target; check-only). - § 6 Security tooling — Aikido on every build; Socket on every dependency change.
- § 7 Repository lockdown — GitHub settings via
./scripts/lockdown-repo.sh. Never copy it into the target repo. A repo admin runs it last, after every earlier item including all(manual)tasks. Account/UI leftovers are(manual)and are last-phase admin work with the script.
Workflow
Run on the first invocation and on every resume (continue, next, next defense PR):
-
Sync
main. Working tree must be clean (git status --short) — stop and report if not.git checkout main && git pull --ff-only origin main. -
Classify. Determine the repo profile (table above) on first run; afterwards read it from
DEFENSE_IN_DEPTH.mdand re-verify only if the repo changed shape. -
Audit.
- If
DEFENSE_IN_DEPTH.mdis missing, the next item is § 1. Scaffolding — from reference.md § 1, dropping sections the profile excludes — happens in that item's PR in Step 4, never during the audit. - If the defense-in-depth sections don't match the current catalog, replace those sections with
the catalog in reference.md § 1 (leave any
Release Management statusblock untouched), then reconcile against repo state. Do not map old checkboxes. - Migration (rides the § 1 PR): if
SECURITY.mdcontains an oldDefense in Depth statusblock, move its state intoDEFENSE_IN_DEPTH.md(map matching items; list dropped ones in the PR body) and cutSECURITY.mddown to the simple shape. Same for aRelease Management statusblock — it moves over untouched. The move is one-shot: afterwards status is never read fromSECURITY.mdagain. - Reconcile every checkbox against actual repo state per
security-status-tracking. For § 5 (npm libraries) run./scripts/check-npmjs.shwith--repoand--workflowtaken from the checkout per reference.md § 5. Requiresnpm login;NPM_TOKENis not allowed. Never copy it into the target repo; it is check-only and is never checked in. A clean run means the readable npmjs items match; a FAIL does not jump the queue. For § 7 runlockdown-repo.sh <owner/repo> --checkwith--required-checksand--allowed-actionstaken from the repo's workflows per reference.md § 7 (audit only — never apply here). A clean--checkmeans the lockdown item is done; a FAIL does not make § 7 the next item while earlier applicable items (auto or(manual)) remain. Skip the Safe Chain item whenpnpm-lock.yamlis absent. Never silently uncheck a regression — stop and report it.
- If
-
Implement the next item.
- File items (§ 1–6): branch from
mainaschore/defense-<section-key>-<item-key>(e.g.chore/defense-pnpm-cooldown,chore/defense-actions-no-commit-back,chore/defense-actions-socket-firewall), make only the change the item requires, update its checkbox to(PR #<n> pending), run the section's local verification (sfw pnpm install --frozen-lockfile,pnpm test/pnpm buildwhere they exist), open the PR per PR rules. Specs live in reference.md for that section.- CODEOWNERS: copy the template from
reference.md § 2. Stop and ask who the
owners are (
@userand/or@org/team) before writing the file; substitute{{OWNERS}}. Never hardcode a username and never guess from the repo owner login. If the user already named owners in this conversation, use those and do not re-ask. - Safe Chain: copy
./scripts/setup-cloud-environment.shand the files intemplates/per reference.md § 2 (merge existing.devcontainer/.cursorconfig; never overwrite it). Skip whenpnpm-lock.yamlis absent. Branchchore/defense-safe-chain-cloud. A leftover PMG / VM-egress line is dropped in that PR. - Release workflow (npm libraries): copy
.github/workflows/release.yamlfrom reference.md § 5. If a publish workflow already exists, switch it to pack +pnpm stage publish ./packed/*.tgz --no-git-checksrather than replacing a custom pipeline. Branchchore/defense-release-stage-publish.
- CODEOWNERS: copy the template from
reference.md § 2. Stop and ask who the
owners are (
(manual)items: report what the maintainer needs to do — from the matching reference section — and continue past them for later auto items; do not treat them as done. All(manual)tasks and lockdown are last-phase admin work: after every auto-implementable applicable item is checked, stop and hand the remaining manuals plus the lockdown command to the admin. The maintainer ticks manuals off.- § 7 lockdown (always last, admin only): do not pick this item while any earlier applicable
item — auto or
(manual)— is unchecked. Never copylockdown-repo.shinto the target repo and never commit it. The agent never runs apply mode. Working tree must be clean. Show--checkwith--required-checksand--allowed-actions. Hand the apply command to a repo admin:lockdown-repo.sh <owner/repo>with those flags taken from the repo's workflows per reference.md § 7. A warning that this copy is not the latest from jaredwray/agentic is not a stop — update the skill and re-run--checkbefore the admin applies. After the admin applies, re-run--checkwith the same flags. Record the result in a PR that updatesDEFENSE_IN_DEPTH.mdand theSECURITY.mdsummary. The script audits CODEOWNERS and requiresrequire_code_owner_reviewon the branch ruleset; it does not write the file.
- File items (§ 1–6): branch from
-
Drive CI to green. Diagnose, fix, and push until every check passes. Do not stop on a red PR.
-
Loop or stop. If the PR merged while you watched (auto-merge, user merged), return to Step 1 immediately. Otherwise stop and report in four lines: PR URL and item; CI state; what's next (plus any
(manual)items waiting on the maintainer); and a literal resume prompt — "Merge the PR when you're ready, then replycontinue(ornext) and I'll open the next defense-in-depth PR." If only(manual)items and/or § 7 remain, report the last-phase admin handoff: remaining manuals (runcheck-npmjs.shfor npmjs settings on libraries), thenlockdown-repo.shlast (never committed). If nothing applicable is left unchecked, report the rollout complete.
Pull request rules
- One item per PR; only one open defense-in-depth PR at a time.
- Title prefixes per
pr-conventions:mono - chore: defense - …(monorepo root/cross-package),<package> - chore: defense - …, orroot - chore: defense - …(single-package repo). Example:keyv - chore: defense - pin all GitHub Actions via actions-up. - Body: one-sentence Summary naming the section, a Status update line
(
DEFENSE_IN_DEPTH.md: <item> → (PR #<n> pending)), Verification checklist of the commands run, anddefense-in-depth-nodejs § <n>as the reference.
Reference
The implementation spec — doc templates, CODEOWNERS and Safe Chain files, the pnpm baseline, the
Socket Firewall step, the check-workflows.yaml template, the staged-publishing model, the lockdown
script's settings table, tooling links — lives in reference.md. Each
DEFENSE_IN_DEPTH.md item names its section.