Skip to content
Merged
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
5 changes: 5 additions & 0 deletions .vscodeignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ node_modules
server
test/
img/
docs/
CLAUDE.md
build-api.js
qcumber.q
secure-processes.md
qcumber.sh
esbuild.mjs
sonar-project.properties
Expand Down
16 changes: 10 additions & 6 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
---
type: Index
title: kdb VS Code Extension Docs
description: In-tree documentation for the kdb VS Code extension, split into user notes and developer notes.
description:
In-tree documentation for the kdb VS Code extension, split into user notes and
developer notes.
tags: [kdb, vscode, documentation]
timestamp: 2026-07-10
---

# kdb VS Code Extension Docs
# kdb VS Code Extension Wiki

Welcome to the developer and user documentation for the
[kdb VS Code extension](https://marketplace.visualstudio.com/items?itemName=KX.kdb).
This is the in-repo wiki for the
[kdb VS Code extension](https://marketplace.visualstudio.com/items?itemName=KX.kdb),
covering developer and user notes.

These docs follow the [Open Knowledge Format](https://cloud.google.com/blog/products/data-analytics/how-the-open-knowledge-format-can-improve-data-sharing/):
These pages follow the
[Open Knowledge Format](https://cloud.google.com/blog/products/data-analytics/how-the-open-knowledge-format-can-improve-data-sharing/):
plain markdown files with YAML frontmatter, `index.md` files for navigation, and
relative cross-links. They were ported from the project's
[GitHub wiki](https://github.com/KxSystems/kx-vscode/wiki).

> The end-user product documentation is hosted separately at
> <https://gitlab.com/kxdev/documentation/vscode-docs/>.
> <https://code.kx.com/vscode/>.

## User Notes

Expand Down
19 changes: 14 additions & 5 deletions src/commands/serverCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ import {
workspaceHas,
} from "../utils/workspace";
import {
validateInsightsServerUrl,
validateServerAlias,
validateServerName,
validateServerPort,
Expand Down Expand Up @@ -120,8 +121,14 @@ export async function addInsightsConnection(
notify(aliasValidation, MessageKind.ERROR, { logger });
return;
}
const serverValidation = validateInsightsServerUrl(insightsData.server);
if (serverValidation) {
notify(serverValidation, MessageKind.ERROR, { logger });
return;
}
const server = insightsData.server!.trim();
if (insightsData.alias === undefined || insightsData.alias === "") {
const host = new url.URL(insightsData.server!);
const host = new url.URL(server);
insightsData.alias = host.host;
}

Expand All @@ -138,10 +145,6 @@ export async function addInsightsConnection(
return;
} else {
const key = insightsData.alias;
let server = insightsData.server || "";
if (!/^https?:\/\//i.exec(server)) {
server = "https://" + server;
}
if (insights === undefined) {
insights = {
key: {
Expand Down Expand Up @@ -201,6 +204,12 @@ export async function editInsightsConnection(
notify(aliasValidation, MessageKind.ERROR, { logger });
return;
}
const serverValidation = validateInsightsServerUrl(insightsData.server);
if (serverValidation) {
notify(serverValidation, MessageKind.ERROR, { logger });
return;
}
insightsData.server = insightsData.server.trim();
const isConnectedConn = isConnected(oldAlias);
await disconnect(oldAlias);
if (insightsData.alias === undefined || insightsData.alias === "") {
Expand Down
2 changes: 1 addition & 1 deletion src/services/dataSourceEditorProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export class DataSourceEditorProvider implements CustomTextEditorProvider {
} catch {
notify(
"No database running in this Insights connection.",
MessageKind.ERROR,
MessageKind.WARNING,
{ logger },
);
meta = Promise.resolve(<MetaObjectPayload>{});
Expand Down
2 changes: 1 addition & 1 deletion src/services/kdbInsights/codeFlowLogin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ async function getAuthPrefix(
insightsUrl,
).toString(),
{
maxRedirects: 0,
maxRedirects: 5,
validateStatus: () => true,
transformResponse: (res) => res,
responseType: "json",
Expand Down
12 changes: 12 additions & 0 deletions src/validators/kdbValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,18 @@ export function validateServerPassword(
return undefined;
}

export function validateInsightsServerUrl(
input: string | undefined,
): string | undefined {
if (input === undefined || input.trim() === "") {
return "Insights connection address is required.";
}
if (!/^https:\/\//i.exec(input.trim())) {
return "Insights connections require a secure https:// URL (for example, https://myinsights.example.com).";
}
return undefined;
}

export function validateTls(input: string | undefined): string | undefined {
if (input !== undefined && input !== "") {
if (!validateUtils.isBoolean(input)) {
Expand Down
2 changes: 1 addition & 1 deletion src/webview/components/kdbNewConnectionView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ export class KdbNewConnectionView extends LitElement {
class="text-field larger option-title"
placeholder="${serverType === ServerType.KDB
? "127.0.0.1 or localhost"
: `myinsights.clouddeploy.com`}"
: `https://myinsights.example.com`}"
Comment thread
bjeffery-kx marked this conversation as resolved.
value="${live(
serverType === ServerType.KDB
? this.kdbServer.serverName
Expand Down
39 changes: 39 additions & 0 deletions test/suite/commands/serverCommand.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,45 @@ describe("serverCommand", () => {
sinon.match.any,
);
});

it("should reject an insecure http:// Insights URL", async () => {
getInsightsStub.returns({});
insightsData.server = "http://insightsservername.com/";
await serverCommand.addInsightsConnection(insightsData);
sinon.assert.notCalled(updateInsightsStub);
sinon.assert.calledWithExactly(
notifyStub,
sinon.match(/require a secure https:\/\/ URL/),
sinon.match.any,
sinon.match.any,
);
});

it("should reject an Insights URL with no protocol", async () => {
getInsightsStub.returns({});
insightsData.server = "insightsservername.com";
await serverCommand.addInsightsConnection(insightsData);
sinon.assert.notCalled(updateInsightsStub);
sinon.assert.calledWithExactly(
notifyStub,
sinon.match(/require a secure https:\/\/ URL/),
sinon.match.any,
sinon.match.any,
);
});

it("should reject an empty Insights URL", async () => {
getInsightsStub.returns({});
insightsData.server = "";
await serverCommand.addInsightsConnection(insightsData);
sinon.assert.notCalled(updateInsightsStub);
sinon.assert.calledWithExactly(
notifyStub,
"Insights connection address is required.",
sinon.match.any,
sinon.match.any,
);
});
});

describe("addKdbConnection", () => {
Expand Down
2 changes: 1 addition & 1 deletion test/suite/webPanels/webViews/kdbNewConnectionView.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ describe("KdbNewConnectionView", () => {
it("should render connection address for Insights", () => {
const result = view.renderConnAddress(ServerType.INSIGHTS);
assert.strictEqual(
JSON.stringify(result).includes("myinsights.clouddeploy.com"),
JSON.stringify(result).includes("https://myinsights.example.com"),
true,
);
});
Expand Down
Loading