mirror of
https://github.com/JuliusBrussee/caveman.git
synced 2026-09-14 18:02:35 +08:00
82864c8f4c
Single-commit port of the Caveman 2 tree onto the original repo history (candidate caveman-2@88878a4 applied over main@3098342). No unrelated-history merge; original history untouched. Preserved v1 surfaces: - skills/caveman/SKILL.md byte-for-byte, plus plugin mirror and caveman.skill zip - legacy CI (Node 18/20/22 installer + Python 3.11 suites) alongside engine-ci - cli/install.js compatibility shim forwarding to bin/install.js - .codex/config.toml ships both hooks and codex_hooks for older Codex (#617) - README Trendshift + Skills.sh badges and local star-history asset - v1.10.0-pinned curl installs; benchmarks/tmp-starcharts ignore rules Fixed for public same-repo release: - SECURITY.md vulnerability reporting points at this repository - release-binaries.yml publishes to this repo via job-scoped GITHUB_TOKEN (cross-repo PAT removed); binary-release environment still gates signing - packages/cli/PUBLISHING.md rewritten for packages/ layout and same-repo flow - profile-contract and provider-catalog lanes skip lane-scope gates on initial import so the launch PR can gate on their real validation steps - ANNOUNCEMENT.md network claim corrected: compression is local; requests still go to the provider you configured Caveman 2 stays opt-in: bin-v1.0.0 binaries and @caveman-ai/cli publish separately after this lands and soaks. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BLvb5QniwYjmcawyssQNw9
61 lines
2.5 KiB
JavaScript
61 lines
2.5 KiB
JavaScript
#!/usr/bin/env node
|
|
import { createHash, createPrivateKey, createPublicKey, sign, verify } from "node:crypto";
|
|
import { readFileSync, writeFileSync } from "node:fs";
|
|
import { resolve } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
export function checksumSignatureBundle(checksums, privateKeyPEM) {
|
|
const privateKey = createPrivateKey(privateKeyPEM);
|
|
return {
|
|
mediaType: "application/vnd.dev.sigstore.bundle.v0.3+json",
|
|
messageSignature: {
|
|
messageDigest: {
|
|
algorithm: "SHA2_256",
|
|
digest: createHash("sha256").update(checksums).digest("base64"),
|
|
},
|
|
signature: sign("sha256", checksums, privateKey).toString("base64"),
|
|
},
|
|
};
|
|
}
|
|
|
|
export function verifyChecksumSignatureBundle(checksums, bundle, publicKeyPEM) {
|
|
const digest = createHash("sha256").update(checksums).digest("base64");
|
|
return bundle?.mediaType === "application/vnd.dev.sigstore.bundle.v0.3+json" &&
|
|
bundle?.messageSignature?.messageDigest?.algorithm === "SHA2_256" &&
|
|
bundle?.messageSignature?.messageDigest?.digest === digest &&
|
|
verify(
|
|
"sha256",
|
|
checksums,
|
|
createPublicKey(publicKeyPEM),
|
|
Buffer.from(bundle?.messageSignature?.signature ?? "", "base64"),
|
|
);
|
|
}
|
|
|
|
function normalizePublicKey(value) {
|
|
return createPublicKey(value).export({ type: "spki", format: "pem" }).toString();
|
|
}
|
|
|
|
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
try {
|
|
const [checksumsPath, outputPath, publicKeyPath] = process.argv.slice(2);
|
|
const privateKeyPEM = process.env.CAVEMAN_BINARY_SIGNING_PRIVATE_KEY_PEM;
|
|
if (!checksumsPath || !outputPath || !publicKeyPath) {
|
|
throw new Error("usage: sign-binary-checksums.mjs <checksums.txt> <output.keysig> <public-key.pem>");
|
|
}
|
|
if (!privateKeyPEM) throw new Error("CAVEMAN_BINARY_SIGNING_PRIVATE_KEY_PEM is required");
|
|
const checksums = readFileSync(checksumsPath);
|
|
const publicKeyPEM = readFileSync(publicKeyPath, "utf8");
|
|
if (normalizePublicKey(privateKeyPEM) !== normalizePublicKey(publicKeyPEM)) {
|
|
throw new Error("binary signing private key does not match committed public key");
|
|
}
|
|
const bundle = checksumSignatureBundle(checksums, privateKeyPEM);
|
|
if (!verifyChecksumSignatureBundle(checksums, bundle, publicKeyPEM)) {
|
|
throw new Error("generated checksum signature failed local verification");
|
|
}
|
|
writeFileSync(outputPath, `${JSON.stringify(bundle)}\n`, { mode: 0o600 });
|
|
} catch (error) {
|
|
process.stderr.write(`${error.message}\n`);
|
|
process.exit(1);
|
|
}
|
|
}
|