forge-bot v1: scaffold, model, config, CI #1

Merged
chris merged 25 commits from v1 into main 2026-11-04 01:57:40 +00:00
Owner

Scaffold: module, shared model types, config loading, CI workflow. Branch v1 accumulates Tasks 8-14; do not merge yet.

Scaffold: module, shared model types, config loading, CI workflow. Branch v1 accumulates Tasks 8-14; do not merge yet.
forge-bot: module, model, config, CI workflow
All checks were successful
ci / test (pull_request) Successful in 42s
ci / image (pull_request) Has been skipped
86faecfa7b
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
forge-bot: validate safety config values, reject empty secrets, harden mktemp
All checks were successful
ci / test (pull_request) Successful in 2s
ci / image (pull_request) Has been skipped
16b8cf848a
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
forge-bot: gofmt config_test
All checks were successful
ci / test (pull_request) Successful in 2s
ci / image (pull_request) Has been skipped
a4e6863d4d
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
inventory: owner-signed head verification; teams.yaml and forge-bot.yaml parsers
All checks were successful
ci / test (pull_request) Successful in 15s
ci / image (pull_request) Has been skipped
3631a762c4
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
inventory: fail-closed keyring, hash/type policy, stricter parsers
All checks were successful
ci / test (pull_request) Successful in 5s
ci / image (pull_request) Has been skipped
aabbc8a0a9
LoadKeyring reads every armored block, rejects duplicate primary keys,
private key material and allow-listed fingerprints with no key.
VerifyCommit rejects non-binary and weak-hash (SHA-1) signatures and
returns an empty fingerprint with every error. ParseFingerprints needs
40/64 hex digits; teams.yaml names are ASCII AlphaDashDot, case-folded
unique, groups free of control characters.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
inventory: strict key reading, secret subkeys, weak key signatures, name hardening
All checks were successful
ci / test (pull_request) Successful in 7s
ci / image (pull_request) Has been skipped
01148a6c8a
LoadKeyring now fails on any packet or entity it cannot parse (a silently
dropped or ignored revocation could leave a stale key trusted), rejects
secret subkeys in public armor, and rejects self-signatures and subkey
bindings that use a hash outside SHA-2/SHA-3. teams.yaml rejects '.' and
'..' names and invisible, format or non-ASCII-space characters in groups.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
keycloak: complete paged reads; SetPicture is the only write
All checks were successful
ci / test (pull_request) Successful in 18s
ci / image (pull_request) Has been skipped
21436e7738
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
keycloak: fix round 1 (events filter, no state fields in PUT, allowlist transport, consistent reads)
All checks were successful
ci / test (pull_request) Successful in 7s
ci / image (pull_request) Has been skipped
a7c5516893
AdminEvents drops authRealm (matches realm UUID); SetPicture omits
enabled/emailVerified/requiredActions/federationLink, re-reads and returns
ErrConcurrentEdit; transport allowlist plus stronger AST guard; single-page
user and member reads; temporary vs permanent lock; redacting String;
token cache floor.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
keycloak: fix round 2 (drop brute-force read, pin origin, refuse redirects, wire-form path check)
All checks were successful
ci / test (pull_request) Successful in 7s
ci / image (pull_request) Has been skipped
33d1be9c7f
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
forgejo: guard comment matches the no-redirect policy
All checks were successful
ci / test (pull_request) Successful in 8s
ci / image (pull_request) Has been skipped
bb8500d5ce
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
guard: per-category breaker with floor and override; selfcheck: forge-bot's own admin events
All checks were successful
ci / test (pull_request) Successful in 9s
ci / image (pull_request) Has been skipped
50164bc5b1
keycloak.Identity gains FirstName, LastName and Attributes (all but picture)
so the concurrent-edit check and the self-check catch any non-picture write.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
plan: fix round 2 (group_unread finding, true-only owners, duplicate logins still lose)
All checks were successful
ci / test (pull_request) Successful in 9s
ci / image (pull_request) Has been skipped
b70add692a
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
selfcheck, guard, keycloak: fix round 1 (match before snapshot, 26.8.1 update semantics, ErrUnchanged, start-anchored overlap window)
All checks were successful
ci / test (pull_request) Successful in 9s
ci / image (pull_request) Has been skipped
0986c4085a
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
selfcheck, keycloak: fix round 2 (seen prune vs read bound, post-PUT errors wrap ErrConcurrentEdit, future-stamped events, write_unaudited)
All checks were successful
ci / test (pull_request) Successful in 9s
ci / image (pull_request) Has been skipped
38f79d3107
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
selfcheck: RecordWrite contract and its loud edges documented
All checks were successful
ci / test (pull_request) Successful in 9s
ci / image (pull_request) Has been skipped
8c96b768f9
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
forge-bot: cycle, apply, audit, metrics, main
All checks were successful
ci / test (pull_request) Successful in 28s
ci / image (pull_request) Has been skipped
59813f9363
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
forge-bot: Task 14 fix round 1 (override bound to the head, blind self-check, mode gate, shutdown, alerts, read scoping)
All checks were successful
ci / test (pull_request) Successful in 14s
ci / image (pull_request) Has been skipped
0746156f68
- override: honoured only if the verified head set or changed it (first
  parent from the signed payload); future committer time rejected
- selfcheck: events_unread finding on a failed admin-event read; records
  expire into write_unaudited even when Check cannot run
- apply gated on the admitting job; SIGTERM finishes the change in flight
  (25 s grace), then stops; main exits 1 if the HTTP server dies
- alerts: owner paging apply-only, first-sample unexpected writes,
  NotConverging and Stale timing; promtool tests
- mapped team/group read failures skip only the teams job
- inventory tests: per-call now (flake)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FWhaDeswMqYvQaVdpL8oit
forge-bot: Task 14 fix round 2 (reported records still match, events_unread for 8m, parent commit check, lint-fatal)
All checks were successful
ci / test (pull_request) Successful in 14s
ci / image (pull_request) Has been skipped
cfde272ba9
- selfcheck: a record that expired into write_unaudited stays matchable
  for 6 h, so the bot's own write read after an outage is clean; records
  capped at 1000
- alerts: ForgeBotSelfCheckBlind{events_unread} for: 8m, so one failed
  read cannot fire it
- override: a 404 at the parent is resolved by asking for the parent
  commit; an unknown parent is a failed read
- rule tests: promtool --lint=all --lint-fatal and unique (alert, labels)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FWhaDeswMqYvQaVdpL8oit
selfcheck: retention, cap and restart edges described accurately
All checks were successful
ci / test (pull_request) Successful in 14s
ci / image (pull_request) Has been skipped
596be7fe6d
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FWhaDeswMqYvQaVdpL8oit
forge-bot: final-review fix pass (held losses write no picture, finding kinds, redacted credentials, govulncheck)
All checks were successful
ci / test (pull_request) Successful in 1m17s
ci / image (pull_request) Has been skipped
460c600a6e
- avatar: a picture removed because access was lost is a loss, so the loss
  breaker holds it with the prohibit; a held bulk loss writes nothing to SSO
- findings: model.Finding lists every kind; it equals the exported label
  set; every alerted kind is raised by the composed bot (access_group_empty
  now raised by the read; invalid_policy unalerted as unreachable); new
  ForgeBotAccountSkipped and ForgeBotConcurrentEdit
- secret.Value holds credentials behind a pointer with redacting
  String/GoString/Format/MarshalJSON/MarshalText/LogValue; config and both
  clients use it; no fmt verb or json.Marshal of a client, config or Runner
  shows a credential
- Owners-team write refusal raises invalid_teams_map; a mapped group
  missing or ambiguous in SSO raises group_unread and is named in the log
- config rejects group paths without a leading / or with empty segments
- CI: govulncheck v1.9.0; go.mod pins toolchain go1.26.10 (stdlib fixes)
- README matches the code

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FWhaDeswMqYvQaVdpL8oit
forge-bot: residual fixes (picture loss only with this cycle's prohibit, owners-unknown withholds it, findings selector parse, dot segments)
All checks were successful
ci / test (pull_request) Successful in 18s
ci / image (pull_request) Has been skipped
ci / test (push) Successful in 18s
ci / image (push) Successful in 5s
9be4857b47
- avatar: a removal is a loss only when it travels with this cycle's
  prohibit (no access, not prohibited, not an Owner); stale removals and an
  Owner's removal are profile changes and never hold an offboarding
- avatar: with no Owners known, those loss removals are withheld with an
  owners_unknown finding, so every loss is withheld
- test: every forge_bot_findings selector is parsed whatever its other
  matchers, so a dead alert is caught
- config: group paths reject . and .. segments
- README breaker row matches

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FWhaDeswMqYvQaVdpL8oit
chris merged commit 9be4857b47 into main 2026-11-04 01:57:40 +00:00
chris deleted branch v1 2026-11-04 01:57:40 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
realliance-ops/forge-bot!1
No description provided.