351 lines
12 KiB
TypeScript
351 lines
12 KiB
TypeScript
import { execFile } from "node:child_process";
|
|
import {
|
|
chmodSync,
|
|
existsSync,
|
|
mkdtempSync,
|
|
mkdirSync,
|
|
readFileSync,
|
|
rmSync,
|
|
statSync,
|
|
symlinkSync,
|
|
writeFileSync,
|
|
} from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { promisify } from "node:util";
|
|
import { afterEach, expect, test, vi } from "vitest";
|
|
import { parse } from "yaml";
|
|
import { WorkspaceRegistry } from "../src/workspaces/registry.js";
|
|
import {
|
|
buildCanonicalEffectiveConfig,
|
|
canonicalEffectiveConfigJson,
|
|
effectiveConfigIdentity,
|
|
} from "../src/workspaces/effective-config.js";
|
|
import type { WorkspaceRegistryConfig } from "../src/workspaces/types.js";
|
|
import {
|
|
publishDeterministicRuntimeConfigLease,
|
|
renderActiveWorkspaceRuntime,
|
|
renderWorkspaceRuntimeFromSnapshotPath,
|
|
} from "../src/workspaces/runtime-config-lease.js";
|
|
|
|
const runFile = promisify(execFile);
|
|
const roots: string[] = [];
|
|
|
|
afterEach(() => {
|
|
vi.unstubAllEnvs();
|
|
roots.splice(0).forEach((root) => rmSync(root, { recursive: true, force: true }));
|
|
});
|
|
|
|
async function git(cwd: string, args: string[]): Promise<string> {
|
|
return (await runFile("git", args, { cwd })).stdout.trim();
|
|
}
|
|
|
|
async function fixture() {
|
|
const root = mkdtempSync(join(tmpdir(), "tht-runtime-lease-"));
|
|
roots.push(root);
|
|
const remote = join(root, "remote.git");
|
|
const source = join(root, "source");
|
|
const registryRoot = join(root, "registry");
|
|
const secretRoot = join(root, "secrets");
|
|
const dataRoot = join(root, "data");
|
|
const harnessDir = join(root, "harness");
|
|
mkdirSync(harnessDir, { recursive: true });
|
|
mkdirSync(join(harnessDir, "config"), { recursive: true });
|
|
writeFileSync(join(harnessDir, "config", "tht.yaml"), `session_storage:
|
|
mode: local
|
|
profile: server
|
|
`);
|
|
|
|
await git(root, ["init", "--bare", "--initial-branch=main", remote]);
|
|
mkdirSync(source);
|
|
await git(source, ["init", "--initial-branch=main"]);
|
|
await git(source, ["config", "user.name", "Runtime Lease Test"]);
|
|
await git(source, ["config", "user.email", "runtime-lease@example.invalid"]);
|
|
writeFileSync(join(source, "thoth-workspaces.yaml"), `schema_version: 1
|
|
workspaces: [{id: psd-clinical, name: Runtime Lease}]
|
|
`);
|
|
mkdirSync(join(source, "psd-clinical", "evidence"), { recursive: true });
|
|
writeFileSync(join(source, "psd-clinical", "workspace.yaml"), `workspace:
|
|
schema_version: 4
|
|
id: psd-clinical
|
|
name: Runtime Lease
|
|
language: en
|
|
dwh:
|
|
engine: postgres
|
|
database: analytics
|
|
schema: mart
|
|
supported_transports: [postgres_direct]
|
|
evidence:
|
|
source:
|
|
type: filesystem
|
|
uri: psd-clinical/evidence
|
|
`);
|
|
writeFileSync(join(source, "psd-clinical", "evidence", "guide.md"), `# hello
|
|
`);
|
|
await git(source, ["add", "."]);
|
|
await git(source, ["commit", "-m", "Canonical workspace"]);
|
|
await git(source, ["remote", "add", "origin", remote]);
|
|
await git(source, ["push", "origin", "main"]);
|
|
|
|
mkdirSync(secretRoot);
|
|
const passwordFile = join(secretRoot, "dwh-password");
|
|
writeFileSync(passwordFile, "secret", { mode: 0o600 });
|
|
chmodSync(passwordFile, 0o600);
|
|
mkdirSync(dataRoot);
|
|
|
|
const registryConfig: WorkspaceRegistryConfig = {
|
|
root: registryRoot,
|
|
remoteUrl: remote,
|
|
branch: "main",
|
|
gitAuthorName: "Runtime Lease Test",
|
|
gitAuthorEmail: "runtime-lease@example.invalid",
|
|
installationId: "test",
|
|
secretRoots: [secretRoot],
|
|
maxImportBytes: 1024 * 1024,
|
|
maxImportEntries: 16,
|
|
};
|
|
const registry = new WorkspaceRegistry(registryConfig);
|
|
await registry.bootstrap();
|
|
const revision = (await registry.list())[0];
|
|
|
|
vi.stubEnv("THT_WS_PSD_CLINICAL_DWH_TRANSPORT", "postgres_direct");
|
|
vi.stubEnv("THT_WS_PSD_CLINICAL_DWH_HOST", "warehouse.internal");
|
|
vi.stubEnv("THT_WS_PSD_CLINICAL_DWH_PORT", "5432");
|
|
vi.stubEnv("THT_WS_PSD_CLINICAL_DWH_USER", "reader");
|
|
vi.stubEnv("THT_WS_PSD_CLINICAL_DWH_PASSWORD_FILE", passwordFile);
|
|
|
|
return {
|
|
dataRoot,
|
|
harnessDir,
|
|
source,
|
|
registry,
|
|
registryConfig,
|
|
revision,
|
|
};
|
|
}
|
|
|
|
const semanticRuntime = {
|
|
internalQdrantUrl: "http://qdrant:6333",
|
|
internalEmbeddingUrl: "http://embedding:11434",
|
|
internalEmbeddingModel: "qwen3-embedding:0.6b",
|
|
internalEmbeddingDimensions: 1024,
|
|
};
|
|
|
|
test("active workspace rendering is byte-identical to direct snapshot rendering", async () => {
|
|
const f = await fixture();
|
|
const direct = renderWorkspaceRuntimeFromSnapshotPath({
|
|
snapshotPath: f.revision.snapshotPath,
|
|
harnessDir: f.harnessDir,
|
|
configPath: "config/tht.yaml",
|
|
dataRoot: f.dataRoot,
|
|
secretRoots: f.registryConfig.secretRoots,
|
|
semanticRuntime,
|
|
});
|
|
const active = await renderActiveWorkspaceRuntime({
|
|
workspaceId: "psd-clinical",
|
|
registry: f.registry,
|
|
registryConfig: f.registryConfig,
|
|
harnessDir: f.harnessDir,
|
|
configPath: "config/tht.yaml",
|
|
dataRoot: f.dataRoot,
|
|
secretRoots: f.registryConfig.secretRoots,
|
|
semanticRuntime,
|
|
});
|
|
|
|
expect(active.renderedConfig).toBe(direct.renderedConfig);
|
|
expect(active.workspaceRevision).toBe(f.revision.commit);
|
|
expect(active.descriptorBlob).toMatch(/^sha256:[0-9a-f]{64}$/);
|
|
expect(active.catalogBlob).toMatch(/^sha256:[0-9a-f]{64}$/);
|
|
});
|
|
|
|
test("renders a revision-qualified annotations root for the active revision", async () => {
|
|
const f = await fixture();
|
|
const active = await renderActiveWorkspaceRuntime({
|
|
workspaceId: "psd-clinical",
|
|
registry: f.registry,
|
|
registryConfig: f.registryConfig,
|
|
harnessDir: f.harnessDir,
|
|
configPath: "config/tht.yaml",
|
|
dataRoot: f.dataRoot,
|
|
secretRoots: f.registryConfig.secretRoots,
|
|
semanticRuntime,
|
|
});
|
|
const rendered = parse(active.renderedConfig) as Record<string, any>;
|
|
|
|
expect(rendered.paths.annotations_root).toBe(
|
|
join(f.dataRoot, "sessions", "psd-clinical", "revisions", f.revision.commit, "artifacts"),
|
|
);
|
|
expect(rendered.roots.annotations_root).toBe(rendered.paths.annotations_root);
|
|
expect(rendered.paths.artifacts).toBe(join(f.dataRoot, "sessions", "psd-clinical", "artifacts"));
|
|
});
|
|
|
|
test("deterministic operator leases are keyed by logical identity and stable across calls", async () => {
|
|
const f = await fixture();
|
|
const first = await publishDeterministicRuntimeConfigLease({
|
|
workspaceId: "psd-clinical",
|
|
registry: f.registry,
|
|
registryConfig: f.registryConfig,
|
|
harnessDir: f.harnessDir,
|
|
configPath: "config/tht.yaml",
|
|
dataRoot: f.dataRoot,
|
|
secretRoots: f.registryConfig.secretRoots,
|
|
semanticRuntime,
|
|
});
|
|
const second = await publishDeterministicRuntimeConfigLease({
|
|
workspaceId: "psd-clinical",
|
|
registry: f.registry,
|
|
registryConfig: f.registryConfig,
|
|
harnessDir: f.harnessDir,
|
|
configPath: "config/tht.yaml",
|
|
dataRoot: f.dataRoot,
|
|
secretRoots: f.registryConfig.secretRoots,
|
|
semanticRuntime,
|
|
});
|
|
|
|
const suffix = first.inputFingerprint.slice(7, 23);
|
|
expect(second.path).toBe(first.path);
|
|
expect(first.path).toBe(join(
|
|
f.dataRoot,
|
|
"sessions",
|
|
"psd-clinical",
|
|
"preprocessing",
|
|
"runtime-config",
|
|
`${f.revision.commit}-${suffix}.yaml`,
|
|
));
|
|
expect(statSync(first.path).mode & 0o777).toBe(0o400);
|
|
expect(statSync(first.manifestPath).mode & 0o777).toBe(0o600);
|
|
expect(readFileSync(first.path, "utf8")).toContain("collection_lifecycle: require_existing");
|
|
expect(readFileSync(first.path, "utf8")).toContain("memory:");
|
|
expect(existsSync(first.manifestPath)).toBe(true);
|
|
expect(first.effectiveConfigIdentity).toMatch(/^workspace:\/\/psd-clinical@v1:[0-9a-f]{64}$/);
|
|
expect(first.configFingerprint).toMatch(/^sha256:[0-9a-f]{64}$/);
|
|
expect(first.inputFingerprint).toMatch(/^sha256:[0-9a-f]{64}$/);
|
|
expect(first.inputFingerprint).not.toBe(first.configFingerprint);
|
|
const manifest = JSON.parse(readFileSync(first.manifestPath, "utf8"));
|
|
expect(manifest).toMatchObject({
|
|
schemaVersion: 1,
|
|
workspaceId: "psd-clinical",
|
|
workspaceRevision: f.revision.commit,
|
|
descriptorBlob: first.descriptorBlob,
|
|
catalogBlob: first.catalogBlob,
|
|
configDigest: first.configDigest,
|
|
bindingDigest: first.bindingDigest,
|
|
effectiveConfigIdentity: first.effectiveConfigIdentity,
|
|
configFingerprint: first.configFingerprint,
|
|
inputFingerprint: first.inputFingerprint,
|
|
path: first.path,
|
|
});
|
|
|
|
vi.stubEnv("THT_WS_PSD_CLINICAL_DWH_HOST", "warehouse-two.internal");
|
|
const changed = await publishDeterministicRuntimeConfigLease({
|
|
workspaceId: "psd-clinical",
|
|
registry: f.registry,
|
|
registryConfig: f.registryConfig,
|
|
harnessDir: f.harnessDir,
|
|
configPath: "config/tht.yaml",
|
|
dataRoot: f.dataRoot,
|
|
secretRoots: f.registryConfig.secretRoots,
|
|
semanticRuntime,
|
|
});
|
|
expect(changed.path).not.toBe(first.path);
|
|
expect(changed.inputFingerprint).not.toBe(first.inputFingerprint);
|
|
expect(changed.configFingerprint).not.toBe(first.configFingerprint);
|
|
expect(readFileSync(changed.path, "utf8")).toContain("warehouse-two.internal");
|
|
});
|
|
|
|
test("runtime rendering rejects untrusted snapshot paths and symlinks", async () => {
|
|
const f = await fixture();
|
|
const outside = join(f.dataRoot, "outside.yaml");
|
|
writeFileSync(outside, readFileSync(f.revision.snapshotPath, "utf8"));
|
|
const symlink = join(f.dataRoot, "alias.yaml");
|
|
symlinkSync(f.revision.snapshotPath, symlink);
|
|
|
|
expect(() => renderWorkspaceRuntimeFromSnapshotPath({
|
|
snapshotPath: outside,
|
|
harnessDir: f.harnessDir,
|
|
configPath: "config/tht.yaml",
|
|
dataRoot: f.dataRoot,
|
|
secretRoots: f.registryConfig.secretRoots,
|
|
semanticRuntime,
|
|
})).toThrow(/trusted runtime snapshot/i);
|
|
expect(() => renderWorkspaceRuntimeFromSnapshotPath({
|
|
snapshotPath: symlink,
|
|
harnessDir: f.harnessDir,
|
|
configPath: "config/tht.yaml",
|
|
dataRoot: f.dataRoot,
|
|
secretRoots: f.registryConfig.secretRoots,
|
|
semanticRuntime,
|
|
})).toThrow(/trusted runtime snapshot/i);
|
|
});
|
|
|
|
|
|
test("operator lease and session snapshot produce byte-identical effective DWH bindings", async () => {
|
|
const f = await fixture();
|
|
const session = renderWorkspaceRuntimeFromSnapshotPath({
|
|
snapshotPath: f.revision.snapshotPath,
|
|
harnessDir: f.harnessDir,
|
|
configPath: "config/tht.yaml",
|
|
dataRoot: f.dataRoot,
|
|
secretRoots: f.registryConfig.secretRoots,
|
|
semanticRuntime,
|
|
});
|
|
const lease = await publishDeterministicRuntimeConfigLease({
|
|
workspaceId: "psd-clinical",
|
|
registry: f.registry,
|
|
registryConfig: f.registryConfig,
|
|
harnessDir: f.harnessDir,
|
|
configPath: "config/tht.yaml",
|
|
dataRoot: f.dataRoot,
|
|
secretRoots: f.registryConfig.secretRoots,
|
|
semanticRuntime,
|
|
});
|
|
|
|
const sessionCanonical = canonicalEffectiveConfigJson(buildCanonicalEffectiveConfig(parse(session.renderedConfig)));
|
|
const operatorCanonical = canonicalEffectiveConfigJson(lease.effectiveConfig);
|
|
expect(operatorCanonical).toBe(sessionCanonical);
|
|
expect(lease.effectiveConfigIdentity).toBe(
|
|
effectiveConfigIdentity("psd-clinical", parse(session.renderedConfig)),
|
|
);
|
|
});
|
|
|
|
test("a content-only Evidence commit keeps the same effective config identity with a new revision lease", async () => {
|
|
const f = await fixture();
|
|
const firstLease = await publishDeterministicRuntimeConfigLease({
|
|
workspaceId: "psd-clinical",
|
|
registry: f.registry,
|
|
registryConfig: f.registryConfig,
|
|
harnessDir: f.harnessDir,
|
|
configPath: "config/tht.yaml",
|
|
dataRoot: f.dataRoot,
|
|
secretRoots: f.registryConfig.secretRoots,
|
|
semanticRuntime,
|
|
});
|
|
const firstIdentity = firstLease.effectiveConfigIdentity;
|
|
|
|
writeFileSync(
|
|
join(f.source, "psd-clinical", "evidence", "guide.md"),
|
|
"# updated content only\n",
|
|
);
|
|
await git(f.source, ["add", "psd-clinical/evidence/guide.md"]);
|
|
await git(f.source, ["commit", "-m", "Evidence content only"]);
|
|
await git(f.source, ["push", "origin", "main"]);
|
|
await f.registry.pull();
|
|
const current = (await f.registry.list())[0];
|
|
|
|
const secondLease = await publishDeterministicRuntimeConfigLease({
|
|
workspaceId: "psd-clinical",
|
|
registry: f.registry,
|
|
registryConfig: f.registryConfig,
|
|
harnessDir: f.harnessDir,
|
|
configPath: "config/tht.yaml",
|
|
dataRoot: f.dataRoot,
|
|
secretRoots: f.registryConfig.secretRoots,
|
|
semanticRuntime,
|
|
});
|
|
|
|
expect(secondLease.workspaceRevision).toBe(current.commit);
|
|
expect(secondLease.workspaceRevision).not.toBe(firstLease.workspaceRevision);
|
|
expect(secondLease.effectiveConfigIdentity).toBe(firstIdentity);
|
|
expect(secondLease.path).not.toBe(firstLease.path);
|
|
});
|