Files
prose-contracts/AGENTS.md
T
abiba-bot 8f1e5eebc4
PR Pipeline — Authorize → Validate → Review → Merge / auth (pull_request) Successful in 5s
PR Pipeline — Authorize → Validate → Review → Merge / validate (pull_request) Successful in 3s
PR Pipeline — Authorize → Validate → Review → Merge / lint (pull_request) Successful in 18s
PR Pipeline — Authorize → Validate → Review → Merge / ai-review (pull_request) Successful in 3s
PR Pipeline — Authorize → Validate → Review → Merge / gate (pull_request) Successful in 1s
feat(security): commit-time secret guard that FAILS the build on a committed credential
The 2026-09-17 purge removed six live credentials that had sat in this repo
for weeks, several in .md prose. Nothing blocked that class of commit, so a
warning in a stream nobody reads was the only signal. This adds a guard that
fails the build instead of warning.

Guard
- scripts/secret-scan.sh: bash + coreutils + grep/sed/awk + git only (the Gitea
  Actions runner executes job steps inside the runner container — BusyBox grep,
  no node/python). Modes: --tree (git-tracked, default), --path DIR (no git),
  --staged (pre-commit), --diff REF. Exit 1 on a finding, 2 on config error.
- scripts/secret-patterns.tsv: checked-in pattern list — sk-, sk-or-v1-,
  sk_live_, literal Bearer tokens, PVEAPIToken=, raw Authorization values, PEM
  private-key blocks, prose credential lines, and password/api_key/secret/token
  assignments carrying a literal value. Prose is scanned exactly like code.
- scripts/secret-allowlist.tsv: one entry per deliberate synthetic example, each
  with a reason. A missing reason is a hard error (fail closed). The 2026-09-17
  purge's `«vault: ...»` placeholders are listed explicitly rather than filtered
  by a general "vault"/"synthetic" rule, so a new occurrence still needs a
  reviewed, reasoned entry.
- A small inert-value classifier drops env refs, paths, dotted code access,
  variable names and right-truncated redactions; it does not know the words
  "synthetic"/"example", so a fabrication is always an explicit exception.
- Findings are printed with the credential masked; a scan never echoes a full
  secret into the log.

Wiring
- .gitea/workflows/pr-pipeline.yaml lint job: explicit "Committed-credential
  scan" step plus the self-test. A finding fails the required
  `pr-pipeline / lint` context, which the merge gate depends on.
- scripts/prose-lint.sh (the local gate): a "Secret scan" section, so
  `bash scripts/prose-lint.sh` before pushing is equivalent to CI.

Tests
- tests/test_secret_scan.sh: 20 cases. Plants pattern-matching fixtures in temp
  trees (outside every allowlisted path) and asserts the guard FAILS, including
  the --staged commit-time path; asserts the tree is quiet; asserts allowlisted
  text at an unlisted path still fails (path-explicit, not word-based); asserts
  a reasonless allowlist entry exits 2.

Verified: guard run against 8245716^ (the pre-fix revision, before the purge)
fails on the real OpenRouter/LiteLLM/Zulip/Proxmox/Stirling credentials; guard
run over the current tree is clean.
2026-09-22 15:04:37 +00:00

144 lines
6.0 KiB
Markdown

# AGENTS.md — Prose Contracts Repo
All agents operating on prose contracts MUST follow this workflow. No exceptions.
## The Rule
**No agent pushes directly to `main`. All changes go through PRs with automated validation.**
## Why
Two incidents taught us this:
1. **The .117→.19 IP fix** — A stale IP in a contract was "fixed" without verification, breaking Zulip. The fix was right but the approach was wrong. Automated consistency checks would have caught it.
2. **The /grafana/ route regression** — An nginx route that was deliberately removed (Jul 2) was re-added to a contract diagram. CI linting now catches this automatically.
## Agent Workflow
```
┌─────────────────────────────────────────────────────────┐
│ 1. Clone repo → create branch → make changes │
│ 2. Push branch → open PR │
│ 3. CI pipeline runs automatically: │
│ ✅ validate: frontmatter (kind, name, description) │
│ ✅ lint: structure + regression detection │
│ ✅ ai-review: LiteLLM reviews diff vs ground truth │
│ 4. All green → merge PR to main │
│ 5. Agents run contracts from main │
└─────────────────────────────────────────────────────────┘
```
## Branch Protection (enforced by Gitea)
| Rule | Enforcement |
|------|------------|
| Direct push to `main` | ❌ Blocked (except abiba-bot for emergencies) |
| PR merge without passing CI | ❌ Blocked — all 3 checks must be green |
| Status check contexts | `pr-pipeline / validate`, `pr-pipeline / lint`, `pr-pipeline / ai-review` |
## What the CI checks for
### Stage 1 — Validate
- YAML frontmatter is valid (proper `---` delimiters)
- `kind` field is one of: `function`, `responsibility`, `gateway`, `pattern`, `test`, `template`
- `name` and `description` fields are present
### Stage 2 — Lint
- Responsibility contracts have `## Maintains`
- Function contracts have `## Parameters` and `## Returns`
- **Regression rules (automatic rejection):**
- `/grafana/` nginx route — was reverted Jul 2, must not reappear
- `CT 122` or `CT 123` as CT ID labels — don't exist in the cluster
- These rules are hardcoded in `scripts/prose-lint.sh`
- **Committed-credential guard:** `scripts/secret-scan.sh` FAILS the build on
credential-shaped strings (patterns in `scripts/secret-patterns.tsv`, prose
included). Tolerated literals are listed one-per-example with a reason in
`scripts/secret-allowlist.tsv`; never allowlist a live credential. It runs in
the CI lint job, in `scripts/prose-lint.sh`, and via
`bash scripts/secret-scan.sh --staged` before committing.
### Stage 3 — AI Review
- Diff is sent to `syslog-auto` model via LiteLLM
- Review checks against infrastructure-control ground truth:
- CT IDs match the PVE cluster inventory in `infrastructure-control.prose.md` Appendix B (100-120 with gaps; no 122/123)
- Grafana is direct LAN :3001, NOT behind nginx
- Zulip is CT 117 on storepve (bridge IP .19)
- Strix Halo :8080 is firewalled to .116 only
- Review is posted to the PR
## Authorization
### Who can change what
| Contract | Sensitivity | Who can change |
|----------|------------|----------------|
| `infrastructure-control.prose.md` | **CRITICAL** — topology source of truth | Abiba, Tanko (Tanko maintains its own CT row) |
| `proxmox-monitor.prose.md` | **CRITICAL** — deployed monitoring | Abiba only |
| `hermes-config-template.prose.md` | **HIGH** — all agent configs | Abiba, Mumuni, Tanko |
| `zulip-health.prose.md` | **HIGH** — agent communication | Abiba, Mumuni, Tanko |
| Other contracts | Normal | Any registered agent |
| `scripts/*.sh` | **HIGH** — runtime scripts | Abiba only |
### Enforcement (self-policing)
The CI does not block based on author identity today (Gitea doesn't support CODEOWNERS natively). Instead, agents self-enforce:
1. Before changing a CRITICAL contract, check with Abiba
2. If you're unsure, tag `@abiba-bot` in the PR description
3. Abiba reviews CRITICAL contract changes before merge
## Emergency Bypass
In an emergency (service down, fix must ship immediately):
1. Push to a branch
2. Open PR with `[EMERGENCY]` in the title
3. CI still runs — but if it fails and the fix is verified, abiba-bot can bypass and push directly to main
4. Post-incident: open a follow-up PR to fix any CI violations
## Quick Start
```bash
# Clone
git clone https://git.sysloggh.net/SyslogSolution/prose-contracts.git
cd prose-contracts
# Create branch
git checkout -b fix/my-change
# Make changes, test locally
bash scripts/prose-lint.sh # run lint locally before pushing
# Push and open PR
git add -A
git commit -m "fix: description of change"
git push origin fix/my-change
# Open PR at https://git.sysloggh.net/SyslogSolution/prose-contracts/pulls
# CI runs automatically — wait for all checks to pass
# Merge when green
```
## Verification Before Acting
**Contracts are leads, not facts.** Live-state fields (IPs, ports, credentials) drift.
Before acting on any value from a contract, verify it against the live system.
Follow the `verify-before-mutate` protocol:
```bash
safe-mutate --verify "CMD" [--expect "PATTERN"] --mutate "CMD" [--reason "WHY"]
```
## Writing New Contracts
Read the [Authoring Guide](docs/AUTHORING-GUIDE.md) before writing any new contract.
It covers the full process: verify → draft → lint → review → ship, with templates
and style rules.
## Maintaining this file
Keep this file for knowledge useful to almost every future agent session in this project.
Do not repeat what the codebase already shows; point to the authoritative file or command instead.
Prefer rewriting or pruning existing entries over appending new ones.
When updating this file, preserve this bar for all agents and keep entries concise.