v0.6.3
·
14 commits
to main
since this release
Immutable
release. Only release title and notes can be modified.
Added
aegis-mcpnow speaks the Model Context Protocol lifecycle:
initialize(version negotiation across 2024-11-05, 2025-03-26, and
2025-06-18),notifications/initialized,tools/list(all seven
scanning tools with JSON-Schema input schemas),tools/call(results
as text content; tool failures asisError: trueresults), and
ping. Generic MCP clients such as Claude Desktop can now use the
server without a translation shim; the original custom JSON-RPC
method set is unchanged and dispatches to the same implementations.- Wire-conformance fixture suites replayed against the real binaries
pin both integration surfaces:aegis-mcp's stdio handshake,
discovery, sandbox rejection, unknown-tool, and parse-error semantics
(crates/aegis-mcp/tests/fixtures/), andaegis-daemon's
Unix-socket JSON-lines protocol — error envelopes, sandbox refusal
without content leakage, blank-line framing, and scan receipts
(crates/aegis-daemon/tests/fixtures/). - The corpus harness now measures per rule, not just in aggregate: any
rule with enough corpus observations must hold a per-rule precision
floor (0.80 at ≥ 2 observations), and hand-assignedconfidence
labels are calibrated against measured precision demote-only
(high≥ 0.95,medium≥ 0.80 at ≥ 3 observations — the gate can
force a label down or a regex fix, never a promotion). A new
tests/corpus/negative/section pins the 2026-09-22 false-positive
audit: each fixed rule (hipaa-phi, mesa-optimization,
k8s-run-as-non-root, code-injection-request, executable-file-upload)
keeps a regression fixture where it must stay silent, preserving the
shape that made the old regex fire. aegis-core::clonenow detects Type-3 (near-miss) clones —
copy-paste with reordered or inserted statements — instead of only
labelling them. Similarity is a longest-common-subsequence ratio over
the two blocks' token sequences (identifiers and literals compared by
role), scored on the best-aligned of a block stride's window phases,
so order and multiplicity count; the previous bag-of-tokens score
ignored both and rated unrelated same-shape functions as Type-1 at
1.0. Blocks grew from 20 to 40 tokens because a near-miss claim
cannot rest on a statement and a half of role-normalized code, so
regions shorter than 40 tokens are no longer compared, overlapping
windows are no longer compared with each other, a file yielding more
than 256 windows is sampled rather than paired in full, and reported
clone locations carry real line numbers (they were always line 1).- Clone detection is wired into the CLI:
aegis scan --detect-clones
runs the detector on every analyzed file and reports the pairs in a
Code clonessection of the human output and understats.clonesin
JSON output (kind, description, similarity, token count, and the two
locations with real line numbers). Clones are a separate output
channel, not findings: they never enter the finding list, risk score,
SARIF document, or exit code, and default scans serialize
byte-identical JSON to previous releases. Aclone_detection
criterion bench feeds the weekly trend.
Security
- Both wire servers now cap request frames at 10 MiB. Previously a
single authorized peer could exhaust server memory with one
arbitrarily long line (read_line/next_linegrow without limit).
aegis-mcpanswers an oversized line with JSON-RPC-32600and ends
the session;aegis-daemonanswers once with a size error and drops
the connection while continuing to serve other clients.
Changed
- The workspace denies
clippy::unwrap_used,clippy::expect_used, and
clippy::panicin production code: errors must be values. The 29
unwrap()/expect()call sites the gate surfaced were removed — 27
by converting internal lock state toparking_lot, which does not
poison and so needs no unwrap-on-lock idiom, and 2 by propagating the
error properly — and the 3 deliberate exceptions (a compile-time
constant regex, epoch arithmetic, a documented panicking convenience
constructor) carry an inline#[allow]naming the invariant it
protects. Test code is exempt throughclippy.toml's
allow-…-in-testsflags. - A new
[lints.rustdoc]table denies broken and private intra-doc
links, and CI gains aRustdocjob that runscargo docwith
RUSTDOCFLAGS=-D warningsso the gate is actually exercised. - The bounded newline framing shared by both wire servers lives in one
place:aegis-core::transport(read_bounded_line,FrameRead,
MAX_FRAME_BYTES) is now the single implementation behind the MCP
stdio server and the daemon socket server, which previously carried
byte-identical copies plus duplicate test suites. -c/--configresolution is deterministic: a value with a path
separator or a.jsonextension is a file path (a typo'd path now
fails with the real I/O error instead of the preset list); a bare
name is always a preset, even if the working directory happens to
contain a file with that name..aegis.ymlloading probes the scan root once: callers that already
located the file useload_user_pattern_definitions_from_path
instead of re-running the directory probe inside
load_user_pattern_definitions.- The daemon's
list_patternsno longer builds a JSON description of
every pattern only to throw it away; it reports the registry count,
which is what the daemon protocol documents. Full pattern metadata
remains the MCP server'slist_patternsresponse. - The CLI's internal scan dispatcher refuses
--stdinwith an
explicit error instead of silently scanning a decoy empty string;
real stdin content flows through the async entry point, which is
unchanged. - A coverage floor now actually gates: the Codecov upload has been
failing on every run for lack of a token, socodecov.yml's targets
were never evaluated. The Coverage job computes a native floor from
the lcov report withscripts/coverage-floor.sh— 97.0% lines
against the CI-measured 97.61% over the counted set (2026-09-24),
ignoringcrates/aegis-wasmand the root shim binary exactly like
codecov.yml, whose project target is synced. The gate logs a
per-crate breakdown of what it counted; the floor ratchets up, never
down to pass.
Removed
- Dead
Scannerstate and config surface that no shipped binary could
observe: the never-readsuppression_managerfield (the scan path
already builds its own), theConfigfieldsstrict_mode,
performance_mode,exit_on_findings,max_file_size_mb,
binary_file_detection,gitignore_respect,aegisignore_respect,
andtimeout_seconds, and theStrictMode/PerformanceModeenums
only those fields carried. Three of the fields were applied in
exactly one place,Scanner::from_config, which no binary in this
workspace calls — the CLI builds scanners from flags instead — so a
gitignore_respect: falsein a profile never actually disabled
ignore handling anywhere; keeping parse-but-ignore fields was the
lie. Existing user profiles still load because serde skips unknown
keys by default. The deadis_path_dangerous/get_sandbox_root
sandbox helpers are gone too. - The
DEFAULT_CATEGORIESconstant,Pattern::regex_matcheshelper,
and the unusedparse_sourceAST wrapper — all unreferenced.
Fixed
- Pattern-finding columns are now 1-indexed within the match's own line.
They previously carried the byte offset within the whole file, so
file.rs:42:18513-style locations could not be opened in an editor and
SARIFstartColumnvalues were meaningless on anything but tiny files.
fingerprint(the baseline key) never included the column, so existing
baselines still match;stable_idvalues change because the column is
part of their material. env-file-in-gitmatched a.envpath at a line start by consuming the
preceding newline character, which attributed the finding to the previous
line — where anaegis:ignore:env-file-in-gitdirective does not sit —
so a deliberately committed-and-suppressed.envmention in
docker/.dockerignorestill failed the scan. The rule now uses^in
multiline mode for the line-boundary case, so the match starts at the
.envitself and inline suppression works.- An unrecognized
--severity-thresholdvalue (or theseverity_threshold
key of a-cprofile) silently disabled the severity filter — a typo
likehihgreported more findings than requested at exit code 1,
with no diagnostic. The value is now validated the way--categories
and the anomaly allow-list always were: the CLI rejects it before any
scan mode runs (including--env/--stdin/--diff), and the
aegis-corescan entry points return
ScanError::InvalidOptions;ScanOptions::validateoffers the same
check to library callers. - Clone reports are bounded: pairing stops at 256 clone pairs per file
(MAX_REPORTED_CLONES), so a minified or generated file where nearly
every window pair qualifies can neither flood the report with a
multi-gigabytestats.cloneslist nor pay for the rest of the
quadratic pairing pass behind it. Previously the per-file pair count
was unbounded (up to 32,640 with a full block grid). - A clone-detector failure on a file is now recorded in the inspection
ledger (<path>#clones, statusFailed) instead of only being
logged, so a failed pass cannot masquerade as "no clones found" in
SARIF run properties and receipts. - Anchored ignore rules (
.aegisignore/.gitignore) now match when
the scan root is absolute: rules are evaluated against the path
relative to the configured root, so"docs/files/js/"fires on
walker paths like/workspace/docs/files/js/mock.jswhere it
previously silently never matched. Path separators are normalized to
/before matching, which also makes these rules work on Windows
(strip_prefixyields backslash relatives there). - The CLI now honors
RUST_LOG. The container images set
RUST_LOG=infoand documented it as the log-level control, but the
binary never read it — it hard-codedaegis=info(aegis=debug
under-v).RUST_LOGnow wins when set;-vremains the
verbosity switch otherwise.
Binary provenance notes
checksums.txtlets you verify the assets against each other, but it
is itself unsigned on this mirror. The signed provenance anchor for
every release is the GitForge release (minisign-signed
attestation.json); the mirror is a distribution copy.- macOS binaries are built on Linux with a zig cross-linker (recorded in
attestation.json) and are not Apple-signed or notarized.
Gatekeeper will quarantine them on first launch: run
xattr -d com.apple.quarantine aegis(or right-click → Open) after
extracting.