mirror of
https://github.com/prompt-security/clawsec.git
synced 2026-06-13 05:28:02 +03:00
5ee8587b1e
* ci: sign advisory feed and checksums in workflows * feat(clawsec-suite): add verifier-side signature and checksum enforcement Implements cryptographic verification for advisory feed loading: - Ed25519 detached signature verification for feed.json - Supports raw base64 and JSON-wrapped signature formats - Pinned public key at advisories/feed-signing-public.pem - SHA-256 checksum manifest (checksums.json) verification - Signed checksums.json.sig prevents partial artifact substitution - Verifies feed.json, feed.json.sig, and public key against manifest - Remote feed: returns null on verification failure (triggers fallback) - Local feed: throws on verification failure (hard fail) - No silent bypass of verification - CLAWSEC_ALLOW_UNSIGNED_FEED=1 temporarily bypasses verification - Warning logged when bypass mode is enabled - Intended for transition period only - guarded_skill_install without --version matches any advisory for skill - Encourages explicit version specification - scripts/sign_detached_ed25519.mjs - signing utility - scripts/verify_detached_ed25519.mjs - verification utility - scripts/generate_checksums_json.mjs - checksum manifest generator - test/feed_verification.test.mjs - 14 verification tests - test/guarded_install.test.mjs - 6 install flow tests - hooks/.../lib/feed.mjs - full rewrite with verification - hooks/.../handler.ts - verification options integration - scripts/guarded_skill_install.mjs - verification integration - skill.json - v0.0.9, new SBOM entries, openssl requirement - SKILL.md - signed install flow, env vars documentation - HOOK.md - new environment variables - ci.yml - added verification test job Refs: fail-closed verification, Ed25519 signatures, checksum manifests * fix: update action versions in CI workflows for improved stability * chore(clawsec-suite): bump version to 0.0.10 * feat: enhance security measures in asset deployment and add changelog for version history * feat: add dry-run signing for advisory artifacts and generate checksums * fix: enhance error handling in loadRemoteFeed for security policy violations * feat: implement Ed25519 signing and verification for advisory artifacts and checksums * feat: implement signing and verification for advisory artifacts and checksums in workflows * feat: update dry-run signing key generation to use Ed25519 algorithm * feat: update Ed25519 signing and verification to use -rawin flag for compatibility * feat: add public key copying to advisory directory and implement safe basename extraction for URLs * feat: remove Product Hunt promotion section from README and Home page
66 lines
1.6 KiB
JavaScript
66 lines
1.6 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import crypto from "node:crypto";
|
|
import fs from "node:fs/promises";
|
|
|
|
function usage() {
|
|
process.stderr.write(
|
|
[
|
|
"Usage:",
|
|
" node scripts/sign_detached_ed25519.mjs --key <private-key.pem> --in <file> --out <file.sig>",
|
|
"",
|
|
"Signs <file> with Ed25519 private key and writes base64 detached signature to <file.sig>.",
|
|
"",
|
|
].join("\n"),
|
|
);
|
|
}
|
|
|
|
function parseArgs(argv) {
|
|
const parsed = {};
|
|
|
|
for (let i = 0; i < argv.length; i += 1) {
|
|
const token = argv[i];
|
|
if (token === "--key") {
|
|
parsed.keyPath = argv[++i];
|
|
} else if (token === "--in") {
|
|
parsed.inPath = argv[++i];
|
|
} else if (token === "--out") {
|
|
parsed.outPath = argv[++i];
|
|
} else if (token === "-h" || token === "--help") {
|
|
parsed.help = true;
|
|
} else {
|
|
throw new Error(`Unknown argument: ${token}`);
|
|
}
|
|
}
|
|
|
|
return parsed;
|
|
}
|
|
|
|
async function main() {
|
|
const { keyPath, inPath, outPath, help } = parseArgs(process.argv.slice(2));
|
|
|
|
if (help) {
|
|
usage();
|
|
process.exit(0);
|
|
}
|
|
|
|
if (!keyPath || !inPath || !outPath) {
|
|
usage();
|
|
throw new Error("Missing required arguments: --key, --in, --out");
|
|
}
|
|
|
|
const privateKeyPem = await fs.readFile(keyPath, "utf8");
|
|
const privateKey = crypto.createPrivateKey(privateKeyPem);
|
|
const data = await fs.readFile(inPath);
|
|
const signature = crypto.sign(null, data, privateKey);
|
|
const signatureBase64 = signature.toString("base64");
|
|
|
|
await fs.writeFile(outPath, `${signatureBase64}\n`, "utf8");
|
|
process.stdout.write(`Signed ${inPath} -> ${outPath}\n`);
|
|
}
|
|
|
|
main().catch((error) => {
|
|
process.stderr.write(`${String(error)}\n`);
|
|
process.exit(1);
|
|
});
|