fix(gates): read leading-whitespace frontmatter in check-skill-version-bump
read_version required --- at byte 0 while skill-size-check accepts leading blank lines, so a file one gate passed the other reported as unversioned, and an unversioned merge-base side let an unbumped change through. Match FRONTMATTER_RE, add case 39, and describe the main-tip check and fail-closed cases in the hook entry. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -189,16 +189,19 @@ repos:
|
|||||||
|
|
||||||
- id: check-skill-version-bump
|
- id: check-skill-version-bump
|
||||||
name: Check changed skills bump metadata.version
|
name: Check changed skills bump metadata.version
|
||||||
description: On every push, fail if a skill directory changed (tests/ excluded) since the merge-base with main without its SKILL.md metadata.version rising (ADR-0022)
|
description: On every push, fail if a skill directory changed (tests/ excluded) since the merge-base with main without its SKILL.md metadata.version rising above both that merge-base's and main's tip's (ADR-0022)
|
||||||
entry: bash scripts/check-skill-version-bump.sh
|
entry: bash scripts/check-skill-version-bump.sh
|
||||||
language: system
|
language: system
|
||||||
stages: [pre-push]
|
stages: [pre-push]
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
always_run: true
|
always_run: true
|
||||||
# Baseline is the merge-base with origin/main (falling back to main),
|
# "Changed" is measured from the merge-base with origin/main (falling
|
||||||
# not the remote branch tip: readers install from main. Fails closed
|
# back to main), not the remote branch tip: readers install from main.
|
||||||
# when no main ref resolves. Merges through Gitea's merge button run no
|
# The version must also beat main's tip, so two branches making the same
|
||||||
# local hook, so they bypass this.
|
# bump cannot both land. Fails closed when no main ref resolves, when
|
||||||
|
# there is no merge-base, or when only local main resolves and already
|
||||||
|
# contains the pushed commit. Merges through Gitea's merge button run no
|
||||||
|
# local hook, so they bypass this. See docs/spec/gates.md.
|
||||||
|
|
||||||
- id: validate-marketplace
|
- id: validate-marketplace
|
||||||
name: Validate marketplace manifest
|
name: Validate marketplace manifest
|
||||||
|
|||||||
@@ -175,12 +175,14 @@ done < "$CHANGED_FILE"
|
|||||||
# python3 crashing, PyYAML failing to import — is a non-zero exit with no OK /
|
# python3 crashing, PyYAML failing to import — is a non-zero exit with no OK /
|
||||||
# INVALID line, which the caller reports as a read failure, never as a missing
|
# INVALID line, which the caller reports as a read failure, never as a missing
|
||||||
# version. Bytes are decoded explicitly so the caller's locale cannot turn a
|
# version. Bytes are decoded explicitly so the caller's locale cannot turn a
|
||||||
# non-ASCII SKILL.md into a crash; `\s*` before each `\n` absorbs CRLF.
|
# non-ASCII SKILL.md into a crash; `[ \t\r]*` before each `\n` absorbs CRLF.
|
||||||
|
# Whitespace before the opening `---` is accepted, matching FRONTMATTER_RE in
|
||||||
|
# factory-audit's lib-boundary-resolver.sh, which skill-size-check applies.
|
||||||
read_version() {
|
read_version() {
|
||||||
python3 -c '
|
python3 -c '
|
||||||
import re, sys, yaml
|
import re, sys, yaml
|
||||||
text = sys.stdin.buffer.read().decode("utf-8-sig", errors="replace")
|
text = sys.stdin.buffer.read().decode("utf-8-sig", errors="replace")
|
||||||
m = re.match(r"---[ \t\r]*\n(.*?)\n---[ \t\r]*(\n|\Z)", text, re.S)
|
m = re.match(r"[ \t\r\n]*---[ \t\r]*\n(.*?)\n---[ \t\r]*(\n|\Z)", text, re.S)
|
||||||
data = None
|
data = None
|
||||||
if m:
|
if m:
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -567,6 +567,27 @@ else
|
|||||||
fi
|
fi
|
||||||
expect_pass "a skill replaced by a symlink is exempt as deleted" "$F"
|
expect_pass "a skill replaced by a symlink is exempt as deleted" "$F"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "--- 39. leading blank lines before the frontmatter are parsed ---"
|
||||||
|
# skill-size-check's FRONTMATTER_RE accepts whitespace before the opening
|
||||||
|
# `---`; this gate must read the same shape. Otherwise the pushed side reports
|
||||||
|
# "missing" for a file the commit hook accepted, and a baseline shaped this way
|
||||||
|
# reads as "no valid version", which lets any version pass.
|
||||||
|
# blank_lead <repo> <skill>: prefix that skill's SKILL.md with blank lines.
|
||||||
|
blank_lead() {
|
||||||
|
local f="$1/plugins/demo/.apm/skills/$2/SKILL.md"
|
||||||
|
{ printf '\n \t\n'; cat "$f"; } > "$f.tmp" && mv "$f.tmp" "$f"
|
||||||
|
}
|
||||||
|
F="$(make_fixture)"
|
||||||
|
(cd "$F" && git checkout -q main)
|
||||||
|
blank_lead "$F" alpha; commit "$F" "alpha leading blank"
|
||||||
|
(cd "$F" && git checkout -q feature && git merge -q main)
|
||||||
|
write_skill "$F" demo alpha 'version: "1.0.0"' "lead body"; blank_lead "$F" alpha; commit "$F"
|
||||||
|
expect_fail "unbumped skill with leading blank lines is held to its baseline version" \
|
||||||
|
"alpha: 1\.0\.0 -> 1\.0\.0 \(not above merge-base\)" "$F"
|
||||||
|
write_skill "$F" demo alpha 'version: "1.0.1"' "lead body 2"; blank_lead "$F" alpha; commit "$F"
|
||||||
|
expect_pass "bumped skill with leading blank lines passes" "$F"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Results: $PASS passed, $FAIL failed"
|
echo "Results: $PASS passed, $FAIL failed"
|
||||||
[[ $FAIL -eq 0 ]]
|
[[ $FAIL -eq 0 ]]
|
||||||
|
|||||||
Reference in New Issue
Block a user