fix: switch pairing setup codes to bootstrap tokens

This commit is contained in:
Peter Steinberger
2026-03-12 22:22:44 +00:00
parent 9cd54ea882
commit bf89947a8e
53 changed files with 1035 additions and 106 deletions

View File

@@ -27,6 +27,12 @@ vi.mock("../process/exec.js", () => ({ runCommandWithTimeout: mocks.runCommandWi
vi.mock("./command-secret-gateway.js", () => ({
resolveCommandSecretRefsViaGateway: mocks.resolveCommandSecretRefsViaGateway,
}));
vi.mock("../infra/device-bootstrap.js", () => ({
issueDeviceBootstrapToken: vi.fn(async () => ({
token: "bootstrap-123",
expiresAtMs: 123,
})),
}));
vi.mock("qrcode-terminal", () => ({
default: {
generate: mocks.qrGenerate,
@@ -156,7 +162,7 @@ describe("registerQrCli", () => {
const expected = encodePairingSetupCode({
url: "ws://gateway.local:18789",
token: "tok",
bootstrapToken: "bootstrap-123",
});
expect(runtime.log).toHaveBeenCalledWith(expected);
expect(qrGenerate).not.toHaveBeenCalled();
@@ -194,7 +200,7 @@ describe("registerQrCli", () => {
const expected = encodePairingSetupCode({
url: "ws://gateway.local:18789",
token: "override-token",
bootstrapToken: "bootstrap-123",
});
expect(runtime.log).toHaveBeenCalledWith(expected);
});
@@ -210,7 +216,7 @@ describe("registerQrCli", () => {
const expected = encodePairingSetupCode({
url: "ws://gateway.local:18789",
token: "override-token",
bootstrapToken: "bootstrap-123",
});
expect(runtime.log).toHaveBeenCalledWith(expected);
});
@@ -227,7 +233,7 @@ describe("registerQrCli", () => {
const expected = encodePairingSetupCode({
url: "ws://gateway.local:18789",
password: "local-password-secret", // pragma: allowlist secret
bootstrapToken: "bootstrap-123",
});
expect(runtime.log).toHaveBeenCalledWith(expected);
expect(resolveCommandSecretRefsViaGateway).not.toHaveBeenCalled();
@@ -245,7 +251,7 @@ describe("registerQrCli", () => {
const expected = encodePairingSetupCode({
url: "ws://gateway.local:18789",
password: "password-from-env", // pragma: allowlist secret
bootstrapToken: "bootstrap-123",
});
expect(runtime.log).toHaveBeenCalledWith(expected);
expect(resolveCommandSecretRefsViaGateway).not.toHaveBeenCalled();
@@ -264,7 +270,7 @@ describe("registerQrCli", () => {
const expected = encodePairingSetupCode({
url: "ws://gateway.local:18789",
token: "token-123",
bootstrapToken: "bootstrap-123",
});
expect(runtime.log).toHaveBeenCalledWith(expected);
expect(resolveCommandSecretRefsViaGateway).not.toHaveBeenCalled();
@@ -282,7 +288,7 @@ describe("registerQrCli", () => {
const expected = encodePairingSetupCode({
url: "ws://gateway.local:18789",
password: "inferred-password", // pragma: allowlist secret
bootstrapToken: "bootstrap-123",
});
expect(runtime.log).toHaveBeenCalledWith(expected);
expect(resolveCommandSecretRefsViaGateway).not.toHaveBeenCalled();
@@ -332,7 +338,7 @@ describe("registerQrCli", () => {
const expected = encodePairingSetupCode({
url: "wss://remote.example.com:444",
token: "remote-tok",
bootstrapToken: "bootstrap-123",
});
expect(runtime.log).toHaveBeenCalledWith(expected);
expect(resolveCommandSecretRefsViaGateway).toHaveBeenCalledWith(
@@ -375,7 +381,7 @@ describe("registerQrCli", () => {
).toBe(true);
const expected = encodePairingSetupCode({
url: "wss://remote.example.com:444",
token: "remote-tok",
bootstrapToken: "bootstrap-123",
});
expect(runtime.log).toHaveBeenCalledWith(expected);
});

View File

@@ -66,12 +66,22 @@ function createGatewayTokenRefFixture() {
};
}
function decodeSetupCode(setupCode: string): { url?: string; token?: string; password?: string } {
function decodeSetupCode(setupCode: string): {
url?: string;
bootstrapToken?: string;
token?: string;
password?: string;
} {
const padded = setupCode.replace(/-/g, "+").replace(/_/g, "/");
const padLength = (4 - (padded.length % 4)) % 4;
const normalized = padded + "=".repeat(padLength);
const json = Buffer.from(normalized, "base64").toString("utf8");
return JSON.parse(json) as { url?: string; token?: string; password?: string };
return JSON.parse(json) as {
url?: string;
bootstrapToken?: string;
token?: string;
password?: string;
};
}
async function runCli(args: string[]): Promise<void> {
@@ -126,7 +136,8 @@ describe("cli integration: qr + dashboard token SecretRef", () => {
expect(setupCode).toBeTruthy();
const payload = decodeSetupCode(setupCode ?? "");
expect(payload.url).toBe("ws://gateway.local:18789");
expect(payload.token).toBe("shared-token-123");
expect(payload.bootstrapToken).toBeTruthy();
expect(payload.token).toBeUndefined();
expect(runtimeErrors).toEqual([]);
runtimeLogs.length = 0;