From 7ed03ed5e77aaf2dcb6d6119f6c321ee0a30de6d Mon Sep 17 00:00:00 2001 From: Rudy Celekli Date: Mon, 28 Sep 2026 01:08:48 -0400 Subject: [PATCH] fix(validation): reject unclosed agent frontmatter --- scripts/lint-agents.sh | 5 ++++ scripts/test-convert-outputs.sh | 9 ++++--- scripts/test-frontmatter-closing.sh | 37 +++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 scripts/test-frontmatter-closing.sh diff --git a/scripts/lint-agents.sh b/scripts/lint-agents.sh index 086b386c..4be7ebcb 100755 --- a/scripts/lint-agents.sh +++ b/scripts/lint-agents.sh @@ -96,6 +96,11 @@ lint_file() { errors=$((errors + 1)) return fi + if ! awk 'NR > 1 && $0 == "---" {found = 1; exit} END {exit !found}' "$file"; then + echo "ERROR $file: missing frontmatter closing ---" + errors=$((errors + 1)) + return + fi # Extract frontmatter (between first and second ---) local frontmatter diff --git a/scripts/test-convert-outputs.sh b/scripts/test-convert-outputs.sh index 5ecdd242..b546e480 100755 --- a/scripts/test-convert-outputs.sh +++ b/scripts/test-convert-outputs.sh @@ -174,9 +174,12 @@ def find_desc(obj): return None def frontmatter(text): - if not text.startswith("---"): raise ValueError("no frontmatter") - parts = text.split("\n---", 1) - return yaml.safe_load(parts[0][3:]) + lines = text.splitlines() + if not lines or lines[0] != "---": raise ValueError("no frontmatter") + for end in range(1, len(lines)): + if lines[end] == "---": + return yaml.safe_load("\n".join(lines[1:end])) + raise ValueError("missing frontmatter closing ---") def parsed_desc(path, fmt): text = open(path, encoding="utf-8").read() diff --git a/scripts/test-frontmatter-closing.sh b/scripts/test-frontmatter-closing.sh new file mode 100644 index 00000000..7017b5f4 --- /dev/null +++ b/scripts/test-frontmatter-closing.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +# An unclosed source frontmatter must not become a deployable empty persona. +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +FIXTURE="$(mktemp -d "${TMPDIR:-/tmp}/agency-frontmatter-closing.XXXXXX")" +trap 'rm -rf "$FIXTURE"' EXIT + +cat > "$FIXTURE/unclosed.md" <<'EOF' +--- +name: Broken Agent +description: This agent is missing its closing frontmatter fence +color: blue +# Identity +# Core Mission +# Critical Rules +EOF + +if bash "$SCRIPT_DIR/lint-agents.sh" "$FIXTURE/unclosed.md" > "$FIXTURE/invalid.log" 2>&1; then + echo "linter accepted an agent with no closing frontmatter fence" >&2 + exit 1 +fi +grep -Fq 'missing frontmatter closing ---' "$FIXTURE/invalid.log" + +cat > "$FIXTURE/valid.md" <<'EOF' +--- +name: Valid Agent +description: This agent has a closing frontmatter fence +color: blue +--- +## Identity +## Core Mission +## Critical Rules +EOF +bash "$SCRIPT_DIR/lint-agents.sh" "$FIXTURE/valid.md" > "$FIXTURE/valid.log" 2>&1 + +echo "PASS: unclosed frontmatter is rejected and a valid agent still passes"