mirror of
https://github.com/garrytan/gbrain.git
synced 2026-08-14 00:48:18 +00:00
feat(doctor): tamper-evident skills/ manifest — generator, doctor drift check, CI freshness guard (#159) (#3453)
Co-Authored-By: Time Attakc <89218912+time-attack@users.noreply.github.com>
This commit is contained in:
committed by
Sina Matian
co-authored by
Time Attakc
parent
8e3699156f
commit
aa5b9e6e2d
Executable
+41
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
# CI guard for skills/skills.lock.json freshness (#159).
|
||||
#
|
||||
# Mirrors scripts/check-eval-glossary-fresh.sh: regenerate the manifest into
|
||||
# a tmp file, diff against the committed version, fail the build if they
|
||||
# drift. Tamper-evidence, not a signature system — the point is that any
|
||||
# change under skills/ ships with an explicit manifest diff.
|
||||
#
|
||||
# Run: bash scripts/check-skills-manifest-fresh.sh
|
||||
# Wired through `bun run verify` (scripts/run-verify-parallel.sh) so PRs that
|
||||
# edit skills/ without regenerating the manifest are caught before review.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
COMMITTED="$REPO_ROOT/skills/skills.lock.json"
|
||||
TMP="$(mktemp)"
|
||||
trap 'rm -f "$TMP"' EXIT
|
||||
|
||||
if [ ! -f "$COMMITTED" ]; then
|
||||
echo "ERROR: $COMMITTED not found." >&2
|
||||
echo "Run: bun run scripts/generate-skills-manifest.ts" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$REPO_ROOT"
|
||||
# Render directly via bun + a one-liner that exposes the module function.
|
||||
bun -e "import { renderSkillsManifest } from './src/core/skills-integrity.ts'; process.stdout.write(renderSkillsManifest('skills'));" > "$TMP"
|
||||
|
||||
if ! diff -q "$COMMITTED" "$TMP" >/dev/null 2>&1; then
|
||||
echo "ERROR: skills/skills.lock.json is stale." >&2
|
||||
echo "" >&2
|
||||
echo "Diff between committed and freshly-generated:" >&2
|
||||
echo "" >&2
|
||||
diff -u "$COMMITTED" "$TMP" >&2 || true
|
||||
echo "" >&2
|
||||
echo "To regenerate: bun run scripts/generate-skills-manifest.ts" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✓ skills/skills.lock.json is fresh"
|
||||
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env bun
|
||||
/**
|
||||
* Regenerates skills/skills.lock.json — the tamper-evidence manifest mapping
|
||||
* every bundled file under skills/ to its sha256 (#159). Not a signature
|
||||
* system: it turns silent skill edits into explicit diffs. `gbrain doctor`
|
||||
* warns (never fails) on drift; scripts/check-skills-manifest-fresh.sh keeps
|
||||
* the committed manifest in sync in CI.
|
||||
*
|
||||
* Run after any change under skills/:
|
||||
* bun run scripts/generate-skills-manifest.ts
|
||||
*/
|
||||
import { writeFileSync } from 'node:fs';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import {
|
||||
SKILLS_MANIFEST_FILENAME,
|
||||
renderSkillsManifest,
|
||||
} from '../src/core/skills-integrity.ts';
|
||||
|
||||
const repoRoot = join(dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const skillsDir = join(repoRoot, 'skills');
|
||||
const outPath = join(skillsDir, SKILLS_MANIFEST_FILENAME);
|
||||
writeFileSync(outPath, renderSkillsManifest(skillsDir));
|
||||
console.log(`Wrote ${outPath}`);
|
||||
@@ -50,6 +50,7 @@ CHECKS=(
|
||||
"check:cli-exec"
|
||||
"check:system-of-record"
|
||||
"check:eval-glossary"
|
||||
"check:skills-manifest"
|
||||
"check:no-pii-agent-voice"
|
||||
"check:synthetic-corpus-privacy"
|
||||
"check:skill-brain-first"
|
||||
|
||||
Reference in New Issue
Block a user