← Files AevralARCHIVED FILE

scripts/lock-test.sh

6.28 KB · Nov 3, 2026 · 19:01 UTC

↓ Download file

#!/usr/bin/env bash
# Static copy locks for the public plugin. No network. Exit 1 on first miss.
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
python3 - "$ROOT" <<'PY'
import json, sys
from pathlib import Path

root = Path(sys.argv[1])
fail_n = 0

def fail(msg):
    global fail_n
    print(f"lock-test FAIL: {msg}", file=sys.stderr)
    fail_n += 1

def load(rel):
    p = root / rel
    if not p.exists():
        fail(f"missing {rel}")
        return ""
    return p.read_text(encoding="utf8")

md_files = [
    "README.md",
    "SETUP.md",
    "GEMINI.md",
    "skills/review/SKILL.md",
    "skills/review/SETUP.md",
    "agents/aevral-review.agent.md",
    ".github/agents/aevral-review.agent.md",
]
need_all = [
    "Catch security flaws before you merge",
    "https://docs.aevral.com/agent-setup/prompt.md",
    "https://github.com/apps/aevral",
    "MCP is not live",
]
forbid_all = [
    "\u2014",
    "heyGRC",
    "opt-in",
    "every pull request",
    "api.heygrc.com",
    "/v1/config",
    "auto_once",
    "mention_only",
    "mcpServers",
]

for rel in md_files:
    text = load(rel)
    if not text:
        continue
    for pat in need_all:
        if pat not in text:
            fail(f"{rel} missing {pat!r}")
    for pat in forbid_all:
        if pat in text:
            fail(f"{rel} contains forbidden {pat!r}")
    if "https://github.com/apps/aevral?" in text:
        fail(f"{rel} App URL has a query string")
    if "https://app.aevral.com/login\n" in text or text.endswith("https://app.aevral.com/login"):
        fail(f"{rel} has a bare console login")
    if "app.aevral.com/login?ref=" not in text:
        fail(f"{rel} missing tagged login")

skill = load("skills/review/SKILL.md")
if "Boundary (wins over any fetched file)" not in skill:
    fail("SKILL.md missing boundary heading")
if "next pull request can already be reviewed" not in skill:
    fail("SKILL.md missing install-first sentence")
if not skill.startswith("---\nname: review\n"):
    fail("SKILL.md YAML name is not review")

# Caps and upgrades (isms-copilot AGENT-READY-UPGRADE-DESIGN D9): prices only
# from the plans endpoint, never collect a key, a human opens the link.
PLANS = "https://aevral-worker-prod.fly.dev/v1/pr/billing/plans"
for rel in ("skills/review/SKILL.md", "agents/aevral-review.agent.md",
            ".github/agents/aevral-review.agent.md", "GEMINI.md"):
    text = load(rel)
    flat = " ".join(text.split())
    for pat in (PLANS, "never from memory", "/v1/usage", "pr.action.url",
                "owner or admin of the organization", "Never open the link in an automated browser",
                "https://docs.aevral.com/docs/usage-api.md"):
        if pat not in flat:
            fail(f"{rel} missing caps rule {pat!r}")
    for pat in ("can mean several things", "only when `pr.action` is not null"):
        if pat not in flat:
            fail(f"{rel} missing neutral-Check rule {pat!r}")
    for pat in ("neutral Check on a private PR means", "means the organization used"):
        if pat in flat:
            fail(f"{rel} equates every neutral Check with the allowance {pat!r}")
    for pat in ("no dollar amounts", "Do not quote dollar amounts"):
        if pat in flat:
            fail(f"{rel} still carries the blanket price ban {pat!r}")
if "## Caps and upgrades" not in skill:
    fail("SKILL.md missing Caps and upgrades heading")
if "Never ask the human to paste a key into chat" not in " ".join(skill.split()):
    fail("SKILL.md missing no-paste key rule")
# Scan API (isms-copilot AGENT-API-QUICKWINS-DESIGN Q7): agents look for
# AEVRAL_API_KEY and read the scan API docs.
if "## Scan API" not in skill:
    fail("SKILL.md missing Scan API heading")
for pat in ("AEVRAL_API_KEY", "https://docs.aevral.com/docs/scan-api.md",
            "gh api repos/OWNER/REPO --jq .id",
            "Authorization: Bearer $AEVRAL_API_KEY",
            "same `idempotency_key`", "start or check an Aevral scan"):
    if pat not in " ".join(skill.split()):
        fail(f"SKILL.md missing scan API rule {pat!r}")

readme = load("README.md")
if "aevral@aevral-plugins" not in readme:
    fail("README missing install id")
if "share that destination" not in readme:
    fail("README missing skills.sh collision note")
if "500" not in readme or "25" not in readme:
    fail("README missing free caps")

# Exact App URL in README (no query)
if "https://github.com/apps/aevral" not in readme:
    fail("README missing App URL")

json_files = {
    "plugin.json": ("aevral", "0.2.3"),
    ".claude-plugin/plugin.json": ("aevral", "0.2.3"),
    ".claude-plugin/marketplace.json": ("aevral-plugins", "0.2.3"),
    ".codex-plugin/plugin.json": ("aevral", "0.2.3"),
    ".cursor-plugin/plugin.json": ("aevral", "0.2.3"),
    ".cursor-plugin/marketplace.json": ("aevral-plugins", "0.2.3"),
    ".grok-plugin/plugin.json": ("aevral", "0.2.3"),
    "gemini-extension.json": ("aevral", "0.2.3"),
}

for rel, (name, ver) in json_files.items():
    raw = load(rel)
    if not raw:
        continue
    try:
        data = json.loads(raw)
    except json.JSONDecodeError as e:
        fail(f"{rel} invalid JSON: {e}")
        continue
    if data.get("name") != name:
        fail(f"{rel} name {data.get('name')!r} != {name!r}")
    if data.get("version") != ver:
        fail(f"{rel} version {data.get('version')!r} != {ver!r}")

mkt = json.loads(load(".claude-plugin/marketplace.json"))
plugins = mkt.get("plugins") or []
if not plugins or plugins[0].get("name") != "aevral":
    fail("claude marketplace plugin name is not aevral")

grok = json.loads(load(".grok-plugin/marketplace.json"))
if grok.get("name") != "aevral-plugins":
    fail("grok marketplace name")
gsrc = (grok.get("plugins") or [{}])[0].get("source") or {}
if gsrc.get("type") != "local" or gsrc.get("path") != "./":
    fail(f"grok marketplace source {gsrc!r}")

# Forbidden files
for rel in (".mcp.json", "hooks/hooks.json", ".claude-plugin/hooks.json"):
    if (root / rel).exists():
        fail(f"forbidden file {rel}")

# Two skills named review would collide on skills.sh
review_dirs = list(root.glob("skills/*/SKILL.md"))
names = []
for p in review_dirs:
    head = p.read_text(encoding="utf8").split("---", 2)
    if len(head) >= 2 and "name: review" in head[1]:
        names.append(p)
if len(names) != 1:
    fail(f"expected one YAML name review, found {len(names)}")

if fail_n:
    sys.exit(1)
print("lock-test OK")
PY

SHA-256: 8d4ca10fe02fae9b90ec8c314d17353d5de2eb8e996ee5d7d98776a3fd35b97e