diff --git a/.config/wt.toml b/.config/wt.toml index c217b4b6e7..1c7a7a550d 100644 --- a/.config/wt.toml +++ b/.config/wt.toml @@ -16,7 +16,7 @@ deps = "uv sync" [[pre-start]] reminder = "echo '>> Reminder: activate the venv in this shell with: source .venv/bin/activate'" -# Background: pnpm install runs while you start working. -# Tail logs via `wt config state logs`. +# Background: avoid running UI package lifecycle scripts before the branch is reviewed. +# Run `cd ui && pnpm install` explicitly when UI dependencies are needed. [post-start] -ui = "cd ui && pnpm install" +ui = "echo '>> UI dependencies were not installed automatically. Run: cd ui && pnpm install'" diff --git a/AGENTS.md b/AGENTS.md index d73d69f068..bb695ef880 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -46,6 +46,7 @@ Use these skills for detailed patterns on-demand: | `prowler-commit` | Professional commits (conventional-commits) | [SKILL.md](skills/prowler-commit/SKILL.md) | | `prowler-pr` | Pull request conventions | [SKILL.md](skills/prowler-pr/SKILL.md) | | `prowler-docs` | Documentation style guide | [SKILL.md](skills/prowler-docs/SKILL.md) | +| `prowler-npm-security-audit` | npm/pnpm supply-chain audit patterns | [SKILL.md](skills/prowler-npm-security-audit/SKILL.md) | | `django-migration-psql` | Django migration best practices for PostgreSQL | [SKILL.md](skills/django-migration-psql/SKILL.md) | | `postgresql-indexing` | PostgreSQL indexing, EXPLAIN, monitoring, maintenance | [SKILL.md](skills/postgresql-indexing/SKILL.md) | | `prowler-attack-paths-query` | Create Attack Paths openCypher queries | [SKILL.md](skills/prowler-attack-paths-query/SKILL.md) | @@ -68,6 +69,7 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST: | After creating/modifying a skill | `skill-sync` | | App Router / Server Actions | `nextjs-16` | | Auditing check-to-requirement mappings as a cloud auditor | `prowler-compliance` | +| Auditing npm/pnpm package security | `prowler-npm-security-audit` | | Building AI chat features | `ai-sdk-5` | | Committing changes | `prowler-commit` | | Configuring MCP servers in agentic workflows | `gh-aw` | @@ -107,6 +109,7 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST: | Review changelog format and conventions | `prowler-changelog` | | Reviewing JSON:API compliance | `jsonapi` | | Reviewing compliance framework PRs | `prowler-compliance-review` | +| Reviewing npm supply-chain policy | `prowler-npm-security-audit` | | Running makemigrations or pgmakemigrations | `django-migration-psql` | | Syncing compliance framework with upstream catalog | `prowler-compliance` | | Testing RLS tenant isolation | `prowler-test-api` | @@ -124,6 +127,7 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST: | Using Zustand stores | `zustand-5` | | Working on MCP server tools | `prowler-mcp` | | Working on Prowler UI structure (actions/adapters/types/hooks) | `prowler-ui` | +| Working on npm package, lockfile, or pnpm configuration | `prowler-npm-security-audit` | | Working on task | `tdd` | | Working with Prowler UI test helpers/pages | `prowler-test-ui` | | Working with Tailwind classes | `tailwind-4` | diff --git a/skills/prowler-npm-security-audit/SKILL.md b/skills/prowler-npm-security-audit/SKILL.md new file mode 100644 index 0000000000..d13e8a74b2 --- /dev/null +++ b/skills/prowler-npm-security-audit/SKILL.md @@ -0,0 +1,122 @@ +--- +name: prowler-npm-security-audit +description: > + Audits npm/pnpm package manager configuration and dependency changes against + npm security best practices, Prowler UI conventions, and supply-chain + hardening requirements. Trigger: PRs or repo audits that touch package.json, + lockfiles, pnpm-workspace.yaml, npmrc, CI install steps, Docker installs, + security dependency updates, or package supply-chain policy. +license: Apache-2.0 +metadata: + author: prowler-cloud + version: "1.0" + scope: [root, ui] + auto_invoke: + - "Auditing npm/pnpm package security" + - "Reviewing npm supply-chain policy" + - "Working on npm package, lockfile, or pnpm configuration" +--- + +## When to Use + +Use this skill when reviewing or changing: + +- `ui/package.json`, `ui/pnpm-lock.yaml`, `ui/pnpm-workspace.yaml`, or `ui/.npmrc` +- UI package-manager migrations, dependency bumps, or lockfile-only changes +- CI, Docker, worktree, or local setup paths that run package installs +- Security-only dependency remediation workflows for npm packages +- npm package-health evidence, trust policy, lifecycle scripts, or supply-chain controls + +Do **not** recommend enabling general UI dependency-update automation in Dependabot or Renovate. Prowler intentionally avoids bot-driven UI version bumps; only security remediation should be considered. + +## Critical Patterns + +Base the audit on [lirantal/npm-security-best-practices](https://github.com/lirantal/npm-security-best-practices) and Prowler's UI rules. + +| Area | What to verify | Red flags | +| --- | --- | --- | +| Lifecycle scripts | `allowBuilds` is explicit and `strictDepBuilds: true` is enabled | Broad or undocumented build allowances; root lifecycle scripts mutating git state | +| Exotic dependencies | `blockExoticSubdeps: true` or equivalent is enabled | Git, tarball, HTTP, file, link, or workspace specs in committed lockfiles without rationale | +| Cooldown | `minimumReleaseAge` exists and security remediation respects the repository policy | Bot-driven general UI version bumps in Dependabot/Renovate; emergency security updates without review evidence | +| Trust policy | `trustPolicy: no-downgrade` is enabled | Open-ended `trustPolicyExclude` entries; exceptions without evidence | +| Determinism | Lockfile committed; CI/Docker use frozen installs; package manager pinned | Floating package managers; future major ranges not exercised in CI | +| CI coverage | Existing gates remain intact | Package-manager migration removes format, lint, tests, audit, or build gates | +| Overrides | Overrides are scoped and documented | Global overrides that force unrelated consumers or incompatible majors | +| Package health | New direct dependencies have rationale and package-health evidence | New packages without maintenance/license/vulnerability/provenance review | +| Local safety | Installs do not unexpectedly mutate shared git state | `postinstall` installs hooks or rewrites files without opt-in | +| Dependency confusion | Private scopes have registry mapping; no plaintext tokens | Unscoped private package names, committed tokens, or ambiguous registries | + +## Prowler Audit Scope + +Primary files: + +```text +ui/package.json +ui/pnpm-lock.yaml +ui/pnpm-workspace.yaml +ui/.npmrc +ui/Dockerfile +.github/workflows/ui-*.yml +.github/dependabot.yml +.github/renovate.json +.config/wt.toml +ui/dependency-log.json +``` + +Also inspect package install scripts under `ui/scripts/` when lifecycle behavior changes. + +## Review Output Format + +Use this structure for review findings: + +```markdown +Verdict: pass | pass-with-issues | fail + +## Findings + +### Blocker + +### High + +### Medium + +### Low + +### Questions + +## Positive controls observed + +## Checks run + +## Not checked +``` + +Each finding must include: + +- file path and line reference when possible; +- evidence; +- risk; +- smallest suggested fix. + +## Commands + +```bash +# Inspect package/security config +cd ui +pnpm audit --audit-level high +pnpm install --frozen-lockfile --prefer-offline +pnpm run healthcheck + +# Search for exotic lockfile sources +rg -n "git\+|github:|bitbucket:|gitlab:|http://|https://|tarball:|file:|link:|workspace:" ui/pnpm-lock.yaml + +# Confirm UI workflows keep expected gates +rg -n "pnpm run (healthcheck|format:check|audit|build|test)" .github/workflows/ui-*.yml +``` + +## Constraints + +- Default to read-only review unless explicitly asked to fix. +- Do not treat frontend package hiding as a security boundary; backend authorization still matters. +- Do not invent package-health claims. Fetch primary evidence when needed. +- Prefer concrete, actionable findings over generic best-practice prose. diff --git a/ui/AGENTS.md b/ui/AGENTS.md index 43a26c74f9..b1832e7011 100644 --- a/ui/AGENTS.md +++ b/ui/AGENTS.md @@ -19,35 +19,38 @@ When performing these actions, ALWAYS invoke the corresponding skill FIRST: -| Action | Skill | -| -------------------------------------------------------------- | ------------------- | -| Add changelog entry for a PR or feature | `prowler-changelog` | -| App Router / Server Actions | `nextjs-16` | -| Building AI chat features | `ai-sdk-5` | -| Committing changes | `prowler-commit` | -| Create PR that requires changelog entry | `prowler-changelog` | -| Creating Zod schemas | `zod-4` | -| Creating a git commit | `prowler-commit` | -| Creating/modifying Prowler UI components | `prowler-ui` | -| Fixing bug | `tdd` | -| Implementing feature | `tdd` | -| Modifying component | `tdd` | -| Refactoring code | `tdd` | -| Review changelog format and conventions | `prowler-changelog` | -| Testing hooks or utilities | `vitest` | -| Update CHANGELOG.md in any component | `prowler-changelog` | -| Using Zustand stores | `zustand-5` | -| Working on Prowler UI structure (actions/adapters/types/hooks) | `prowler-ui` | -| Working on task | `tdd` | -| Working with Prowler UI test helpers/pages | `prowler-test-ui` | -| Working with Tailwind classes | `tailwind-4` | -| Writing Playwright E2E tests | `playwright` | -| Writing Prowler UI E2E tests | `prowler-test-ui` | -| Writing React component tests | `vitest` | -| Writing React components | `react-19` | -| Writing TypeScript types/interfaces | `typescript` | -| Writing Vitest tests | `vitest` | -| Writing unit tests for UI | `vitest` | +| Action | Skill | +| -------------------------------------------------------------- | ---------------------------- | +| Add changelog entry for a PR or feature | `prowler-changelog` | +| App Router / Server Actions | `nextjs-16` | +| Auditing npm/pnpm package security | `prowler-npm-security-audit` | +| Building AI chat features | `ai-sdk-5` | +| Committing changes | `prowler-commit` | +| Create PR that requires changelog entry | `prowler-changelog` | +| Creating Zod schemas | `zod-4` | +| Creating a git commit | `prowler-commit` | +| Creating/modifying Prowler UI components | `prowler-ui` | +| Fixing bug | `tdd` | +| Implementing feature | `tdd` | +| Modifying component | `tdd` | +| Refactoring code | `tdd` | +| Review changelog format and conventions | `prowler-changelog` | +| Reviewing npm supply-chain policy | `prowler-npm-security-audit` | +| Testing hooks or utilities | `vitest` | +| Update CHANGELOG.md in any component | `prowler-changelog` | +| Using Zustand stores | `zustand-5` | +| Working on Prowler UI structure (actions/adapters/types/hooks) | `prowler-ui` | +| Working on npm package, lockfile, or pnpm configuration | `prowler-npm-security-audit` | +| Working on task | `tdd` | +| Working with Prowler UI test helpers/pages | `prowler-test-ui` | +| Working with Tailwind classes | `tailwind-4` | +| Writing Playwright E2E tests | `playwright` | +| Writing Prowler UI E2E tests | `prowler-test-ui` | +| Writing React component tests | `vitest` | +| Writing React components | `react-19` | +| Writing TypeScript types/interfaces | `typescript` | +| Writing Vitest tests | `vitest` | +| Writing unit tests for UI | `vitest` | --- diff --git a/ui/README.md b/ui/README.md index 998dc84a37..f001d1be5c 100644 --- a/ui/README.md +++ b/ui/README.md @@ -100,10 +100,18 @@ git clone git@github.com:prowler-cloud/ui.git pnpm install ``` -**Note:** The `pnpm install` command will automatically configure prek Git hooks for code quality checks. If hooks are not installed, run from the repo root: +**Note:** The `pnpm install` command does not configure Git hooks automatically. To install prek hooks for code quality checks, run one of the following: + +From `ui/`: ```bash -prek install +pnpm run setup:hooks +``` + +From the monorepo root: + +```bash +cd ui && pnpm run setup:hooks ``` #### Run the development server @@ -124,10 +132,18 @@ pnpm run dev ## Git Hooks -The UI uses [prek](https://github.com/j178/prek) for pre-commit checks, configured in [`.pre-commit-config.yaml`](.pre-commit-config.yaml). `pnpm install` runs the postinstall script that installs hooks automatically. To re-install manually: +The UI uses [prek](https://github.com/j178/prek) for pre-commit checks, configured in [`.pre-commit-config.yaml`](.pre-commit-config.yaml). Git hook setup is opt-in so package installs do not mutate shared git state automatically. To install or re-install manually: + +From `ui/`: ```bash -prek install --overwrite +pnpm run setup:hooks +``` + +From the monorepo root: + +```bash +cd ui && pnpm run setup:hooks ``` On each commit, prek runs Prettier and ESLint against the staged files, plus a project-wide TypeScript check and the unit tests related to the staged changes. The full Next.js build runs in CI, not on commit. diff --git a/ui/package.json b/ui/package.json index b03d7a55b5..57c3d5345e 100644 --- a/ui/package.json +++ b/ui/package.json @@ -17,6 +17,7 @@ "lint:fix": "eslint . --fix --max-warnings 40", "lint:knip": "knip --max-issues 494", "lint:knip:fix": "knip --fix --max-issues 494", + "setup:hooks": "node scripts/setup-git-hooks.js", "start": "next start", "start:standalone": "node .next/standalone/server.js", "test": "vitest run", diff --git a/ui/scripts/postinstall.js b/ui/scripts/postinstall.js index ea46e57098..4d55404a79 100644 --- a/ui/scripts/postinstall.js +++ b/ui/scripts/postinstall.js @@ -5,7 +5,11 @@ * * This script runs after npm install to: * 1. Update dependency log (if the script exists) - * 2. Setup git hooks (if the script exists) + * 2. Harden the MSW service worker when present + * + * Git hook installation is intentionally opt-in because postinstall runs during + * normal package installs and should not mutate shared git hook state unless the + * developer asked for onboarding setup. */ const fs = require("fs"); @@ -89,5 +93,10 @@ runScriptIfExists("./update-dependency-log.js", "deps:log"); // Keep this before setup-git-hooks because that script can exit the process. hardenMswServiceWorker(); -// Run git hooks setup -runScriptIfExists("./setup-git-hooks.js", "setup-git-hooks"); +if (process.env.PROWLER_UI_SETUP_GIT_HOOKS === "1") { + runScriptIfExists("./setup-git-hooks.js", "setup-git-hooks"); +} else { + console.log( + "Skip git hooks setup (run `pnpm run setup:hooks` or set PROWLER_UI_SETUP_GIT_HOOKS=1 to opt in)", + ); +}