JuliusBrussee/caveman · error
CAVEMAN_BINARY_SIGNING_PRIVATE_KEY_PEM is required
Error message
CAVEMAN_BINARY_SIGNING_PRIVATE_KEY_PEM is required
What it means
Thrown by scripts/sign-binary-checksums.mjs when the environment variable CAVEMAN_BINARY_SIGNING_PRIVATE_KEY_PEM is unset or empty. The script takes the public key from the command line but the private key only from the environment, so the secret never appears in shell history or process arguments. This check runs after argument validation and before any file is read.
Source
Thrown at scripts/sign-binary-checksums.mjs:45
"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);
}
}
View on GitHub (pinned to 27d5a3981a)
Solutions
- Provide the key via the environment: `CAVEMAN_BINARY_SIGNING_PRIVATE_KEY_PEM="$(cat signing-key.pem)" node scripts/sign-binary-checksums.mjs ...`.
- In CI, add CAVEMAN_BINARY_SIGNING_PRIVATE_KEY_PEM as a secret on the signing job.
- Keep the private key out of files and arguments — if it lives only on another machine, copy it securely first.
Example fix
# before node scripts/sign-binary-checksums.mjs dist/checksums.txt dist/checksums.keysig keys/binary-public.pem # after CAVEMAN_BINARY_SIGNING_PRIVATE_KEY_PEM="$(cat ~/.secure/binary-signing.pem)" \ node scripts/sign-binary-checksums.mjs dist/checksums.txt dist/checksums.keysig keys/binary-public.pem
Defensive patterns
Strategy: validation
Validate before calling
#!/usr/bin/env bash
set -euo pipefail
: "${CAVEMAN_BINARY_SIGNING_PRIVATE_KEY_PEM:?CAVEMAN_BINARY_SIGNING_PRIVATE_KEY_PEM is required}" Prevention
- Fail fast in the release script with ${VAR:?} before doing any work.
- Store the secret in CI as a masked variable and on the signer via a secret manager — never in argv or files in the repo.
When it happens
Trigger: Running the signer in a shell or CI job where CAVEMAN_BINARY_SIGNING_PRIVATE_KEY_PEM was never exported, was exported empty, or was lost when switching agents/machines.
Common situations: New release machine or CI runner without the secret configured; signing from a fresh shell after the key was only `export`ed in another session; secret name typo.
Related errors
- usage: sign-binary-checksums.mjs <checksums.txt> <output.key
- binary signing private key does not match committed public k
- generated checksum signature failed local verification
- %s is not set; cannot encrypt/decrypt secrets
- %s is not valid base64: %w
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/1bc5668e994fe446.
Report an issue: GitHub.