Skip to content
Open
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
4 changes: 4 additions & 0 deletions vscode/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## [Unreleased]

### Added
- `bawbel.aveApiUrl` setting: the base URL for AVE record links (default
https://api.aveproject.org). A value that is not an http(s) URL falls back to the default.

### Fixed
- Hover shows the OWASP AIVSS score (`aivss_score`) as `AIVSS: x/10`. It read the
retired `cvss_ai` field, which bawbel-scanner no longer emits, and showed
Expand Down
1 change: 1 addition & 0 deletions vscode/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ To remove: right-click the faded hint → **Remove suppression**.
| `bawbel.failOnSeverity` | `high` | Minimum severity shown as error squiggle |
| `bawbel.scanExtensions` | `[.md,.yaml,.yml,.json,.txt]` | Extensions to auto-scan |
| `bawbel.bawbelPath` | `""` | Path to bawbel binary (auto-detected if empty) |
| `bawbel.aveApiUrl` | `https://api.aveproject.org` | Base URL of the AVE records API; finding links open `<base>/records/<AVE ID>`. Must be http(s) |
| `bawbel.showStatusBar` | `true` | Show status bar item |

---
Expand Down
7 changes: 7 additions & 0 deletions vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,13 @@
"default": "",
"description": "Absolute path to the bawbel binary. Leave empty to auto-detect (checks PATH and common pip install locations)."
},
"bawbel.aveApiUrl": {
"type": "string",
"default": "https://api.aveproject.org",
"pattern": "^https?://",
"patternErrorMessage": "Must be an http:// or https:// URL.",
"description": "Base URL of the AVE records API. Finding links open <base>/records/<AVE ID>. A value that is not an http(s) URL is ignored and the default is used."
},
"bawbel.showStatusBar": {
"type": "boolean",
"default": true,
Expand Down
24 changes: 24 additions & 0 deletions vscode/src/core/links.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* core/links.ts: Bawbel VS Code Extension
*
* The one place that turns settings into AVE links. Call sites never build a records
* URL by hand.
*/

import * as vscode from "vscode";
import { aveRecordUrl, resolveAveApiUrl } from "./urls";

/** The AVE API base URL: the bawbel.aveApiUrl setting, validated, or the default. */
export function aveApiUrl(): string {
return resolveAveApiUrl(vscode.workspace.getConfiguration("bawbel").get("aveApiUrl"));
}

/** The link to one AVE record. */
export function aveRecordLink(aveId: string): string {
return aveRecordUrl(aveApiUrl(), aveId);
}

/** The link to the AVE records list. */
export function aveRecordsIndexLink(): string {
return `${aveApiUrl()}/records`;
}
2 changes: 1 addition & 1 deletion vscode/src/core/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export type StatusState =
export const SUPPRESS_FILE = ".bawbel-suppress.json";
export const OUTPUT_CHANNEL = "Bawbel Scanner";
export const EXTENSION_ID = "bawbel.bawbel-scanner";
export const AVE_RECORDS_BASE = "https://api.aveproject.org";
export const DEFAULT_AVE_API_URL = "https://api.aveproject.org"; // setting: bawbel.aveApiUrl
export const MARKETPLACE_URL = "https://marketplace.visualstudio.com/items?itemName=bawbel.bawbel-scanner";

export const SCAN_EXTENSIONS_DEFAULT = [".md", ".yaml", ".yml", ".json", ".txt"];
Expand Down
33 changes: 33 additions & 0 deletions vscode/src/core/urls.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* core/urls.ts: Bawbel VS Code Extension
*
* Pure URL helpers. No vscode import, so they run and can be checked in plain Node.
* core/links.ts reads the settings and calls these.
*/

import { DEFAULT_AVE_API_URL } from "./types";

/**
* The AVE API base URL to use for a raw setting value. The value is parsed as a URL and
* must be http(s) with a host; the result is rebuilt from origin and path (percent-encoded,
* no query or fragment, no trailing slash). Anything else gives DEFAULT_AVE_API_URL, so a
* bad setting never produces a link to an unexpected scheme or a broken HTML attribute.
*/
export function resolveAveApiUrl(raw: unknown): string {
if (typeof raw === "string") {
try {
const url = new URL(raw.trim());
if ((url.protocol === "https:" || url.protocol === "http:") && url.hostname) {
return `${url.origin}${url.pathname}`.replace(/\/+$/, "");
}
} catch {
// not a URL: fall through to the default
}
}
return DEFAULT_AVE_API_URL;
}

/** The URL of one AVE record under base. */
export function aveRecordUrl(base: string, aveId: string): string {
return `${base}/records/${encodeURIComponent(aveId)}`;
}
4 changes: 2 additions & 2 deletions vscode/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ import {
SCAN_EXTENSIONS_DEFAULT,
OUTPUT_CHANNEL,
SUPPRESS_FILE,
AVE_RECORDS_BASE,
} from "./core/types";
import { aveRecordsIndexLink } from "./core/links";

import { Scanner, autoScanRequest, fullWorkspaceScanRequest, fullFolderScanRequest } from "./features/scanner";
import { DiagnosticsManager } from "./features/diagnostics";
Expand Down Expand Up @@ -260,7 +260,7 @@ async function cmdInstallCLI(): Promise<void> {
}

function cmdOpenAveRecords(): void {
vscode.env.openExternal(vscode.Uri.parse(`${AVE_RECORDS_BASE}/records`));
vscode.env.openExternal(vscode.Uri.parse(aveRecordsIndexLink()));
}

// ── Event handlers ────────────────────────────────────────────────────────────
Expand Down
5 changes: 3 additions & 2 deletions vscode/src/features/codeActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@

import * as path from "path";
import * as vscode from "vscode";
import { BawbelFinding, AVE_RECORDS_BASE, SUPPRESS_FILE } from "../core/types";
import { BawbelFinding, SUPPRESS_FILE } from "../core/types";
import { aveRecordLink } from "../core/links";
import { isSuppressed, loadSuppressions } from "../core/suppressions";
import { DiagnosticsManager } from "./diagnostics";

Expand Down Expand Up @@ -157,7 +158,7 @@ export class BawbelCodeActionProvider implements vscode.CodeActionProvider {
details.command = {
command: "vscode.open",
title: "Open AVE record",
arguments: [vscode.Uri.parse(`${AVE_RECORDS_BASE}/records/${aveId}`)],
arguments: [vscode.Uri.parse(aveRecordLink(aveId))],
};
actions.push(details);
}
Expand Down
8 changes: 4 additions & 4 deletions vscode/src/features/diagnostics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ import {
BawbelFileResult,
SEVERITY_INDEX,
SEVERITY_EMOJI,
AVE_RECORDS_BASE,
SUPPRESS_FILE,
} from "../core/types";
import { aveRecordLink } from "../core/links";
import { getRemediation, hasSpecificRemediation } from "../core/remediation";
import { isSuppressed, loadSuppressions } from "../core/suppressions";

Expand Down Expand Up @@ -235,14 +235,14 @@ export class DiagnosticsManager {
`Engine: ${f.engine}`,
].filter(Boolean).join(" | "),
owasp ? `OWASP: ${owasp}` : "",
`Details: ${AVE_RECORDS_BASE}/records/${f.ave_id}`,
`Details: ${aveRecordLink(f.ave_id)}`,
].filter(s => s !== undefined).join("\n");

const diag = new vscode.Diagnostic(range, message, vsSev);
diag.source = "Bawbel";
diag.code = {
value: f.ave_id,
target: vscode.Uri.parse(`${AVE_RECORDS_BASE}/records/${f.ave_id}`),
target: vscode.Uri.parse(aveRecordLink(f.ave_id)),
};

if (f.severity === "LOW") {
Expand All @@ -267,7 +267,7 @@ export class DiagnosticsManager {
diag.tags = [vscode.DiagnosticTag.Unnecessary];
diag.code = {
value: f.ave_id,
target: vscode.Uri.parse(`${AVE_RECORDS_BASE}/records/${f.ave_id}`),
target: vscode.Uri.parse(aveRecordLink(f.ave_id)),
};
return diag;
}
Expand Down
3 changes: 2 additions & 1 deletion vscode/src/ui/reportPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*/

import * as vscode from "vscode";
import { aveRecordsIndexLink } from "../core/links";
import { runCommand } from "../core/cli";
import { BawbelFileResult } from "../core/types";

Expand Down Expand Up @@ -129,7 +130,7 @@ export class ReportPanel {
<body>
<h2>Bawbel Report — ${escapeHtml(name)}</h2>
${html}
<p class="meta">Generated by bawbel report · <a href="https://api.aveproject.org/records">AVE records</a></p>
<p class="meta">Generated by bawbel report · <a href="${escapeHtml(aveRecordsIndexLink())}">AVE records</a></p>
</body>
</html>`;
}
Expand Down
Loading