|
| 1 | +--- |
| 2 | +name: scan-code |
| 3 | +description: >- |
| 4 | + Scans a Power Pages code-site project for dependency vulnerabilities |
| 5 | + (`npm audit`) and JavaScript/TypeScript code issues (ESLint), installs |
| 6 | + the matching ESLint plugins for the detected framework (React, Vue, |
| 7 | + Angular, Astro), and produces a single HTML report with package and |
| 8 | + code findings shown in separate sections. Severities are kept verbatim |
| 9 | + from the underlying tools. Use when the user wants to scan local |
| 10 | + source code, check dependencies, lint the project, audit packages, |
| 11 | + find code vulnerabilities, or run a pre-publish code check — even if |
| 12 | + they say "check my code" or "find security issues in my source" |
| 13 | + without naming `npm audit` or ESLint. |
| 14 | +user-invocable: true |
| 15 | +argument-hint: "[optional: --review <out-dir>]" |
| 16 | +allowed-tools: Read, Write, Bash, Glob, Grep, AskUserQuestion, TaskCreate, TaskUpdate, TaskList |
| 17 | +model: opus |
| 18 | +--- |
| 19 | + |
| 20 | +> **Plugin check**: Run `node "${CLAUDE_PLUGIN_ROOT}/scripts/check-version.js"` — if it outputs a message, show it to the user before proceeding. |
| 21 | +
|
| 22 | +# Scan Code |
| 23 | + |
| 24 | +Scan the local Power Pages code-site project for two classes of issues: |
| 25 | + |
| 26 | +- **Package vulnerabilities** — `npm audit` against `package.json` / `package-lock.json`. |
| 27 | +- **Code issues** — ESLint against project source, with framework-aware plugins. |
| 28 | + |
| 29 | +The skill writes both result sets and renders one HTML report with the two scans as separate sections. Findings carry the **verbatim severity** emitted by each tool (npm audit: `critical`/`high`/`moderate`/`low`/`info`; ESLint: `error`/`warning`). |
| 30 | + |
| 31 | +This skill scans local source code only. It does not call the live site. |
| 32 | + |
| 33 | +**Initial request:** $ARGUMENTS |
| 34 | + |
| 35 | +## Gotchas |
| 36 | + |
| 37 | +- **`npm audit` needs a lockfile.** Without `package-lock.json` it cannot resolve transitive versions — the audit section is reported as `skipped` and the user is asked to run `npm install` first. |
| 38 | +- **ESLint workspace is bootstrapped in `<projectRoot>/.scan-code/`.** Plugins are installed there (not in the user's `package.json`) to keep the project clean. The folder ships a `.gitignore` of `*` so it stays untracked. Deleting it forces a fresh install on the next run. |
| 39 | +- **Severities are not remapped.** The HTML template understands every native severity these tools emit. Do not rewrite severity strings — pass them through. |
| 40 | +- **Server-rendered frameworks are not supported.** Power Pages code sites only support React, Vue, Angular, and Astro. Other projects produce a `skipped` lint section. |
| 41 | + |
| 42 | +## Workflow |
| 43 | + |
| 44 | +1. **Prerequisites** — locate project, detect review mode |
| 45 | +2. **Run package audit** — `npm audit` → `scan-code-packages.json` |
| 46 | +3. **Run code lint** — detect framework, install ESLint plugins, lint → `scan-code-eslint.json` |
| 47 | +4. **Render or hand off** — review mode: stop; interactive mode: render HTML |
| 48 | +5. **Walk through follow-ups** — only if findings exist and not in review mode |
| 49 | + |
| 50 | +## Task tracking |
| 51 | + |
| 52 | +Create tasks in three groups. Mark each `in_progress` when starting, `completed` when done. |
| 53 | + |
| 54 | +| Group | When | Tasks | |
| 55 | +|-------|------|-------| |
| 56 | +| 1 | At start | Check prerequisites | |
| 57 | +| 2 | After prerequisites pass | Run package audit · Run code lint | |
| 58 | +| 3 | After both scans complete (interactive only) | Render report · Walk through follow-ups | |
| 59 | + |
| 60 | +In review mode, skip Group 3 — the orchestrator owns rendering. |
| 61 | + |
| 62 | +--- |
| 63 | + |
| 64 | +## 1. Prerequisites |
| 65 | + |
| 66 | +### 1.1 Locate the project, detect review mode |
| 67 | + |
| 68 | +Use `Glob` to find `**/powerpages.config.json`. If none is found, tell the user the site needs to be created first with `/create-site`, then stop. |
| 69 | + |
| 70 | +If `$ARGUMENTS` contains `--review <out-dir>`, remember the output directory. Step 4 becomes "write JSON only" and Step 5 is skipped. |
| 71 | + |
| 72 | +### 1.2 Verify the project has a `package.json` |
| 73 | + |
| 74 | +Confirm `<PROJECT_ROOT>/package.json` exists. If not, this is not a code-site project — tell the user, then stop. |
| 75 | + |
| 76 | +### 1.3 Pick the output paths |
| 77 | + |
| 78 | +| Mode | Package output | Lint output | |
| 79 | +|------|----------------|-------------| |
| 80 | +| Review | `<REVIEW_DIR>/scan-code-packages.json` | `<REVIEW_DIR>/scan-code-eslint.json` | |
| 81 | +| Interactive | `<SYSTEM_TEMP>/scan-code/scan-code-packages.json` | `<SYSTEM_TEMP>/scan-code/scan-code-eslint.json` | |
| 82 | + |
| 83 | +Create the directory if it does not exist. In interactive mode, delete any prior contents of `<SYSTEM_TEMP>/scan-code/` first. |
| 84 | + |
| 85 | +--- |
| 86 | + |
| 87 | +## 2. Run the package audit |
| 88 | + |
| 89 | +```bash |
| 90 | +node "${CLAUDE_PLUGIN_ROOT}/skills/scan-code/scripts/audit.js" \ |
| 91 | + --projectRoot "<PROJECT_ROOT>" \ |
| 92 | + --output "<PACKAGE_OUTPUT_PATH>" |
| 93 | +``` |
| 94 | + |
| 95 | +The script: |
| 96 | + |
| 97 | +- Runs `npm audit --json` in `<PROJECT_ROOT>`. |
| 98 | +- Transforms each `vulnerabilities` entry into a finding (one per advisory cluster). |
| 99 | +- Severities are kept verbatim from npm (`critical`, `high`, `moderate`, `low`, `info`). |
| 100 | +- Returns `{ "status": "skipped", "reason": "..." }` if `package-lock.json` is missing or npm itself errors. |
| 101 | + |
| 102 | +Tell the user, in one sentence, that the package audit completed (and how many issues if any). |
| 103 | + |
| 104 | +--- |
| 105 | + |
| 106 | +## 3. Run the code lint |
| 107 | + |
| 108 | +```bash |
| 109 | +node "${CLAUDE_PLUGIN_ROOT}/skills/scan-code/scripts/lint.js" \ |
| 110 | + --projectRoot "<PROJECT_ROOT>" \ |
| 111 | + --output "<LINT_OUTPUT_PATH>" |
| 112 | +``` |
| 113 | + |
| 114 | +What the script does on first run: |
| 115 | + |
| 116 | +1. Reads `<PROJECT_ROOT>/package.json` to detect the framework — React, Vue, Angular, or Astro. |
| 117 | +2. Writes `<PROJECT_ROOT>/.scan-code/package.json` with the matching ESLint + plugin set. |
| 118 | +3. Runs `npm install --prefix <PROJECT_ROOT>/.scan-code/` to install them. |
| 119 | +4. Writes `<PROJECT_ROOT>/.scan-code/eslint.config.mjs` with framework-aware rules **and an embedded ignore list** for `node_modules`, `.powerpages-site`, `dist`, `build`, `docs`, `coverage`, `public`, `.scan-code`, and minified bundles. |
| 120 | +5. Runs ESLint over `src/**/*` (with framework extensions) plus root-level config files only. |
| 121 | +6. Emits findings with severities kept verbatim (`error`, `warning`). |
| 122 | + |
| 123 | +Subsequent runs reuse the workspace. Pass `--reinstall` to force re-provisioning. |
| 124 | + |
| 125 | +If no supported framework is detected, the script returns `{ "status": "skipped", ... }` — surface that as a single info finding in the report. |
| 126 | + |
| 127 | +--- |
| 128 | + |
| 129 | +## 4. Render or hand off |
| 130 | + |
| 131 | +### 4.1 Review mode — hand off and stop |
| 132 | + |
| 133 | +If invoked with `--review <out-dir>`, the two JSON files are already in place. Stop — the orchestrator (`/security-review`) consolidates them into the master report. |
| 134 | + |
| 135 | +### 4.2 Interactive mode — render the HTML report |
| 136 | + |
| 137 | +Compose a 1–2 sentence plain-language summary covering totals across both sections, then render: |
| 138 | + |
| 139 | +```bash |
| 140 | +node "${CLAUDE_PLUGIN_ROOT}/scripts/build-review-data.js" \ |
| 141 | + --reportName "Code Scan" \ |
| 142 | + --inputDir "<SYSTEM_TEMP>/scan-code/" \ |
| 143 | + --siteName "<SITE_NAME>" \ |
| 144 | + --goalLabel "Source code & packages" \ |
| 145 | + --scopeLabel "<PROJECT_ROOT>" \ |
| 146 | + --summary "<SUMMARY_TEXT>" \ |
| 147 | + --output "<SYSTEM_TEMP>/scan-code/data.json" |
| 148 | + |
| 149 | +node "${CLAUDE_PLUGIN_ROOT}/scripts/render-review.js" \ |
| 150 | + --output "<PROJECT_ROOT>/docs/scan-code-<YYYY-MM-DD-HHMMSS>.html" \ |
| 151 | + --data "<SYSTEM_TEMP>/scan-code/data.json" |
| 152 | +``` |
| 153 | + |
| 154 | +The filename **must** include the local timestamp (e.g. `scan-code-2026-05-22-141530.html`). Open the rendered HTML in the user's default browser. |
| 155 | + |
| 156 | +Delete `<SYSTEM_TEMP>/scan-code/` after rendering succeeds. |
| 157 | + |
| 158 | +### 4.3 Record skill usage |
| 159 | + |
| 160 | +> Reference: `${CLAUDE_PLUGIN_ROOT}/references/skill-tracking-reference.md` |
| 161 | +> |
| 162 | +> Use `--skillName "ScanCode"`. |
| 163 | +
|
| 164 | +--- |
| 165 | + |
| 166 | +## 5. Walk through follow-ups |
| 167 | + |
| 168 | +Skip in **review mode**. Skip when both sections have zero issues. |
| 169 | + |
| 170 | +Group findings by remedy: |
| 171 | + |
| 172 | +- **Package vulnerabilities with auto-fix** → tell the user the exact `npm audit fix` invocation reported in each finding's `fix` field. |
| 173 | +- **Package vulnerabilities without auto-fix** → recommend reviewing the advisory link and updating manually. |
| 174 | +- **ESLint errors / warnings** → suggest running `eslint --fix` in the project for auto-fixable issues, then reviewing the rest by file. |
| 175 | + |
| 176 | +If nothing meaningful applies, end the skill — do not ask just to ask. |
| 177 | + |
| 178 | +--- |
| 179 | + |
| 180 | +## Constraints |
| 181 | + |
| 182 | +- **Severities are verbatim.** Do not rewrite, bucket, or rename severity strings. The shared HTML template knows every value these tools emit. |
| 183 | +- **Source code only.** Never lint `node_modules`, `.powerpages-site`, `docs`, `dist`, `build`, `coverage`, `public`, or `.scan-code/` itself. The generated ESLint config carries these ignores. |
| 184 | +- **Do not modify the user's `package.json`.** ESLint and its plugins live in the side workspace at `<projectRoot>/.scan-code/`. |
| 185 | +- **No new HTML template.** Render via the shared template under `scripts/lib/templates/`. Package and code findings are routed through separate JSON files so they appear as two sidebar sections. |
0 commit comments