Repository navigation
One edit to a shared payload was seven HIGH incidents, and the rung that explained it was lost to every git timeout - #61
Open
opencdlee-dotcom wants to merge 4 commits into
Conversation
…hat explained it was lost to every git timeout Precision plan step S7 (Phase 3): the operator's own LaunchAgents. Gap 1: one payload edit, seven cases. #383 and #392-#397 were one edit to ~/Ai/Universe/tools/aikit/schedule/run.py (4a1646366adf -> 25ee9a4593c2), one incident per com.aikit.* plist that runs it. check_persistence now collects a change confined to a payload's bytes (same program, argv, env and payload path; never an attack-defined job) and emits ONE finding per (payload, new sha): case persistence:payload-update:<payload>, the referring labels in the detail and their plist paths in referrer_paths. Same shape as the OS-program case. _accept_into_baseline promotes every job a verdicted payload case names, so one benign-positive ends the re-assertion for all of them. Store migration persistence_payload_case_20260923 folds open per-plist incidents whose newest evidence is payload-only into that case (evidence matched, created_at < now, adjudicated rows untouched). Gap 2: why custody read null. The rung did reach the payload. _custody(run.py, sha) answered local-commit (MEDIUM) on 193 of the 217 scans that recorded the change. The 24 scans that recorded custody null and HIGH were the scans where git did not answer: 11-190 s per plist there, against 0-1 s when it answered (probe timeouts are 10-15 s). Seven plists asked git about the same file seven times a scan. Each non-answer flipped the case back to HIGH and wrote a new event. The payload is now graded once per scan, by _custody_payload. It asks the same intent-then-git questions. When git gives no answer at all, it asks whether the bytes were already explained: by the custody ledger (a rung this payload earned on an earlier scan, now remembered) or by an intent receipt for the same sha at another path. Either one carries as copy-of-graded, the weakest rung. On the recorded corpus that takes run.py from 24 HIGH scans to 1 (the first sighting, before any answer existed). #319 (~/.local/bin/improver bytes -> a588f96d11b4) was never asked. An extension-less payload fails _intent_worthy, and its receipt binds the source path the agent wrote (.../VSCode Projects/improver/improver.py), not the installed copy. _custody_payload drops that hook-mode prefilter, and _intent_receipt finds the receipt by sha. Result: copy-of-graded, MEDIUM. Also touched in the same branch: the per-job payload custody lookup now honours attack_defined, as its comment already promised. Before this, a DYLD-injected job whose payload was committed recorded custody=self-committed on an attack-defined finding. The severity was untouched, but the chain and routing tiers read that field. Gap 3: producer fields. On current code the NEW finding already resolves a producer class through its subject. The seven cited incidents lack one only in their pre-2026-08-29 evidence, which predates subjects and the runner subcommand fix (script_target None) and cannot be recovered. The NEW finding now also carries program_sha and target_sha flat, and target_sha on the subject, so recorded evidence names both halves of what the job executes. Also touched: tests/conftest.py. The new ledger writer turned an existing test leak into a write. FamiliesAreTheAdjudicationSurface re-diffs the REAL LaunchAgents through _accept_into_baseline, and during this branch's suite run it appended a local-commit row for run.py to the operator's ~/.aegis/custody.jsonl. That row has been removed by hand. The suite now refuses and reports any _custody_remember aimed at the real ledger, the same way it handles the notary anchor. The guard also stops a pre-existing leak: TestWritEnforcementIsActuallyWired reached the real ledger 45 times through _grade_binary. Tests: tests/test_persistence_payload_case.py (28). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…adder never read them
`_package_receipt` covered Homebrew, VS Code, pipx, uv's interpreters, winget,
Chocolatey and the distro managers. Two installers on a developer's machine
leave a receipt just as checkable, and their binaries were the process
sensor's residue: an ad-hoc `~/.local/bin/uv` (#344, #514) and the Playwright
browser cache (#346, #433-#435).
- `_cargo_dist_receipt`: reads `<config>/<d>/<d>-receipt.json` (nothing else),
and answers when the path resolves to `<install_prefix>/<binary>` for a
binary the receipt lists. Roots taken from the uv 0.11.6 installers
(cargo-dist 0.31.0): `${XDG_CONFIG_HOME:-$HOME/.config}` on posix,
`%XDG_CONFIG_HOME%` else `%LOCALAPPDATA%` on Windows; hierarchical and
cargo-home layouts install under `bin/`. A `binaries` entry with a separator
is refused. Parsed once per scan, cleared by `_reset_custody_probes`.
- `_playwright_receipt`: a file under a `<browser>-<rev>` directory directly
beneath a Playwright cache root that holds `INSTALLATION_COMPLETE`, the
marker the download worker writes after extracting. Roots as Playwright's
registry resolves them; an absolute `PLAYWRIGHT_BROWSERS_PATH` is honoured,
"0" and relative values are not guessed.
Both answer only `package-managed`, the vouched tier. They are
same-uid-forgeable, exactly like the Homebrew receipt already trusted: one
step, never to LOW, risk weight 0.25, and `_grade_binary` never consults them
for attack-defined evidence.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…to agent/precision-s7/integration
Precision plan S7 follow-up. Seven com.aikit.* LaunchAgents (#287 #288 #295
#296 #300 #302 #307: `uv run .../schedule/run.py <job>`) and xbar (#399)
reached the incident tier because a NEW persistence item carried no custody
rung at all. The CHANGED branch had a ladder and NEW had none. The seven
aikit incidents each interrupted HIGH on every sighting.
check_persistence now grades a NEW item by what it EXECUTES
(_custody_executes):
* the program goes through the binary ladder (_grade_binary: vouch,
package receipt -- now including cargo-dist and Playwright from the
merged receipts branch -- build output, carried copies);
* the payload script, when there is one, goes through _custody_payload;
* the item's rung is the WEAKER of the two (_weaker_rung: the rung the
risk tier weighs heavier, then the one that leaves the higher
severity). A strong program running an unexplained script explains
nothing, and an explained script run by an unexplained program explains
nothing either. No payload means the program's rung alone;
* attack-defined jobs (hostile argv, loader-injection env) get no rung,
as everywhere;
* _persistence_exec_extra states the argv rule: the item gets no rung if
the argv can run anything beyond program + payload. That covers a URL
anywhere, a stripped launcher wrapper, an interpreter with no payload
file (`python -m`, `npx pkg`), and anything before the payload except
the runner's one declared subcommand (`uv run --with evil`,
`--directory D python -m m`). For a non-interpreter it covers a path
argument, or any argument to a launcher such as `open -b`. Arguments
after the payload are the payload's own input. The rule fails closed.
* The finding records `custody` and is demoted by it. Program and payload
answers are memoized per call, so seven jobs sharing uv and run.py ask
once.
Direct measurement on this body today (live snapshot, ledger writer
disabled, store read-only): all seven aikit items grade uv as
package-managed (cargo-dist:astral-sh/uv@0.11.6) and run.py as
local-commit. The weaker rung is local-commit, so HIGH -> MEDIUM (digest).
That covers 321 recorded NEW-item HIGH events across the seven incidents.
xbar gets no rung on this base: publisher-signed ships with S5, and there
is no receipt for /Applications/xbar.app. Its NEW item already reads LOW
with today's trust (developer-id); the 271 HIGH events on #399 were
recorded while the trust was misread as `unsigned`. Weak rungs do not stop
a finding from joining a chain (S3's _custody_explained), so chains like
#296 can still form.
tests/test_custody_roster.py: check_persistence custody debt ratcheted 2 -> 1.
Merged origin/agent/precision-p2b/receipts (PR #63) first, as briefed.
Tests: 15 new cases in tests/test_persistence_payload_case.py
(NewItemIsGradedByWhatItRuns); the publisher-signed case is skipped until
S5's rung exists on the branch.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Owner
Author
|
Follow-up pushed (2e5bb9f, after merging PR #63's receipts branch): a NEW persistence item is now graded by what it executes. The program goes through _grade_binary and the payload through _custody_payload, and the item takes the weaker of the two rungs. Attack-defined jobs get no rung. _persistence_exec_extra sets the argv rule: nothing may run beyond program + payload. Measured today, read-only: the seven com.aikit.* items get uv package-managed + run.py local-commit, so they go HIGH -> MEDIUM (digest). xbar (#399) gets no rung on this base, because publisher-signed ships with S5; its NEW item is already LOW with today's trust. Full suite: 2219 passed, 7 skipped, 30 xfailed. 🤖 Generated with Claude Code |
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.
Precision plan step S7 (Phase 3): the operator's own LaunchAgents. Based on
agent/fable-precision/integration.What the live store showed
com.aikit.*→run.py bytes 4a1646366adf -> 25ee9a4593c2custody: nullon those findingslocal-commit(MEDIUM); the 24 that recordednull/HIGH took 11–190 s per plist against 0–1 s when git answered~/.local/bin/improvera588f96d11b4exists, custody never asked_intent_worthy, and the receipt binds the source path the agent wrote, not the installed copysubject_json); the empty ones are pre-2026-08-29 events, which predate subjects and the runner-subcommand fix (script_targetNone)Change
check_persistence: a change confined to a payload's bytes (same program, argv, env, payload path; never attack-defined) is collected and emitted as one finding per (payload, new sha): fingerprintpersistence:payload-update:<payload>:<sha>, casepersistence:payload-update:<payload>, the labels in the detail, the plist paths inreferrer_paths. Mirrors the OS-program case._custody_payload: the payload is graded once per scan. Intent receipt, then git, with no hook-mode prefilter. When git gives no answer, the bytes are asked whether they were already explained: by the custody ledger (a rung this payload earned before, now remembered) or by an intent receipt for the same sha at another path (_intent_receipt). Either carries ascopy-of-graded, the weakest rung. An actual git answer (untracked,remote-foreign) is never overridden._accept_into_baseline: one benign-positive on a payload case promotes every job it names (only jobs the recomputed diff still reproduces).persistence_payload_case_20260923: folds open per-plist incidents whose newest evidence is payload-only into the payload case (evidence-matched,created_at < now, adjudicated rows untouched). It folds 0 on the live store today, because #383/#392–#397 have already aged out.program_sha+target_sha,target_shaon the subject.custody=self-committedon an attack-defined finding.tests/conftest.pynow refuses and reports any_custody_rememberaimed at the real~/.aegis/custody.jsonl.FamiliesAreTheAdjudicationSurfacere-diffs the real LaunchAgents, and during this branch's first suite run it wrote a reallocal-commitrow for run.py. That row was removed by hand. The guard also stops a pre-existing leak:TestWritEnforcementIsActuallyWiredreached the real ledger 45 times through_grade_binary.Effect on the recorded corpus (read-only, scripted from
events)copy-of-graded(receipt at the source path).healthcheck.sh(#286/#365/#366): no receipt, not in a repo, no carry. It stays HIGH, as it should.backtest replay --days 30 --reobservePaired run on the same store snapshot, base
0d7d3b6vs this branch: identical (persistence 54 interrupt / 27 digest / 5638 seen; noise re-opened 127/214; open 132; assay 9/21). The only difference is the assay's random token. The harness replays persistence findings as recorded; S0b adds re-observation, so it cannot see this change. The morning baseline (persistence 54, 126/213, open 131) drifted because the corpus moved: #534 was closedre-gradedin the live store in between.Tests
tests/test_persistence_payload_case.py, 28 cases, green underSIM_BODY=win|linux|mac. Full suite result is in the builder report.🤖 Generated with Claude Code