Skip to content

fix(trusty-installer): make trusty-memory and trusty-analyze signable targets - #5018

Open
bobmatnyc wants to merge 3 commits into
mainfrom
fix/trusty-memory-signable
Open

fix(trusty-installer): make trusty-memory and trusty-analyze signable targets#5018
bobmatnyc wants to merge 3 commits into
mainfrom
fix/trusty-memory-signable

Conversation

@bobmatnyc

@bobmatnyc bobmatnyc commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Defect

trusty-memory and trusty-analyze were missing from SIGNABLE_BINARIES
(crates/trusty-installer/src/commands/macos_signing/mod.rs). Owner ruled
2026-08-06 on both.

The exclusion was never a decision. I looked before changing anything —
module doc, SIGNABLE_BINARIES comments, release-workflow.md,
common-pitfalls.md, git log -S"SIGNABLE_BINARIES", and a search for a
MEMORY_SET that had been tried and reverted. Nothing. The table grew one
reported symptom at a time — #2558
search, #2721 tm,
#2951 the GUI,
#4277 tagent — and
nobody filed these two.

Evidence — trusty-memory

The original premise needed correcting on one point.
~/Library/Application Support/trusty-memory/ is not the reason — an
application's own data directory is not TCC-protected, so reading the palace
store prompts for nothing. The real surface is the $HOME walk:

trusty-memory setup (crates/trusty-memory/src/commands/setup.rs:415) and
trusty-memory migrate (.../migrate.rs:142) call
trusty_common::claude_config::discover_claude_settings, which recurses $HOME
to depth 8 looking for .claude/settings*.json and rewrites the ones it
finds. Its skip-list (crates/trusty-common/src/claude_config.rs:30) covers
target, node_modules, .git, Library, Applications, .Trash, build,
dist, .cache, .npm, .cargo — but not ~/Desktop, ~/Documents, or
~/Downloads, so a read_dir is attempted on each. Every cargo install mints
a fresh cdhash, so any grant keyed to the old one stops matching.

cargo install --path crates/trusty-memory produces THREE binaries and all
three are signed — #2721
is the recorded lesson that signing part of an install set leaves the rest
ad-hoc while the prompt keeps recurring.

Evidence — trusty-analyze (judge this section on its own)

Promoted in the same ruling, added here rather than in a follow-up PR because it
touches the same table, the same clap enum, and the same guard tests as the
round already in flight.

Identical to trusty-memory: trusty-analyze setup --global
(crates/trusty-analyze/src/commands/setup.rs:129) makes the same
discover_claude_settings walk of $HOME to depth 8, reaching ~/Desktop,
~/Documents, and ~/Downloads through the same skip-list gap.

Weaker, and the distinction is kept rather than flattened: trusty-memory
walks $HOME on its default setup path. trusty-analyze only does so
behind --global; project mode patches .mcp.json in the project root and
never leaves it. Narrower in how often it is reached, identical when it is.

Hardened Runtime placement was confirmed independently, not inherited by
analogy.
cargo tree -p trusty-analyze -i fastembed shows fastembed as a
direct dependency of trusty-analyze — trusty-memory reaches it
transitively through trusty-common's memory-core. Different edges, same
conclusion: both carry the unverified ONNX-dylib-under-library-validation
exposure, so both fall through to plain explicit in use_hardened_runtime,
which is exactly SEARCH_SET's policy. hardened_runtime_policy pins each
separately.

One binary. cargo metadata confirms trusty-analyze has exactly one bin
target; its only other target is the trusty_analyze library. There is no
bundled sibling to miss the way tm was missed in #2721. binaries_for_set_covers_analyze
pins that.

trusty-review stays excluded, re-verified: no discover_claude_settings
call, no $HOME walk, no other-app file access — grepping it for
.claude/Desktop/Documents/Downloads/Containers//Volumes returns only
Bedrock model-name strings (us.anthropic.claude-sonnet-4-6). Nothing to keep a
grant for.

Resolution

Set Binaries Install path
MEMORY_SET trusty-memory, trusty-bm25-daemon, trusty-memory-mcp-bridge scripts/install-trusty-memory-signed.sh / make install-memory-signed / tctl sign trusty-memory
ANALYZE_SET trusty-analyze tctl sign trusty-analyze (no wrapper script — that is the whole surface)

SignTargetArg::Memory and ::Analyze in cli.rs were load-bearing, not
cosmetic:
clap rejects any value the enum does not list before
commands::sign::run is reached, so a table row alone leaves the target
unreachable.

Neither gets an automatic tctl install post-install hook, matching
trusty-agents (#4277) — post_install_search / post_install_mpm remain the
only two.

Review findings

Finding 1 (MEDIUM) — the guard closed one direction and left the mirror open

every_sign_target_arg_resolves_to_a_real_set read as_set_name() but never
the clap #[value(name = …)] that actually gates the CLI. A variant with a
typo'd attribute passed all tests while tctl sign <set> was rejected and the
docs advertised it as valid — the same vacuity class the test was added to
close, one level up. Both strings are now pinned against each other.

Proof it works, and the proof the coordinator asked for: adding
trusty-analyze with a deliberately typo'd clap name goes red with no new
test written
:

SignTargetArg::Analyze accepts `trusty-analzye` on the command line but resolves
to set `trusty-analyze` — `tctl sign trusty-analyze` would be rejected by clap
test result: FAILED. 26 passed; 1 failed

Finding 2 (MEDIUM) — script and doc were overclaiming

The PR body hedged that persistence was unconfirmed; the artifacts did not. The
script told the operator signing "makes the approval persist across every future
cargo install" and the doc read as verified guidance. Both now state what signing
establishes — a stable designated requirement, the precondition for a
durable grant — and separate that from an outcome nobody measured.

🔴 Responsible-process attribution, folded into both and flagged here as
unresolved.
macOS attributes Files-and-Folders access to the responsible
process
, which for a shell-invoked CLI is usually the terminal rather than the
binary — and setup/migrate (and setup --global) is exactly that case. If
the attribution lands on the terminal, signing these binaries does not change
that path's prompting at all. The launchd-started daemon is attributed to
the binary, so a stable identity applies there. Nobody has confirmed which way
the CLI path resolves, and the doc and script are now written to stay true
either way. I have not tried to resolve macOS semantics here.

Finding 3 (LOW) — substring check tightened

The tip test used contains, which passes spuriously on any prefix-shaped name
(a future trusty-mem set would be "found" inside trusty-memory) and said
nothing when the tip advertised a target that is not a set. It now parses the
<a|b|c> group and compares exactly, in both directions.

signing_persistence_tip's list had already gone stale — it still said
<trusty-search|trusty-mpm> after #4277 shipped trusty-agents.

In-flight collision

Two files overlap #5011,
unchanged from the first round:

macos_signing/, the new script, the Makefile, and the docs are untouched by
#5011. Happy to rebase whenever you sequence it.

Gates

Gate Result
cargo fmt --check exit 0
cargo clippy -p trusty-installer --all-targets -- -D warnings exit 0
cargo test -p trusty-installer 560 passed; 0 failed; 4 ignored (+ 3/3, 3/3 in the integration binaries)
cargo check --workspace --exclude trusty-code-gui --exclude trusty-mpm-gui exit 0
bash scripts/check_line_cap.sh 3742 files; 7 allowlisted, 0 violations — OK
bash scripts/check_sld.sh 56 spec docs + 3119 code files; 0 errors, 0 warnings
bash scripts/check_test_pointers.sh 22072 citations; 0 dangling — OK
bash scripts/check_changelog_fragment.sh OK trusty-installer: fragment present and valid
bash -n + shellcheck on the new script clean; --dry-run exercised end to end

cargo check --workspace (unfiltered) fails, pre-existing and environmental:
trusty-code-gui panics with The frontendDist configuration is set to "ui/dist" but this path doesn't exist. crates/trusty-code-gui/ui/dist is untracked, so it
never exists in a fresh worktree, and
git diff --name-only origin/main...HEAD -- crates/trusty-code-gui/ crates/trusty-mpm-gui/
is empty. Excluding those two, the workspace check is clean.

Neither known baseline flake
(execute_doctor_against_test_daemon, ensure_managed_config_dir_emits_the_frozen_skill_warning,
#4931) fired.

Fail-before proof

Every guard was broken at what it names and confirmed red before being restored:

Break Red
Drop the trusty-bm25-daemon row binaries_for_set_covers_memory, signable_binaries_table_is_pinned (2 failed, 24 passed)
SignTargetArg::Memory"trusty-memroy" via as_set_name() every_sign_target_arg_resolves_to_a_real_set: names a set with no binaries
#[value(name = "trusty-analzye")] on the NEW variant, as_set_name() intact every_sign_target_arg_resolves_to_a_real_set — the Finding-1 fix, caught with no new test written
Revert the tip to <trusty-search|trusty-mpm> signing_persistence_tip_names_every_signable_set — fires on the pre-existing #4277 staleness, not just the new rows
Typo a set name in the table 5 failed, incl. every_declared_set_is_a_named_constant

Not verified

Real codesign was not run — no install, sign, or launchctl on this machine
per the dispatch. Everything asserted here is from the code and the table. Actual
TCC grant persistence across a reinstall, and the responsible-process question
above, both still want manual confirmation on a machine with the Developer ID
certificate.

🤖🤖🤖 Generated with trusty-mpm — https://github.com/bobmatnyc/trusty-tools

trusty-memory was missing from SIGNABLE_BINARIES for no recorded reason —
no comment, doc, ADR, or commit message ever gave one. The table grew a row
per reported symptom (#2558 search, #2721 tm, #2951 the GUI, #4277 tagent)
and nobody filed the trusty-memory case. Owner ruled 2026-08-06 that it
belongs there.

The TCC surface is the $HOME walk, not the palace store. `trusty-memory
setup` and `trusty-memory migrate` call discover_claude_settings, which
recurses $HOME to depth 8 for .claude/settings*.json and rewrites what it
finds; the skip-list covers Library and Applications but not ~/Desktop,
~/Documents, or ~/Downloads. Every cargo install mints a fresh cdhash and
revokes whatever was approved. Its own store under ~/Library/Application
Support/trusty-memory/ is NOT the reason — an application's own data
directory is not TCC-protected.

All three binaries `cargo install --path crates/trusty-memory` produces are
signed, applying the #2721 lesson that signing part of an install set leaves
the rest ad-hoc and the prompt still recurring.

Hardened Runtime takes trusty-search's conservative side of the split rather
than trusty-mpm's always-on one: trusty-memory links ort/fastembed through
trusty-common's memory-core, so it carries the identical unverified
ONNX-dylib-under-library-validation exposure. MEMORY_SET needs no special
case in use_hardened_runtime — falling through to plain `explicit` is
exactly SEARCH_SET's policy.

Two guards that would have caught this class of omission:

- every_set_member_has_a_real_identifier iterated the hardcoded array
  [SEARCH_SET, MPM_SET, AGENTS_SET], so a set added to the table but not to
  the array was never checked. It now reads the set names out of
  SIGNABLE_BINARIES itself.
- SignTargetArg, not binaries_for_set, is the real gate on `tctl sign` —
  clap rejects an unlisted value before commands::sign::run runs. A table row
  without a matching variant is signable in principle and unreachable in
  practice. every_sign_target_arg_resolves_to_a_real_set now pins both
  directions.

signing_persistence_tip's target list had already gone stale after #4277
(trusty-agents was missing); a test now checks it against the table.

🤖🤖🤖 Generated with trusty-mpm — https://github.com/bobmatnyc/trusty-tools
@bobmatnyc bobmatnyc added the trusty-mpm trusty-mpm platform and related work label Aug 6, 2026
@bobmatnyc bobmatnyc self-assigned this Aug 6, 2026
The per-PR number is what keeps two concurrent PRs from conflicting on the
same file (#4476); the fragment was written before the PR existed.

🤖🤖🤖 Generated with trusty-mpm — https://github.com/bobmatnyc/trusty-tools
@bobmatnyc

Copy link
Copy Markdown
Owner Author

Verdict: APPROVE

Adversarial review at 239312a5, RUNG 5. Independent worktree, detached at the PR head. No codesign, tctl sign, install script, cargo install, or launchctl was run — per dispatch. CI state ignored (GitHub Actions outage); judged on local gates and my own runs.

Zero CRITICAL, zero HIGH. Three findings below, all MEDIUM/LOW.


Claim verification

1. The security rationale — CONFIRMED, independently.

Every load-bearing element checks out:

  • SCAN_SKIP_DIRS (crates/trusty-common/src/claude_config.rs:30-42) is exactly target, node_modules, .git, Library, Applications, .Trash, build, dist, .cache, .npm, .cargo. No Desktop, Documents, or Downloads.
  • Depth is 8 — DEFAULT_SETTINGS_MAX_DEPTH (claude_config.rs:44), reached through default_settings_max_depth() at both call sites.
  • collect_claude_settings (claude_config.rs:88-125) recurses into every non-skipped subdirectory of $HOME and calls read_dir on it. ~/Desktop, ~/Documents, ~/Downloads are therefore enumerated.
  • It writes, not just reads: setup.rs:415patch_one and migrate.rs:142migrate_config_file, both landing in write_json_atomic (claude_config.rs:163), which also drops a .bak copy beside each file it touches.

The correction to the original premise is right too — the palace store under ~/Library/Application Support/trusty-memory/ is the app's own data directory and is not TCC-protected. The $HOME walk is the surface. The PR does not rest on a bad premise.

2. Both guard directions — CONFIRMED, by running the breaks.

every_set_member_has_a_real_identifier did iterate the hardcoded [SEARCH_SET, MPM_SET, AGENTS_SET] and now derives from the table via declared_sets(). every_sign_target_arg_resolves_to_a_real_set pins both directions through assert_eq!(from_cli, declared). I broke each direction rather than taking the assertion on faith:

Break I applied Result
Add a set + table row, no SignTargetArg variant every_sign_target_arg_resolves_to_a_real_set FAILED (+3 others) — 555 passed; 4 failed
SignTargetArg::Memory => "trusty-memroy", table row intact every_sign_target_arg_resolves_to_a_real_set FAILED — ``tctl sign trusty-memroy names a set with no binaries in SIGNABLE_BINARIES — `557 passed; 2 failed`

Both directions are genuinely pinned. See finding 1 for the direction that is not.

3. Hardened-Runtime policy — CONFIRMED, and it is intended rather than accidental.

cargo tree -p trusty-memory -i fastembed on this branch:

fastembed v5.13.4
└── trusty-common v0.29.0
    ├── trusty-bm25-daemon v0.1.3
    │   └── trusty-memory v0.22.0
    └── trusty-memory v0.22.0

ort v2.0.0-rc.12 sits above fastembed. The exposure is real, and it reaches trusty-bm25-daemon as well as trusty-memory, so the set-wide policy is right.

use_hardened_runtime is explicit || set == MPM_SET || set == AGENTS_SET (macos_signing/mod.rs:311-313). MEMORY_SET falls through to explicit, which is bit-identical to SEARCH_SET's behavior. The fallthrough is the intended policy, not a coincidence: the default for an unnamed set is "do not harden automatically", which is the conservative direction, and hardened_runtime_policy pins all four sets across both explicit values. Adding a set == MEMORY_SET arm would have been dead code.

4. Test honesty — CONFIRMED. I applied all three claimed breaks, plus two of my own.

Break Claimed Observed
Drop the trusty-bm25-daemon row exactly 2 red binaries_for_set_covers_memory + signable_binaries_table_is_pinned; 557 passed; 2 failed
as_set_name"trusty-memroy" CLI-to-table guard red every_sign_target_arg_resolves_to_a_real_set red with the exact quoted message ✅ (parse_sign also fires — a bonus the PR body understates, not a discrepancy)
Revert the tip string red on the pre-existing trusty-agents omission signing_persistence_tip omits the 'trusty-agents' target

The third one is the notable result: the new test catches a bug that predates this PR, which is the difference between a guard and a restatement of the diff.

5. Scope restraint — CONFIRMED on both conclusions. The restraint was right; the gap is real.

Complete caller set for discover_claude_settings across the workspace: trusty-memory (setup + migrate), trusty-analyze (commands/setup.rs:129), trusty-mpm (hooks + tm install/doctor), trusty-search (setup + migrate).

  • trusty-analyze belongs. setup_claude_code (crates/trusty-analyze/src/commands/setup.rs:125-141) makes the identical depth-8 $HOME walk and patches every file found, gated behind --global. It also links ort/fastembed. The author's read is exact.
  • trusty-review does not. No discover_claude_settings call. Its only home_dir uses are its own ~/.trusty-review/http_addr (service/mod.rs:73) and a launchd path. Grep hits for Desktop/Documents/Downloads/Volumes are confined to test fixtures. Confirmed clean.

Not changing trusty-analyze was the correct call — the ruling named one crate. But it does mean that after this merges, three of the four $HOME-walking crates are signed and trusty-analyze is the lone unsigned one, now with a written record saying it qualifies. That is a known gap shipping deliberately, which is fine as long as it is tracked. Recommending Promote for the owner to decide; I am not filing anything.

6. What only a real signing run could establish. See finding 2 — the PR body's hedge is correct and does not propagate into the docs and script it ships.

7. Pre-existing bug — CONFIRMED fixed and in scope. signing_persistence_tip did still say <trusty-search|trusty-mpm>, stale since #4277. Now <trusty-search|trusty-mpm|trusty-memory|trusty-agents> and guarded. This is not scope creep: the PR had to touch that string to add its own target, the omission is in the function it was already editing, and leaving a known-wrong adjacent line to a follow-up PR would be the worse call.


Findings

Severity File Line Issue Fix Disposition
MEDIUM crates/trusty-installer/src/commands/macos_signing/tests.rs 199-231 every_sign_target_arg_resolves_to_a_real_set reads as_set_name() but never the clap #[value(name = …)], so the enum↔table link is pinned while the clap-name↔enum link is not. A future set added exactly the way this PR added trusty-memory, with only the clap name typo'd, is green on all 559 tests and unreachable from the CLI — the same vacuity class this PR set out to close, one level up. Add to the same test: iterate SignTargetArg::value_variants(), and for each assert v.to_possible_value().expect("no variant is skipped").get_name() == v.as_set_name(). ~5 lines. Fix here
MEDIUM scripts/install-trusty-memory-signed.sh / docs/reference/release-workflow.md 227-228 / 451-511 The PR body correctly says grant persistence is unconfirmed. That hedge does not survive into the artifacts users read: the script tells the operator "the stable Developer ID identity makes the approval persist across every future cargo install", and the new doc section reads as verified guidance. Nothing here was validated by a signing run. One sentence in the doc section: the Files-and-Folders persistence for trusty-memory follows the #873/#2721/#4277 precedent but has not been confirmed on a machine with the cert. Soften the script line to match. Fix here
LOW crates/trusty-installer/src/commands/macos_signing/tests.rs 240-247 signing_persistence_tip_names_every_signable_set uses tip.contains(set). A future set whose name is a prefix of an existing one (trusty-mem) passes spuriously against trusty-memory. Match on the pipe-delimited token rather than a bare substring. Parent

Notes

On finding 2, the part I could not settle from code. macOS attributes a Files-and-Folders TCC request to the responsible process. For a CLI binary invoked from a shell that is usually the terminal emulator, not the binary — which is precisely the path (trusty-memory setup / migrate) the PR cites as its justification. The daemon path (trusty-bm25-daemon under launchd) is not subject to that nuance, and the #873/#2721/#4277 precedent suggests signing did help there. I flag it because it is the one way the change could deliver less than the docs promise; it is not a reason to hold the PR, since signing is cheap, defensive, and consistent with every sibling crate.

use_hardened_runtime(MEMORY_SET, false) is unreachable today. Only post_install_search and post_install_mpm exist and are called (commands/install.rs:485,505); the PR deliberately adds no memory hook. So the conservative half of the policy has no runtime effect right now — same pre-existing situation as AGENTS_SET since #4277. Correctly disclosed in the doc's "No automatic post-install hook" callout. Not a defect; noting it so the truth table is not read as describing live behavior.

Fail-open check. Clean. run_sign's fail-soft path warns loudly and advances nothing; cargo install failure still exits non-zero; sign_set_strict fails closed with NoBinariesFound when nothing was signed (macos_signing/mod.rs:687-692). The skip-if-missing behavior at mod.rs:679 and mod.rs:881 is pre-existing and correct for optional bundled binaries.

Table accuracy. All three binary names verified against crates/trusty-memory/Cargo.tomltrusty-memory (:31), trusty-bm25-daemon (:51), trusty-memory-mcp-bridge (:69) — and default = ["axum-server"] (:190) confirms a plain cargo install --path crates/trusty-memory produces all three. Order puts the primary binary first, so binaries_for_set(MEMORY_SET).first() behaves as the MPM_SET rule requires.

Gates I ran myself, in my own worktree:

cargo fmt --check && cargo clippy -p trusty-installer --all-targets -- -D warnings && cargo test -p trusty-installer
EXIT=0
test result: ok. 559 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out
test result: ok. 3 passed; 0 failed  (integration)
test result: ok. 3 passed; 0 failed  (integration)

bash -n + shellcheck scripts/install-trusty-memory-signed.sh   EXIT=0
line-cap: 3742 tracked .rs file(s); 7 allowlisted, 0 violations — OK.
sld-lint: 56 spec doc(s) + 3115 code file(s); 0 error(s), 0 warning(s)
OK   trusty-installer: changelog.d fragment present and valid

Changelog fragment carries one category (Fixed) with sub-bullets under a single bullet — correct form.

Not treated as a defect: the #5011 overlap on sign.rs and cli.rs. The author flagged it accurately; it is merge sequencing, not a code issue.

🤖🤖🤖 Generated with trusty-mpm — https://github.com/bobmatnyc/trusty-tools

…tions

Owner ruling 2026-08-06 promotes trusty-analyze alongside trusty-memory.
It qualifies on the same test one step weaker: `trusty-analyze setup
--global` (crates/trusty-analyze/src/commands/setup.rs:129) makes the
identical discover_claude_settings walk of $HOME to depth 8, but only behind
--global, where trusty-memory walks $HOME on its default setup path. One
binary — the crate's only other target is a library.

Its Hardened-Runtime placement was confirmed independently rather than
inherited by analogy: `cargo tree -p trusty-analyze -i fastembed` shows
fastembed as a DIRECT dependency (trusty-memory reaches it transitively via
trusty-common's memory-core), so it lands on SEARCH_SET's conservative side
for its own reason. hardened_runtime_policy pins both.

trusty-review stays out: no $HOME walk, no other-app file access.

Review findings:

1. MEDIUM — every_sign_target_arg_resolves_to_a_real_set read as_set_name()
   but never the clap #[value(name = …)] that actually gates the CLI, so a
   variant with a typo'd attribute passed while `tctl sign <set>` was
   rejected. Same vacuity class the test was added to close, one level up.
   Both strings are now pinned against each other. Proof it works: adding
   trusty-analyze with a deliberately typo'd clap name goes red with no new
   test written.

2. MEDIUM — the script and the doc promised the TCC grant would "persist
   across every future cargo install" while the PR body correctly hedged
   that nothing was validated by a signing run. Both now state what signing
   establishes (a stable designated requirement — the precondition) and
   record that macOS attributes Files-and-Folders access to the responsible
   process, which for a shell-invoked CLI is usually the terminal rather
   than the binary. That is exactly the setup/migrate path the rationale
   rests on, so the CLI-path outcome is unresolved; the launchd daemon path
   is attributed to the binary and is not affected.

3. LOW — the tip test used substring `contains`, which passes spuriously on
   any prefix-shaped set name and is blind to a target advertised that is
   not a set. It now parses the `<a|b>` group and compares exactly, in both
   directions.

🤖🤖🤖 Generated with trusty-mpm — https://github.com/bobmatnyc/trusty-tools
@bobmatnyc bobmatnyc changed the title fix(trusty-installer): make trusty-memory a signable target fix(trusty-installer): make trusty-memory and trusty-analyze signable targets Aug 6, 2026
@bobmatnyc

Copy link
Copy Markdown
Owner Author

Verdict: APPROVE

Re-review at 388eb90a. Fresh detached worktree. No codesign, tctl sign, install script, or launchctl was run. CI ignored (Actions outage); judged on local gates and my own runs.

No issues found at >80% confidence. All three round-1 findings are closed, and I verified each by breaking it rather than reading the fix. The trusty-analyze addition holds on its own evidence.


Round-1 findings — all three closed, verified by breaking them

Finding 1 (guard closed one direction) — CLOSED, and it generalises.

The fix pins possible.get_name() against as_set_name() per variant (macos_signing/tests.rs:230-244). I reproduced the author's reported break and then ran the test that actually matters.

Break I applied Result
Typo Analyze's clap name → "trusty-analzye" every_sign_target_arg_resolves_to_a_real_set FAILED — SignTargetArg::Analyze accepts `trusty-analzye` on the command line but resolves to set `trusty-analyze` — `tctl sign trusty-analyze` would be rejected by clap · 558 passed; 2 failed
New 6th variant (Code/CODE_SET), clap name typo'd, table + constant + tip + pinned-table all correct, no new test written every_sign_target_arg_resolves_to_a_real_set FAILED alone — SignTargetArg::Code accepts `trusty-cdoe` … `tctl sign trusty-code` would be rejected by clap · 559 passed; 1 failed

The second row is the one I care about. That is byte-for-byte the scenario I built in round 1 that was green on all 559 tests; it is now red with nothing written for it. parse_sign did not fire (no hand-written block for a variant nobody added one for), so the new assertion is carrying it alone. The guard generalises rather than being tuned to today's five variants.

Finding 2 (doc/script overclaimed) — CLOSED, and the wording survives either attribution outcome.

The artifacts now separate what signing establishes from what it achieves: "a stable designated requirement in place of a cdhash that changes on every rebuild. That is the necessary precondition for a durable TCC grant. It is not on its own evidence that one was obtained." That sentence is true whichever way macOS attribution lands.

The responsible-process caveat is in both places, and correctly split rather than blanket-hedged — CLI path unresolved, launchd daemon attributed to the binary so a stable identity does apply there. The script's old promise is gone: install-trusty-memory-signed.sh:234 used to end "the stable Developer ID identity makes the approval persist across every future cargo install" and now reads "Approve those prompts when they appear", followed by the two caveats. No hedging in the body while the script still promises — I checked that specifically.

release-workflow.md:477 also tightened "revokes whatever was approved" to "any grant keyed to the old one stops matching", which is the accurate mechanism.

Finding 3 (substring contains) — CLOSED, both directions, and the old test provably missed one.

Now parses the <a|b|c> group and compares exact sets (tests.rs:283-302).

Break I applied Result
Set trusty-mem added to table, tip not updated (prefix of trusty-memory) FAILED — advertises [… "trusty-memory" …] but SIGNABLE_BINARIES declares [… "trusty-mem", "trusty-memory" …]
Tip advertises trusty-bogus, not a real set FAILED — advertises [… "trusty-bogus" …] but SIGNABLE_BINARIES declares […]

Then the decisive one: I kept the prefix break in place and reverted only the test body to the round-1 contains version. test result: ok. 2 passed; 0 failed. The old test is green on the exact defect the new one catches, in both directions. The fix is real, not cosmetic.


The trusty-analyze addition — judged on its own evidence

Both dependency edges verified separately, and they are genuinely different.

$ cargo tree -p trusty-analyze -i fastembed
fastembed v5.13.4
└── trusty-analyze v0.8.0            ← direct

$ cargo tree -p trusty-memory -i fastembed
fastembed v5.13.4
└── trusty-common v0.29.0            ← transitive, via memory-core
    ├── trusty-bm25-daemon v0.1.3
    │   └── trusty-memory v0.22.0
    └── trusty-memory v0.22.0

Different edges, same conclusion — and the conclusion does not depend on the analogy. One thing the PR does not spell out that strengthens it: fastembed is optional = true in trusty-analyze (Cargo.toml:108), but default = ["http-server", "bundled-ort"] (:135) and bundled-ort = ["dep:fastembed", …] (:143), so a standard cargo install trusty-analyze does pull it. The exposure is real on the default install path, not just a possible feature combination.

Both genuinely fall through. use_hardened_runtime is unchanged at explicit || set == MPM_SET || set == AGENTS_SET (macos_signing/mod.rs:350-352). Neither MEMORY_SET nor ANALYZE_SET has a special case; both reach explicit, which is bit-identical to SEARCH_SET. hardened_runtime_policy pins all five sets across both explicit values.

One bin target — confirmed via cargo metadata, not the manifest:

trusty-analyze -> [('trusty_analyze', ['lib']), ('trusty-analyze', ['bin'])]
trusty-memory  -> [('trusty_memory', ['rlib']), ('trusty-bm25-daemon', ['bin']),
                   ('trusty-memory', ['bin']), ('trusty-memory-mcp-bridge', ['bin'])]

Exactly one executable, so there is no bundled sibling to miss the way tm was missed in #2721, and binaries_for_set_covers_analyze pins it at one entry.

The --global distinction is accurate. setup_claude_code (crates/trusty-analyze/src/commands/setup.rs:124-141) branches: global → the depth-8 discover_claude_settings walk; otherwise a single patch_mcp_server on project_dir(project)?.join(".mcp.json"). Project mode performs no recursion at all — one write, to one directory. Keeping the distinction rather than flattening it is right.

trusty-review re-verified, not accepted. Zero discover_claude_settings calls. Every grep hit for .claude/Desktop/Documents/Downloads/Containers//Volumes across src/ is a Bedrock model-name string (us.anthropic.claude-sonnet-4-6). Still correctly excluded.


Gates

Chained with &&, so reaching a later gate proves every earlier one passed:

cargo fmt --check && cargo clippy -p trusty-installer --all-targets -- -D warnings
  && cargo test -p trusty-installer && bash -n … && shellcheck …
  && check_line_cap.sh && check_sld.sh

test result: ok. 560 passed; 0 failed; 4 ignored     ← matches the claim
test result: ok. 3 passed; 0 failed   (path_shadow_e2e)
test result: ok. 3 passed; 0 failed   (second integration binary)
line-cap: 3742 tracked .rs file(s); 7 allowlisted, 0 violations — OK.
sld-lint: 56 spec doc(s) + 3115 code file(s); 0 error(s), 0 warning(s)
grep -c 'FAILED|^error' over the whole run: 0

changelog-fragment gate: OK trusty-installer: fragment present and valid

Neither baseline flake fired. Changelog fragment carries one category (Fixed) with sub-bullets under a single bullet — correct form, and it was updated to cover trusty-analyze rather than left describing only memory.

One gate I could not observe, stated rather than assumed. check_test_pointers.sh did not complete — three concurrent sessions on this machine are running it simultaneously and mine produced no output across ~19 minutes. I did not take the author's word for it either. Instead I ran the equivalent check scoped to this diff: extracted every tests::/cli_tests:: citation from the changed files' doc comments and resolved each against the actual fn definitions. Zero dangling. The three apparent misses were extraction artifacts — cli is use crate::cli::SignTargetArg (tests.rs:232), and run_unknown_target_is_error / run_known_target_is_noop_on_non_macos live in sign.rs:142,159, outside the two files I grepped for definitions.


Notes

Considered and dropped, so you know it was looked at. The Hardened Runtime table gives trusty-analyze off in the automatic column, where trusty-agents gets "N/A — not a tctl install member". trusty-analyze is a stable member (stable_set.rs:177), but no automatic hook exists for it — post_install_search / post_install_mpm remain the only two. So "off" describes the outcome correctly by fallthrough, and the analyze section states plainly that tctl sign is the whole surface. Not a defect; not filed.

No wrapper script or make target for trusty-analyze, unlike trusty-memory. Correct call — one binary reached by tctl sign trusty-analyze needs no script, and adding one would duplicate logic for nothing.

Fail-open check: clean. This round is table rows, docs, and tests. No new failure branches; use_hardened_runtime is untouched.

Unchanged from round 1: the actual TCC outcome still wants one manual confirmation on a machine with the Developer ID cert. That is now correctly recorded in the artifacts themselves rather than only in the PR body, which is what I asked for.

The #5011 overlap is unchanged and is merge sequencing, not a code issue.

🤖🤖🤖 Generated with trusty-mpm — https://github.com/bobmatnyc/trusty-tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

trusty-mpm trusty-mpm platform and related work

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants