Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
faf8d6e
feat(aegis): chain-of-custody grading — the monitor learns who "me" is
opencdlee-dotcom Aug 13, 2026
3dd0682
docs(readme): agent-surface custody grading + intent CLI
opencdlee-dotcom Aug 13, 2026
9eba4ec
feat(aegis): fleet-signed rung — cross-device custody via SSH commit …
opencdlee-dotcom Aug 13, 2026
4f291cb
fix(tests): pin bare-origin branch + clean env — CI git lacks the dan…
opencdlee-dotcom Aug 13, 2026
cf9f2e9
feat(aegis): custody grading for every sensor + hash the payload, not…
opencdlee-dotcom Aug 20, 2026
58a3667
fix(aegis): baseline died on any machine with a privilege-walled surface
opencdlee-dotcom Aug 20, 2026
651f84b
fix(aegis): a proven privilege wall stops masquerading as a degraded …
opencdlee-dotcom Aug 20, 2026
829a0d2
fix(aegis): the detector was not blind, it was unreadable
opencdlee-dotcom Aug 20, 2026
e33fe29
fix(aegis): `learn` reported itself as baseline tampering
opencdlee-dotcom Aug 20, 2026
98f2326
docs(aegis): the README promised tuning it no longer describes
opencdlee-dotcom Aug 20, 2026
742540a
fix(aegis): rotating-endpoint tolerance learned nothing from real ver…
opencdlee-dotcom Aug 20, 2026
94c2c5c
fix(aegis): harden response authorization and scan fidelity
opencdlee-dotcom Aug 21, 2026
9743f96
fix(aegis): the alert count was identity churn, not detection
opencdlee-dotcom Aug 21, 2026
7159328
fix(aegis): close response and incident identity gaps
opencdlee-dotcom Aug 23, 2026
742dbe4
fix(aegis): a project venv is package output too, and amfid was count…
opencdlee-dotcom Aug 23, 2026
1182d64
fix(aegis): parse captured site-packages paths portably
opencdlee-dotcom Aug 23, 2026
e099eea
fix(aegis): the outbound sensor was counting sockets, not facts
opencdlee-dotcom Aug 24, 2026
e0a350d
The Windows leg was a 24-minute oracle for a defect a Mac could have …
opencdlee-dotcom Aug 24, 2026
7279c68
The guard I shipped did not catch the thing it was written for (#9)
opencdlee-dotcom Aug 24, 2026
9d8cdbf
Custody's second rung was macOS-only too, and the ratchet is empty (#10)
opencdlee-dotcom Aug 25, 2026
3062599
A row that cannot fail is not coverage (#11)
opencdlee-dotcom Aug 25, 2026
b9236e3
Foundational fixes: declared identity, one migration runner, one rout…
opencdlee-dotcom Aug 25, 2026
c676187
Silence is not an objection, and repetition is not news
opencdlee-dotcom Aug 30, 2026
c6db17e
A verdict nobody gives teaches nothing
opencdlee-dotcom Aug 30, 2026
f54038f
Provenance tier: novelty age-out, real disputes, one verdict per fact
opencdlee-dotcom Aug 30, 2026
9565709
A verdict that never reaches the baseline ends nothing
opencdlee-dotcom Aug 30, 2026
c6b4e93
Durable accepted state: verdicts reach the baseline
opencdlee-dotcom Aug 30, 2026
170ed38
The coverage section was wrong on most scans
opencdlee-dotcom Aug 30, 2026
7a1a93d
Precision, provenance, durable accepted state, and a report that is t…
opencdlee-dotcom Aug 30, 2026
ddd300e
A family number is a position, and positions move
opencdlee-dotcom Aug 30, 2026
60f70b0
Family verdicts resolve against one snapshot
opencdlee-dotcom Aug 30, 2026
e25a54f
Answer the question before showing the evidence
opencdlee-dotcom Aug 30, 2026
f5cd819
A rotated address is one fact recurring
opencdlee-dotcom Aug 30, 2026
1387ac3
The report is true when it is read, and a rotated address is one fact
opencdlee-dotcom Aug 30, 2026
77a6e9b
The port was doing what the address used to
opencdlee-dotcom Aug 30, 2026
5263a9c
An operator-confirmed SSH key/origin stops re-alerting like a stranger
opencdlee-dotcom Aug 30, 2026
1a55b45
Allowlist aegis's own redaction-test fixtures for the public leak gate
opencdlee-dotcom Aug 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 67 additions & 23 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ jobs:
- os: macos-latest
python: "3.12"
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python }}
- run: python -m pip install --upgrade pip pytest
Expand All @@ -43,31 +43,45 @@ jobs:
# executed on Windows: the parsers were tested against captured output and the
# registry plumbing against an injected fake `winreg`. This job runs the real
# thing on a real Windows kernel.
#
# Process spawning is far more expensive here than on POSIX, which is why
# Windows is always the last leg to report and why work gets called done
# while it is still running.
#
# The job cap was cut 60->30 once on a guess ("observed healthy ~13 min")
# that turned out to be stale — the suite had grown substantially since that
# number was taken and nobody re-measured. The very next run proved it wrong:
# py3.12's Test suite step alone measured 1206s (20:06) and got cut off
# mid-report by a 20-minute STEP cap sized on the same stale guess, turning a
# clean pass (427 passed, 145 skipped, zero failures) into a reported failure
# via KeyboardInterrupt.
#
# And it kept growing: measured 2026-08-23, Test suite 1424-1467s (23:44 /
# 24:27) against that 35-minute step cap. Nothing announced the growth — the
# comment asking the next person to "re-measure rather than nudge the
# constant" is not a mechanism, and the only signal a cap is outgrown is a
# KeyboardInterrupt that reads exactly like a test failure.
#
# `--durations=25` is NOT a fix for that. Be precise about what it buys,
# because crediting it with more is how the next person skips building the
# real signal: it publishes the slowest CASES, not the step's total against
# its cap, and it prints only when pytest finishes — so on the one run that
# actually hits the cap it prints nothing at all. What it does buy is a
# per-body cost profile that did not exist before. Its first run already paid
# for itself: the top two cases measured 189.41s and 188.25s here against
# 35.48s and 35.74s on macOS, a uniform ~5.2x that makes the (cheap, local)
# macOS profile a usable model for this (expensive, remote) one.
windows:
name: windows-latest / py${{ matrix.python }}
runs-on: windows-latest
# Process spawning is far more expensive here than on POSIX, and the live
# harness additionally runs two full scans against the real machine (which
# classify real binaries through real PowerShell).
#
# This value was cut 60->30 once on a guess ("observed healthy ~13 min")
# that turned out to be stale — the suite had grown substantially since
# that number was taken and nobody re-measured. The very next run proved
# it wrong: py3.12's Test suite step alone measured 1206s (20:06) and got
# cut off mid-report by a 20-minute STEP cap sized on the same stale
# guess, turning a clean pass (427 passed, 145 skipped, zero failures) into
# a reported failure via KeyboardInterrupt. Re-measured from that run's own
# logs: Test suite ~1176-1206s, harness ~681-767s. Sized below with real
# headroom over MEASURED numbers, not a guess — and if this suite keeps
# growing, re-measure again rather than nudge the constant.
timeout-minutes: 45
strategy:
fail-fast: false
matrix:
python: ["3.9", "3.12"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python }}
- run: python -m pip install --upgrade pip pytest
Expand All @@ -79,16 +93,46 @@ jobs:
# KeyboardInterrupt failure four seconds past an undersized cap.
- name: Test suite
timeout-minutes: 35
run: python -m pytest tests/ -q
run: python -m pytest tests/ -q --durations=25
- name: selftest.py (real detection logic on this machine)
timeout-minutes: 5
run: python selftest.py

# The live harness is its own JOB, not a step of the one above.
#
# It was a trailing step guarded by `if: always()` — the guard existed
# because this harness is the only evidence the Windows code works on
# Windows, so a suite failure must not hide it. But a step cannot start
# before the 24-minute suite ahead of it finishes, so its measured ~12.6 min
# was pure addition: 37-39 minutes before Windows said anything at all.
#
# As a job it runs CONCURRENTLY with the suite on a second runner (free for
# public repos), which cuts the Windows critical path to roughly max(25, 13)
# instead of their sum, and gets the `always()` semantics structurally rather
# than by a guard — a failing suite cannot delay or mask it, because they no
# longer share a runner. It needs no pytest: the harness is stdlib + aegis.
windows-live:
name: windows-live / py${{ matrix.python }}
runs-on: windows-latest
timeout-minutes: 25
strategy:
fail-fast: false
matrix:
python: ["3.9", "3.12"]
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python }}
# Measured in THIS position on the first run after the split (2026-08-24):
# 625s on py3.9 and 816s on py3.12. That 816s is outside the 681-767s
# range this step used to be sized against — those numbers were taken
# while it ran third, behind a 24-minute suite, on a warm runner. Sizing
# a cap from measurements taken in a different position is the exact
# mistake this file has already made twice, so the cap stays at 25 and
# the new numbers are recorded here instead of being trimmed toward.
- name: Live Windows harness (real registry, schtasks, CIM, Authenticode)
timeout-minutes: 25
# `always()`: this harness is the only evidence that the Windows code
# works on Windows, so a suite failure must not hide it. It reports its
# own pass/fail and still fails the job on its own terms.
if: always()
env:
AEGIS_WIN_LIVE: "1"
run: python tests/win_live_harness.py
20 changes: 20 additions & 0 deletions .leakgate-allow
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# aegis's own test suite deliberately contains synthetic OS paths (fixture
# data for deterministic cross-platform tests) and fake secrets (fixture data
# proving redact_sensitive() strips them) — the exact "a secret SCANNER whose
# test suite must contain fake secrets" case leakgate.py's own docstring
# names. Narrowed per its guidance: an identity rule that structurally trips
# on this repo's content is disabled by class; a secret-shaped rule is never
# disabled by class, only allowed by the exact synthetic value it matched.

rule:posix-home-path
rule:windows-user-path

# Fake credentials that exist specifically to prove redact_sensitive() strips
# them (tests/test_battle_20260812.py, tests/test_regression.py,
# tests/test_protective_tier.py) — not real. sk-live- is this suite's own
# naming convention for synthetic OpenAI-shaped fixtures (self-describing
# names like "ThisMustNeverReachDisk" — never how a real key looks).
CorrectHorseBatteryStaple9x
hunter2verylongsecret
correct-horse-battery-staple
sk-live-
Loading
Loading