init
This commit is contained in:
@@ -0,0 +1,306 @@
|
||||
---
|
||||
name: dependencies-audit
|
||||
description: "MUST be used whenever fixing dependency issues in a Flows app. This skill finds AND fixes vulnerabilities, outdated packages, deprecated dependencies, and license issues — it does not just report them. Triggers: dependencies, packages, fix dependencies, update packages, fix vulnerabilities, npm audit fix, pnpm audit fix, CVE fix, outdated, deprecated, supply chain, license."
|
||||
allowed-tools: Read, Glob, Grep, Shell, Write
|
||||
metadata:
|
||||
argument-hint: "[path to package.json, or leave blank to audit the root package.json]"
|
||||
---
|
||||
|
||||
# Dependencies Fix
|
||||
|
||||
Find and fix all dependency issues in **$ARGUMENTS** (or the root `package.json` if no argument is given) — vulnerabilities, outdated packages, deprecated dependencies, license problems, and supply-chain risks. This skill produces the `review-packages.md` artifact required by the Flows app review process.
|
||||
|
||||
---
|
||||
|
||||
## Step 1 — Read and list all dependencies
|
||||
|
||||
```bash
|
||||
# List all dependencies and devDependencies
|
||||
node -e "
|
||||
const pkg = require('./package.json');
|
||||
console.log('=== Dependencies ===');
|
||||
Object.entries(pkg.dependencies || {}).forEach(([name, ver]) => console.log(name + ' @ ' + ver));
|
||||
console.log('\\n=== Dev Dependencies ===');
|
||||
Object.entries(pkg.devDependencies || {}).forEach(([name, ver]) => console.log(name + ' @ ' + ver));
|
||||
"
|
||||
```
|
||||
|
||||
Record the total count of dependencies and devDependencies.
|
||||
|
||||
---
|
||||
|
||||
## Step 2 — Look up npm metadata and update outdated packages
|
||||
|
||||
For each package, gather:
|
||||
- **Latest version** on npm
|
||||
- **Weekly downloads**
|
||||
- **Last publish date**
|
||||
- **Deprecated** flag
|
||||
|
||||
```bash
|
||||
# Batch lookup — run for each package (example for a single package)
|
||||
npm view <package-name> --json 2>/dev/null | node -e "
|
||||
const data = JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));
|
||||
console.log(JSON.stringify({
|
||||
name: data.name,
|
||||
latest: data['dist-tags']?.latest,
|
||||
modified: data.time?.modified,
|
||||
deprecated: data.deprecated || false,
|
||||
}));
|
||||
"
|
||||
|
||||
# For weekly downloads, use the npm API
|
||||
curl -s "https://api.npmjs.org/downloads/point/last-week/<package-name>" | node -e "
|
||||
const data = JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));
|
||||
console.log(data.downloads);
|
||||
"
|
||||
```
|
||||
|
||||
For efficiency, batch multiple lookups. If the project has many dependencies, use a script:
|
||||
|
||||
```bash
|
||||
node -e "
|
||||
const { execSync } = require('child_process');
|
||||
const pkg = require('./package.json');
|
||||
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
||||
|
||||
for (const [name, usedVersion] of Object.entries(allDeps)) {
|
||||
try {
|
||||
const info = JSON.parse(execSync('npm view ' + name + ' --json 2>/dev/null', { encoding: 'utf8' }));
|
||||
const latest = info['dist-tags']?.latest || 'unknown';
|
||||
const modified = info.time?.modified || 'unknown';
|
||||
const deprecated = info.deprecated ? 'YES' : 'No';
|
||||
console.log([name, usedVersion, latest, modified, deprecated].join(' | '));
|
||||
} catch {
|
||||
console.log(name + ' | ' + usedVersion + ' | LOOKUP FAILED');
|
||||
}
|
||||
}
|
||||
"
|
||||
```
|
||||
|
||||
### Fix: Update outdated packages
|
||||
|
||||
For each package that is >1 major version behind, update it:
|
||||
|
||||
```bash
|
||||
pnpm update <package>@latest
|
||||
```
|
||||
|
||||
For packages that are 1+ minor versions behind, update to latest minor:
|
||||
|
||||
```bash
|
||||
pnpm update <package>
|
||||
```
|
||||
|
||||
After updating, run `pnpm install` and `pnpm run build` to verify nothing breaks. If a major update breaks the build, revert that specific update and note it as a manual-fix item.
|
||||
|
||||
---
|
||||
|
||||
## Step 3 — Run security audit and fix vulnerabilities
|
||||
|
||||
```bash
|
||||
# Run audit with the project's package manager
|
||||
pnpm audit --json 2>/dev/null || npm audit --json 2>/dev/null
|
||||
|
||||
# Also run production-only audit (what ships to users)
|
||||
pnpm audit --prod --json 2>/dev/null || npm audit --production --json 2>/dev/null
|
||||
```
|
||||
|
||||
Parse the JSON output for:
|
||||
- Severity counts (critical, high, moderate, low)
|
||||
- Per-vulnerability details (package, severity, title, patched version, advisory URL)
|
||||
|
||||
Any package with a known CVE is an automatic **Fail** in the health column.
|
||||
|
||||
### Fix: Resolve vulnerabilities
|
||||
|
||||
Run `pnpm audit fix` to auto-fix what's possible. For remaining high/critical CVEs that can't be auto-fixed, manually update the vulnerable package in `package.json` to the patched version and run `pnpm install`. If the patched version has breaking changes, apply the minimum code changes needed to adapt. If a vulnerability is in a transitive dependency, use `pnpm overrides` in `package.json` to force the patched version:
|
||||
|
||||
```json
|
||||
{
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"vulnerable-package": ">=2.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
After applying fixes, re-run `pnpm audit` to confirm the vulnerabilities are resolved. Run `pnpm run build` to verify nothing breaks.
|
||||
|
||||
---
|
||||
|
||||
## Step 4 — Assign health scores and fix Fail-scored packages
|
||||
|
||||
For each package, assign a health indicator:
|
||||
|
||||
| Health | Criteria |
|
||||
|--------|----------|
|
||||
| **Pass** | >100k weekly downloads AND updated within last 12 months AND not deprecated AND version is current or near-current (within 1 major) |
|
||||
| **Warn** | 10k–100k weekly downloads OR >12 months since last publish OR >1 major version behind |
|
||||
| **Fail** | <10k weekly downloads OR no update in 2+ years OR deprecated OR known CVE |
|
||||
|
||||
Edge cases:
|
||||
- `@cognite/*` packages: trust Cognite-internal packages even if download counts are low
|
||||
- `@types/*` packages: trust DefinitelyTyped packages; focus on whether the version matches the main package
|
||||
- Newly published packages (<6 months old): flag as **Warn** for review, not auto-Fail on low downloads
|
||||
|
||||
### Fix: Replace Fail-scored packages
|
||||
|
||||
For each Fail-scored package:
|
||||
|
||||
- **If deprecated:** find and install the recommended replacement. Update all imports across the codebase.
|
||||
- **If unmaintained (2+ years):** find an actively maintained alternative with equivalent functionality. Replace it.
|
||||
- **If low downloads and not `@cognite/*`:** evaluate whether it's truly needed. If a native JS/TS equivalent exists or the functionality is simple, remove the dependency and implement inline.
|
||||
|
||||
After each replacement, run `pnpm install` and `pnpm run build` to verify the replacement works.
|
||||
|
||||
---
|
||||
|
||||
## Step 5 — Check for supply-chain risks and mitigate
|
||||
|
||||
```bash
|
||||
# Check for install scripts (preinstall, postinstall, prepare)
|
||||
node -e "
|
||||
const { execSync } = require('child_process');
|
||||
const pkg = require('./package.json');
|
||||
const allDeps = Object.keys({ ...pkg.dependencies, ...pkg.devDependencies });
|
||||
|
||||
for (const name of allDeps) {
|
||||
try {
|
||||
const info = JSON.parse(execSync('npm view ' + name + ' --json 2>/dev/null', { encoding: 'utf8' }));
|
||||
const scripts = info.scripts || {};
|
||||
const risky = ['preinstall', 'install', 'postinstall'].filter(s => scripts[s]);
|
||||
if (risky.length > 0) {
|
||||
console.log('INSTALL SCRIPT: ' + name + ' — ' + risky.join(', '));
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
"
|
||||
|
||||
# Check for packages with very few maintainers (single point of failure)
|
||||
# This is informational, not blocking
|
||||
```
|
||||
|
||||
### Fix: Evaluate and mitigate install script risks
|
||||
|
||||
For each dependency with install scripts, determine if the script is legitimate (e.g., native module compilation for `sharp`, `esbuild`, `better-sqlite3`). Known build tools and native module packages are expected to have install scripts.
|
||||
|
||||
If the package is not a known build tool and has suspicious install scripts, replace it with a safer alternative. After replacement, run `pnpm install` and `pnpm run build` to verify.
|
||||
|
||||
---
|
||||
|
||||
## Step 6 — Check license compatibility and replace problematic packages
|
||||
|
||||
```bash
|
||||
# List all licenses
|
||||
npx license-checker --summary 2>/dev/null || node -e "
|
||||
const { execSync } = require('child_process');
|
||||
const pkg = require('./package.json');
|
||||
const allDeps = Object.keys({ ...pkg.dependencies, ...pkg.devDependencies });
|
||||
|
||||
for (const name of allDeps) {
|
||||
try {
|
||||
const info = JSON.parse(execSync('npm view ' + name + ' --json 2>/dev/null', { encoding: 'utf8' }));
|
||||
console.log(name + ': ' + (info.license || 'UNKNOWN'));
|
||||
} catch {}
|
||||
}
|
||||
"
|
||||
```
|
||||
|
||||
Acceptable licenses for Flows apps (commercial distribution):
|
||||
- MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, 0BSD, Unlicense, CC0-1.0
|
||||
|
||||
Licenses that need legal review:
|
||||
- GPL-2.0, GPL-3.0, LGPL-2.1, LGPL-3.0, AGPL-3.0, MPL-2.0, EUPL-1.1
|
||||
- Any "UNKNOWN" or missing license
|
||||
|
||||
### Fix: Replace packages with problematic licenses
|
||||
|
||||
For each package with a copyleft license (GPL, AGPL) or unknown license in **production dependencies**, find an MIT/Apache-2.0 licensed alternative and replace it. Update all imports across the codebase.
|
||||
|
||||
For **devDependencies** with copyleft licenses, these are lower risk but still flag for awareness.
|
||||
|
||||
After each replacement, run `pnpm install` and `pnpm run build` to verify.
|
||||
|
||||
---
|
||||
|
||||
## Step 7 — Generate the review-packages.md artifact (post-fix state)
|
||||
|
||||
Re-run the metadata lookups after all fixes have been applied to capture the post-fix state. Then produce the output in the format required by the Flows app review process:
|
||||
|
||||
```markdown
|
||||
## Package audit: [app name]
|
||||
|
||||
### Dependencies
|
||||
|
||||
| Package | Used version | Latest | Weekly downloads | Last published | Deprecated | CVEs | Health |
|
||||
| ------- | ------------ | ------ | ---------------- | -------------- | ---------- | ---- | ------ |
|
||||
| react | ^18.2.0 | 18.3.1 | 25M | 2024-04-26 | No | 0 | Pass |
|
||||
| some-old-lib | ^1.0.0 | 1.0.3 | 5k | 2021-03-15 | No | 0 | Fail |
|
||||
|
||||
### Dev Dependencies
|
||||
|
||||
| Package | Used version | Latest | Weekly downloads | Last published | Deprecated | CVEs | Health |
|
||||
| ------- | ------------ | ------ | ---------------- | -------------- | ---------- | ---- | ------ |
|
||||
| vitest | ^1.6.0 | 2.0.1 | 8M | 2024-07-01 | No | 0 | Pass |
|
||||
|
||||
### Security audit
|
||||
|
||||
| Severity | Count |
|
||||
| -------- | ----- |
|
||||
| Critical | 0 |
|
||||
| High | 0 |
|
||||
| Moderate | 0 |
|
||||
| Low | 0 |
|
||||
|
||||
#### Vulnerabilities
|
||||
|
||||
| Package | Severity | Title | Patched in | Advisory |
|
||||
| ------- | -------- | ----- | ---------- | -------- |
|
||||
| (none found) | — | — | — | — |
|
||||
|
||||
### License summary
|
||||
|
||||
| License | Count | Packages |
|
||||
| ------- | ----- | -------- |
|
||||
| MIT | 45 | react, react-dom, ... |
|
||||
| Apache-2.0 | 3 | ... |
|
||||
|
||||
### Supply-chain flags
|
||||
|
||||
| Package | Risk | Details |
|
||||
| ------- | ---- | ------- |
|
||||
| (none found) | — | — |
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 8 — Report remaining issues
|
||||
|
||||
Summarize what was fixed and what remains:
|
||||
|
||||
### Fixed
|
||||
|
||||
| Category | Count | Details |
|
||||
|----------|-------|---------|
|
||||
| Packages updated | N | list of packages and version changes |
|
||||
| CVEs resolved | N | list of CVEs fixed |
|
||||
| Deprecated deps replaced | N | old package -> new package |
|
||||
| License issues resolved | N | old package -> new package |
|
||||
|
||||
### Remaining (could not auto-fix)
|
||||
|
||||
List only issues that could not be automatically fixed:
|
||||
- Breaking changes from major updates that need manual code adaptation
|
||||
- Licenses that need legal review (e.g., LGPL in transitive dependencies)
|
||||
- Packages with no maintained alternative available
|
||||
- Vulnerabilities with no patched version available yet
|
||||
|
||||
For each remaining item, explain why it could not be auto-fixed and what the app author needs to do.
|
||||
|
||||
---
|
||||
|
||||
## Done
|
||||
|
||||
State the overall health verdict: how many Pass/Warn/Fail after fixes, how many issues were resolved, and any remaining items that need manual attention from the app author.
|
||||
Reference in New Issue
Block a user