diff --git a/CHANGELOG.md b/CHANGELOG.md index e031454..e092bbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,107 @@ All notable changes to the Pipeline-Check VS Code extension. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow [SemVer](https://semver.org/). +> ⚠ **Release note for publish.yml:** the release-notes extractor (an +> `awk` script in publish.yml) prints every line between the **first** +> and **second** `## [` headers. When cutting a release, fold the +> entries under `## [Unreleased]` into the new `## [X.Y.Z] — ` +> section **above** Unreleased, or remove the Unreleased block for the +> release commit. Otherwise the GitHub release ships boilerplate. + +## [Unreleased] + +PRs landing on `main` between releases append entries here. The +release commit collapses this section into `## [X.Y.Z] — `. + +The current run-up to v0.2.0 has the work below queued — landing +order depends on which PRs in the [#11–#14 stack](https://github.com/greylag-ci/pipeline-check-vscode/pulls) +merge first. + +### Added + +- **Inline CodeLens summary.** Each scanned file carries a + `Pipeline-Check: 2 critical · 1 high` lens at line 1. Click reveals + the Findings panel. Re-emits on every diagnostic publish so the + text tracks the latest scan. (R26) +- **Status bar item.** Bottom-left of the window, shows the top two + non-zero severities (e.g. `$(shield) 3C 1H`) with a tooltip that + breaks down the full per-severity tally. Click reveals the + Findings panel. (R9) +- **Keyboard navigation.** `Alt+F8` / `Shift+Alt+F8` jump between + Pipeline-Check findings in editor order (fsPath ascending, then by + line); wraps at both ends. Mirrors VS Code's `F8` muscle memory + for the global "Next Problem" command. (R12) +- **Per-provider toggles.** New `pipelineCheck.disabledProviders` + setting silences whole providers. `dockerfile` covers both + `Dockerfile` and `Containerfile` (same syntax). Useful in a + monorepo where Pipeline-Check would otherwise lint a sub-project's + Dockerfile that has its own lint pipeline. (R25) +- **Rule documentation link in leaf tooltip.** When the server + publishes a `Diagnostic.code.target` URL, the Findings tree's + leaf tooltip appends a clickable + `$(book) documentation` link below the message body. (R8) +- **Client-side structured logging.** The extension's output channel + now interleaves `[client] HH:MM:SS.mmm` lines around activation + and command invocations with the LSP's `window/logMessage` + traffic. Easier to triage bug reports — start/ok/failed + breadcrumbs land in the same surface users already focus via + *Show language server output*. (R16) +- **Pre-release channel.** Tags like `v0.2.0-rc.1` ship to the + marketplace pre-release channel; the matching GitHub release is + marked `prerelease`. Detection is by the presence of a `-` after + the semver core. (R24) + +### Changed + +- **`@vscode/test-electron` integration suite** now runs in CI + (Linux only, via `xvfb-run -a`). Five tests pin activation, the + command-registration contract, the Findings view registration, + the configuration schema completeness, and the workspace-trust + capability declarations. Catches what unit tests can only + approximate. (R17) +- **Three-OS test matrix** — `[ubuntu-latest, windows-latest, + macos-latest]`. The LSP child-process spawn path is + Windows-sensitive; matrix CI catches the LF/CRLF and + path-separator bugs single-OS CI silently misses. (R21) +- **Activation surface narrowed.** Triggers are + `workspaceContains:` patterns matching the providers we actually + scan (the `documentSelector` uses the same patterns). Opening an + unrelated `package.json` or `mkdocs.yml` no longer wakes up the + extension. (H4) +- **Trigger-pattern list lives in one place.** Extracted into + `src/providers.ts` as a single `PROVIDERS` map; the `documentSelector`, + `activationEvents`, and the LSP middleware's per-provider filter + all read from it. A regression test asserts the manifest's + `activationEvents` stay in lockstep with the patterns. (R14) +- **Shared `vi.mock("vscode")` factory** under `src/__testStubs__/`. + Unit tests now share a single stub instead of redefining the + surface per file. (R18) +- **Marketplace description length** gated in CI at the + 145-character truncation point so future edits don't blow it. (R20) + +### Fixed + +- **`Restart language server` toast no longer fires on failure** — + if the server failed to come up, the error notification already + carries the install hint; the success toast used to fire too, + giving the user contradictory signals. (R2) +- **`stopClient` has a 2-second hard ceiling** on the LSP child's + shutdown. A deadlocked server used to hold the deactivate path + indefinitely; VS Code reported "Window not responding" until the + user force-quit. (R3) +- **`groupByFile` no longer round-trips Uri through string** for + every group node. Bucket value carries the original Uri. (R4) +- **`compareByLocation` sorts on `fsPath`** instead of the full URI + string. Cross-scheme entries (file:// vs untitled://) no longer + bunch at one end. (R5) +- **`collectFindings` is memoised per refresh** — buildRoot and + updateBadge used to walk the global diagnostic store twice per + refresh. (R6) +- **`onDidChangeDiagnostics` skips refreshes from unrelated + publishers.** ESLint / mypy / redhat.yaml keystroke chatter no + longer rebuilds the tree. The skip-check also catches *clears* + (a stale leaf can't outlive a cleared file). (R7) + ## [0.1.1] — 2026-05-19 Production-readiness pass. v0.1.0 was effectively unusable on a clean diff --git a/README.md b/README.md index a8b0991..8353966 100644 --- a/README.md +++ b/README.md @@ -11,19 +11,30 @@ Lint CI/CD pipelines for 22 providers against OWASP Top 10 CI/CD Risks and 14 other compliance frameworks. 810+ rules, inline in your editor: severity-graded gutter squiggles, hover descriptions with `--explain` prose, and recommended-action hints. Built on the same rule registry as the [pipeline-check](https://github.com/dmartinochoa/pipeline-check) CLI, so editor findings match `pipeline_check --output json` byte-for-byte (modulo position translation). +## Features + +- **Inline diagnostics** — gutter squiggles + the Problems panel get a row per finding, severity-graded so CRITICAL and HIGH read red, MEDIUM yellow, LOW info-blue. Hover shows the rule title, the `--explain` prose, and a link to the rule documentation. +- **Findings panel** — dedicated slot in the activity bar with a Pipeline-Check pipeline glyph. Re-groups findings by **severity** (default), **file**, or **rule** via the title-bar **Change Grouping** button; activity-bar icon carries a live count badge. +- **Status bar item** — bottom-left of the window, shows the top two severity counts at a glance (e.g. `🛡 3C 1H`). Click reveals the Findings panel. +- **CodeLens summary** — every scanned file carries a `Pipeline-Check: 2 critical · 1 high` lens at line 1. Click navigates to the Findings panel. +- **Keyboard navigation** — `Alt+F8` / `Shift+Alt+F8` jump between findings, with wrap at both ends. Mirrors VS Code's `F8` for "next problem" so muscle memory carries over. +- **Tunable signal** — `pipelineCheck.severityThreshold` quiets the editor surface (`low` / `medium` / `high` / `critical`) without restarting the server; `pipelineCheck.disabledProviders` silences whole providers in a monorepo where Pipeline-Check would otherwise lint files belonging to a sub-project. + ## What it scans Pilot provider coverage (single-file workflow providers plus Dockerfile): @@ -70,33 +81,50 @@ pip install "pipeline-check[lsp]" | Setting | Default | Description | |---|---|---| -| `pipelineCheck.serverCommand` | `python` | Command used to launch the language server. Override if `pipeline_check` is installed under a different interpreter. | -| `pipelineCheck.serverArgs` | `["-m", "pipeline_check.lsp"]` | Arguments passed to the server command. | +| `pipelineCheck.serverCommand` | `python` | Command used to launch the language server. Override if `pipeline_check` is installed under a different interpreter. Marked `machine-overridable`: workspace overrides require an explicit prompt. | +| `pipelineCheck.serverArgs` | `["-m", "pipeline_check.lsp"]` | Arguments passed to the server command. Marked `machine-overridable` for the same reason. | | `pipelineCheck.severityThreshold` | `low` | Lowest severity that produces a diagnostic. One of `low`, `medium`, `high`, `critical`. Mirrors the CLI's `--severity-threshold`. | +| `pipelineCheck.disabledProviders` | `[]` | Provider IDs to silence entirely. Diagnostics for files matching a disabled provider's path glob are dropped before they reach the editor. One of `github-actions`, `gitlab`, `azure`, `bitbucket`, `circleci`, `cloud-build`, `buildkite`, `drone`, `jenkins`, `dockerfile` (covers Containerfile too). | | `pipelineCheck.trace.server` | `off` | Traces LSP traffic. Set to `verbose` when debugging. | +## Commands and keybindings + +All commands appear in the Command Palette under the **Pipeline-Check** category. + +| Command | Default keybinding | +|---|---| +| **Restart language server** — kills and respawns the LSP process | | +| **Show language server output** — focuses the output channel (LSP server logs + `[client]` client-side breadcrumbs) | | +| **Go to Next Finding** | Alt+F8 | +| **Go to Previous Finding** | Shift+Alt+F8 | +| **Change Grouping** (Findings view) — Quick Pick: Severity / File / Rule | | +| **Refresh** (Findings view) — re-render from the current diagnostic stream | | + +## Workspace trust + +Pipeline-Check spawns the configured Python interpreter to analyze workflow files. To keep that subprocess from running on first-open of a freshly-cloned repository, the extension declares `capabilities.untrustedWorkspaces: "limited"` — it stays inactive until the workspace is trusted. The `serverCommand` / `serverArgs` settings are `machine-overridable`, so a malicious `.vscode/settings.json` can't silently swap the interpreter or inject arbitrary args even after trust is granted. + ## Development ```bash npm install -npm run compile # one-shot compile -npm run watch # rebuild on change +npm run compile # typecheck + esbuild dev bundle +npm run watch # bundle on change +npm test # vitest unit suite +npm run test:integration # @vscode/test-electron — boots a real extension host +npm run smoke # loads dist/extension.js with a vscode stub +npm run lint ``` -Press F5 in VS Code with this folder open to launch an extension-host instance with the extension loaded. Two debug profiles ship in `.vscode/launch.json`: +Press F5 in VS Code with this folder open to launch an extension-host instance with the extension loaded. Two debug profiles ship in [.vscode/launch.json](.vscode/launch.json): - **Run Extension**: opens a fresh window with no workspace. Use this when iterating on the client wiring against a checkout of your own code. - **Run Extension (sample workflow)**: opens `test-fixtures/sample-workflow/` as the workspace. The fixture is a deliberately-vulnerable GitHub Actions workflow and should produce four diagnostics (GHA-001, GHA-004, GHA-015, GHA-016) the moment you open the file. Quickest way to confirm the client → server round-trip works end-to-end. -Two commands are registered in the running extension: - -- **Pipeline-Check: Restart language server**: kills and respawns the LSP process. Useful after editing the Python server in a sibling checkout. -- **Pipeline-Check: Show language server output**: focuses the `Pipeline-Check` output channel where the server's `window/logMessage` traffic lands. - ## Packaging ```bash -npx @vscode/vsce package # produces pipeline-check-.vsix +npm run package # delegates to `vsce package`, produces pipeline-check-.vsix ``` ## Releasing @@ -104,18 +132,23 @@ npx @vscode/vsce package # produces pipeline-check-.vsix Publishing is fully automated by [.github/workflows/publish.yml](.github/workflows/publish.yml). Tag a commit with `vX.Y.Z` matching `package.json#version`, push the tag, and the workflow packages the `.vsix`, publishes to both the VS Code Marketplace and Open VSX, and attaches the artifact to a GitHub Release with the matching `CHANGELOG.md` section as release notes. ```bash -git tag v0.1.0 -git push origin v0.1.0 +git tag v0.1.2 +git push origin v0.1.2 ``` -Two repo secrets gate the publish jobs: +**Tag-naming convention:** + +- `vX.Y.Z` → stable marketplace channel. +- `vX.Y.Z-rc.N` (or any version with a `-` after the semver core) → pre-release channel; the GitHub release is also marked `prerelease`. + +Two repo secrets gate the publish jobs, both stored as **environment secrets** on the `production` GitHub Environment (required reviewer must approve before the publish steps run): | Secret | Where it comes from | |---|---| | `VSCE_PAT` | Azure DevOps PAT scoped to *Marketplace → Manage*, bound to the `greylag-ci` publisher. | | `OVSX_PAT` | Open VSX access token from the user-settings page, bound to the `greylag-ci` namespace. | -Every PR and every push to `main` is gated by [.github/workflows/ci.yml](.github/workflows/ci.yml) on the same three checks the release runs first (lint, type-compile, and a clean `vsce package`), so a contributor whose change cannot ship never makes it past review. +Every PR and every push to `main` is gated by [.github/workflows/ci.yml](.github/workflows/ci.yml) running across `[ubuntu-latest, windows-latest, macos-latest]` with: lint, typecheck, unit tests (vitest), bundle smoke (loads `dist/extension.js` against a `vscode` stub to verify the package is loadable), `npm audit --omit=dev --audit-level=high`, `vsce package`, and on Linux the `@vscode/test-electron` integration suite. Release-day surprises stay rare.
Architecture @@ -133,6 +166,10 @@ The extension spawns `python -m pipeline_check.lsp` as a child process and excha
+## Security + +Report vulnerabilities privately via GitHub's [Private vulnerability reporting](https://github.com/greylag-ci/pipeline-check-vscode/security/advisories/new) — see [SECURITY.md](SECURITY.md) for the response SLA and threat model. + ## License [MIT](LICENSE). diff --git a/ROADMAP.md b/ROADMAP.md index a666534..be91bf3 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,41 +1,44 @@ # Roadmap -Production-readiness work for the Pipeline-Check VS Code extension, queued -from the pre-marketplace security and packaging review. Items are grouped -by severity; tick the box when the change lands on `main`. - -The "must-haves before next publish" set is **C1, C2, H1, H2**. All four -are landed on `prod-ready-hardening`; the publish job is now gated on -the `production` GitHub Environment. - -### Maintainer action items before merging this branch - -1. **Confirm the `production` GitHub Environment is configured** with - required reviewers and that `VSCE_PAT` / `OVSX_PAT` live as - environment secrets (not repo secrets). The workflow now references - `environment: production`; the gate is only as strong as the - environment's review rules. -2. **Disable the default CodeQL setup** so the advanced - [.github/workflows/codeql.yml](.github/workflows/codeql.yml) (which - runs `security-extended`) can upload SARIF. Settings → Code security - → Code scanning → "CodeQL analysis" → click "Set up" / settings → - switch from "Default" to "Advanced" (or disable default outright). - Until this is done, the `analyze` check on PR #1 will fail with - "CodeQL analyses from advanced configurations cannot be processed - when the default setup is enabled". -2. **Enable Private Vulnerability Reporting** on the repo (Settings → - Code security). Without it, the link in [SECURITY.md](SECURITY.md) - 404s and external reporters have nowhere private to file. -3. **Enable Discussions** on the repo (Settings → General → Features). - Without it, the `qna` link in [package.json](package.json) 404s - from the marketplace listing. -4. **Smoke-test the activation narrowing (H4)** — open each provider's - sample workflow in the extension-host window (F5 with sample-workflow - profile) and confirm diagnostics still appear. The change drops - any custom workflow paths. -5. **Verify the published v0.1.0 actually fails to activate** in a - clean VS Code (the C1 hypothesis). If confirmed, this branch - becomes a 0.1.1 hotfix. +Production-readiness work for the Pipeline-Check VS Code extension. The +pre-marketplace security and packaging review (C/H/M/L items below) is +fully landed in v0.1.1. The in-depth code review of 2026-05-19 (R items +at the bottom) is two-thirds landed across PRs #11–14. + +### Status snapshot + +| Layer | State | +|---|---| +| **v0.1.0 → v0.1.1** | Shipped 2026-05-19. C1–C2, H1–H4, M1–M5, L1–L6 all closed. | +| **v0.1.1 → v0.2.0 (in flight)** | R1–R9, R12, R14, R16–R18, R20, R21, R24–R26 landed on stacked PRs #11–#14; merge them in order, then tag. | +| **Blocked** | R10/R15/R29 (need scan-workspace merged), R11 (need suppression-comment syntax), R13/R27 (server-side change), R19 (interactive screenshot session), R22 (eslint-flat-config WIP), R23 (CodeQL setup), R28 (telemetry decision). | + +### Maintainer action items (still outstanding) + +These cannot land from a branch and have been queued since the +production-readiness pass. Each one's failure mode is small enough +that v0.2.0 can ship without them, but the listing improves once +they're done. + +1. **Resolve the CodeQL default-setup conflict.** The advanced + [.github/workflows/codeql.yml](.github/workflows/codeql.yml) runs + `security-extended`; the org's default CodeQL setup conflicts and + the `analyze` check stays red. Settings → Code security → Code + scanning → switch CodeQL from "Default" to "Advanced". If org + policy forbids that, delete `codeql.yml` and lose + `security-extended`. +2. **Enable Private Vulnerability Reporting.** Settings → Code + security. Without it, the link in [SECURITY.md](SECURITY.md) 404s + for external reporters. +3. **Enable Discussions.** Settings → General → Features. Without it, + the `qna` link in [package.json](package.json) 404s on the + marketplace listing. +4. **Manual H4 smoke** — F5 with the sample-workflow profile, open + each provider's trigger file, confirm diagnostics still appear. + The activation narrowing drops custom workflow paths intentionally + but the regression risk is non-zero. +5. **Capture marketplace screenshots** ([R19](#review-pass-2026-05-19--improvements-from-in-depth-code-review)). + Highest-leverage conversion improvement still pending. --- @@ -399,97 +402,106 @@ on their own. The findings below came out of a holistic review of the codebase after v0.1.1 shipped. Categories cluster related work into reviewable PRs. +PR landing order (all stacked on `main`): +- **#11** `review-followups` — R1–R9, R21 +- **#12** `review-followups-batch-2` — R12, R14, R16, R18, R20 +- **#13** `review-followups-batch-3` — R24, R25, R26 +- **#14** `review-followups-batch-4` — R17 + +Total: 19 of 29 review items landed; the rest are blocked on external +inputs (suppression syntax, screenshots) or stacked branches +(scan-workspace). + ### Code-level fixes (cheap wins) -- [ ] **R1** Reorder the `filterByThreshold` import in - [src/extension.ts:72](src/extension.ts#L72) up to the rest of the - import block. Currently sits after a function declaration. -- [ ] **R2** "Restart language server" toast at - [src/extension.ts:223](src/extension.ts#L223) fires even when - `startClient()` failed. Guard with `if (client)`. -- [ ] **R3** Add a timeout to `stopClient()` - ([src/extension.ts:185-192](src/extension.ts#L185-L192)) — - a deadlocked LSP child holds the deactivate path indefinitely. -- [ ] **R4** `groupByFile` does `key = f.uri.toString()` then - `vscode.Uri.parse(key)` to get the Uri back - ([src/findingsView.ts:357-385](src/findingsView.ts#L357-L385)). - Use a `Map` keyed on the Uri directly. -- [ ] **R5** `compareByLocation` - ([src/findingsView.ts:413](src/findingsView.ts#L413)) sorts on - `uri.toString()` which includes the `file://` scheme prefix. - Sort on `fsPath` instead. +- [x] **R1** Reorder the `filterByThreshold` import in extension.ts up + to the rest of the import block. (PR #11) +- [x] **R2** "Restart language server" toast no longer fires when + `startClient()` failed. (PR #11) +- [x] **R3** `stopClient()` races the LSP shutdown against a 2-second + timer; dispose explicitly on timeout. (PR #11) +- [x] **R4** `groupByFile` carries the original Uri alongside the + string key; no `Uri.parse` round-trip. (PR #11) +- [x] **R5** `compareByLocation` sorts on `fsPath`. (PR #11) ### Performance -- [ ] **R6** Cache `collectFindings()` per refresh. Currently called - twice per refresh (`buildRoot` + `updateBadge`); each walks every - diagnostic in the workspace. -- [ ] **R7** Filter `onDidChangeDiagnostics` by the event's `uris` - payload — skip the refresh when none of the changed URIs carry a - pipeline-check diagnostic. +- [x] **R6** `collectFindings()` memoised behind a per-refresh cache. + (PR #11) +- [x] **R7** `onDidChangeDiagnostics` skips refreshes whose URI batch + doesn't touch a pipeline-check diagnostic — plus a + `lastFindingUris` set so cleared findings still trigger a + refresh. (PR #11) ### UX gaps -- [ ] **R8** Wire `Diagnostic.code.target` into the leaf tooltip. The - server publishes the rule's docs URL; we read `code.value` and - throw the URL away. Add a docs link at the bottom of the leaf - tooltip (set `isTrusted = true` on the `MarkdownString`). -- [ ] **R9** Status bar item showing critical/high counts. Click - reveals the Findings panel. -- [ ] **R10** Rename `pipelineCheck.findings.refresh` — re-renders - from current diagnostics, doesn't trigger a fresh scan. Once - scan-workspace lands, have refresh call `scanWorkspace()`. -- [ ] **R11** `CodeAction` provider for suppression comments. - Right-click a finding → "Suppress GHA-001 for this line" that - inserts the CLI's suppression syntax. -- [ ] **R12** "Go to next/previous finding" commands with keybindings. -- [ ] **R13** Set `Diagnostic.tags` for `Deprecated` / - `Unnecessary` where the rule indicates it. Server-side change. +- [x] **R8** Leaf tooltip appends a `$(book) documentation` + link when the server publishes `Diagnostic.code.target`. (PR #11) +- [x] **R9** Status bar item on the left at priority 100 showing the + top two non-zero severities (e.g. `$(shield) 3C 1H`). (PR #11) +- [ ] **R10** Rename / repurpose `pipelineCheck.findings.refresh` to + call `scanWorkspace()` once the scan-workspace branch lands. + *(Blocked on scan-workspace merging.)* +- [ ] **R11** `CodeAction` provider for suppression comments. *(Blocked + on the upstream pipeline-check CLI's suppression syntax.)* +- [x] **R12** Alt+F8 / Shift+Alt+F8 jump between findings, wrap at + both ends. (PR #12) +- [ ] **R13** Set `Diagnostic.tags` for `Deprecated` / `Unnecessary` + where the rule indicates it. *(Server-side change — file + upstream.)* ### Architecture -- [ ] **R14** Extract the candidate-file pattern list from - `activationEvents`, `documentSelector`, and (post-merge) - `SCAN_PATTERNS` into a single shared TS module. Today the list - lives in three places. -- [ ] **R15** Add `onCommand:pipelineCheck.scanWorkspace` to - `activationEvents` so opening an isolated file from outside the - workspace can still trigger activation. -- [ ] **R16** Client-side structured logging into the output channel - with a `[client]` prefix. Breadcrumbs for bug reports. +- [x] **R14** Trigger-pattern list extracted into `src/providers.ts` + (`PROVIDERS` map + `TRIGGER_PATTERNS`). A regression test asserts + the package.json `activationEvents` stay in lockstep. (PR #12) +- [ ] **R15** `onCommand:pipelineCheck.scanWorkspace` activation + event. *(Blocked on scan-workspace merging.)* +- [x] **R16** `[client] HH:MM:SS.mmm ` logging into the + LanguageClient's outputChannel. `withTiming(label, fn)` wraps + thunks with start/ok/failed breadcrumbs. (PR #12) ### Testing -- [ ] **R17** `@vscode/test-electron` integration tests covering real - LSP publish and tree render. -- [ ] **R18** Extract the `vi.mock("vscode", ...)` factory into a - shared `src/__testStubs__/vscode.ts`. +- [x] **R17** `@vscode/test-electron` integration suite covering + activation, command registration, view registration, settings + schema, and the workspace-trust capability. (PR #14) +- [x] **R18** `vi.mock("vscode")` factory extracted into + `src/__testStubs__/vscode.ts`. (PR #12) ### Marketplace -- [ ] **R19** **Ship the screenshots** the HTML comment at - [README.md:13-25](README.md#L13-L25) has been waiting for since - v0.1.0. Highest-leverage marketplace conversion improvement. -- [ ] **R20** CI check that `package.json#description` stays ≤ 145 - characters (the marketplace-search truncation limit). +- [ ] **R19** **Ship the screenshots** the HTML comment in README.md + has been waiting for since v0.1.0. *(Needs an interactive + VS Code session.)* See [docs/screenshots/README.md](docs/screenshots/README.md) + for the capture recipe. +- [x] **R20** CI fails the build if `package.json#description` + exceeds 145 characters. Today's description is 141 chars. (PR #12) ### CI / release -- [ ] **R21** Test matrix: - `[ubuntu-latest, windows-latest, macos-latest]`. The - `LF → CRLF` warnings on every git operation hint at the bugs. -- [ ] **R22** Finish the eslint flat-config migration so the - drift between eslint v8 and TS 6 / esbuild 0.28 stops widening. +- [x] **R21** Three-OS matrix: `[ubuntu-latest, windows-latest, + macos-latest]`. `npm audit` and the vsix upload pinned to + Linux. (PR #11) +- [ ] **R22** Finish the eslint flat-config migration so drift between + eslint v8 and TS 6 / esbuild 0.28 / @types/node 25 stops + widening. *(WIP stash on the maintainer's `pr10` checkout.)* - [ ] **R23** Resolve the CodeQL default-setup conflict — disable - default setup or delete codeql.yml. Don't ship with a - permanently-red required check. -- [ ] **R24** `vsce publish --pre-release` channel for the next - minor bump. + default setup or delete `codeql.yml`. *(Needs repo-settings + change.)* +- [x] **R24** Pre-release channel via tag naming + (`vX.Y.Z-rc.N` → pre-release). (PR #13) ### Strategic -- [ ] **R25** Per-provider toggles in settings. -- [ ] **R26** Inline `CodeLens` summarising findings per file. -- [ ] **R27** Workspace-level config file shared with the CLI. +- [x] **R25** `pipelineCheck.disabledProviders` setting silences + providers wholesale. (PR #13) +- [x] **R26** Inline `CodeLens` summary at the top of each scanned + file. (PR #13) +- [ ] **R27** Workspace-level config file (`.pipeline-check.toml`) + shared with the CLI. *(Needs upstream coordination.)* - [ ] **R28** Opt-in telemetry (`vscode.env.isTelemetryEnabled`). -- [ ] **R29** Scan-on-save mode. + *(Privacy-sensitive design decision; deferred pending product + direction.)* +- [ ] **R29** Scan-on-save mode. *(Depends on scan-workspace + merging.)*