docs(readme): explain the reasoning behind three design choices - #260
Merged
Conversation
Three places where a security reviewer's obvious follow-up question went unanswered, so the claim read as naive or arbitrary: 1. "Each record is HMAC-signed" — but the key defaults to .aigis/audit_key on the same machine as the agent, so the signature does not prove the developer running the agent didn't edit the log. The README never said this. Adds a section stating the boundary and the three actual mitigations (explicit key held off-machine, ACLs on the key file, SIEM forwarding — the one that holds for insider threat). 2. "The shipped rules are a deny-list" — stated the fact and the fail-closed recipe but never why deny-list is the default. Adds the reason (an agent that can't run `ls` is not usable) and notes that enumerating allow rules is real work. 3. The six capability axes are near-binary with no "ask the user" option, which invites "why not an allowlist?" Adds the reasoning (a prompt only protects someone who can judge it) and the non-obvious constraint behind git having three values (capability allows are evaluated before the baseline, so a blanket `git push*` allow would re-enable force-push). Every claim verified against the code: signed_log.py:114-157 for the key path and the Windows ACL caveat, policy.py:72 for default_decision, profiles.py:59 for the git values, tests/test_profiles.py:91 for the only-git-emits-allow assertion. Signed-off-by: killertcell428 <killertcell428@gmail.com>
The previous version of this branch introduced question-form labels
("Why there is no ask-the-user setting", "What the signed log does not
prove"), which raise the doubt before answering it. Reversed: each label
now states the conclusion, and the body explains why it holds.
Why there is no "ask the user" setting
-> Judgement happens here, once, for the whole group
What the signed log does not prove
-> The key's location bounds what the signature proves
Also drops the "that is the right question to ask" framing in the audit
section and replaces it with a plain ordering of the three mitigations by
what they cover. Anchor links updated to match; the Japanese heading
dropped its comma so the generated anchor is unambiguous.
Signed-off-by: killertcell428 <killertcell428@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Three claims in the README stated a fact but not the reasoning behind it. Left that way, each one reads as either naive or arbitrary to the audience the README is written for.
Each addition states its conclusion up front and then explains why it holds — no posed questions, no "you might be wondering".
1. HMAC signing — the key's location bounds what it proves
The biggest gap. The key defaults to
.aigis/audit_keyon the same machine as the agent (signed_log.py:114), auto-generated. The signature therefore catches an outside editor, not the log's own author — the developer running the agent has the key.The README claimed tamper-evidence without qualifying it. Adds a section naming the boundary and the three mitigations, ordered by what they cover:
chmodisn't enforced there (signed_log.py:152)2. Deny-list default — the reason it's the default
Previously stated the fact and the fail-closed recipe but not why deny-list is the shipped default. Adds it: an agent that can't run
lsisn't usable. Also notes that enumerating allow rules for a fail-closed posture is real work, so it can be budgeted rather than discovered later.3. Near-binary capability axes — judgement is a team-level decision
shell: none | unrestrictedwith no allowlist invites the assumption that an allowlist was simply overlooked. Adds the reasoning: a prompt only protects someone in a position to judge it, and a non-engineer interrupted mid-task either approves everything or refuses everything.Also documents the constraint behind
githaving three values rather than an on/off switch: capability rules are evaluated before the baseline, so any axis emitting a blanketgit push*allow would sit in front of the baseline's*--force*deny and silently re-enable force-push.Verification
Every claim checked against code, not docs:
.aigis/audit_key, auto-generateddefault_decisionisallowgitvalues arenone/local/pushgitis the only allow-emitting axisTest plan
#the-keys-location-bounds-what-the-signature-proves,#鍵の置き場所が署名で証明できる範囲を決める)tests/test_profiles.pylink resolves