All notable changes to SecureCycle are documented here.
SecureCycle 1.0.0 is the repository-hardening release: documentation now matches the current GitHub repository and extension UI, Marketplace-facing metadata is present in the extension manifest, tests run in CI, and release packaging has an auditable VSIX path.
- Marketplace metadata in
package.json: publisher, license, repository, homepage, bugs URL, categories, keywords, gallery banner, and CI badge. - Node test suites for release-critical behavior:
- policy loading fallbacks and explicit empty policy selectors
- provider/model validation for OpenAI, Anthropic, Gemini, Groq, and custom endpoints
- package/VSIX metadata checks that protect runtime dependency packaging
- CI test and VSIX file-audit steps on every push and pull request.
- Tag-based release workflow that builds a VSIX, uploads it as an artifact, and attaches it to the matching GitHub release.
docs/release-checklist.mdwith the repeatable release process for version bumps, test validation, package audits, and release tagging.
- README updated to use the canonical clone URL
https://github.com/Mosec2525/securecycle.git. - README commands and screenshots now describe the current Analysis panel and Control Center instead of older Scan/Findings panel wording.
- Package version aligned to
1.0.0. .vscodeignoretightened for release packaging while preserving production dependencies required by the compiled extension.
npm testnow compiles the extension and runs Node's built-in test runner.npm run release:dry-runruns tests, dependency audit, and VSIX file listing.npm run release:vsixruns tests, dependency audit, and produces a.vsixpackage.
- Replaced the one-normal plus one-taint selector model with
activePolicyFiles, allowing any number of active policy files. - Normal and taint policies can now be active together in any combination.
- Workspace selector files now use
activePolicyFilesas the source of truth while keepingpresetsas a compatibility mirror for bundled default and taint policies.
- Empty active policy selections now produce zero findings instead of silently falling back to
rules/default.yaml. - Deleting an active custom policy removes it from
activePolicyFilesinstead of re-enabling default rules.
- Delete buttons for custom policy files from the Rules list and detail page.
- Empty normal and taint policy templates so zero-rule policies behave predictably.
- Added support for keeping one normal policy and one taint policy active at the same time.
- Activating a normal policy replaces only the previous normal policy.
- Activating a taint policy replaces only the previous taint policy.
- Scans merge active normal and taint policies before running Semgrep.
- Workspace selector support for
activeNormalPolicyFileandactiveTaintPolicyFile. - Backward compatibility for older
.vibesec.yamlfiles usingpresetsoractivePolicyFile.
- Added Groq as a first-class AI provider.
- Groq API keys beginning with
gsk_are detected automatically and saved under the Groq provider. - Default Groq endpoint is
https://api.groq.com/openai/v1/chat/completions. - Default Groq model is
llama-3.1-8b-instant.
- Pasting a Groq key into any API key field automatically selects Groq and applies the Groq default model.
- Custom / Other remains available for OpenAI-compatible providers that require a custom endpoint.
- Saving an API key now also selects that provider as the active provider.
- The Settings page action now says
Save & useso provider switching is explicit. - Testing a provider reads the configured model field correctly and falls back to built-in provider defaults when needed.
- Removed the duplicated Custom / Other API key row.
- Custom / Other API keys are stored separately in VS Code SecretStorage.
- Custom / Other requires an exact model name instead of accidentally reusing a built-in provider model.
- Custom endpoints accept either a full
/chat/completionsURL or a base/v1URL that SecureCycle completes automatically. - Added OpenRouter-friendly headers and improved OpenAI-compatible response parsing.
Sprint 7 adds taint analysis — tracking how untrusted data flows from a source (user input, file read, environment variable) through assignments and helper calls to a sink (shell exec, SQL query, deserializer, HTTP request) within a single file. Built on Semgrep's free mode: taint engine — no Semgrep Pro, no new dependencies, no auth. The data flow is surfaced as a dedicated Data flow block in every taint-finding card with click-to-jump rows for source / intermediates / sink, included in every AI fix prompt so the model knows exactly where to sanitise, and flagged with a TAINT chip on the Control Center's Rules page.
- New
vibesec:taintpreset — 8 hand-written taint-mode rules across Python and JS/TS:vibesec.taint-command-injection-python—request.* / sys.argv / os.environ→subprocess.*(shell=True) / os.system / os.popen, sanitised byshlex.quote.vibesec.taint-command-injection-node—req.body/query/params/headers/cookies / process.argv / process.env→child_process.exec*.vibesec.taint-sql-injection-node—req.*→db.query/execute/run/all/get.vibesec.taint-path-traversal-python—request.* / sys.argv / input()→open() / os.path.join.vibesec.taint-path-traversal-node—req.*→fs.readFile* / fs.createReadStream.vibesec.taint-unsafe-deserialization-python—request.* / sys.stdin.read()→pickle.loads / pickle.load / yaml.load.vibesec.taint-xss-node—req.*→res.send / res.write / innerHTML / outerHTML / document.write.vibesec.taint-ssrf-python—request.*→requests.get/post/request / urllib*.urlopen / httpx.*.
- Opt-in via
presets: [vibesec:taint]in.vibesec.yaml. The default policy template now ships a commented-out reference line so users see the option.
src/scanner.tsnow parsesextra.dataflow_tracefrom Semgrep's JSON output into a structuredFinding.taintfield. Defensive parser handles the["CliLoc"|"CliCall", {...}]tagged-tuple shape Semgrep emits, with graceful fallback to the finding's own location if the trace is partial.- Each taint finding emits a dedicated
scaninfo log (Taint: <rule> — source L42 → sink L58) so the Logs page shows the data flow without extra UI.
- New
TaintFlowandTaintLocationtypes insrc/types.ts.Finding.taint?is optional — search-mode findings are unchanged. PanelFinding.taint?mirrors the same shape with workspace-relative paths.webview/types.tsupdated in lockstep.- New
goToLocationwire message ({ absPath, line }) lets the React panel jump to arbitrary file:line — used by every step in a Data flow block.
- New collapsible Data flow section below the metadata grid, rendered only when the finding carries taint data.
- Three row types: SOURCE (where untrusted data enters), STEP N (intermediate variable assignments), SINK (the dangerous call). Sink row uses a red callout border so the danger point is visually distinct.
- Each row is a button that dispatches
goToLocation— one click opens the file and selects the line. - A small accent-colored
TAINTchip in the section header signals the analysis mode.
buildVulnInstruction(per-vuln) injects a dedicated "Data flow:" section listing source, intermediate steps, and sink — each on its own line with the relevant snippet. The numbered checklist that follows adds an explicit step: Identify where to sanitise or validate the data along the source-to-sink path.buildFileInstruction(per-file) andbuildProjectInstruction(per-project) tag each taint finding with a compacttaint: src L42 → sink L58annotation so file-level and project-level prompts stay scannable.
RuleEntrygains amode: "search" | "taint"field.rulesIndex.tsreadsmodefrom raw YAML;webview/controlCenter/types.tsupdated in lockstep.- Each taint rule renders a small accent-colored
TAINTchip next to its title in the Rules page detail table. - The bundled
taint.yamlfile gets a hand-tuned description: "Taint analysis — tracks user input from source to dangerous sink within a file."
vscode.ExtensionContext.subscriptionsregisters no new disposables — taint integration reuses every existing channel (diagnostics, log bus, panel state, scan history).- Version bumped
0.6.4→0.7.0.
- No new dependencies. No new build steps.
npm run compileand the existing F5 launch configuration cover the full sprint.
Sprint 6 adds a second webview — the SecureCycle Control Center — that opens as a full editor-area tab next to the existing Analysis sidebar. It surfaces four pages (Dashboard / Settings / Logs / Rules) sourced live from the extension's own state, makes every vibesec.* setting two-way bindable from a real UI, persists scan history per-workspace, and ships a structured logging pipeline with disk persistence so users can inspect what happened during prior sessions. Visual direction is from the Claude Design output at Extension Design/SecureCycle Extension Webview/ (CDN React/Babel and Google Fonts stripped, all assets bundled locally to satisfy CSP). The existing Analysis sidebar is untouched.
- New
src/controlCenterView.ts—ControlCenterControllerhosting a singleton editor-areaWebviewPanel(vibesec.controlCenter). Mirrors the patterns inpanelView.ts: per-render CSP nonce,localResourceRootslocked tomedia/, theme bridge viaonDidChangeActiveColorTheme, ready-handshake replay,retainContextWhenHidden: true. Subsequentshow()calls reveal the existing panel rather than spawning a duplicate. - New
src/controlCenterMessages.ts— discriminated-union wire protocol (mirrored verbatim inwebview/controlCenter/types.ts). Theready→inithandshake replays settings, scan history, log ring buffer, and the rules index in one message. - New command
vibesec.openControlCenter("Open Control Center") with$(settings-gear)icon. - New
view/titlemenu binding so the gear button shows up in the Analysis sidebar's view title bar — both entry points open the same singleton panel. - New
webview/controlCenter/source folder, bundled by esbuild intomedia/webview/controlCenter.{js,css}via a second entry point inesbuild.webview.mjs(entryNames: '[name]'keeps outputs flat). - Design CSS ported with two CSP-required substitutions: Google Fonts
@importremoved andGeist/Geist Monorebound tovar(--vscode-font-family)/var(--vscode-editor-font-family)so typography inherits the user's VS Code config.
- All 8
vibesec.*settings rendered as two-way-bound controls (text input / toggle / segmented enum), grouped per the design (Engine / Behavior / AI assistance). - Default values are read live from
cfg.inspect(key).defaultValue— no hardcoded duplication ofpackage.jsondefaults. - "Open settings.json" opens the workspace settings file (or user settings if no folder is open).
- "Reset to defaults" prompts via
vscode.window.showWarningMessage({ modal: true })and only proceeds on explicit confirmation; clears each key withcfg.update(k, undefined, target)so values fall back to the package.json declared defaults. vscode.workspace.onDidChangeConfiguration("vibesec")listener pushes refreshed snapshots, keeping the UI in sync with externalsettings.jsonedits.
- New
src/scanHistoryStore.ts—workspaceState-backed history capped at 200 entries; firesonDidChangeafter every mutation. Each entry tracks{ ts, filesScanned, filesSkipped, duration, findings: { error, warning, info }, trigger }. runScanOnTargetsnow records a history entry on every non-empty completion. Thetriggerfield is sourced from the call site: explorer right-click →selection, on-save →onSave, everything else →manual.- Dashboard renders:
- 1d / 7d / 30d range selector (re-bucketed client-side; no extra round-trip).
- Summary header: total findings, scan count, last-scan relative time, average duration, trigger label.
- Severity breakdown cards (error / warning / info) with percentage of total.
- Recent scans table (last 6 in range).
- Right rail: 4 quick-action tiles wired to existing commands (
scanWorkspace, focus Analysis panel,openPolicyFile,reloadPolicy); environment card; SVG sparkline of findings per bucket.
- "Clear history" affordance wipes
workspaceStateafter a single confirmation.
- New
src/logBus.ts— process-wide singleton withinfo / warn / error(type, msg, detail?), a 1000-event ring buffer, and asubscribe()API. Safe to import before activation. - New
src/logStore.ts— JSON Lines persistence under<globalStorageUri>/logs/vibesec.log, with rotation tovibesec.log.1at ~2 MB. On activation, the store tail-loads up to 1000 events back into the bus's ring buffer so the Logs page shows prior-session events immediately. - Tee to
vscode.OutputChannel("SecureCycle")so users can read raw events from VS Code's standard Output panel. - Instrumentation (no behavior change):
src/scanner.ts— fatal Semgrep exits logsemgrep errorwith stderr; non-fatal stderr surfaces assemgrep warn.src/policy.ts— load success / read failure / YAML parse error / partial-failure all logpolicyevents.src/llmClient.ts—callLlmis wrapped with start/success/error logs that include HTTP status and round-trip latency.src/promptGenerator.ts—promptinfo events per per-vuln / per-file / per-project build, with provider + model.src/extension.ts— high-levelscanevents at start / cancel / complete / fully-failed; policy-excluded files batched into a singleskip warn.
- Logs page:
- Summary strip (total / errors / warnings / info).
- Type filter (scan / prompt / skip / semgrep / policy / api / other) + level filter + free-text search across
msg + detail. - Newest-first list, click-to-expand detail rows.
- Copy filtered events to clipboard; Clear truncates ring buffer + on-disk file.
- New
src/rulesIndex.ts— parses bundledrules/*.yamland (when present) the workspace.vibesec.yaml, normalizing both into aRuleFileEntry[]+RuleEntry[]shape that mirrors the design. Best-effort: malformed YAML produces an empty file withparseErrorset instead of throwing. Confidence ladder mapsHIGH=0.95/MEDIUM=0.7/LOW=0.4. - Rules page renders:
- Summary card: total rules, bundled / custom / external file counts.
- Two-level navigation — file list grouped by source → per-file rule table.
- Per-file row: name, source chip, description, severity dots, rule count, parse-error indicator if applicable.
- Per-file detail: stat cards (Total / Enabled / Error / Warning / Info), search + severity filter, table with Severity / Rule (id + language tags) / Category / CWE / Confidence / On.
- Open YAML button on file headers posts
openRuleFile; the controller resolves the absolute path and opens it in a regular editor tab viaworkspace.openTextDocument+window.showTextDocument.
- File-system watchers on
**/.vibesec.yamland<extensionUri>/rules/*.{yaml,yml}push liverulesUpdatedmessages so edits in another tab reflect on the page without a manual refresh. - Per-rule live toggles are intentionally deferred — the toggle column displays current state but is read-only in v1. The "external" group renders as a disabled placeholder.
webview/AnalysisPanel.tsxand the Control Center now consume the version string frominitmessages (sourced fromcontext.extension.packageJSON.version) instead of a hardcoded literal — future bumps are a singlepackage.jsonedit.- New CSS primitives in
webview/controlCenter/controlCenter.css:.toggle,.segmented,.input,.settings-row,.kv-grid,.qa,.sev-card,.sev,.tag,.toast,.confidence-bar/.confidence-fill,.rule-file-row,.rule-source-tag,.rule-count-chip,.rules-header,.rule-row,.logs-header,.log-row,.log-detail,.search-wrap,.filter-row,.sidebar-version.
runScanOnTargetsnow takes atriggerparameter;vibesec.scanSelectedand the on-save handler pass it through. Cancelled scans with no findings are excluded from history to avoid noisy sparklines.- The on-save listener now calls
runScanOnFiledirectly withtrigger="onSave"instead of dispatchingvibesec.scanCurrentFile, so the scan-history entry is tagged correctly. - Version bumped
0.5.0→0.6.4.package-lock.jsonbrought in sync (was still at0.4.0).
esbuild.webview.mjsnow ships two entry pairs (Analysis panel + Control Center).entryNames: '[name]'keeps the output tree flat.- Both webview bundles remain CSP-clean: only React's bundled error-decoder URL and W3C namespace constants appear as literal strings; no remote network requests.
Sprint 5 replaces SecureCycle's two native TreeView panels with a single React-based analysis webview that lives in the activity-bar sidebar. The new panel is a faithful port of the design mockup at Extension Design/SecureCycle extension/vibesec-panel/ — file picker with checkboxes, severity-filtered finding cards with metadata grid (Category / Confidence / CWE / OWASP), expandable details, and a Full Fix tab that surfaces ready-to-paste AI prompts grouped per file. Severity is now aligned 1:1 with the YAML policy schema (error / warning / info), and findings carry colored callout-style left borders so errors and warnings are visible at a glance. Under the hood, Semgrep rule metadata is now forwarded losslessly into every Finding, which is what powers the panel's metadata grid.
- New
src/panelView.ts—PanelControllerimplementingvscode.WebviewViewProvider. Owns the sidebar webview, builds CSP-locked HTML with a per-render nonce, hosts the message bridge, and exposespushState(),pushProgress(),notifyPromptCopied(),reveal() - New
webview/source folder bundled by esbuild intomedia/webview/:AnalysisPanel.tsx— top-level component; renders empty / loading / populated / noFindings / error states and the Results / Full Fix tabsFileTree.tsx— multi-select file picker with checkboxes, indeterminate folder states, ext-color icons, and select-all / clear actionsVulnCard.tsx— expandable finding card with severity tag, rule id, title, description, file:line jump-link, and a 2×2 metadata grid (Category / Confidence / CWE / OWASP)FixFileGroup.tsx— Full Fix tab's per-file prompt block (groups findings, exposes per-file Copy chip, calls into the existing prompt cache)SegmentedTabs.tsx,icons.tsx,vscode.ts,main.tsx,types.ts— supporting primitivesstyles.css— port of the design system (~1080 lines): dark + light themes,vs-accent-green/vs-accent-monovariants,vs-density-comfortable/vs-density-compact, callout-style severity borders, syntax tokens, animations, scrollbar treatments
- New
src/panelMessages.ts— discriminated-union message protocol shared between the extension and the React bundle (mirrored verbatim inwebview/types.ts) - New
vibesec.analysisPanelview registered under the existingvibesecactivity-bar container as a webview view (replaces the oldvibesec.scanPanelandvibesec.findingsPanelTreeViews)
- New
esbuild.webview.mjs— IIFE-format browser bundle, no remote sources, noeval,react+react-dombundled inline, optional--watchmode - New
webview/tsconfig.json—jsx: "react-jsx",module: "esnext",noEmit: true(esbuild handles emission) - New npm scripts:
compilenow runstsc -p ./ && node esbuild.webview.mjsbuild:webviewandwatch:webviewfor webview-only iterations
- New devDependencies:
esbuild,react,react-dom,@types/react,@types/react-dom
- Filter chips reduced from the design's four-tier (Critical / High / Medium / Low) to the YAML policy's three actual tiers (Error / Warning / Info), so the UI never lies about what the schema can express
- New full-card-height callout-style left borders on finding cards (markdown blockquote vibe):
- Error → solid red (
var(--sev-critical)) - Warning → solid amber/yellow (
var(--sev-medium)) - Info → default subtle border (no callout treatment)
- Error → solid red (
- New severity tag pill rules (
.sev-tag-error,.sev-tag-warning,.sev-tag-info) with both dark- and light-theme variants
- New
Wandicon button in the panel side-header: pre-warms the prompt cache in the background by dispatchingvibesec.generatePrompts(which respects the activevibesec.promptModesetting). Disabled until findings exist - New accent-styled Generate button in the Full Fix tab summary bar, next to Copy all — same dispatch, contextually obvious placement
- Replaces the prior auto-on-scan generation pattern (it never auto-ran, but copy chips now have a clearer pre-warm path)
- Webview detects VS Code's body class on boot (
vscode-light,vscode-dark,vscode-high-contrast,vscode-high-contrast-light) and applies the matching design class (vs-theme-light/vs-theme-dark) - Re-themes within ~1 frame on
vscode.window.onDidChangeActiveColorThemevia athemeChangedpostMessage - No
--vscode-*token bridging — the design palette is preserved end-to-end for visual fidelity
Finding.metadatais a new optionalRecord<string, unknown>populated by the scanner directly fromsemgrep --json'sextra.metadatafield. Whatever a rule (bundled, registry, or user-authored) carries —cwe,owasp,references,likelihood,impact,technology,category,confidence— flows untouched into the panel- The panel's metadata adapter (
toPanelMetainpanelMessages.ts) safely extracts CWE / OWASP arrays, Category, and Confidence with em-dash fallbacks so the metadata grid never shows blank cells
CustomRulenow acceptspattern-either,pattern-regex, taint mode (mode: "taint"withpattern-sources+pattern-sinks), and any extra Semgrep-recognised field via an open index signature- Policy validation accepts any of:
pattern/patterns/pattern-either/pattern-regex, OR taint mode with both sources and sinks - Rule bodies are now passed through to Semgrep losslessly (
{ ...raw, ...normalised-fields }), so registry rules and future rule sources retainfix,paths,options,pattern-not, etc. without needing per-field allowlisting
vibesec.openPanelOnScan(boolean, defaultfalse) — when on, focus the analysis panel automatically whenever a scan starts
- Removed both
createTreeViewcalls (vibesec.scanPanel,vibesec.findingsPanel);FindingsProvideris kept as the in-memory single source of truth for findings + prompt cache, but no longer registered as a TreeDataProvider - New
PanelControllerinstantiation with hooks delegating back torunScanOnTargets,goToFinding,copyPromptForFinding,copyPromptForFilePath,vibesec.copyPromptForAll,vibesec.generatePrompts runScanOnTargetsnow callspanel.pushProgress(percent, basename)once per file so the panel's progress bar advances in step with the existing notification progressvibesec.scanSelectedrepurposed to read URIs from VS Code's Explorer right-click context (first arg = clicked URI, second arg = full multi-selection). The panel has its own internal file selection- Stale fs watcher and workspace folder listener removed — the panel rebuilds its tree on demand via
getWorkspaceTree
contributes.views.vibeseccollapsed to a singlevibesec.analysisPanelwebview viewcontributes.viewsWelcomecleared (the React panel handles all empty / error / no-findings states internally)contributes.menus:- All
view/titleandview/item/*entries scoped to the removed TreeViews dropped - New
explorer/context"Scan with SecureCycle" entry onvibesec.scanSelected - New
editor/title"Scan Current File" entry onvibesec.scanCurrentFile
- All
- Version bumped to
0.5.0
vibesec.scanPanelandvibesec.findingsPanelTreeView registrationsvibesec.refreshScanTreecommand (no provider to refresh)vibesec.openPanelcommand (the sidebar view IS the panel — no command needed)src/scanProvider.tsScanProviderclass,ScanNodetypes,isScanFileNode/isScanFolderNodehelpers — file trimmed to a constants module exporting onlyIGNORED_DIR_NAMES(still used by both the multi-target scan walker and the panel's tree builder)
Sprint 4 unlocks two major capabilities: multi-target scanning (scan multiple files, folders, or the entire project in one go) and AI fix prompts (generate copy-paste instructions that tell an AI assistant exactly how to fix each finding). API keys are stored securely using VS Code's built-in secret storage — nothing is written to disk or settings files.
- Scan Whole Project (
vibesec.scanWorkspace) — new title-bar button ($(run-all)) on the Scan panel; walks the entire workspace recursively, skips ignored directories (node_modules,.git,dist, etc.) and non-scannable files, and aggregates all findings into one panel update - Scan Selected now handles multiple files and folders — selecting a folder in the Scan panel and clicking play recursively scans every scannable file inside it
- Batch scans run under
vscode.window.withProgresswith a "Scanning N / M files…" counter and a Cancel button that stops mid-scan cleanly - New async
expandTargetToFiles()helper inextension.ts— walks directories usingfs.promises.readdir, skips symlinks, dot-directories, andIGNORED_DIR_NAMES - New
src/scannableExtensions.tsmodule — single source of truth for which extensions are scannable; shared between the Scan panel file browser and the multi-target walker
- New
src/promptGenerator.ts— builds structured natural-language instructions from one or more findings and sends them to the configured LLM; returns the model's response as plain textgeneratePromptForVuln(finding, opts)— one model call per finding; includes ±5 lines of source context around the offending lines (marked with>)generatePromptForFile(filePath, findings, opts)— one call batching all findings in a filegeneratePromptForProject(findings, opts)— one call covering every finding across the whole scan
- New
src/llmClient.ts— thin HTTP client for all three providers using Node 18+ built-infetch(no new dependency)- OpenAI:
POST /v1/chat/completions - Anthropic:
POST /v1/messageswithanthropic-version: 2023-06-01header - Gemini:
POST /v1beta/models/{model}:generateContent - Friendly error messages for 401 (key rejected), 429 (rate limit), 5xx (provider down), and network failures
- 60-second timeout via
AbortController pingProvider()helper sends a minimal 1-token request for key verification
- OpenAI:
- New
src/secrets.ts— wrapper around VS CodeSecretStorage; keys stored undervibesec.apiKey.openai,vibesec.apiKey.anthropic,vibesec.apiKey.gemini SecureCycle: Set API Key— picks provider from a quick-pick, prompts for key withshowInputBox({ password: true })so the key is masked while typingSecureCycle: Clear API Key— removes the stored key for a chosen providerSecureCycle: Test API Key— sends a ping to verify the key works; shows a success or error notification
- Generate Prompts (
$(sparkle)) — title-bar button on the Findings panel; pre-generates prompts for all findings in batch according to the activepromptMode; shows progress and supports cancellation - Copy Prompt for Vulnerability (
$(comment-discussion)) — inline button on individual finding rows; generates on demand (or reads cache) and copies to clipboard - Copy Prompt for File (
$(comment-discussion)) — inline button on file group rows - Copy Prompt for All (
$(comment-discussion)) — title-bar button; copies the single project-level prompt - Prompts are lazily generated — no API call happens until the user clicks; scanning never triggers LLM calls automatically
- Generated prompts are cached in memory on
FindingsProviderand reused on subsequent clicks; cache is cleared whenever a new scan runs
Three new entries in Settings → SecureCycle:
| Setting | Type | Default | Description |
|---|---|---|---|
vibesec.llmProvider |
dropdown | anthropic |
Which AI provider to use (OpenAI / Anthropic / Gemini) |
vibesec.llmModel |
string | claude-haiku-4-5 |
Model ID — defaults to cheapest tier per provider |
vibesec.promptMode |
dropdown | perFile |
How prompts are sliced: per file, per vulnerability, or per project |
vibesec.fileExtensions |
string | (space-separated list) | Space-separated file extensions to scan; edit in one text field |
vibesec.fileExtensionschanged from a JSON array (long list UI) to a plain string — users type extensions separated by spaces in a single compact text fieldvibesec.llmProviderauto-suggests the cheapest default model when changed:gpt-5-nano(OpenAI),claude-haiku-4-5(Anthropic),gemini-2.5-flash-lite(Gemini)
- New walkthrough step "Hook up an AI provider for fix prompts" added to the existing first-install walkthrough; guides users to
SecureCycle: Set API Key; completes automatically once the command is run
runScanOnFile()is now the inner loop of a newrunScanOnTargets(targets)batch runnervibesec.scanSelectednow iterates all selected items, expands folders recursively, and passes the full file list torunScanOnTargets- New
resolveModel(provider, configuredModel)helper — detects provider-model mismatches using string-prefix heuristics and falls back to the provider default - New
resolveLlmCallContext()helper — reads provider + key + model from settings/secrets and surfaces actionable errors if anything is missing
setState()clears the prompt cache on every call — stale prompts are never shown after a re-scan- New accessors
getAllFindings(),getFindingsForFile(),getFilePaths()used by prompt commands - New static
FindingsProvider.keysobject exposes cache key helpers so callers don't need to importtypes.tsseparately
IGNORED_DIR_NAMESis now exported — reused by the multi-target walker inextension.ts- Removed local
SCANNABLE_EXTENSIONSconstant — replaced bygetScannableExtensions()fromscannableExtensions.ts - Added
isScanFolderNode()export
- Added
LlmProvider("openai" | "anthropic" | "gemini") - Added
PromptMode("perVulnerability" | "perFile" | "perProject") - Added
FindingId(branded string type for per-finding cache keys) - Added
PromptCache(Map<string, string>) - Added
findingId(f),promptCacheFileKey(path),PROMPT_CACHE_PROJECT_KEYhelpers
- Version bumped
0.3.0→0.4.0 - 8 new commands registered:
scanWorkspace,setApiKey,clearApiKey,testApiKey,generatePrompts,copyPromptForVuln,copyPromptForFile,copyPromptForAll - New title-bar and inline context-menu entries for prompt commands
commandPalettevisibility rules hide internal commands (copyPromptForVuln,copyPromptForFile) from the palette
| File | Purpose |
|---|---|
src/scannableExtensions.ts |
Shared extension list + isScannableUri() helper |
src/secrets.ts |
VS Code SecretStorage wrapper, per-provider key management |
src/llmClient.ts |
HTTP clients for OpenAI, Anthropic, Gemini with error mapping |
src/promptGenerator.ts |
Prompt assembly engine, three granularities |
Full UI/UX sprint. SecureCycle gets its own activity bar icon, a Scan panel (multi-select file tree for choosing what to scan), a redesigned Findings panel with folder grouping (Folder → File → Finding → Detail) and severity-first visual hierarchy, a full accessibility pass, three user-configurable settings, auto-scan-on-save, a first-install walkthrough, and a Copy Description action. A UI style guide is included to keep future sprints consistent.
- SecureCycle now has its own dedicated icon in the VS Code activity bar — a shield with a lightning bolt — separate from the Explorer sidebar
- New
media/vibesec-icon.svg— single-path SVG withfill="currentColor"andfill-rule="evenodd"so VS Code can mask it correctly in dark, light, and high-contrast themes - New
viewsContainers.activitybarentry inpackage.jsonwith idvibesec - The Findings panel (
vibesec.findingsPanel) is now hosted inside this dedicated container instead of the Explorer
- Scan (
$(play)) and Reload Policy ($(refresh)) buttons now appear directly in the Findings panel title bar — no need to open the command palette for the most common actions - Wired via
contributes.menus["view/title"]scoped toview == vibesec.findingsPanel
- New
vibesec.scanPanelview in the SecureCycle activity bar container, alongside Findings - New
src/scanProvider.ts— TreeDataProvider listing the workspace as a collapsible file tree with theme-aware icons - Native
canSelectMany: true— click to select, Ctrl/Cmd+click to add, Shift+click for range - Auto-filters noise directories (node_modules, .git, dist, build, etc.) and identifies 25+ scannable file extensions
vibesec.scanSelectedcommand — title-bar play button reads selection and runs scanvibesec.refreshScanTreecommand — manual rebuild + auto-rebuild via filesystem watcher on create/delete
- Tree hierarchy is now Folder → File → Finding → FindingDetail (was File → Finding → FindingDetail)
- Folder nodes show workspace-relative paths with severity-tinted icons
- Files within folders sorted by finding count then alphabetically
- All three non-findings states are now rendered via
contributes.viewsWelcomeinpackage.jsonwith clickable action buttons, replacing the plain texttreeView.messagestrings from Sprint 2 empty(no scan yet): "No scan has run yet." with[$(play) Scan Current File]and[$(gear) Open Policy File]buttonsnoFindings(clean scan):$(pass-filled)icon + "No security issues found. Your last scan came back clean."error(scan failed):$(error)icon + "Scan encountered an error." +[$(settings-gear) Open SecureCycle Settings]deep-link- State is driven by the
vibesec.panelStatecontext key, set viavscode.commands.executeCommand("setContext", ...)inextension.tson every state transition
- Finding nodes are now two-level: a compact primary row and an expandable description child
- Primary row (
vibesecFinding):Line Nas the label,CATEGORYas the dimmed description — the most important identifiers are visible at a glance without reading the full message - Description child (
vibesecFindingDetail): full finding message, expanded on demand — keeps the panel scannable when there are many findings - Clicking the primary row still navigates to the finding in the editor; clicking the arrow expands the description
- New
vibesec.copyDescriptioncommand registered inextension.ts - A
$(copy)inline button appears on the description child row when hovered — one click copies the full finding message to the clipboard - Also available via right-click → Copy Description context menu on description nodes
- Both wired via
contributes.menus["view/item/inline"]and["view/item/context"]scoped toviewItem == vibesecFindingDetail
- All severity icons (
error,warning,info) are now rendered withvscode.ThemeColorapplied to theirThemeIcon— the icon tint matches the severity - Three custom color tokens contributed via
contributes.colors:vibesec.errorForeground— defaults match VS Code'serrorForeground(#F48771 dark / #E51400 light)vibesec.warningForeground— matcheseditorWarning.foreground(#CCA700 dark / #915100 light)vibesec.infoForeground— matcheseditorInfo.foreground(#75BEFF dark / #306EAD light)
- File node icons (
file-code) are tinted with the worst severity color in that file — a file with any error shows a red icon; a warning-only file shows yellow - Colors are consistent with VS Code's native diagnostic squiggles by design
- Findings within each file are now sorted: errors first → warnings → info → then by ascending line number within each severity tier
- Files are sorted by most findings first, then alphabetically by filename — the noisiest files surface to the top automatically
- Finding primary rows show a short uppercase category tag derived from the rule ID (e.g.
vibesec.command-injection-os-system→COMMAND-INJECTION,vibesec.weak-hash-md5-python→WEAK-HASH) - Implemented in
formatRuleCategory()infindingsProvider.ts— strips thevibesec.prefix and takes the first two dash-segments
- File nodes now show the parent directory name in their description: e.g.
test-samples · 4 issuesinstead of just4 issues - Helps distinguish files with the same name in different directories when scanning across a project
- Description child tooltips include a bold severity header (
$(error) **ERROR — vibesec.rule-id**), the full message, and a language-tagged code block for the snippet — Python snippets get Python syntax highlighting, TypeScript gets TypeScript, etc. - Severity is stated in plain text in the tooltip header, not conveyed by color alone
- Both file nodes and finding nodes now set
item.accessibilityInformationso screen readers announce useful descriptions instead of raw label/description strings:- File node:
"insecure.py, 4 issues, worst severity error" - Finding node:
"error, line 12, COMMAND-INJECTION" - Description child:
"Description: Command injection via subprocess.run(shell=True)..."
- File node:
Three new user-configurable settings, accessible from Settings → SecureCycle:
| Setting | Type | Default | Description |
|---|---|---|---|
vibesec.semgrepPath |
string | "semgrep" |
Path to the Semgrep binary for non-standard installs |
vibesec.autoScanOnSave |
boolean | false |
Auto-scan on file save — opt-in only |
vibesec.showInlineDecorations |
boolean | true |
Toggle inline squiggles on/off without disabling the panel |
semgrepPathis scopedmachine-overridable(can be set per-machine or per-workspace)autoScanOnSaveandshowInlineDecorationsare scopedresource(can vary per workspace folder)
- New
vscode.workspace.onDidSaveTextDocumentlistener inextension.ts - Only triggers when
vibesec.autoScanOnSaveistrue(off by default) and the saved document is the currently active file - Re-reads the setting on every save event — toggling the setting takes effect immediately without reloading VS Code
- Reuses the existing
vibesec.scanCurrentFilecommand rather than duplicating scan logic
- When
vibesec.showInlineDecorationsisfalse, the scan command callsdiagnosticCollection.delete()instead ofset()— the Findings panel still populates normally, but no squiggles appear in the editor
scanFile()inscanner.tsnow accepts an optionalsemgrepPathparameter (default:"semgrep") passed through toexecFile()- The
extension.tsscan command readsvibesec.semgrepPathfrom settings and forwards it on every scan
- New
contributes.walkthroughsentry inpackage.json— appears in VS Code's Help → Get Started tab on first install - Three guided steps:
- Install Semgrep — pip/brew install instructions, link to open terminal (no completion event — can't detect install)
- Run your first scan — auto-checks when the user runs
vibesec.scanCurrentFilefor the first time - Customize with a policy file — auto-checks when the user runs
vibesec.openPolicyFile
- Step content sourced from
media/walkthrough/install.md,scan.md, andpolicy.md - Walkthrough is re-openable anytime from the Welcome tab or
Welcome: Open Walkthroughin the command palette — does not appear on every launch
- New
UI_STYLE_GUIDE.mdat the repo root documenting the complete design system for future sprints:- Color tokens and their WCAG rationale
- Icon system (codicons + custom SVG)
- Typography conventions (label vs. description vs. tooltip)
- Sorting rules
- Accessibility requirements (contrast, screen-reader, keyboard, color-independence)
- Empty/error state patterns
- Settings reference
- Guidelines for extending the design system in future sprints
- Version bumped
0.2.0→0.3.0 - All commands now have
"category": "SecureCycle"— they group cleanly in the command palette - Added
vibesec.scanPanelview,scanSelected,refreshScanTree,copyDescriptioncommands viewscontainer changed from"explorer"to"vibesec"activity bar with dedicated icon- Added
viewsWelcomeentries,commandPalettehiding for internal commands, color contributions, configuration settings, walkthrough
- Added
FolderNode— tree hierarchy is now Folder → File → Finding → FindingDetail severityIcon()appliesvscode.ThemeColorto eachThemeIcon- Sorting: error → warning → info → line number within files; most findings first across files
- File icons tinted with worst severity; folder icons tinted similarly
- Compact primary row (Line N + category) with expandable description child
getViewMessage()returnsundefined—viewsWelcomehandles all empty states
- New
runScanOnFile()shared helper —scanCurrentFileandscanSelectedfunnel through it - New
ScanProvider+ scan tree view withcanSelectMany: true - Filesystem watcher keeps scan tree in sync
updatePanel()drivessetContextforviewsWelcomewhen-clauses- Reads
semgrepPath,autoScanOnSave,showInlineDecorationsfrom settings
scanFile()signature extended with an optionalsemgrepPath: string = "semgrep"parameterexecFile("semgrep", ...)replaced withexecFile(semgrepPath, ...)— the only line changed
- Severity is communicated through three independent layers: icon shape (circle-X / triangle / circle-i), text label (category + line), and color — color is never the sole indicator
- Custom color tokens inherit VS Code's WCAG AA-compliant diagnostic color defaults for dark, light, and both high-contrast themes
accessibilityInformationis set on all tree nodes- Keyboard navigation works natively via VS Code's TreeView (arrow keys, Enter to activate, F6 to focus panel toolbar)
Adds a full policy configuration system, a dedicated Findings side panel, and a bundled ruleset — turning SecureCycle from a basic scanner into a configurable, team-ready security tool.
- New
policy.tsmodule — loads and validates a.vibesec.yamlfile from the workspace root - Supports presets (e.g.
vibesec:default) to activate bundled or registry rule packs - Supports severity filtering via
minSeverity(error / warning / info) and per-rule overrides - Supports inline custom rules in Semgrep format directly inside the policy file
- Supports external rule files (workspace-relative YAML paths via
externalRuleFiles) - Supports file exclusion patterns (glob-based, e.g.
**/node_modules/**,**/*.test.ts) - Policy is cached per workspace — no re-parsing on every scan
- Always returns a usable config even if the file is missing or invalid (graceful degradation with error messages)
- New command:
SecureCycle: Reload Policy— force-reloads.vibesec.yamlfrom disk - New command:
SecureCycle: Open Policy File— creates or opens.vibesec.yamlwith a starter template
- New
findingsProvider.tsmodule — implements a VS Code side panel under the Explorer - Findings are grouped by file in a collapsible tree
- Each finding shows severity icon, rule ID, message, and line number
- Click a finding to jump directly to its location in the editor
- Hover a finding for a rich markdown tooltip (rule ID, full message, code snippet)
- Panel badge shows total finding count
- Contextual empty-state messages guide the user when no scan has run or no issues were found
- New command:
SecureCycle: Go to Finding(used internally by tree-click navigation)
- ~30 rules included out of the box — no internet connection required
- Covers OWASP Top 10 categories:
- A03 Injection — command injection (
subprocess,os.system,child_process), SQL injection, code injection (eval,exec) - A02 Cryptographic Failures — weak hashing (MD5, SHA-1)
- A07 Auth Failures — hardcoded passwords, API keys, secrets, tokens
- A08 Integrity Failures — insecure deserialization (
pickle), unsafe YAML load - XSS —
innerHTML,document.write,outerHTMLassignment - A05 Misconfiguration — Flask
debug=True, CORS allow-all - A06 Outdated Components —
random.random()(Python),Math.random()(JS) - A04 Insecure Design — path traversal (
open,readFile)
- A03 Injection — command injection (
- Rules cover Python, JavaScript, and TypeScript
- Each rule includes CWE mapping, OWASP category, confidence level, and a human-readable message
- Referenced via the
vibesec:defaultpreset in.vibesec.yaml
test-samples/.vibesec.yaml— example policy usingvibesec:defaultpreset with severity filters and exclusionstest-samples/.vibesec-custom.yaml— example policy with custom inline rules only (no presets)test-samples/custom-rules.yaml— example external rule file with hardcoded secret, SQL injection, and insecure random detections
js-yaml(^4.1.0) — YAML parsing for policy files and rule filesminimatch(^9.0.4) — glob pattern matching for file exclusion
scanFile()now accepts aPolicyConfigand extension path as arguments (previously only took a file path)- Removed
configForFile()— the old function that picked Semgrep registry rules based on file extension (e.g.r/python.lang.security). Config is now fully driven by the policy file - Added
buildConfigArgs()— constructs--configarguments from active presets and custom rules - Added
resolvePreset()— mapsvibesec:preset names to bundled rule file paths - Added
writeTempRuleFile()— serializes inline custom rules to a temp JSON file for Semgrep, then cleans up after scan - Added
effectiveSeverity()— applies per-rule severity overrides from policy - Added
meetsMinSeverity()— filters findings below theminSeveritythreshold - Added
cleanRuleId()— strips path prefixes from Semgrep rule IDs for cleaner display
- Now manages a policy cache (
Map<string, PolicyConfig>) keyed by workspace root - Checks file exclusion patterns before scanning — skips excluded files with a notification
- Passes loaded policy into
scanFile()on every scan - Added progress notification UI (spinner with "Scanning…" message)
- Added policy error display — shows validation errors from
.vibesec.yamlas warnings - Added inline policy file template (used by the
openPolicyFilecommand) - Now wires up the
FindingsProviderTreeView alongside the existingDiagnosticCollection
- Added
SeverityLeveltype ("error" | "warning" | "info") - Added
SEVERITY_RANKnumeric map for severity comparison - Added
CustomRule— full Semgrep-shaped rule definition (id, message, severity, languages, pattern/patterns) - Added
PatternClause— single pattern expression (pattern, pattern-not, pattern-inside, pattern-regex) - Added
SeveritySettings— minSeverity + per-rule override map - Added
FilePatterns— include/exclude glob arrays - Added
RawPolicy— unvalidated shape of a parsed.vibesec.yaml - Added
PolicyConfig— validated, ready-to-use config object (presets, severity, rules, files, isDefault flag) Findinginterface: unchanged in shape, now typed againstSeverityLevel
configForFile()fromscanner.ts— replaced by the policy-drivenbuildConfigArgs()system. The old approach auto-selected Semgrep registry rule packs based on file extension (e.g..py→r/python.lang.security). This was removed because it required internet access and offered no customization.
src/extension.ts— VS Code entry point; registersvibesec.scanCurrentFilecommand, shows inline squiggles viaDiagnosticCollectionsrc/scanner.ts— Semgrep CLI runner;scanFile(filePath)executes Semgrep and returns findings;configForFile()picked rule packs by file extension;parseSemgrepOutput()converts JSON toFinding[]src/types.ts—Findinginterface (ruleId, message, severity, filePath, line/col range, snippet)test-samples/insecure.py— intentionally vulnerable Python file for testing (command injection, weak hash, hardcoded secret, SQL injection)package.json,tsconfig.json,.vscodeignore,package-lock.json.vscode/launch.json— F5 debug launcher (Extension Development Host)