Development record
2026-07-12 — iss-66 rules-loader trust boundary. Fixed the two mechanical items:
2026-07-12 — iss-66 rules-loader trust boundary. Fixed the two mechanical items:
the Load Lstat→ReadFile TOCTOU on .abcd/rules.json (now open-once O_NOFOLLOW +
fstat, C19) and the session-state dir moved off the world-writable shared /tmp to
the per-user cache dir (P14). P15 document-accepted, NOT changed: a per-repo
.abcd/rules.json can set a default domain dormant and flip the global kill
switch (Merge is intentionally per-field + sticky-kill-switch). Rationale: rules
are an opt-in, opinionated-but-overridable config layer; .abcd/rules.json is a
committed file (editing it needs repo write access, like any committed guardrail),
and the real enforcement of dangerous actions is harness-level (git-guardrails
hooks, the iss-62 identity gate, pre-commit), not the injected advisory prose.
Silencing a domain removes prose, not a hard gate. Deferred design alternative
(surfaced, not taken): introduce a protected "guardrail" domain class that a
per-repo override cannot set dormant and that the kill switch cannot silence —
this adds a new protected-domain concept to the rules contract, a maintainer
decision, not an autonomous change.
Frontmatter
| id | dcn-2607120000000002 |
|---|---|
| type | decision |
| date | 2026-07-12 |
.abcd/work/decisions/dcn-2607120000000002-iss-66-rules-loader-trust-boundary-fixed.md
open on GitHub ↗ · commit history ↗
mentions2
- iss-62abcd-managed repos must guarantee the user's chosen git identity (name + email) is honoured on every commit. ahoy doctor should detect when the effective git author/committer identity diverges from the user's GitHub identity — a stray repo-local user.name/user.email override (e.g. a sandbox 'Test User <test@example.com>' shadowing the global identity), or committer != author — and, rather than silently setting it, PROPOSE a default (the global git identity, or the gh-authenticated account) and ASK the user to confirm before writing repo-local config. Motivation: a repo-local 'Test User <test@example.com>' override silently authored/committed 54 commits (pushed to origin) before detection this run, forcing a history rewrite + force-push to correct. A managed-repo identity gate at ahoy/doctor time catches it before the first commit.
- iss-66rules loader trust-boundary (itd-3): an untrusted per-repo .abcd/rules.json can silence default guardrail domains — Merge() ORs the global kill switch (rules.go:156) and mergeDomain lets an override set any default domain dormant, so a cloned repo suppresses all rule injection (P15); session-state lives in a predictable shared /tmp path (os.TempDir/abcd-rules-state, sha256(session).json, session defaults to constant default) letting a local co-tenant suppress injection fail-open (inject.go:99, P14); Load() Lstats rules.json then os.ReadFile re-resolves by name, a symlink-swap TOCTOU (rules.go:132, C19). Detector: override cannot disable a default guardrail/kill-switch; state under UserCacheDir+ownership check; open-once O_NOFOLLOW+fstat. Corpus: P15, P14, C19.