mirror of
https://github.com/prompt-security/clawsec.git
synced 2026-06-17 07:21:21 +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
111 lines
3.6 KiB
YAML
111 lines
3.6 KiB
YAML
name: Sign and Verify File
|
|
description: Sign a file with the CI private key and verify the signature against one or more files.
|
|
|
|
inputs:
|
|
private_key:
|
|
description: PEM-encoded private key contents.
|
|
required: true
|
|
private_key_passphrase:
|
|
description: Optional passphrase for encrypted private keys.
|
|
required: false
|
|
default: ""
|
|
input_file:
|
|
description: File to sign.
|
|
required: true
|
|
signature_file:
|
|
description: Output path for base64 signature.
|
|
required: true
|
|
verify_files:
|
|
description: Newline-separated list of files to verify with the generated signature. Defaults to input_file.
|
|
required: false
|
|
default: ""
|
|
public_key_output:
|
|
description: Optional output path for the derived public key.
|
|
required: false
|
|
default: ""
|
|
|
|
outputs:
|
|
signature_file:
|
|
description: Signature file path.
|
|
value: ${{ steps.sign.outputs.signature_file }}
|
|
public_key_file:
|
|
description: Public key file path when public_key_output is set.
|
|
value: ${{ steps.sign.outputs.public_key_file }}
|
|
|
|
runs:
|
|
using: composite
|
|
steps:
|
|
- id: sign
|
|
shell: bash
|
|
env:
|
|
PRIVATE_KEY: ${{ inputs.private_key }}
|
|
PRIVATE_KEY_PASSPHRASE: ${{ inputs.private_key_passphrase }}
|
|
INPUT_FILE: ${{ inputs.input_file }}
|
|
SIGNATURE_FILE: ${{ inputs.signature_file }}
|
|
VERIFY_FILES_RAW: ${{ inputs.verify_files }}
|
|
PUBLIC_KEY_OUTPUT: ${{ inputs.public_key_output }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
if [ -z "${PRIVATE_KEY:-}" ]; then
|
|
echo "::error::Missing required private key input."
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -f "${INPUT_FILE}" ]; then
|
|
echo "::error file=${INPUT_FILE}::Input file not found for signing."
|
|
exit 1
|
|
fi
|
|
|
|
umask 077
|
|
tmp_dir="$(mktemp -d)"
|
|
cleanup() {
|
|
rm -rf "${tmp_dir}"
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
key_file="${tmp_dir}/private.pem"
|
|
pub_file="${tmp_dir}/public.pem"
|
|
sig_bin="${tmp_dir}/signature.bin"
|
|
|
|
printf '%s' "${PRIVATE_KEY}" > "${key_file}"
|
|
|
|
passin_args=()
|
|
if [ -n "${PRIVATE_KEY_PASSPHRASE:-}" ]; then
|
|
passin_args=(-passin "pass:${PRIVATE_KEY_PASSPHRASE}")
|
|
fi
|
|
|
|
openssl pkey -in "${key_file}" "${passin_args[@]}" -pubout -out "${pub_file}"
|
|
|
|
mkdir -p "$(dirname "${SIGNATURE_FILE}")"
|
|
# Sign with Ed25519 (requires -rawin flag for raw input)
|
|
openssl pkeyutl -sign -rawin -inkey "${key_file}" "${passin_args[@]}" -in "${INPUT_FILE}" \
|
|
| openssl base64 -A > "${SIGNATURE_FILE}"
|
|
|
|
openssl base64 -d -A -in "${SIGNATURE_FILE}" -out "${sig_bin}"
|
|
|
|
verify_files="${VERIFY_FILES_RAW}"
|
|
if [ -z "${verify_files}" ]; then
|
|
verify_files="${INPUT_FILE}"
|
|
fi
|
|
|
|
while IFS= read -r verify_file; do
|
|
[ -z "${verify_file}" ] && continue
|
|
if [ ! -f "${verify_file}" ]; then
|
|
echo "::error file=${verify_file}::Verification target does not exist."
|
|
exit 1
|
|
fi
|
|
# Verify Ed25519 signature (requires -rawin flag for raw input)
|
|
openssl pkeyutl -verify -rawin -pubin -inkey "${pub_file}" -sigfile "${sig_bin}" -in "${verify_file}" >/dev/null
|
|
done <<< "${verify_files}"
|
|
|
|
if [ -n "${PUBLIC_KEY_OUTPUT}" ]; then
|
|
mkdir -p "$(dirname "${PUBLIC_KEY_OUTPUT}")"
|
|
cp "${pub_file}" "${PUBLIC_KEY_OUTPUT}"
|
|
echo "public_key_file=${PUBLIC_KEY_OUTPUT}" >> "${GITHUB_OUTPUT}"
|
|
else
|
|
echo "public_key_file=" >> "${GITHUB_OUTPUT}"
|
|
fi
|
|
|
|
echo "signature_file=${SIGNATURE_FILE}" >> "${GITHUB_OUTPUT}"
|