Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions AUDIT.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,17 @@ Run [`WORKFLOW.md`][workflow]'s methodology against the repo's **own** Actions:

- **Secrets** - confirm each required secret exists (name only; values are not readable). Check the Actions store and, where the mechanism needs it (Docker Hub, codegen App), the Dependabot store too.

- **Dependabot ecosystem coverage** - for each ecosystem the repo's tree implies, `.github/dependabot.yml` must declare it: `github-actions` when `.github/workflows/` is present (its workflows reference actions) - otherwise those versions go stale and a stood-up merge-bot has no action-update PRs to auto-merge - and `devcontainers` when a `.devcontainer` is present. The mechanical check (`spec/audit.py`) asserts each implied ecosystem's **presence**; a tree-implied ecosystem declared nowhere is a **drift finding** (the file exists; its absence would instead be a file-presence letter). Then confirm **by inspection** that each declared ecosystem **dual-targets `main` + `develop`** per the [Branching Model][agents-branching-model] - the regex below cannot pair an ecosystem with its `target-branch`. Language ecosystems (`nuget`/`uv`/`npm`) are directory-scoped and audited by inspection too.

```sh
# Anchor to the line start (optional list dash) so a commented-out '# package-ecosystem:' is not counted.
decl=$(gh api "repos/<owner>/<repo>/contents/.github/dependabot.yml?ref=<ground>" --jq '.content' | base64 -d | grep -oE '^[[:space:]]*-?[[:space:]]*package-ecosystem:[[:space:]]*"?[a-z-]+' | grep -oE '[a-z-]+$' | sort -u)
Comment thread
ptr727 marked this conversation as resolved.
has() { gh api "repos/<owner>/<repo>/contents/$1?ref=<ground>" >/dev/null 2>&1; }
has .github/workflows && { grep -qx github-actions <<<"$decl" && echo "github-actions: present" || echo "github-actions: MISSING (workflows present)"; }
has .devcontainer && { grep -qx devcontainers <<<"$decl" && echo "devcontainers: present" || echo "devcontainers: MISSING (.devcontainer present)"; }
# then read dependabot.yml and confirm each present ecosystem has both a main and a develop target-branch entry
```

## 7. Verdict Model

Per dimension, record `operational | not-operational | N/A`, each with a letter verdict and an intent verdict:
Expand Down Expand Up @@ -125,6 +136,7 @@ The convergence model: the hub audits and the agent **applies** the fixes via ta
<!-- Repo -->

[agents]: ./AGENTS.md
[agents-branching-model]: ./AGENTS.md#branching-model
[audit-runner]: ./spec/audit.py
[codestyle]: ./CODESTYLE.md
[copilot-runbook]: ./.github/copilot-instructions.md
Expand Down
24 changes: 24 additions & 0 deletions spec/audit.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@

Usage: python3 spec/audit.py [RepoName ...] (default: every cataloged repo)
"""
import base64
import json
import pathlib
import re
import subprocess
import sys

Expand Down Expand Up @@ -177,6 +179,28 @@ def audit_repo(entry, spec):
for name in sorted(present - claimed_names):
findings.append(("DRIFT", f"secrets: {name} in the {store} store is claimed by no applicable mechanism (stale?)"))

# --- Dependabot ecosystem coverage ---
# A repo's tree implies Dependabot ecosystems it must track: github-actions when it ships workflows
# (the action versions they reference otherwise go stale, and a merge-bot then has no PRs to auto-merge),
# devcontainers when it ships a .devcontainer. dependabot.yml is YAML (no stdlib parser), so scan the
# declared package-ecosystem values by regex - anchored to the line start so a commented-out entry
# (# package-ecosystem: ...) is not read as declared. This asserts an implied ecosystem's *presence*
# only; that each declared ecosystem dual-targets main+develop (the fleet norm) is verified by
# inspection, not here. Only runs when dependabot.yml exists; its absence is already a file-presence
# LETTER below. Language ecosystems (nuget/uv/npm) are directory-scoped and not yet cross-checked here.
db = gh(f"repos/{slug}/contents/.github/dependabot.yml?ref={ground}", ok404=True)
if db and db.get("content"):
declared = set(re.findall(r'^[ \t]*-?[ \t]*package-ecosystem:[ \t]*["\']?([\w-]+)', base64.b64decode(db["content"]).decode("utf-8", "replace"), re.M))
implied = {}
workflows = gh(f"repos/{slug}/contents/.github/workflows?ref={ground}", ok404=True)
if isinstance(workflows, list) and any(e["name"].endswith((".yml", ".yaml")) for e in workflows):
implied["github-actions"] = ".github/workflows/ is present"
if gh(f"repos/{slug}/contents/.devcontainer?ref={ground}", ok404=True) is not None:
implied["devcontainers"] = ".devcontainer/ is present"
for eco, why in sorted(implied.items()):
if eco not in declared:
findings.append(("DRIFT", f"dependabot: {eco} ecosystem not declared though {why}; add it for both main and develop per the fleet norm"))

# --- File presence on the ground-truth branch ---
seen_paths = set()
for item in spec["files"]["baseline"]:
Expand Down
3 changes: 2 additions & 1 deletion spec/project-types.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@
"appliesTo": "*",
"checks": [
{ "id": "setup.secrets.present", "verdict": "letter", "assert": "Every requiredSecret for the repo's publish mechanisms is configured (per spec/secrets.json).", "intentRef": "repo-config/README.md" },
{ "id": "setup.secrets.noforbidden", "verdict": "letter", "assert": "No forbidden secret is present (e.g. a static NUGET_API_KEY on an OIDC repo).", "intentRef": "spec/secrets.json" }
{ "id": "setup.secrets.noforbidden", "verdict": "letter", "assert": "No forbidden secret is present (e.g. a static NUGET_API_KEY on an OIDC repo).", "intentRef": "spec/secrets.json" },
{ "id": "setup.dependabot.ecosystems", "verdict": "intent", "assert": "For each ecosystem the repo's tree implies, .github/dependabot.yml declares it (dual-target main+develop per the fleet norm): github-actions when .github/workflows/ is present (its workflows reference actions, else their versions go stale and a stood-up merge-bot has no PRs to auto-merge), devcontainers when a .devcontainer is present. A missing implied ecosystem is a drift finding. Language ecosystems (nuget/uv/npm) are directory-scoped, audited by inspection.", "intentRef": "AGENTS.md#branching-model" }
]
},
"linter-parity": {
Expand Down