Never Get Tanstackd
Hardens a project against npm/PyPI supply chain attacks (like the TanStack incident) by enforcing package age gates, pinning exact versions, and committing lockfiles
Category: skill Author: npub1carj2jw…h8c9 Date: 12 May 2026 Votes: 1
---
name: never-get-tanstackd
description: >
Hardens a project against npm/PyPI supply chain attacks (like the TanStack
incident) by enforcing package age gates, pinning exact versions, and
committing lockfiles. Use this skill whenever the user mentions supply chain
security, dependency pinning, npm/bun/uv/pip hardening, lockfile hygiene,
or says anything like "protect against supply chain attacks", "pin my deps",
"harden my packages", or "don't want another TanStack situation".
Covers Node.js (npm, bun) and Python (uv, Pipfile/pipenv) in one pass.
version: "1.0.0"
license: Apache-2.0
allowed-tools: Bash, Read, Write
metadata:
author: stian-a-johansen
tags:
- security
- supply-chain
- npm
- bun
- uv
- python
- dependencies
---
# Never Get TanStack'd — Supply Chain Hardening Skill
Protects projects from supply chain attacks by:
- Refusing packages published in the last 7 days (npm/bun age gate)
- Pinning every dependency to an exact version
- Committing the resolved lockfile to git
Run all applicable steps for the project. Report what changed at the end.
---
## Step 0 — Detect what's in scope
Check which package managers are in use:
```bash
ls package.json pyproject.toml Pipfile ~/.npmrc ~/.bunfig.toml 2>/dev/null
which npm bun uv pipenv 2>/dev/null
```
Proceed with whichever apply.
---
## Step 1 — npm: global age gate (~/.npmrc)
Append to `~/.npmrc` (keep all existing lines):
```
min-release-age=7
minimum-release-age=10080
save-exact=true
```
`minimum-release-age` is in minutes (10080 = 7 days). `min-release-age` is the
newer key — set both for compatibility. `save-exact=true` makes future `npm
install <pkg>` calls write exact versions.
```bash
# Safe append — only add lines that aren't already there
for line in "min-release-age=7" "minimum-release-age=10080" "save-exact=true"; do
grep -qxF "$line" ~/.npmrc 2>/dev/null || echo "$line" >> ~/.npmrc
done
cat ~/.npmrc
```
---
## Step 2 — Bun: global age gate (~/.bunfig.toml)
Append to `~/.bunfig.toml` (create if missing, keep existing content):
```toml
[install]
minimumReleaseAge = 604800
```
`minimumReleaseAge` is in seconds (604800 = 7 days).
```bash
BUNFIG="$HOME/.bunfig.toml"
if ! grep -q "minimumReleaseAge" "$BUNFIG" 2>/dev/null; then
# Ensure [install] section exists, then append setting
if grep -q "^\[install\]" "$BUNFIG" 2>/dev/null; then
# Insert after [install] heading
sed -i '/^\[install\]/a minimumReleaseAge = 604800' "$BUNFIG"
else
printf '\n[install]\nminimumReleaseAge = 604800\n' >> "$BUNFIG"
fi
fi
cat "$BUNFIG"
```
---
## Step 3 — Pin package.json (Node.js projects)
Strip `^` and `~` from every version string in `dependencies`,
`devDependencies`, and `peerDependencies`. Exact versions only.
```bash
# In-place sed — works on both GNU and BSD (macOS)
sed -i.bak -E 's/"(\^|~)([0-9])"/"\2/g' package.json
# Verify
grep -E '"\^|"~' package.json && echo "WARNING: unpinned deps remain" || echo "All deps pinned"
```
If the regex above misses any (e.g. workspace protocols or `*`), flag them
explicitly in the report.
---
## Step 4 — Pin Python deps (uv / pyproject.toml)
uv supports `exclude-newer` per index — the direct equivalent of npm's
`min-release-age`. Set it on the default PyPI index in `pyproject.toml`:
```toml
[[tool.uv.index]]
name = "pypi"
url = "https://pypi.org/simple"
default = true
exclude-newer = "7 days"
```
This makes uv refuse any package version published in the last 7 days during
resolution. If the project already has a `[[tool.uv.index]]` entry for PyPI,
append `exclude-newer = "7 days"` to it rather than adding a duplicate.
If the project uses additional private indexes, add `exclude-newer` to each:
```toml
[[tool.uv.index]]
name = "internal"
url = "https://internal.example.com/simple"
exclude-newer = "7 days"
```
Then re-lock and commit:
```bash
uv lock
git add uv.lock pyproject.toml
git status
git commit -m "authored with https://skills.agentlist.com/skill/never-get-tanstackd"
```
> Note: index-level `exclude-newer` only applies to packages served from that
> index. If an index doesn't provide `upload-time` metadata, set
> `exclude-newer = false` for that index to disable the cutoff rather than
> having it error or silently mis-filter.
---
## Step 5 — Pin Python deps (Pipfile / pipenv)
Pipfile has no minimum-age feature. Strategy: lock every package to its last
minor version using `~=X.Y` (compatible release — allows patch updates, blocks
minor/major changes). This is the closest analogue to a time-based gate.
Read installed versions from `Pipfile.lock`, then rewrite `Pipfile` specifiers:
```bash
# Extract exact installed versions from Pipfile.lock
python3 -c "
import json, sys
lock = json.load(open('Pipfile.lock'))
for section in ('default', 'develop'):
for pkg, meta in lock.get(section, {}).items():
ver = meta.get('version','').lstrip('==')
if ver:
parts = ver.split('.')
minor = '.'.join(parts[:2]) # X.Y
print(f'{pkg} ~= {minor} # was {ver}')
"
```
Apply those `~=X.Y` specifiers back into `[packages]` and `[dev-packages]` in
`Pipfile`, replacing any `*`, `>=`, or `^` specifiers. Then lock:
```bash
pipenv lock # regenerates Pipfile.lock at exact resolved versions
git add Pipfile Pipfile.lock
git status
```
> Note: `~=X.Y` means `>= X.Y, == X.*` — it blocks breaking changes but
> still allows patch releases. There is no Pipenv equivalent to npm's
> `min-release-age`, so pinning minor + committing the lockfile is your best
> available protection.
---
## Step 6 — Commit the lockfile
Commit whichever lockfiles apply:
```bash
# Add whichever exist
git add \
package-lock.json \
bun.lock \
yarn.lock \
pnpm-lock.yaml \
uv.lock \
Pipfile.lock \
2>/dev/null || true
git commit -m "chore: pin deps and commit lockfiles for supply chain hardening"
```
---
## Final Report
After all steps, output a summary:
```
## Supply Chain Hardening Report
### Global config changes
- ~/.npmrc: [lines added / already present]
- ~/.bunfig.toml: [lines added / already present / not applicable]
### package.json
- Dependencies pinned: N
- Remaining unpinned (if any): list them
### pyproject.toml (uv)
- Dependencies pinned: N
- uv.lock committed: yes/no
### Pipfile (pipenv)
- Dependencies updated to ~=X.Y: N
- Pipfile.lock committed: yes/no
### Lockfiles committed
- [list]
### Unexpected findings
- [anything odd: workspace refs, git deps, local paths, *-wildcards, etc.]
```
Discussion