Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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] — <date>`
> 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] — <date>`.

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) <rule-id> 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
Expand Down
77 changes: 57 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).

<!--
Once docs/screenshots/01-inline.png, 02-problems-panel.png, and
03-hover.png exist, uncomment the block below. See
docs/screenshots/README.md for the capture recipe. The marketplace
Once docs/screenshots/01-inline.png, 02-findings-panel.png,
03-hover.png, and 04-status-bar.png exist, uncomment the block below.
See docs/screenshots/README.md for the capture recipe. The marketplace
listing renders these via GitHub's raw blob URL, so they don't need
to ship inside the .vsix.

![Inline findings in the editor gutter](docs/screenshots/01-inline.png)

![The Problems panel with clickable rule IDs](docs/screenshots/02-problems-panel.png)
![Findings panel in the activity bar, grouped by severity](docs/screenshots/02-findings-panel.png)

![Hover tooltip showing problem, description, and fix](docs/screenshots/03-hover.png)
![Hover tooltip showing problem, description, and rule docs link](docs/screenshots/03-hover.png)

![Status bar item showing the per-severity tally](docs/screenshots/04-status-bar.png)
-->

## 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):
Expand Down Expand Up @@ -70,52 +81,74 @@ 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** | <kbd>Alt</kbd>+<kbd>F8</kbd> |
| **Go to Previous Finding** | <kbd>Shift</kbd>+<kbd>Alt</kbd>+<kbd>F8</kbd> |
| **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 <kbd>F5</kbd> 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 <kbd>F5</kbd> 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-<version>.vsix
npm run package # delegates to `vsce package`, produces pipeline-check-<version>.vsix
```

## Releasing

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.

<details>
<summary>Architecture</summary>
Expand All @@ -133,6 +166,10 @@ The extension spawns `python -m pipeline_check.lsp` as a child process and excha

</details>

## 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).
Loading