Skip to content

Commit 73a2a2a

Browse files
ourwayclaude
andcommitted
chore(release-hygiene): CI matrix, CHANGELOG, README security model
- GitHub Actions: ruff + mypy + bandit(-lll) + full pytest on Python 3.10-3.14 (Ubuntu) plus a macOS 3.14 job — the audit's biggest gap was that every gate ran by hand on one machine - CHANGELOG.md: 0.7.0 retrospective entry + Unreleased section for the post-release fixes; earlier versions summarized - README: Security Model section stating plainly what the guardrails do (blocklist, ownership, .trust5 protection, process hygiene, SSRF defense, encrypted tokens) and what they do NOT do (no adversarial sandbox — use a container/VM for untrusted specs) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 0a478cb commit 73a2a2a

3 files changed

Lines changed: 159 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
tags: ["v*"]
7+
pull_request:
8+
9+
jobs:
10+
test:
11+
name: py${{ matrix.python-version }} / ${{ matrix.os }}
12+
runs-on: ${{ matrix.os }}
13+
strategy:
14+
fail-fast: false
15+
matrix:
16+
os: [ubuntu-latest]
17+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
18+
include:
19+
- os: macos-latest
20+
python-version: "3.14"
21+
steps:
22+
- uses: actions/checkout@v4
23+
24+
- uses: actions/setup-python@v5
25+
with:
26+
python-version: ${{ matrix.python-version }}
27+
28+
- name: Install
29+
run: |
30+
python -m pip install --upgrade pip
31+
pip install -e ".[dev]"
32+
33+
- name: Ruff
34+
run: ruff check .
35+
36+
- name: Mypy
37+
run: mypy .
38+
39+
- name: Bandit (high severity)
40+
run: bandit -r trust5 -q -lll -x trust5/assets
41+
42+
- name: Tests
43+
run: pytest -q

CHANGELOG.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Changelog
2+
3+
All notable changes to Trust5 are documented here. Versions before 0.7.0
4+
predate this changelog.
5+
6+
## [Unreleased]
7+
8+
### Fixed
9+
- **Test discovery no longer hands package markers to pytest** — passing
10+
`tests/__init__.py` as a CLI argument made pytest collect the whole package
11+
on top of explicitly listed files, double-counting every test (a 106-test
12+
suite reported as 121). `conftest.py` is likewise excluded from runnable
13+
test lists; the write-protection layer still covers both.
14+
- **Venv safety net fires once Python files actually exist** — it previously
15+
ran only in the Setup stage, which sees an empty directory when the planner
16+
emits no setup commands; suites then ran on whatever `pytest` the ambient
17+
environment provided. Validate now re-runs the idempotent net at its
18+
runtime language-detection point, and the net installs the project's
19+
`requirements.txt` into the venv.
20+
- **Planner non-compliance is loud** — a plan missing the mandatory
21+
`SETUP_COMMANDS` / `QUALITY_CONFIG` / EARS-criteria blocks now emits
22+
explicit warnings, and the quality gate announces when SPEC compliance is
23+
skipped for lack of criteria instead of passing vacuously.
24+
- **`trust5 loop` test runs are hardened** — the LSP loop executed the test
25+
command via raw `subprocess.run(shell=True, timeout=120)`; it now uses the
26+
same process-group/tree-kill primitive and configured timeout as the rest
27+
of the pipeline (closes the audit's one high-severity bandit finding).
28+
29+
### Changed
30+
- The documented `mypy .` gate passes as written: production code stays
31+
strict; test modules are parsed and import-resolved but not type-scored.
32+
- `cryptography` cap widened (`<44``<46`).
33+
- CI (GitHub Actions): ruff, mypy, bandit, and the full test suite on
34+
Python 3.10–3.14 (Ubuntu) plus a macOS job.
35+
- README gained a Security Model section describing what the guardrails do
36+
and do not guarantee.
37+
38+
## [0.7.0] - 2026-07-23
39+
40+
### Added
41+
- **Interface contracts** — the planner emits per-module public signatures in
42+
the MODULES block; every test-writer and implementer prompt is held to
43+
them, keeping parallel modules compatible.
44+
- **One-shot test arbitration** — after two identical failing-test cycles
45+
with no pass progress, the repairer may fix the module's own tests under
46+
audit rules (justify against acceptance criteria; no deletion, no
47+
tautologies, no renaming).
48+
- **Watchdog live per-module jump accounting** — worst-module rules,
49+
module-scoped rebuild signals, and re-driven watchdogs on auto-retry.
50+
51+
### Fixed
52+
- **The "Raft wall"** — the defect stack that made hard multi-module tasks
53+
bail deterministically: double jump counting (30 budget was really 15),
54+
progress measured in tests *executed* instead of *passed*, a dead 120s
55+
test timeout overriding configuration, head-only output truncation hiding
56+
pytest failures, the final repair's work never being tested, bailed
57+
modules being unhealable, and futile auto-retries after designed
58+
exhaustion (now non-retryable walls + integration-validate healing).
59+
- Planner-declared module `deps` drive parallel stage sequencing.
60+
- Repeated-failure detection keys on failing-test identity, not raw output.
61+
- Flat-layout Python packages are importable by the test runner
62+
(project root on `PYTHONPATH`).
63+
- Entry/demo scripts must belong to a module — unowned planned files were
64+
never created and failed their acceptance criteria unconditionally.
65+
- Serial `trust5 loop` retry storm stopped; loop actually runs.
66+
67+
### Changed
68+
- Requires `stabilize >= 0.19.1, < 0.20` — atomic jumps, restart-proof
69+
message dedup, zombie-stage re-claim, queue lock heartbeat (prevents
70+
double execution of long agent tasks), and duplicate-`StartTask`-proof
71+
recovery sweeps.
72+
- `trust5.__version__` reports the real version (was stuck at 0.1.0).
73+
74+
## [0.6.4] and earlier
75+
76+
Context engine (token-accounted compaction), capability tools
77+
(whitespace-tolerant Edit, MultiEdit, TodoWrite, read-only SubAgent,
78+
parallel read tools, Anthropic prompt caching), streaming stall fallback,
79+
disk-persisted tool results, file-freshness guard, TUI status bar and live
80+
todo panel, process-explosion watchdog, WebFetch SSRF defense, encrypted
81+
token store. Not individually changelogged.

README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ and event sourcing.
2828
14. [File Layout](#file-layout)
2929
15. [Timeouts and Limits](#timeouts-and-limits)
3030
16. [Troubleshooting](#troubleshooting)
31+
17. [Security Model](#security-model)
3132

3233
---
3334

@@ -544,6 +545,40 @@ Ollama requires no login. Ensure the Ollama server is running at
544545
545546
---
546547
548+
## Security Model
549+
550+
Trust5 executes LLM-generated shell commands and code **on your machine**.
551+
Its guardrails are accident containment for a fallible-but-trusted model —
552+
they are **not an adversarial sandbox**.
553+
554+
What the guardrails do:
555+
556+
- **Destructive-command blocklist** — `rm -rf` outside the project directory,
557+
`mkfs`/`dd`, `curl | bash`, `chmod 777`, fork bombs, and similar patterns
558+
are refused before execution.
559+
- **File ownership** — implementer/repairer agents may only write their own
560+
module's files; test files are read-only for them (a one-shot, audited
561+
arbitration can grant a repairer access to its module's tests).
562+
- **Internal state protection** — writes into `.trust5/` (pipeline database,
563+
event log) are blocked at both the file-tool layer and the shell layer.
564+
- **Process hygiene** — every subprocess runs in its own process group and the
565+
whole tree is killed on timeout; test runs additionally have a 1-second
566+
watchdog that kills the group on process-count or memory explosion.
567+
- **WebFetch SSRF defense** — private/loopback addresses are refused with DNS
568+
resolution pinning, redirects are not auto-followed, responses are size-capped.
569+
- **Credentials** — OAuth tokens are stored encrypted (Fernet) under
570+
`~/.trust5/` with `0600` permissions; the event socket is `0600`. Note the
571+
encryption key lives beside the ciphertext, so this protects against other
572+
users on the machine, not against something running as *your* user.
573+
574+
What they do **not** do: create a jail. A prompt-injected or otherwise
575+
misbehaving model can still run arbitrary code as your user — pattern
576+
blocklists are bypassable by construction. For specs, dependencies, or
577+
codebases you do not trust, run Trust5 inside a container or VM, and treat
578+
generated code as untrusted until you have reviewed it.
579+
580+
---
581+
547582
## License
548583
549584
See LICENSE file for details.

0 commit comments

Comments
 (0)