Files
clawsec/skills/hermes-attestation-guardian/scripts/check_advisories.mjs
T
David Abutbul 26af277afd feat(hermes-attestation-guardian): v0.1.0 release hardening (verify gate + trust policy + .mjs scan context) (#200)
* feat(hermes-attestation-guardian): release v0.0.2 hardening

* docs(wiki): add v0.0.2 hardening update note

* docs: add Hermes support coverage to README and compatibility report

* fix(hermes-attestation-guardian): address baz review on crontab detection and doc dedup

* feat(wiki): add PR-200 skill feature/platform matrix

* docs(wiki): rewrite PR-200 matrix as narrative capability mapping

* docs(readme): add skill feature matrix with requested headers

* docs(readme): replace unknowns with mapped yes/no feature matrix

* docs: move NanoClaw and CI/CD details from README to wiki modules

* docs(readme): remove platform/suite sections and keep wiki module pointers

* docs(readme): refresh project structure to match current repo

* feat(hermes-attestation-guardian): add signed advisory feed verification pipeline

* feat(hermes-attestation-guardian): add advisory-gated guarded skill verification

* feat(hermes-attestation-guardian): add advisory scheduler helper and phase-3 parity docs

* docs(wiki): expand hermes attestation guardian capability coverage

* fix(pr-200): address Baz review findings across Hermes parity rollout

* test(sandbox): extend Hermes regression to cover feed, guarded verify, and advisory scheduler

* fix(pr-200): address Baz semver parsing and feed-state fallback visibility

* fix(ci): suppress shellcheck false positives in sandbox inline docker script

* fix(hermes-attestation-guardian): fail closed on unsupported advisory ranges

* fix(hermes-attestation-guardian): restore safe install verdict in sandbox

* fix(sandbox): capture guarded verify exit under set -e

* fix(semver): fail closed on malformed affected specifiers

* docs(readme): clarify hermes capability matrix wording

* refactor(feed): share signed artifact verification flow

* refactor(cron): share managed block helpers across setup scripts

* fix(feed): require checksum manifest artifacts when enabled

* chore(hermes-skill): relocate sandbox test, refresh docs, and add v0.1.0 release notes

* chore(docs): remove remaining hermes parity plan file

* chore(release): roll hermes-attestation-guardian to v0.1.0

* chore(release): remove standalone v0.1.0 release notes file

* docs(hermes): update README status to v0.1.0

---------

Co-authored-by: David Abutbul <David.a@prompt.security>
2026-04-21 13:56:50 +03:00

102 lines
3.1 KiB
JavaScript

#!/usr/bin/env node
import fs from "node:fs";
import { defaultCachedFeedPath, defaultFeedStatePath, loadFeedVerificationState, resolveFeedConfig } from "../lib/feed.mjs";
function usage() {
process.stdout.write(
[
"Usage: node scripts/check_advisories.mjs",
"",
"Prints human-readable advisory feed verification status and cached feed summary.",
"",
].join("\n"),
);
}
function summarizeBySeverity(feed) {
const advisories = Array.isArray(feed?.advisories) ? feed.advisories : [];
const counts = {};
for (const advisory of advisories) {
const severity = String(advisory?.severity || "unknown").trim().toLowerCase() || "unknown";
counts[severity] = (counts[severity] || 0) + 1;
}
return counts;
}
function printSeveritySummary(counts) {
const entries = Object.entries(counts);
if (entries.length === 0) {
process.stdout.write("Advisory severities: (none)\n");
return;
}
const sorted = entries.sort((a, b) => a[0].localeCompare(b[0]));
process.stdout.write(
`Advisory severities: ${sorted.map(([severity, count]) => `${severity}=${count}`).join(", ")}\n`,
);
}
function main() {
const argv = process.argv.slice(2);
if (argv.includes("--help") || argv.includes("-h")) {
usage();
return;
}
const config = resolveFeedConfig({});
const statePath = config.statePath || defaultFeedStatePath();
const cachedFeedPath = config.cachedFeedPath || defaultCachedFeedPath();
const state = loadFeedVerificationState(statePath);
if (!state) {
process.stdout.write(`Feed verification state: unknown (missing state file: ${statePath})\n`);
process.exitCode = 2;
return;
}
process.stdout.write(`Feed verification state: ${state.status || "unknown"}\n`);
process.stdout.write(`Source: ${state.source || "unknown"}\n`);
process.stdout.write(`Last checked: ${state.checked_at || "unknown"}\n`);
process.stdout.write(`State file: ${statePath}\n`);
process.stdout.write(`Cached feed: ${cachedFeedPath}\n`);
if (state.error) {
process.stdout.write(`Last error: ${state.error}\n`);
}
if (state.allow_unsigned_bypass) {
process.stdout.write("WARNING: unsigned advisory feed bypass is active.\n");
}
if (!fs.existsSync(cachedFeedPath)) {
process.stdout.write("Cached advisory feed: unavailable\n");
process.exitCode = state.status === "verified" ? 1 : 0;
return;
}
let feed;
try {
feed = JSON.parse(fs.readFileSync(cachedFeedPath, "utf8"));
} catch (error) {
process.stdout.write(`Cached advisory feed JSON parse error: ${error?.message || String(error)}\n`);
process.exitCode = 1;
return;
}
process.stdout.write(`Feed version: ${feed?.version || "unknown"}\n`);
process.stdout.write(`Feed updated: ${feed?.updated || "unknown"}\n`);
process.stdout.write(`Advisory count: ${Array.isArray(feed?.advisories) ? feed.advisories.length : 0}\n`);
printSeveritySummary(summarizeBySeverity(feed));
if (state.status === "unverified") {
process.exitCode = 1;
}
}
try {
main();
} catch (error) {
process.stderr.write(`CRITICAL: ${error?.message || String(error)}\n`);
process.exit(1);
}