Compare commits

...
9 changed files with 218 additions and 54 deletions
+3 -3
View File
@@ -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'"
+4
View File
@@ -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` |
+122
View File
@@ -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.
+32 -29
View File
@@ -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` |
---
+20 -4
View File
@@ -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.
+4
View File
@@ -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",
@@ -167,10 +168,13 @@
"@hono/node-server": "1.19.14",
"@internationalized/date": "3.10.0",
"@isaacs/brace-expansion": "5.0.1",
"@langchain/langgraph-checkpoint>uuid": "11.1.1",
"@langchain/langgraph>uuid": "11.1.1",
"@react-aria/interactions>react": "19.2.6",
"@react-aria/ssr>react": "19.2.6",
"@react-aria/ssr>react-dom": "19.2.6",
"@react-aria/visually-hidden>react": "19.2.6",
"@sentry/webpack-plugin>uuid": "11.1.1",
"fast-xml-parser": "5.8.0",
"hono": "4.12.18",
"lodash": "4.18.1",
+13 -14
View File
@@ -20,6 +20,9 @@ overrides:
minimatch@>=10: 10.2.3
minimatch@<4: 3.1.4
qs: 6.14.2
'@langchain/langgraph-checkpoint>uuid': 11.1.1
'@langchain/langgraph>uuid': 11.1.1
'@sentry/webpack-plugin>uuid': 11.1.1
rollup@>=4: 4.59.0
serialize-javascript: 7.0.5
@@ -4188,6 +4191,7 @@ packages:
'@smithy/core@3.24.1':
resolution: {integrity: sha512-3mT7o4qQyUWttYnVK3A0Z/u3Xha3E81tXn32Tz6vjZiUXhBrkEivpw1hBYfh84iFF9CSzkBU9Y1DJ3Q6RQ231g==}
engines: {node: '>=18.0.0'}
deprecated: Deprecated due to bug in browser bundling instructions https://github.com/smithy-lang/smithy-typescript/issues/2025
'@smithy/credential-provider-imds@4.3.1':
resolution: {integrity: sha512-0S/acwHnqX4WrjXzhdiDRxsG2s9SC0cpPIK9nZ1R6UOHd+j7uL28+4bHu22urbLk2TVw3fkp6na/+fkUt/pLNQ==}
@@ -4788,6 +4792,7 @@ packages:
'@ungap/structured-clone@1.3.0':
resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
deprecated: Potential CWE-502 - Update to 1.3.1 or higher
'@upsetjs/venn.js@2.0.0':
resolution: {integrity: sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==}
@@ -6053,6 +6058,7 @@ packages:
glob@10.5.0:
resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==}
deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
hasBin: true
globals@14.0.0:
@@ -8273,19 +8279,14 @@ packages:
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
uuid@10.0.0:
resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==}
deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).
uuid@11.1.1:
resolution: {integrity: sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==}
hasBin: true
uuid@13.0.2:
resolution: {integrity: sha512-vzi9uRZ926x4XV73S/4qQaTwPXM2JBj6/6lI/byHH1jOpCzb0zDbfytgA9LcN/hzb2l7WQSQnxITOVx5un/wGw==}
hasBin: true
uuid@9.0.1:
resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
hasBin: true
vary@1.1.2:
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
engines: {node: '>= 0.8'}
@@ -10958,7 +10959,7 @@ snapshots:
'@langchain/langgraph-checkpoint@1.0.2(@langchain/core@1.1.45(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.4.0(@opentelemetry/api@1.9.0))(openai@6.37.0(ws@8.20.1)(zod@4.4.3))(ws@8.20.1))':
dependencies:
'@langchain/core': 1.1.45(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.4.0(@opentelemetry/api@1.9.0))(openai@6.37.0(ws@8.20.1)(zod@4.4.3))(ws@8.20.1)
uuid: 10.0.0
uuid: 11.1.1
'@langchain/langgraph-sdk@1.9.2(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.4.0(@opentelemetry/api@1.9.0))(openai@6.37.0(ws@8.20.1)(zod@4.4.3))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(ws@8.20.1)':
dependencies:
@@ -10985,7 +10986,7 @@ snapshots:
'@langchain/langgraph-sdk': 1.9.2(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.4.0(@opentelemetry/api@1.9.0))(openai@6.37.0(ws@8.20.1)(zod@4.4.3))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(ws@8.20.1)
'@langchain/protocol': 0.0.15
'@standard-schema/spec': 1.1.0
uuid: 10.0.0
uuid: 11.1.1
zod: 4.4.3
optionalDependencies:
zod-to-json-schema: 3.25.1(zod@4.4.3)
@@ -13516,7 +13517,7 @@ snapshots:
dependencies:
'@sentry/bundler-plugin-core': 4.7.0
unplugin: 1.0.1
uuid: 9.0.1
uuid: 11.1.1
webpack: 5.104.1(lightningcss@1.30.2)(postcss@8.5.14)
transitivePeerDependencies:
- encoding
@@ -16704,7 +16705,7 @@ snapshots:
roughjs: 4.6.6
stylis: 4.3.6
ts-dedent: 2.2.0
uuid: 13.0.2
uuid: 11.1.1
micromark-core-commonmark@2.0.3:
dependencies:
@@ -18454,12 +18455,10 @@ snapshots:
util-deprecate@1.0.2: {}
uuid@10.0.0: {}
uuid@11.1.1: {}
uuid@13.0.2: {}
uuid@9.0.1: {}
vary@1.1.2: {}
vaul@1.1.2(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.6(react@19.2.6))(react@19.2.6):
+8 -1
View File
@@ -33,7 +33,14 @@ allowBuilds:
# --- Level 3: Trust Policy + Exotic Subdeps ---
# Fail when a package's trust evidence is downgraded (e.g., new publisher).
trustPolicy: no-downgrade
trustPolicyExclude: []
trustPolicyExclude:
# next-auth: real beta releases currently do not publish provenance, while an
# earlier one-off manual test release did. Keep this scoped to the exact
# reviewed version so a bump fails until re-reviewed.
- "next-auth@5.0.0-beta.30"
# semver: legacy 6.x releases predate modern npm provenance. Keep this scoped
# to the exact transitive version so a bump fails until re-reviewed.
- "semver@6.3.1"
# Block transitive dependencies from using exotic specifiers (git URLs, tarballs).
blockExoticSubdeps: true
+12 -3
View File
@@ -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)",
);
}