--- 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 --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/" | 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 @latest ``` For packages that are 1+ minor versions behind, update to latest minor: ```bash pnpm update ``` 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.