v0.13.0
TL;DR
Nineteen commits since v0.12.1 give TrustSight a supported programmatic interface, put the CLI and that interface on one evaluation layer, bound every hostile input the differ, tokenizer and regex engine can be handed, pin CI actions to immutable SHAs, harden seed archive extraction, and reorganise the rules reference into one page per rule category behind a new RuleCategory taxonomy that the doc gate enforces.
Changed
-
The rules reference is one page per category.
reference/rules.mdbecamereference/rules/, with an index carrying the type legend and a quick-reference table for all 128 rules, one page perRuleCategory, andsystem.mdholding everything that is not an individual rule definition: therules.tomlfield table, the severity weights, the FATAL short-circuit, the measured fire rates, the Class A to E taxonomy, the C-series and D-series sections, and the reserved identifier ranges. Every meta anchor (#c-series,#d-series,#fatal-rules,#class-d-rules,#experimental-fire-rates,#not-rules, ...) keeps its spelling onsystem.md, which also keeps a stub anchor for every rule id pointing at the page that now defines it, so no#rXXXlink breaks. Rule text is unchanged: all 128 sections were diffed against the previous file, and the only edits are link depth. The index legend and table are generated byscripts/build_rules_index.py, andtests/test_docs.pyfails if a rule is uncategorised, documented on a page its category does not own, left behind insystem.md, or missing from the index. -
The rules reference documents every implemented rule. Sections were added for R132 (Indirect Command Expansion) and R136 to R140 (Committed File Executed Without Declaration, Fetch Then Execute, Downloaded Source File Executed, Service ExecStart Targets Undeclared Binary, PATH Injection With Undeclared Directory), plus a Declared-practice subsection for P001 to P007; the delivery section header and the Tier A span now cover R001-R140.
-
Differ input is bounded and deterministic. Generated patches, companion files, paths, and extracted URL tokens now have explicit limits; companion blobs are checked before reading, malformed hunks fail closed, and URL and file summaries use stable ordering. Adversarial differ tests and security gates cover hostile size, malformed syntax, and repeatability.
-
Diff truncation is UTF-8-safe and shared across analysis paths. Git and offline analysis use the same bounded prefix helper and preserve an explicit truncation flag, so partial multibyte input cannot corrupt parser text and truncated results stay covered by
diff_truncated. -
Configured regexes fail closed at runtime. A pattern that exceeds the bounded adversarial probe budget is refused by the rule compiler instead of being run against package-controlled text.
scripts/regex_audit.pyaudits configured and source patterns, andscripts/benchmark_regex_engines.pygives an optional comparison against the third-partyregexengine without adding it as a runtime dependency. -
Regex backtracking remains bounded by input clamping. Rule matching still uses Python's standard
remodule; every logical line is clamped to 8 KiB before matching and the security gates measure hostile matching time. A staged regex hardening plan is documented in the security model rather than adding a runtime dependency without comparative evidence. -
Tokenizer hostile-input coverage was expanded. A deterministic fuzz harness exercises assignments, nested and cyclic expansion, malformed quoting, arrays, namerefs, command substitutions, diff markers, Unicode, memoization and the
scan_diffboundary. It asserts bounded output, termination, deterministic results and JSON-safe integration output, without changing the deliberately open R133 to R135 behaviour. -
Seed archive handling is stricter. Seed imports cap archive member counts and refuse symlinks, hardlinks, device nodes and FIFOs before extraction, on top of the existing size and path-containment limits.
-
CI actions are pinned to immutable commit SHAs. GitHub workflow actions no longer follow mutable version tags, and the signed-commit workflow shares one canonical critical-path list with the security policy and the contributor guidance.
-
Documentation and default-report language were aligned with the security model. The README now describes deterministic evidence reports rather than risk-score verdicts, documents the opt-in
--scoreand--riskdisplay, drops the obsolete LLM wording, and points at the published documentation site. The contributor guide gained a section on categorising and documenting a new rule.
Added
-
A public API (
trustsight.api). Every flow the CLI drives is available as a library:TrustSightexposesinspect,analyze_text,review,refresh_corpus,watch,pivot,history,packages,forget,prune,configandstatus, returning frozen dataclasses (Report,ReviewResult,Finding,HistoryEntry,TrackedPackage,CycleReport,PivotResult, ...) whoseto_dict()is byte-identical to the corresponding--jsonoutput. Twenty names are exported and documented; a name that is not inpython-api.mdfails the build, so the surface cannot grow by accident. Thetrustsightpackage resolves these names lazily (PEP 562), soimport trustsightfor__version__alone never loads typer, rich or the analysis stack. The CLI and the API share one pipeline: the review engine moved out ofcli/review.pyintotrustsight.review, andcli/review.pykeeps its historical spellings as re-exports.review --jsonduring a metadata bootstrap now reports{"status": "metadata_downloaded", ...}and stays a pure JSON document. See python-api.md. -
Shared CLI and API evaluation semantics. Both surfaces now consume one reporting layer for findings, verdicts, risk bands, coverage, changes, suppressions and JSON serialization. API limits, explicit package lists and watch parameters are validated before analysis begins, and API results are returned as dataclasses without rendering terminal output. Two properties the CLI has always had travel with them: coverage qualifies the verdict (
Report.riskis the band the analysis supports, never re-derived from the score), and a failed analysis is a result rather than a gap (ReviewResult.failuresandReviewResult.complete). -
Public API inputs are bounded before side effects. Package and indicator names, repository and package lists, PKGBUILD text, metadata text, and history and review limits now have explicit ceilings with type and boolean validation, so a caller cannot reach the analysis stack with an unbounded argument.
-
A rule taxonomy (
RuleCategory).src/trustsight/categories.pygives every documented rule exactly one category naming the kind of claim it makes:fetch-and-execution,obfuscation,deception,install-and-persist,staging-and-recon,integrity,naming-and-dependency,maintainer-and-metadata,temporal,composition,count-based,corpus-behavioral, andcrossfire(reserved, no rules implemented). This is a different axis from the per-rulecategoryfield, which names the capability a match touched and is what R072 counts when it looks for capability density; R072 iscategory = "meta"andRuleCategory.COMPOSITION.RULE_CATEGORIESmaps all 128 documented rule sections,category_of()andrules_in()read it, and nothing about findings, scoring or the report payload changes. -
Adversarial security coverage. Deterministic tokenizer fuzzing, regex audits, differ hostile-input checks, archive hardening tests and critical-path policy tests are now part of the test and security-gate coverage, alongside a regression suite that pins every past defect which reached a release.
Fixed
-
A rule could be documented in one place and defined in another. The doc gate read a single file and matched on
### Rxxx:, so a rule section could sit under any heading and still pass. It now resolves the page from the rule'sRuleCategoryand fails on a section that landed on a page its category does not own. -
A cross-page anchor in the split reference did not resolve. The naming-and-dependency page linked
count-based.md#r075, but R075's heading anchor is#r075-rule. Caught by thedoc cross-references resolvegate, which walks everydocs/**link and resolves both the file and the anchor.
Stats
- 19 commits since v0.12.1
- 84 files changed, +8112 / -2415
- 2029 tests (47 files), all passing
- 51/51 security gates, 10/10 calibration gates
- 128 documented rule sections across 13 categories
- Package version 0.13.0