mirror of
https://github.com/nexu-io/open-design.git
synced 2026-09-20 06:15:06 +08:00
85d2e4893c
* fix(amr): recover expired cloud sessions * fix(diagnostics): redact dynamic API routes * fix(daemon): honor settings in AMR diagnostics * fix(daemon): align workspace auth revisions * fix(web): gate expired cloud sessions on sign-in * fix(web): scope cloud sign-in gate to cloud execution * test(web): align cloud auth fixture * fix(web): recover transient run authority failures * test(daemon): expect retryable authority detail * test(e2e): align BYOK auth boundary * test(e2e): align expired cloud recovery flows
86 lines
3.1 KiB
TypeScript
86 lines
3.1 KiB
TypeScript
import { mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
|
|
import JSZip from "jszip";
|
|
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
|
|
import { buildDiagnosticsZip } from "../src/zip.js";
|
|
|
|
let tempDir: string;
|
|
|
|
beforeEach(async () => {
|
|
tempDir = await mkdtemp(join(tmpdir(), "diagnostics-test-"));
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await rm(tempDir, { recursive: true, force: true });
|
|
});
|
|
|
|
describe("buildDiagnosticsZip", () => {
|
|
it("packages logs with redacted manifest and machine info", async () => {
|
|
const logPath = join(tempDir, "daemon.log");
|
|
await writeFile(logPath, "GET /api?token=abc123 ok\n", "utf8");
|
|
|
|
const result = await buildDiagnosticsZip({
|
|
context: {
|
|
app: { name: "open-design", version: "1.2.3", packaged: false },
|
|
source: "test",
|
|
namespace: "default",
|
|
},
|
|
sources: [{ name: "logs/daemon/latest.log", absolutePath: logPath, kind: "text" }],
|
|
redaction: { username: "alice" },
|
|
});
|
|
|
|
const zip = await JSZip.loadAsync(result.zip);
|
|
const log = await zip.file("logs/daemon/latest.log")!.async("string");
|
|
expect(log).toContain("token=[REDACTED]");
|
|
|
|
const manifest = JSON.parse(await zip.file("summary/manifest.json")!.async("string"));
|
|
expect(manifest.app.name).toBe("open-design");
|
|
expect(manifest.namespace).toBe("default");
|
|
expect(manifest.files[0].name).toBe("logs/daemon/latest.log");
|
|
expect(manifest.warnings).toEqual([]);
|
|
|
|
const machine = JSON.parse(await zip.file("summary/machine-info.json")!.async("string"));
|
|
expect(typeof machine.platform).toBe("string");
|
|
expect(machine.hostname).toBe("[REDACTED]");
|
|
expect(machine.username).toBe("[REDACTED]");
|
|
});
|
|
|
|
it("includes redacted in-memory summaries for failures that happened before a run existed", async () => {
|
|
const result = await buildDiagnosticsZip({
|
|
context: { app: { name: "open-design" }, source: "test" },
|
|
sources: [],
|
|
redaction: { username: "alice" },
|
|
summaries: {
|
|
"runtime-health.json": {
|
|
amr: { sessionState: "reauth_required", credentialRevision: "safe-digest" },
|
|
note: "/Users/alice/private",
|
|
},
|
|
},
|
|
});
|
|
|
|
const zip = await JSZip.loadAsync(result.zip);
|
|
const runtimeHealth = await zip.file("summary/runtime-health.json")!.async("string");
|
|
expect(runtimeHealth).toContain('"sessionState": "reauth_required"');
|
|
expect(runtimeHealth).toContain('/Users/<USER>/private');
|
|
expect(runtimeHealth).not.toContain('/Users/alice');
|
|
});
|
|
|
|
it("records a warning placeholder when a file cannot be read", async () => {
|
|
const result = await buildDiagnosticsZip({
|
|
context: {
|
|
app: { name: "open-design" },
|
|
source: "test",
|
|
},
|
|
sources: [{ name: "logs/missing.log", absolutePath: join(tempDir, "no-such.log"), kind: "text" }],
|
|
});
|
|
|
|
const zip = await JSZip.loadAsync(result.zip);
|
|
const placeholder = await zip.file("logs/missing.log")!.async("string");
|
|
expect(placeholder).toContain("file unavailable");
|
|
expect(result.manifest.warnings.length).toBe(1);
|
|
});
|
|
});
|