/*
Facilitates integrity management commands for application builds, including initialization, updates, verification, and signing.
- Do not handle raw content parsing or manipulation of build files.
- Do not manage application configuration or orchestration.
- RFC-1097: step 6 — compass.migrate codemod run
Mechanical v1 to v2 header migration across the workspace: 942 files rewritten — CHANGE_SUMMARY windows collapsed into history, forbidden v1 blocks stripped, KEY_DECISIONS seeded from @ai-invariant comments (5 files) or TODO placeholders (103 files), blocks reordered to canonical order.
- RFC-1097: sweep — werkstatt-engine clean
Sweep batch 4: 73 Compass headers on headerless engine files (certification, component-runtime, isolation, evolution, testing), real KEY_DECISIONS on 75 files (kernel, cache, dht, swim, gitmesh, runtime), ~80 purpose expansions (CONTRACT-02/PURPOSE-02), non-goals on 13 CONTRACT-03 files, CS-07 history literal fix repo-wide (253 files). Policy: .template.ts/.template.astro excludedPaths. werkstatt-engine now 0 diagnostics.
- RFC-1249: wire werkstatt.commands.validate into packages.check + retire CMD-OUTPUT debt
*/
import path from "node:path";
import type {
KernelCommandInput,
KernelCommandResult,
KernelRuntimeContext,
} from "@warpgogol/werkstatt-engine/kernel";
import {
buildLatestDir,
compareManifestWithLocalArtifacts,
ensureDir,
generateSigningKeyPairPemAsync,
loadPublicKeyPem,
loadSignedManifest,
optionalEnv,
requireEnv,
runBackfillRevisions,
runInit,
runRecordBuild,
runUpdate,
runVerify,
signedManifestPath,
signLatestBuildArtifacts,
verifyManifestSignature,
writeText,
} from "@warpgogol/werkstatt-engine/integrity";
import { createDefaultIO, type WorkspaceIO } from "@warpgogol/werkstatt-shared/kernel/workspace-io";
function requireApp(context: KernelRuntimeContext) {
if (!context.site) {
throw new Error("This command requires an app-scoped runtime context.");
}
return context.site;
}
function getStringArg(
input: KernelCommandInput,
index: number,
fallback?: string,
): string | undefined {
return fallback;
}
export async function runIntegrityInit(
_input: KernelCommandInput,
context: KernelRuntimeContext,
): Promise {
const app = requireApp(context);
if (context.dryRun) {
return {
exitCode: 0,
summary: `[integrity.init] dry-run: would initialize integrity for ${app.name}`,
};
}
await runInit({ cwd: app.directory });
return {
exitCode: 0,
summary: `[integrity.init] complete for ${app.name}`,
nextSteps: [
{
action: `Update integrity manifests: pnpm exec werkstatt run integrity.update`,
kind: "optional",
},
],
};
}
export async function runIntegrityUpdate(
input: KernelCommandInput,
context: KernelRuntimeContext,
): Promise {
const app = requireApp(context);
if (context.dryRun) {
return {
exitCode: 0,
summary: `[integrity.update] dry-run: would update integrity manifests for ${app.name}`,
};
}
await runUpdate({ cwd: app.directory, baseRef: getStringArg(input, 0) });
return {
exitCode: 0,
summary: `[integrity.update] complete for ${app.name}`,
nextSteps: [
{ action: `Verify integrity: pnpm exec werkstatt run integrity.verify`, kind: "optional" },
],
};
}
export async function runIntegrityVerify(
_input: KernelCommandInput,
context: KernelRuntimeContext,
): Promise> {
const app = requireApp(context);
const report = await runVerify({ cwd: app.directory });
return {
data: { ok: report.ok },
exitCode: report.ok ? 0 : 1,
summary: report.ok
? `[integrity.commands] Integrity verification passed.`
: `[integrity.commands] Integrity verification failed.`,
nextSteps: report.ok
? undefined
: [
{
action: `Fix the integrity violations above, then re-run: pnpm exec werkstatt run integrity.verify`,
kind: "required",
},
],
};
}
export async function runIntegrityBuildRecord(
input: KernelCommandInput,
context: KernelRuntimeContext,
): Promise {
const app = requireApp(context);
const distDir = getStringArg(input, 0, "dist") ?? "dist";
if (context.dryRun) {
return {
exitCode: 0,
summary: `[integrity.build-record] dry-run: would record build outputs from ${distDir}`,
};
}
await runRecordBuild({ cwd: app.directory, builder: "local", distDir });
return {
exitCode: 0,
summary: `[integrity.build-record] complete for ${app.name}`,
nextSteps: [
{ action: `Sign the build: pnpm exec werkstatt run integrity.sign`, kind: "optional" },
],
};
}
async function loadPrivateKeyPem(
appDirectory: string,
io: WorkspaceIO = createDefaultIO().io,
): Promise {
const keyPath = await optionalEnv("SIGNING_PRIVATE_KEY_PATH", appDirectory);
if (keyPath) {
return await io.readFile(path.resolve(appDirectory, keyPath));
}
const defaultKeyPath = path.join(appDirectory, ".integrity/keys/studio.private.pem");
try {
return await io.readFile(defaultKeyPath);
} catch {
// Fallback to env variable
}
return requireEnv("SIGNING_PRIVATE_KEY", appDirectory);
}
export async function runIntegritySign(
_input: KernelCommandInput,
context: KernelRuntimeContext,
): Promise> {
const app = requireApp(context);
if (context.dryRun) {
return {
exitCode: 0,
summary: `[integrity.sign] dry-run: would sign ${buildLatestDir(app.directory)}`,
};
}
const privateKeyPem = await loadPrivateKeyPem(app.directory);
const publicKeyUrl = await optionalEnv("PUBLIC_KEY_URL", app.directory);
const result = await signLatestBuildArtifacts({
cwd: app.directory,
privateKeyPem,
publicKeyUrl,
});
context.logger.info(`Build directory: ${buildLatestDir(app.directory)}`);
context.logger.info(
`Public key URL: ${publicKeyUrl ?? "(embedded URL omitted for this signature)"}`,
);
context.logger.info(`Build ID: ${result.payload.buildId}`);
context.logger.info(`Signed at: ${result.payload.signedAt}`);
context.logger.info(`Outputs digest: ${result.payload.outputsDigest}`);
context.logger.info(`Provenance digest: ${result.payload.provenanceDigest}`);
context.logger.info(`Output files: ${Object.keys(result.outputs.outputs).length}`);
context.logger.info(`Signature bytes: ${result.signatureBuffer.byteLength}`);
context.logger.info(`Signature preview: ${result.signatureHex.slice(0, 32)}...`);
context.logger.info(`Signed manifest: ${signedManifestPath(app.directory)}`);
return {
data: { reusedExistingSignature: result.reusedExistingSignature },
exitCode: 0,
summary: result.reusedExistingSignature
? "Release signature already matched the current build artifacts. Existing signed files were kept unchanged."
: "Release signed successfully. Anyone holding your public key can verify this release independently.",
};
}
export async function runIntegrityVerifyRelease(
input: KernelCommandInput,
context: KernelRuntimeContext,
): Promise> {
const app = requireApp(context);
const manifestSource =
getStringArg(input, 0, signedManifestPath(app.directory)) ?? signedManifestPath(app.directory);
const manifest = await loadSignedManifest(manifestSource);
const publicKeyPemPath = await optionalEnv("PUBLIC_KEY_PEM_PATH", app.directory);
const publicKeyUrl = await optionalEnv("PUBLIC_KEY_URL", app.directory);
// Fallback to default public key location if no other source provided
let resolvedKeyPath: string | undefined = publicKeyPemPath;
if (!resolvedKeyPath && !publicKeyUrl && !manifest.publicKeyUrl) {
const defaultPublicKeyPath = path.join(app.directory, "public/studio.public.pem");
if (await context.io.exists(defaultPublicKeyPath)) {
resolvedKeyPath = defaultPublicKeyPath;
}
// No default key file → will fail below with proper error
}
// Resolve relative paths against app.directory (loadPublicKeyPem uses path.resolve against process.cwd())
if (resolvedKeyPath && !path.isAbsolute(resolvedKeyPath)) {
resolvedKeyPath = path.resolve(app.directory, resolvedKeyPath);
}
const publicKeyPem = await loadPublicKeyPem({
manifest,
publicKeyPemPath: resolvedKeyPath,
publicKeyUrl,
});
const signatureValid = await verifyManifestSignature({ manifest, publicKeyPem });
context.logger.info(`Manifest source: ${manifestSource}`);
context.logger.info(`Build ID: ${manifest.buildId}`);
context.logger.info(`Signed at: ${manifest.signedAt}`);
context.logger.info(`Algorithm: ${manifest.algorithm}`);
context.logger.info(
`Public key source: ${publicKeyPemPath ?? publicKeyUrl ?? manifest.publicKeyUrl ?? "(not provided)"}`,
);
context.logger.info(`Payload version: ${manifest.payloadVersion}`);
context.logger.info(`Outputs digest: ${manifest.payload.outputsDigest}`);
context.logger.info(`Provenance digest: ${manifest.payload.provenanceDigest}`);
context.logger.info(`Result: ${signatureValid ? "VALID" : "INVALID"}`);
let localCheckFailed = false;
const localBuildDir = buildLatestDir(app.directory);
if (
!manifestSource.startsWith("https://") &&
path.resolve(manifestSource).startsWith(path.resolve(localBuildDir))
) {
const digestCheck = await compareManifestWithLocalArtifacts(app.directory, manifest);
context.logger.info(`outputs.json: ${digestCheck.outputsDigestMatches ? "MATCH" : "MISMATCH"}`);
context.logger.info(
`build-provenance.json: ${digestCheck.provenanceDigestMatches ? "MATCH" : "MISMATCH"}`,
);
if (!digestCheck.outputsDigestMatches || !digestCheck.provenanceDigestMatches) {
localCheckFailed = true;
}
}
const ok = signatureValid && !localCheckFailed;
return {
data: { signatureValid },
exitCode: ok ? 0 : 1,
summary: ok
? "Release verified successfully. Anyone holding the public key can verify this release independently."
: undefined,
};
}
export async function runIntegrityGenerateSigningKeypair(
input: KernelCommandInput,
context: KernelRuntimeContext,
): Promise> {
const app = requireApp(context);
const privateKeyTarget = path.resolve(
app.directory,
getStringArg(input, 0, ".integrity/keys/studio.private.pem") ??
".integrity/keys/studio.private.pem",
);
const publicKeyTarget = path.resolve(
app.directory,
getStringArg(input, 1, "public/studio.public.pem") ?? "public/studio.public.pem",
);
if (context.dryRun) {
return {
data: { privateKeyTarget, publicKeyTarget },
exitCode: 0,
summary: `[integrity.keys.generate] dry-run: would write ${privateKeyTarget} and ${publicKeyTarget}`,
};
}
const { privateKeyPem, publicKeyPem } = await generateSigningKeyPairPemAsync();
await ensureDir(path.dirname(privateKeyTarget));
await ensureDir(path.dirname(publicKeyTarget));
await Promise.all([
writeText(privateKeyTarget, privateKeyPem),
writeText(publicKeyTarget, publicKeyPem),
]);
context.logger.info(`Private key: ${privateKeyTarget}`);
context.logger.info(`Public key: ${publicKeyTarget}`);
return {
data: { privateKeyTarget, publicKeyTarget },
exitCode: 0,
summary: "[integrity.commands] Ed25519 key pair generated.",
};
}
export async function runIntegrityBackfillRevisions(
_input: KernelCommandInput,
context: KernelRuntimeContext,
): Promise {
const app = requireApp(context);
if (context.dryRun) {
return {
exitCode: 0,
summary: `[integrity.backfill-revisions] dry-run: would update revision counters for ${app.name}`,
};
}
await runBackfillRevisions({ cwd: app.directory });
return { exitCode: 0, summary: `[integrity.backfill-revisions] complete for ${app.name}` };
}