Skip to content

feat(vscode): show Dvalin findings in the Problems panel - #158

Merged
arthurpanhku merged 2 commits into
mainfrom
feat/vscode-extension
Aug 8, 2026
Merged

feat(vscode): show Dvalin findings in the Problems panel#158
arthurpanhku merged 2 commits into
mainfrom
feat/vscode-extension

Conversation

@arthurpanhku

Copy link
Copy Markdown
Owner

Summary

The scan only reached people already willing to run a CLI. This puts it where the work happens: findings show up as squiggles and Problems entries on open and on save — no chat, no prompt, no API key, because scanning is deterministic and uses no model.

  • Diagnostics on the lines that caused them, with the rule id linking to its CWE reference.
  • A quick fix that runs dvalincode dvalin . --fix --verify in a visible terminal.
  • A status bar item with the health score, click to re-scan.

Two decisions worth reviewing

Severity banding is duplicated from the CLI on purpose. bandOf() mirrors findingSeverity() in src/commands/dvalin.ts. A finding shown as an error in the editor must be the one --fail-on high blocks in CI — if these drift, the editor and the pipeline disagree about what "high" means, which is worse than the duplication. The mirroring is called out in a comment on both sides of the boundary and covered by tests.

The fix runs in a terminal, not in the background. Scanning is local and deterministic. Repair is not: it uses the configured model, edits files, and runs tests. Running that silently on a quick-fix click would be the wrong default for this project — the terminal makes it watchable and interruptible, the same reason the CLI keeps repair behind an explicit --fix.

Testing

src/findings.ts and src/scan.ts deliberately do not import vscode, so the parts that are easy to get wrong are testable without an extension host. 29 unit tests, covering:

  • severity bands including an unparseable securitySeverity
  • 1-based CLI lines → 0-based editor lines, including missing, zero, and inverted line numbers
  • Windows path separators (the CLI can emit them; path.join would produce a broken URI)
  • CLI failure classification: non-zero exit, non-JSON stdout, missing binary, empty command

tests/integration.test.ts checks the JSON contract against the real published CLI — the one thing unit tests cannot prove. Verified passing against dvalincode@0.15.0: the eval fixture on source line 3 maps to editor line 2, bands to Error, and carries the CWE-94 help URI. It is skipped unless DVALIN_E2E=1 because it needs network.

Bundle builds at 11.4kb. Root npm run check still green at 323/49.

Security and AI Governance

  • This change does not expand file, shell, network, model, or approval permissions.
  • If it changes agent behavior, prompts, policy, providers, audit logging, or release/build security, I updated the relevant governance evidence in docs/.
  • If it introduces a new model/provider/tool or new data flow, I completed docs/governance/AI-CHANGE-IMPACT-ASSESSMENT.md.

Third box, deliberately unticked. This adds a new surface onto existing behaviour rather than new behaviour: the extension shells out to the same CLI with the same flags a user would type, and the repair path goes through runAgentTurn exactly as the terminal does — same policy chokepoint, same audit chain. Two things a reviewer should still weigh:

  • The extension spawns a process from a user setting (dvalin.command). It is spawn with an argv array, never a shell string, so a setting cannot inject a command — but it is still user-controlled execution.
  • scanOnSave means a save now triggers a subprocess. Scoped to builtin by default (41ms on this repo) and guarded against overlapping runs.

Notes

This job exists because of what I found auditing the workflows. src/gui is excluded from tsconfig.json and has no tests, yet imports from src/core/ — so it is invisible to CI and only breaks when release-gui.yml runs, which was three weeks ago. The extension has the same shape (own package, own tsconfig, unreachable from the root npm run check), so it gets a vscode-extension CI job in this PR rather than the same fate.

Not included, deliberately: publishing to the VS Code Marketplace. That needs a publisher account and a VSCE_PAT, and it should be a separate decision once the extension has been used against a real repo. The manifest is Marketplace-shaped (publisher, categories, keywords, repository.directory) so that step is only a vsce publish away.

Comment thread editors/vscode/tests/integration.test.ts Fixed
@socket-security

socket-security Bot commented Aug 8, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedesbuild@​0.25.12911007388100
Added@​types/​vscode@​1.125.01001008088100
Added@​types/​node@​26.2.01001008195100

View full report

arthurpanhku and others added 2 commits August 8, 2026 09:32
The scan only reached people willing to run a CLI. This puts it where the
work already happens: findings arrive as squiggles and Problems entries on
open and on save, with no chat, no prompt, and no API key — scanning is
deterministic and needs no model at all.

Severity banding mirrors `findingSeverity()` in src/commands/dvalin.ts on
purpose. A finding shown as an error in the editor is the one
`--fail-on high` blocks in CI; if the two drifted, the editor and the
pipeline would disagree about what "high" means.

The quick fix runs `dvalin . --fix --verify` in a visible terminal rather
than silently in the background. Scanning is local and deterministic;
repair uses the configured model, edits files, and runs tests, so it should
be watchable and interruptible — the same reason the CLI keeps it behind an
explicit flag.

`src/findings.ts` and `src/scan.ts` do not import `vscode`, so the banding
and range arithmetic are unit-tested without an extension host: 29 tests
covering severity bands, 1-based to 0-based conversion, inverted and
missing line numbers, Windows separators, and CLI failure classification.
`tests/integration.test.ts` checks the JSON contract against the published
CLI and is skipped unless DVALIN_E2E=1, since it needs network.

CI gets a vscode-extension job. The extension has its own package and
tsconfig, so the root `npm run check` cannot reach it — without the job it
would be invisible to CI exactly the way src/gui is today, and would break
silently until someone tried to publish it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…fixture

Two failures from the previous commit, both self-inflicted:

The VS Code extension job died with "Cannot find package 'vitest'". With no
config in editors/vscode, vitest walks up and loads the repository root's
vitest.config.ts, which resolves `vitest` from the root node_modules — a
job that only installs this package has none. It passed locally only
because the root install already existed. A local config pins the root.

The Dvalin self-scan failed on `editors/vscode/tests/integration.test.ts`:
its fixture writes an `eval` call as a string so the scan has something to
find. That is the same category as the three files already listed, so it
joins them in .dvalincodeignore rather than the gate being loosened.

Verified the repo scans clean again, and that src/ is still covered by
planting a real eval and confirming it is caught.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@arthurpanhku
arthurpanhku force-pushed the feat/vscode-extension branch from 927b1ed to 799291f Compare August 8, 2026 01:33
@arthurpanhku
arthurpanhku merged commit f21a05e into main Aug 8, 2026
13 checks passed
@arthurpanhku
arthurpanhku deleted the feat/vscode-extension branch August 8, 2026 01:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants