mirror of
https://github.com/msitarzewski/agency-agents.git
synced 2026-10-10 04:35:07 +00:00
fix(ci): reject undeployable runbook rosters
This commit is contained in:
+29
-12
@@ -8,7 +8,8 @@
|
||||
# team deploy, mapping each roster slug to a catalog agent. If a slug there
|
||||
# doesn't resolve to a real agent file, the app can't deploy that team — so this
|
||||
# check fails the build when:
|
||||
# 1. runbooks.json is not valid JSON, or an entry is missing a required field
|
||||
# 1. runbooks.json is not valid JSON, or an entry has empty required metadata
|
||||
# or no deployable agent roster
|
||||
# 2. any roster `agents[]` slug does not match an agent .md filename stem
|
||||
# 3. any `doc` path does not exist
|
||||
# 4. a runbook `slug` is duplicated
|
||||
@@ -53,21 +54,37 @@ if not isinstance(runbooks, list) or not runbooks:
|
||||
|
||||
seen_slugs = set()
|
||||
total_refs = 0
|
||||
for rb in runbooks:
|
||||
for index, rb in enumerate(runbooks, 1):
|
||||
if not isinstance(rb, dict):
|
||||
errors.append(f"runbook #{index} must be an object")
|
||||
continue
|
||||
rid = rb.get("slug", "<no slug>")
|
||||
for field in ("slug", "title", "mode", "doc", "roster"):
|
||||
if field not in rb:
|
||||
errors.append(f"runbook '{rid}' is missing required field \"{field}\"")
|
||||
if rb.get("slug") in seen_slugs:
|
||||
errors.append(f"duplicate runbook slug '{rb.get('slug')}'")
|
||||
seen_slugs.add(rb.get("slug"))
|
||||
for field in ("slug", "title", "mode", "doc"):
|
||||
value = rb.get(field)
|
||||
if not isinstance(value, str) or not value.strip():
|
||||
errors.append(f"runbook '{rid}' requires a nonempty '{field}' string")
|
||||
if isinstance(rid, str):
|
||||
if rid in seen_slugs:
|
||||
errors.append(f"duplicate runbook slug '{rid}'")
|
||||
seen_slugs.add(rid)
|
||||
doc = rb.get("doc")
|
||||
if doc and not os.path.isfile(doc):
|
||||
if isinstance(doc, str) and doc.strip() and not os.path.isfile(doc):
|
||||
errors.append(f"runbook '{rid}': doc path does not exist: {doc}")
|
||||
for g in rb.get("roster", []):
|
||||
for slug in g.get("agents", []):
|
||||
roster = rb.get("roster")
|
||||
if not isinstance(roster, list) or not roster:
|
||||
errors.append(f"runbook '{rid}' requires a nonempty 'roster' array")
|
||||
continue
|
||||
for group_index, g in enumerate(roster, 1):
|
||||
if not isinstance(g, dict):
|
||||
errors.append(f"runbook '{rid}' / group #{group_index} must be an object")
|
||||
continue
|
||||
agents = g.get("agents")
|
||||
if not isinstance(agents, list) or not agents:
|
||||
errors.append(f"runbook '{rid}' / group '{g.get('group','?')}' requires a nonempty 'agents' array")
|
||||
continue
|
||||
for slug in agents:
|
||||
total_refs += 1
|
||||
if slug not in real:
|
||||
if not isinstance(slug, str) or slug not in real:
|
||||
errors.append(f"runbook '{rid}' / group '{g.get('group','?')}': "
|
||||
f"slug '{slug}' does not match any agent .md filename stem")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user