Skip to content

chore(deps): update dependency sheeki03/tirith to v0.3.3 - #5618

Closed
renovate-fullsend[bot] wants to merge 1 commit into
mainfrom
renovate/sheeki03-tirith-0.x
Closed

chore(deps): update dependency sheeki03/tirith to v0.3.3#5618
renovate-fullsend[bot] wants to merge 1 commit into
mainfrom
renovate/sheeki03-tirith-0.x

Conversation

@renovate-fullsend

@renovate-fullsend renovate-fullsend Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

ℹ️ Note

This PR body was truncated due to platform limits.

This PR contains the following updates:

Package Update Change
sheeki03/tirith patch 0.3.10.3.3

Warning

Some dependencies could not be looked up. Check the Dependency Dashboard for more information.


Release Notes

sheeki03/tirith (sheeki03/tirith)

v0.3.3

Compare Source

Added
  • Evasion-resistant prompt-injection detection: a shared deobfuscate text-normalization pass (zero-width / invisible strip, Unicode confusable skeleton, NFKC, inter-character whitespace collapse, bounded leetspeak fold, and short base64 / hex decode behind a printable gate). Prompt-injection and config-file scanning now run against these normalized variants in addition to the raw input; raw scanning is never replaced. Typoglycemia (character transposition) is out of scope for now.
  • PromptInjectionObfuscated (High): a new rule for an injection seed that matches only after deobfuscation, where the obfuscation itself is the signal. Raw matches still fire IgnorePreviousInstructions / PromptInjectionInOutput.
  • OutputDataExfiltration (High, MITRE T1041): a new exfil rule for markdown / URL beacons carrying a secret-shaped token or canary, secret-shaped URL query values, and "read a sensitive path then send / post / upload" directives (including the "do not tell the user" stealth directive).
  • injection_seeds_custom policy field: add your own prompt-injection seed regexes via .tirith/policy.yaml, user, or org policy. A repo-scoped policy may add seeds (it can only tighten). Invalid regexes are reported by tirith policy validate and skipped rather than failing the load.
  • mcp_redact_injection policy field (default off): opt-in to downgrade an injection-only MCP tool-output block to a redacted warning, blanking the seed spans and forwarding the rest. Only user / org scope can enable it (a repo-scoped policy cannot weaken this), and it refuses to downgrade when any non-injection finding blocks or when structured content is present.
  • threatdb ExfilEndpoint source (Primary tier): a known-exfiltration-endpoint hostname source, populated from the CI threat feed.
Fixed
  • .deb / verify-self byte mismatch (issue #​146): the Debian package now ships the exact canonical release binary instead of a separate rebuild, so an apt-installed tirith passes tirith verify-self. A release CI guard asserts the .deb binary is byte-identical to the published tarball binary. The .rpm is still rebuilt against the target distro's glibc (so it keeps running on RHEL / Rocky 9) and is intentionally not byte-identical.
  • verify-self no longer falsely flags source-built installs: cargo install, AUR, and the distribution .rpm are compiled from source or against a different libc, so they cannot be byte-compared to the generic release binary. They now report an honest "unverified" (exit 0) rather than a false "modified or replaced" failure, and AUR installs on Arch and its derivatives are detected as such. Homebrew is handled the same way: the homebrew-core formula builds from source (distributed as a bottle), so a mismatch downgrades to "unverified" naming brew install sheeki03/tap/tirith, while the prebuilt tap binary still verifies.
  • Scoop autoupdate URL: the release workflow no longer corrupts the manifest's autoupdate template (a loose version-matching pattern was rewriting the literal v$version to v0.3.2$version).

v0.3.2

Compare Source

Added
  • M5 platform & reach: tirith lab (offline adversarial training corpus); Windows / PowerShell rules (ExecutionPolicy bypass, Defender exclusions, inline IEX download-execute).

  • M5.5 / M6 install & fix: tirith fix (interactive safe-command rewriter); tirith install across 12 backends; tirith doctor --quick.

  • M7 output & egress firewall: tirith view, output, share, redact, clipboard, logs; output-direction detection (OSC 52 clipboard writes, fake prompts, hyperlink / title manipulation); gateway run --filter-output, mcp-server --sanitize-tool-output.

  • M8 operational context: tirith context, ssh, iac, sudo, devcontainer, codespaces, prompt-status; labeled-prod, IaC-apply, sudo-escalation, and container rules.

  • M9 workstation hygiene: tirith hygiene, persistence, aliases, env, exec, path, hooks; credential-hygiene, persistence-foothold, PATH-hijack, and executable-provenance rules.

  • M10 blast radius & isolation: tirith preview, watch, taint, intend, baseline, temp-run, fetch --save; blast-radius, taint, and opt-in anomaly rules.

  • M11 trust ecosystem: tirith command-card, commands, canary, secret, incident; signed-attestation and canary-honeytoken rules.

  • M12 browser & visual provenance: tirith visual-audit, browser (Chrome native-messaging host), paste --with-source; paste_source_mismatch rule.

  • M13 onboarding, dashboard & rule DSL: tirith onboard, dashboard, rule (custom when: predicate DSL), ai; AI-config drift rules; 7 policy templates.

  • M14 IDE integration: tirith lsp language server with editor analysis profiles.

  • Agent-session guardrails: tirith pending (decision registry), tirith audit verify (tamper-evident hash chain), per-rule suppression cooldown, checkpoint restore reporting, agent-memory config scanning, deferred outcome (tirith check --defer, exit code 4), and cross-event correlation rules.

  • CLI transparency & safety UX: tirith status (protection health, non-zero on degrade), tirith policy effective, tirith trust from-last-trigger, global --quiet / TIRITH_QUIET, tirith daemon start --detach; tirith check --suggest (renamed from --suggest-safe-command).

  • Agent governance — engine wiring, bypass-path origin stamp, and shared YAML helper (M4 item 8 chunk 3) — chunk 3 of the per-agent governance work. Turns chunk 2's observation-only agent_rules schema into enforcement, fixes the engine's bypass-path double-log so a TIRITH=0-bypassed BLOCK records exactly one audit entry with agent_origin populated, and consolidates the duplicated yaml_safe_scalar / yaml_safe_inline_comment helpers into a single shared module. (1) Engine wiring — apply_agent_rules runs inside post_process_verdict. A new helper crate::escalation::apply_agent_rules(&mut Verdict, &Policy) consults policy::agent_decision against verdict.agent_origin and applies the minimal chunk-3 cut: Denied forces action = Block and appends a fresh Finding { rule_id: RuleId::AgentDeniedByPolicy, severity: High, … } whose description names the matched origin (Debug-escaped) and the policy file path; Allowed and Unspecified leave the verdict alone (and agent_origin: None is treated as Unspecified — an engine path that never set an origin has nothing to match against). The splice is after escalation and before warning recording so escalation-driven Blocks stay Block and the Warn-recording path correctly skips when chunk 3 flips to Block. Existing detection findings are preserved — agent_rules layers on top, never replaces. Allow is NOT a bypass — a verdict the engine already blocked stays blocked even if the caller is on the allow-list; richer "trusted agent" semantics (severity overrides on allow, approval_required: true, per-origin fail_mode) are deferred to a future chunk pending real telemetry from chunk-2's tirith agent sessions reads. (2) New RuleId::AgentDeniedByPolicy wired through every safeguard touchpoint: verdict.rs (enum variant), scoring.rs (the structural arm of is_threat_intel_rule returns false), build.rs (EXPECTED_RULES), golden_fixtures.rs (ALL_RULE_IDS + EXTERNALLY_TRIGGERED_RULES since the rule fires from policy state, not from input characters), assets/data/rule_explanations.toml (full operator-facing entry — title, category policy, severity rationale, threat-model recap, false-positive guidance pointing at tirith agent allow, remediation). The four golden_fixtures.rs safeguard tests (test_all_rule_ids_have_fixture_coverage, test_no_url_rules_have_no_url_fixtures, test_extractor_ids_cover_rule_triggers, test_tier1_does_not_gate_findings) and test_rule_id_list_is_complete all pass — every touchpoint stays in sync. (3) Bypass-path origin stamp. Pre-chunk-3, when TIRITH=0 was honored, engine::analyze_inner called crate::audit::log_verdict itself — inside the engine, before the CLI got a chance to set agent_origin. Then the CLI also called log_verdict, producing a double audit entry where the first entry was missing origin and the second one had it. Chunk 3 removes the engine's bypass-path audit entirely; the caller is now the single audit site for the engine-driven analysis paths (cli/check.rs, cli/paste.rs, mcp/tools.rs::call_check_command) and always stamps agent_origin first. cli/paste.rs and mcp/tools.rs previously SKIPPED audit on bypass_honored (trusting analyze() to have logged); both now audit unconditionally after stamping origin. cli/check.rs was already auditing in this branch; it now stops double-logging because the engine no longer logs. The same review-round pass extended the stamping invariant to the analysis-then-audit paths that previously called audit::log_verdict without setting verdict.agent_origin: cli/install.rs (both the package-manager and URL forms) and cli/ecosystem.rs::scan now resolve the CLI origin (resolve_cli_origin(interactive)) and stamp it on the verdict before the audit write, so tirith install and tirith ecosystem scan audit lines are attributed instead of landing in tirith agent sessions' "unknown" group. The gateway path stamps AgentOrigin::Gateway on the in-memory raw verdict in chunk 1 and persists the same constant in its local stderr-JSONL AuditEntry<'a> via a new always-set agent_origin field — closing a pre-chunk-3-follow-up gap where the in-memory verdict carried origin but the serialized line dropped it. The audit-aggregator tirith agent sessions documentation in crates/tirith/src/main.rs is updated to reflect the closed audit sites; the help text is explicit that origin attribution is best-effort and a future analysis-then-audit path that does not stamp origin will still land its entries in the "unknown" group rather than be silently attributed. (4) Chunk-2 test retired. agent_rules_chunk2_loading_changes_no_verdict (in crates/tirith-core/src/policy.rs) was the explicit "chunk 3 must retire this" contract; it's gone, replaced by five chunk-3 tests in crates/tirith-core/src/escalation.rs::tests: agent_rules_deny_forces_block_on_allow_verdict, agent_rules_deny_keeps_block_on_already_blocked_verdict, agent_rules_allow_does_not_bypass_block, agent_rules_unspecified_leaves_verdict_unchanged, and the critical regression guard agent_rules_unset_does_not_introduce_finding (legacy policies with no agent_rules block stay byte-for-byte identical to pre-chunk-3 behavior). Plus apply_agent_rules_returns_true_only_on_denied (helper signature), apply_agent_rules_no_origin_is_treated_as_unspecified (None handling), and agent_rules_finding_description_escapes_hostile_origin_payload (Debug-format pinning so a future control-byte-bearing origin can't leak through the audit description). The narrower "engine::analyze itself ignores agent_rules" claim — which IS still true; enforcement lives in post_process_verdict, not the raw engine — is pinned by a new engine_analyze_does_not_consult_agent_rules test that replaces the retired one. The chunk-2 field-level invariant (agent_rules_chunk2_observation_only_invariant) is preserved with an updated docstring noting it now guards against agent_rules accidentally bleeding into adjacent mechanisms (allowlist / blocklist / severity overrides). (5) Shared YAML helper module — crates/tirith/src/cli/yaml.rs. Pre-chunk-3, yaml_safe_scalar and yaml_safe_inline_comment lived as two byte-identical copies in cli/mcp.rs and cli/agent.rs. Chunk 3 consolidates both into a single pub(crate) module so future changes (and the DEL-escape post-process that previously had to be ported by hand) live in one place. Both call sites now import safe_scalar as yaml_safe_scalar (and same for safe_inline_comment + YAML_NEEDS_QUOTING_BYTES) so the existing call-site code and tests stay readable. The exhaustive round-trip test in cli/mcp.rs::yaml_safe_scalar_round_trips_through_yaml_parser (every YAML special character, every C0 control byte, DEL, multi-byte UTF-8, empty string) still passes byte-for-byte; the shared module ships its own smoke-test suite (safe_scalar_empty_becomes_quoted, safe_scalar_plain_identifier_is_bare, safe_scalar_quotes_yaml_indicator_byte, safe_scalar_quotes_control_bytes, safe_scalar_escapes_del_for_yaml_roundtrip, safe_inline_comment_passes_safe_strings_unchanged, safe_inline_comment_escapes_control_bytes) so this module is green on its own. (6) Design doc updateddocs/agent-governance-design.md § 5 flipped from "shipped in chunk 2 (observation-only)" to a full chunk-3 status table mapping AgentDecision → verdict effect, and § 6's chunk-2 out-of-scope items "policy enforcement" and "the bypass-path double-log" are marked Resolved in chunk 3. A new chunk-3 out-of-scope block documents the deferred richer matcher payloads. Trust model unchanged from chunks 1 + 2. Every signal feeding AgentOrigin is still operator-trust, never adversary-resistant — TIRITH_INTEGRATION, MCP clientInfo, CI env vars, is_terminal() are all settable by any process running as the user. agent_rules enforcement layers on top of caller-claimed signals: a policy author who treats a deny match as "this came from a hostile caller" is wrong; they're rejecting whatever the caller claimed their identity is. Use this for operator-trust scoping (the operator declares "I don't run my MCP server's tools/call on commands my CI ran"), not for adversarial security. Like every other engine path, apply_agent_rules is off the tier-1/2/3 detection hot path and touches no network.

  • Agent governance — CLI surface + agent_rules policy schema (M4 item 8 chunk 2) — chunk 2 of the per-agent governance work, building on chunk 1's AgentOrigin scaffolding. Chunk 2 was observation-only: it made chunk 1's recorded signal inspectable and added the policy schema chunk 3 wires on, but no engine path consulted agent_rules to change a verdict in this chunk. Enforcement landed in chunk 3. The original regression test agent_rules_chunk2_loading_changes_no_verdict (in crates/tirith-core/src/policy.rs) was retired in chunk 3 as that chunk's contract required. (1) New CLI group — tirith agent — four subcommands grouped under a single verb mirroring tirith mcp. tirith agent sessions reads the local JSONL audit log, groups every verdict entry by its recorded AgentOrigin, and reports per-group counts, last-seen timestamps, and an Allow/Warn/Block histogram (with WarnAck folded into the warn bucket). Hook-telemetry rows are filtered out (those are not verdicts and carry agent_origin: None by design). Entries with no agent_origin land in an explicit "unknown" bucket rather than being silently dropped — honesty over apparent tidiness. --format json emits a stable envelope (schema_version, log_path, group_count, total_entries, groups). A missing audit log is NOT an error: it reports plainly with zero groups and exits 0. tirith agent explain <query> drills into one session id (exact match) or command substring (case-insensitive, also against the rendered origin label so an operator can search for "claude-code"), surfacing up to 20 matches sorted newest-first with the attribution chain: AgentOrigin, redacted command, action, timestamps, rule IDs, bypass state, and policy path. tirith agent policy init scaffolds .tirith/agent-policy.yaml.example from the audit log's distinct observed origins — every entry commented out by design (mirrors tirith mcp policy init's convention — importing a scaffold must never silently widen trust). The scaffold is deterministic: origins are sorted by (kind, payload), the header is fixed, and no timestamps are embedded, so two runs against the same log produce a byte-identical file. A missing log writes a header-only template rather than failing — the operator gets a starting point either way. --force overwrites an existing example; without it, the example is preserved. tirith agent allow --kind <kind> [--tool <name>] validates an (kind, tool?) matcher pair and prints the YAML snippet an operator pastes under agent_rules.allow: in their policy. It deliberately does NOT mutate any policy file — agent_rules is observation-only today, and silently appending would suggest enforcement that does not exist yet; the operator integrates it themselves the same way they integrate tirith mcp policy init's example output. Validation: kind must be human / agent / mcp / gateway / ci / ide; --tool on a payloadless kind (human, gateway) is rejected up-front because it would match nothing; an empty --tool "" is rejected for the same reason. (2) Policy schema — agent_rules — additive field on ScanPolicyConfig's parent Policy struct. AgentRules { allow: Vec<AgentMatcher>, deny: Vec<AgentMatcher> }, with AgentMatcher { kind: AgentOriginKind, tool: Option<String> } where AgentOriginKind is a separate closed enum mirroring AgentOrigin's discriminator (cleaner deserialization, rejects an unknown kind at policy-load time rather than silently matching nothing). String matching is case-sensitive exactclaude-code does not match Claude Code; the design doc records (Q2) that normalization is intentionally deferred until chunk 3 has a real telemetry sample set. (3) Pure decision helper — policy::agent_decision(&policy, &origin) -> AgentDecision — walks deny in declaration order (first match → Denied), then allow (first match → Allowed), else Unspecified. The helper is not consulted by the engine in chunk 2; chunk 3 will wire it into the verdict pipeline. A tool filter applied to Human or Gateway is harmless (those variants carry no caller-claimed payload — the helper matches nothing); the policy validator surfaces it as a warning so the operator notices the typo. (4) Policy validator updatespolicy_validate.rs adds agent_rules to the known top-level fields list (so it doesn't trip the "unknown field" warning) and emits Warning-level diagnostics for matchers shaped wrong: tool on a payloadless kind, empty tool: "". threat_intel was also added to the known list — a pre-existing typo-guard gap that's now closed. (5) Policy template updates — the full, individual, ci-strict, and ai-agent-heavy templates produced by tirith policy init now include documented but commented-out agent_rules examples tuned to each scenario (CI gets a kind: ci, tool: github-actions allow; ai-agent-heavy gets both allow and deny examples). All templates still validate. (6) Design doc updateddocs/agent-governance-design.md § 5 flipped from "preview, not built in this chunk" to "shipped in chunk 2", with command-line examples, exit-code semantics, the matcher shape decision (closed kind + free-form tool, per Q1's recommendation), and the schema-vs-enforcement boundary. Out-of-scope sections clearly delineate chunk-1, chunk-2, and chunk-3 boundaries. (7) YAML safety — server / origin payloads passed through yaml_safe_scalar are quoted-and-escaped before they reach the example file or the tirith agent allow snippet output. A maliciously-crafted tool name containing :, #, newline, or ANSI escape cannot break the YAML structure or inject control sequences when the operator cats the file. The snippet round-trips cleanly through serde_yaml after pasting; a dedicated test covers a hostile-payload scaffold parsing back unchanged. Trust model unchanged from chunk 1. Every signal feeding AgentOrigin remains operator-trust, never adversary-resistant — TIRITH_INTEGRATION, MCP clientInfo, CI env vars, is_terminal() are all settable by any process running as the user. agent_rules is for filtering, dashboarding, and observability; if a policy decision must withstand a hostile environment, layer real authentication elsewhere. No new RuleId. Whether enforcement should produce a distinct RuleId or reuse an existing one is a chunk-3 decision. Like every other observability surface, every command is a local file operation: it touches no network and is off the tier-1/2/3 detection hot path.

  • Agent governance — design spike + observability scaffolding (M4 item 8 chunk 1) — the first artifact of the per-agent governance work, deliberately split off from any enforcement code. (1) Design document at docs/agent-governance-design.md recording the threat model (every signal is operator-trust, not adversary-resistant — TIRITH_INTEGRATION, MCP clientInfo, is_terminal(), every CI provider env var is settable by any process running as the user), the closed enum surface, the population path through VerdictAuditEntry, a preview of the planned tirith agent sessions / explain / policy init / allow subcommands (chunk 2+), and a section of open questions for the next chunk. The design is explicit that chunk 1 is observation-only: no policy gate consumes the new signal, no RuleId is added, no Action is changed, and the safeguard tests in golden_fixtures.rs stay untouched. (2) AgentOrigin enum at crates/tirith-core/src/agent_origin.rs — a closed tagged union with six variants (Human { interactive }, Agent { tool, version? }, Mcp { client_name, client_version? }, Gateway, Ci { provider? }, Ide { name }). Every caller-supplied free-form string (tool name, client name, provider, IDE name, version) passes through sanitize_caller_label / sanitize_caller_version: trim ASCII whitespace, drop ASCII control bytes + Unicode invisible / format / surrogate codepoints (the same classes the byte-scan rules already flag in command input — re-emitting them through the origin label would defeat the scan), and cap at 256 bytes for labels / 64 bytes for versions with char-boundary truncation so a multibyte UTF-8 sequence is never sliced mid-codepoint. A million-byte hostile TIRITH_INTEGRATION cannot crash, cannot inject newlines into an audit log line, cannot inject ANSI escapes into a terminal, cannot bloat the entry — every constructor path is covered by a unit test. (3) CLI-side environment resolverresolve_cli_origin(interactive) reads the current process env in fixed priority order: TIRITH_INTEGRATION set → Agent, named CI provider env set (GITHUB_ACTIONS, GITLAB_CI, BUILDKITE, CIRCLECI, JENKINS_URL, TRAVIS, TF_BUILD, BITBUCKET_BUILD_NUMBER, TEAMCITY_VERSION, DRONE, CODEBUILD_BUILD_ID) → Ci { provider: Some(canonical-tag) }, generic CI=trueCi { provider: None }, else Human { interactive }. The provider tag (github-actions, etc.) is a fixed string chosen by tirith — never assembled from attacker bytes. CI=false is correctly treated as "not CI". (4) MCP-side per-session origin store at crates/tirith-core/src/mcp/origin.rs — the dispatcher captures initialize.clientInfo once and writes it to a process-scoped RwLock<Option<AgentOrigin>>; every subsequent tools/call reads it back. Absent clientInfo records Mcp { client_name: "unknown-mcp-client" } rather than falling back to Human — "this came from MCP" remains structurally true even when the client is anonymous. client_info is no longer #[allow(dead_code)]. (5) Plumbing into the verdict and audit layersVerdict.agent_origin: Option<AgentOrigin> and AuditEntry.agent_origin: Option<AgentOrigin> are both additive, both serde-default-on-parse (old log.jsonl lines without the field still load through audit_aggregator::AuditRecord), and both skip_serializing_if = "Option::is_none" (a verdict that never had its origin set produces no agent_origin field on the wire). The CLI check / paste paths stamp the origin on the raw verdict immediately after engine::analyze; the MCP tool handlers (tirith_check_command, tirith_check_url, tirith_check_paste) read from the session store; the gateway request and notification paths both stamp AgentOrigin::Gateway. log_verdict_with_raw reads verdict.agent_origin and copies it to AuditEntry.agent_origin — no caller wiring changes; populating the verdict is sufficient. Hook-telemetry and trust-change audit entries leave agent_origin: None (those entry types are not verdicts and their existing integration field already identifies the hook). No new RuleId, no policy enforcement, no schema bump. Chunk 1 ends here; chunk 2 wires the tirith agent subcommands and the per-origin policy gate.

  • MCP policy governance — scan.trusted_mcp_servers, scan.mcp_allowed_tools, and tirith mcp policy init — chunk 3 of the Agent & MCP governance work. The policy field scan.trusted_mcp_servers already existed in the schema but was not consulted by any rule; chunk 3 wires it through. An MCP server NAME listed there now suppresses every per-server MCP config finding (mcp_insecure_server, mcp_untrusted_server, mcp_suspicious_args, mcp_overly_permissive, and mcp_duplicate_server_name when the duplicate's name is itself trusted), and filters drift entries with that name out of the mcp_server_drift finding — so a server the operator has reviewed and accepted neither raises config-side noise nor counts as drift. The filter is fine-grained: when every drift is for a trusted server, no drift finding fires; when some drifts are for trusted servers and others are not, only the untrusted ones surface — the trusted entries are dropped, not "trust the whole batch or none". An unparseable lockfile still fires (we cannot know which servers it concerned), exactly as it did before. Trust matching is case-sensitive and exact-string — MCP server names are arbitrary identifiers, not URLs, so locale-insensitive folding would be the wrong default. New policy field — scan.mcp_allowed_tools — a HashMap<String, Vec<String>> keyed by MCP server name, listing the exact tool names that server may expose. Two effects, both surfacing through the existing mcp_server_drift rule (no new RuleId): (1) At drift time, when drift exposes a tool to a server whose name is a key in mcp_allowed_tools and that tool is NOT in the allowed set, the drift finding is upgraded from the default Medium to High severity — adding a tool outside the allowed set is a stronger signal than ordinary drift. The ladder covers both drift shapes that can introduce new tool exposure: a Changed drift (an existing server gains a new tool — checked via tools_added), and an Added drift (a brand-new server appears with a disallowed tool in its declared tool list). Without the Added arm, an attacker could smuggle a disallowed tool by introducing a new server rather than mutating an existing one, and the finding would stay at the default Medium; the ladder applies symmetrically to both paths. Drift inside the allowed set keeps Medium; an mcp_allowed_tools entry of [] for a server forbids ANY tool on that server (every new tool is out-of-set); a Removed drift does not feed the ladder because the ladder is about new exposure, never lost exposure. (2) At lockfile load, when the lockfile itself records tools outside the allowed set for a server (the failure mode of "an MCP tool was snuck past tirith mcp lock"), a High-severity mcp_server_drift finding fires naming the offending tools — alongside any other drift findings, so an operator sees both the immediate violation and the broader inventory state. A server NOT listed in mcp_allowed_tools is unconstrained — the gate is opt-in. New command — tirith mcp policy init — scaffolds a starter MCP policy from the current .tirith/mcp.lock. It writes .tirith/mcp-policy.yaml.example listing every currently-locked server as a trusted_mcp_servers candidate (deduplicated by name, since the same name can legitimately appear in two configs) and every currently-recorded tool list as an mcp_allowed_tools entry. Every entry is commented out by design — importing the example must NEVER silently widen trust; the operator reviews the scaffold, uncomments what they intend to declare, and merges it into .tirith/policy.yaml themselves. A separate .example file is cleaner than mutating an existing policy.yaml (the operator can diff the scaffold against their working policy and integrate the bits they want). The scaffold is deterministic — running mcp policy init twice against the same lockfile produces a byte-identical example file; the lockfile is already sorted by (name, source_config), and the scaffold sorts further via BTreeSet / BTreeMap. Server / tool names are YAML-quoted-and-escaped before they reach the example — a maliciously-crafted server name containing a :, #, newline, or ANSI escape cannot break the YAML structure or inject control sequences when the operator cats the file. --force overwrites an existing example file; without it, an existing example is preserved (the operator may have edited it to track their working policy). --format json emits a structured planned-policy preview (server count, tool count, the scaffold itself) so a CI integration can ingest the proposal without reading the file. A missing lockfile is NOT fatal — a header-only scaffold is still written so the operator has a starting point; an unparseable lockfile IS fatal (exit 1) because we cannot tell what to list. No new RuleId. Chunk 3 reuses McpServerDrift for the lockfile-side disallowed-tool flag and the existing Mcp* rules for the config-side suppression — the four golden_fixtures.rs safeguard tests, the structural arm in scoring.rs, the EXPECTED_RULES map in build.rs, the ALL_RULE_IDS list, and rule_explanations.toml need no schema changes. The policy template (policy.yaml) gains documented but commented-out trusted_mcp_servers / mcp_allowed_tools examples in the full, individual, ci-strict, and ai-agent-heavy variants, so a fresh tirith policy init shows what the fields look like even before the operator runs mcp policy init. Policy validation already accepted scan.mcp_allowed_tools as a known field name (it was added in the schema work that introduced the field). Like every other mcp subcommand, policy init is a local file operation — no network, off the tier-1/2/3 detection hot path.

  • MCP lockfile drift detection — tirith mcp verify, tirith mcp diff, and the mcp_server_drift scan rule — chunk 2 of the Agent & MCP governance work. tirith mcp verify rebuilds the current inventory and compares it against the committed .tirith/mcp.lock: it exits 0 when the two match, 1 when drift is detected (a server added, removed, or altered — transport, env, declared tools, or URL credentials), and 2 on a usage error (no lockfile to verify against, lockfile unreadable, repo root unresolved). The exit-code split lets a CI integration distinguish "the lockfile is stale" (1, the build must fail) from "there is no lockfile to verify" (2, the build must abort with a clear message). tirith mcp diff shows the same drift but informationally — it exits 0 whether or not drift is present (drift is reported, not enforced), but a usage error (missing lockfile, unreadable lockfile, unresolvable repo root) still exits 2 so a piped consumer can distinguish "no drift" from "I could not check" — for inspecting a config change before refreshing the lockfile. Both support --format json with a stable envelope (schema_version, repo_root, lock_path, command, lockfile_format_version, drift_count, added_count, removed_count, changed_count, in_sync, and a sorted drifts array; the drift list is byte-stable regardless of inventory order). Drift is also detected in the tirith scan FileScan path via a new RuleId::McpServerDrift rule (Severity Medium, "review me" not "block"): when tirith scan walks a repository and reaches .tirith/mcp.lock, the rule parses the lockfile, rebuilds the inventory from the repo's MCP configs, and fires when the two differ — so a pre-commit hook or CI scan catches an MCP-surface change the same way it catches an un-pinned action or smuggled instruction. The structured drift core distinguishes every category from the chunk-2 brief: server added, server removed, transport changes (KindChanged, UrlChanged, UserinfoAdded / Removed / Swapped, CommandChanged, ArgsChanged, EnvChanged), per-env-variable changes (Added / Removed / ValueHashChanged), and per-tool changes (Added / Removed / Set / Reordered). It rides on the chunk-1 inventory hash: when current_lock.inventory_hash == lockfile.inventory_hash the drift is provably empty and the per-server diff is skipped entirely; only when the inventory hash differs does the merge walk by (name, source_config) produce structured drift entries. Moving an unchanged server between config files is a non-event (chunk 1's content_hash deliberately excludes source_config) — drift only fires when the server itself changed. Privacy invariant. Neither verify nor diff — nor the new scan rule — ever prints an env value, a URL userinfo string, or even a hash; only the name of the variable or credential that changed reaches the human output and the JSON envelope. The lockfile already stripped raw values into salted hashes in chunk 1; drift detection observes that the hash changed, never the underlying secret. Drift entries are safe to print to a terminal, serialize as JSON, and commit to an audit log. Like every other mcp subcommand, verify and diff are local file operations — no network, off the tier-1/2/3 detection hot path — and discovery is repo-local only.

  • MCP server inventory and lockfile — tirith mcp lock — the first command of the Agent & MCP governance work. tirith mcp lock discovers every Model Context Protocol (MCP) server a repository declares — across .mcp.json / mcp.json / mcp_settings.json and the IDE config variants under .vscode/, .cursor/, .windsurf/, .cline/, .amazonq/, .continue/, .kiro/ — parses each into a structured inventory (per server: its name, transport — a remote url, or a local command + args + the subprocess env it injects — and declared tools), and writes a deterministic lockfile to .tirith/mcp.lock at the repository root. Both known config-shape variants (mcpServers and the servers alias) are handled; a server object declaring neither a url nor a command is captured with an explicit "unknown transport" rather than dropped. The lockfile carries a top-level format_version (currently 4), a per-server content hash (over name + transport — including a stdio server's env and a URL transport's userinfo_hash — + tools, independent of which config file the server lives in; every variable-length component is length-prefixed so the hash is collision-free), the captured config list, and an inventory_hash over the whole inventory; the lockfile's servers are sorted by (name, source_config) before the inventory hash is computed, so the file and its hash are byte-stable regardless of config-discovery order and a git diff of .tirith/mcp.lock shows exactly what changed in the repo's MCP surface. Env values are never persisted in the lockfile. An env value declared in .mcp.json is commonly a credential (API_TOKEN, GITHUB_PERSONAL_ACCESS_TOKEN, OPENAI_API_KEY, …) and .tirith/mcp.lock is designed to be committed, so each env entry serializes as { name, value_hash } where value_hash is the lowercase-hex SHA-256 of name || ':' || value. The name acts as a per-entry salt so a low-entropy value (1, true) is not brute-forceable across servers, and the raw value is consumed and dropped inside the parser before reaching any struct field or output. Drift detection is unchanged in spirit — a value change still flips value_hash, which still flips the per-server content hash — but a committed mcp.lock no longer carries plaintext secrets. URL userinfo (HTTP Basic Auth) is never persisted either. A URL declared as https://user:token@host:port/path is the symmetric leak class: the lockfile is committed, so the raw user:token would land in version control. The same salted-hash scheme is applied to the URL transport: the URL is stored with userinfo stripped (https://host:port/path), and a userinfo_hash = sha256(server_name || ':' || userinfo) — salted by the MCP server's name — is recorded; it is folded into the per-server content hash so a userinfo swap registers as drift. A URL that carried no userinfo serializes with userinfo_hash omitted (not set to a sentinel), so "no credential" is structurally distinct on the wire from "credential present"; a non-parseable URL is stored verbatim with no hash (we refuse to mangle a string we cannot structurally parse). The mcp lock human summary additionally debug-escapes every env name before printing ("{name:?}", which renders each control byte as a \u{NN} / \n / \r escape rather than the raw byte), so a maliciously-crafted name containing ANSI escapes, newlines, or other terminal control bytes cannot inject control sequences into the operator's terminal; a redacted URL whose source declared credentials prints with a fixed (credentials in source URL) annotation so the redaction is visible without revealing the credential or its hash. This is a local file operation — no network, off the tier-1/2/3 detection hot path — and discovery is repo-local only: user-level configs such as ~/.claude/ are never inventoried, and the guarantee is enforced — a config path that is a symlink, sits under a symlinked directory, or whose canonicalized path escapes the repo root is rejected rather than followed. A malformed configuration file (not valid JSON, or no MCP-server object) contributes no entries and is never an error or a panic — it is reported as "unparseable", and the lockfile reflects only the configs tirith could read. Finding no MCP configuration at all is likewise not an error: it is reported plainly and an empty-but-valid lockfile is still written as a baseline. tirith mcp lock is a new subcommand group; the existing tirith mcp-server (run tirith as an MCP server) is unchanged. --format json reports the captured config / server counts and the full lockfile document. tirith mcp verify / mcp diff (drift detection against a committed lockfile) are planned follow-up work.

  • Package provenance / maintainer-risk scoring — tirith package risk and tirith package explain (offline signals) — tirith can now score a package's supply-chain risk the way tirith score scores a URL: a deterministic, fully explainable sum of named factors — no model, no learned weights, no statistical classifier — every score reproducible by hand. This is the offline-signals phase: every signal is computed without any network or registry-API call. tirith package risk <ecosystem> <name> prints the score and a one-line-per-signal summary; tirith package explain <ecosystem> <name> adds the factor-by-factor derivation (mirroring tirith score --explain); both support --format json. The offline signals: (1) Name vs. popular packages — the dominant factor, sourced from the local threat database's popular set. A name that is a known-popular package scores 0 (recognized); a name one Levenshtein edit from a known-popular package scores high (the classic typosquat/slopsquat shape, via check_popular_distance); an unknown name gets a small baseline only — unknown is not the same as malicious. A new exact-match ThreatDb::is_popular_package accessor backs the "is recognized" check (the existing check_popular_distance deliberately skips exact matches). (2) Known malicious typosquat — additive: the threat DB's typosquat index independently lists this exact name as a malicious typosquat (via check_typosquat) — a confirmed bad name, stronger than a mere resemblance. (3) Install / lifecycle-script presence — additive, and only when the package content is locally available: tirith inspects a package directory you already have (auto-discovered under node_modules / site-packages relative to the cwd, or an explicit --path) — it never downloads the package. For npm it reads package.json for a non-empty preinstall / install / postinstall lifecycle hook; for PyPI it checks for a setup.py. (4) Bundled binary-blob presence — additive, also local-content-only: a bounded directory walk for native/compiled artifacts (.so, .dll, .dylib, .node, .wasm, .jar, …). The final score is min(100, sum), with the clamp reported as an explicit negative factor so the breakdown always sums exactly to the displayed number — a test asserts that invariant across every signal combination. The score is advisory and standalone: package risk is not a detection rule, produces no Verdict, and changes no Action, exit code, or audit log; existing detection and verdicts are untouched. The offline signals are always computed; registry-API-backed provenance signals are an opt-in addition behind --online (see the next entry) and never touch the hot path.

  • Package risk — registry-API-backed provenance signals (tirith package risk --online)package risk / package explain can now optionally consult a package's registry API for provenance / maintainer-risk signals, on top of the always-on offline signals above. This is strictly opt-in and off the hot path: API calls run only behind an explicit --online flag (offline is the default, consistent with tirith's offline-first network policy), --offline / TIRITH_OFFLINE force offline even with --online, and tirith never adds network to tirith check or any other path — package risk --online is the sole entry point. The registry is selected by the <ecosystem> argument: the npm registry API, the PyPI JSON API, and the crates.io API are supported (other ecosystems degrade gracefully). Six registry-API signals, each an explicit named factor in the same deterministic factor-sum model as the offline phase — no ML, no black-box scoring, every factor reproducible by hand: (1) package / version age — a package first published, or a latest version released, very recently (the textbook fresh-typosquat shape; the package-level signal is the larger one and subsumes the smaller version-level one); (2) abandoned ownership — the registry lists an established package with zero maintainers / owners (an account-takeover precursor; a single registry document carries the current owner set, not its history, so a literal transfer cannot be proven from it — an established package that has lost every listed owner is the shape that can be); (3) version spike — the latest version is an abnormal major-version jump from the previous one (a hijacked release often ships an inflated version to capture a semver range); (4) download counts — very low downloads over the registry's reported window (near-zero adoption is a weak signal); (5) repo / source-URL mismatch — the registry lists no usable source-repository URL (provenance cannot be traced to reviewable source); (6) yanked / deprecated status — the registry itself marks the latest version yanked or deprecated. Network hygiene: the registry HTTP client uses reqwest with an explicit timeout and a response-size cap, exactly as runner.rs / selfupdate.rs do. Graceful degradation: a network failure, timeout, HTTP error, unparseable response, or unsupported ecosystem is never a crash, hang, or block — it degrades to the offline score with an honest api signals: unavailable (reason). Successful registry responses are cached on disk with a TTL (under the tirith state dir) so repeated package risk runs do not hammer the registries. The package_risk::ApiSignals seam now carries three states — not_computed (offline run, the default), available (an --online run that reached the registry), and unavailable (an --online run that degraded) — and --format json exposes the gathered provenance under api_signals. Offline scoring is unchanged: the API signals only add factors, every offline-phase test still passes, and the score stays advisory and standalone (no Verdict, no exit-code or audit-log change).

  • Install-command coverage — package-manager and infrastructure install patterns — tirith now detects high-risk patterns in package-manager and infrastructure install commands (apt/dnf/yum/zypper/pacman, brew, kubectl, helm, terraform), focusing on the dangerous pattern rather than the tool so a legitimate apt install foo, brew install foo, kubectl apply -f ./local.yaml, terraform init, or helm install ./chart stays clean. Seven new rules: (1) repo_add_from_pipe (High) — a network download piped through tee into an apt sources.list file, or redirected straight into one, so the repo definition is added and its signing key trusted without any review; a local file piped into tee does not fire. (2) unsigned_repo_trust (High) — an apt sources entry marked [trusted=yes] (tolerant of [arch=amd64 trusted=yes]), or apt-get run with --allow-unauthenticated / --allow-insecure-repositories — all disable GPG signature verification. (3) gpg_check_disabled (High) — dnf/yum/zypper run with --nogpgcheck, an inline gpgcheck=0 repo setting, or pacman SigLevel = Never. (4) kubectl_apply_remotekubectl apply/create/replace -f given a remote URL (High for a raw-content blob like raw.githubusercontent.com or a URL-shortener that hides the source, Medium for any other remote URL); a local file or -k kustomize directory does not fire. (5) helm_untrusted_repo (Medium) — helm install/upgrade/repo add/pull pointed at a chart-repository host not in the recognized set; a local chart path does not fire. (6) terraform_remote_module (Medium) — terraform init -from-module (or tofu) sourcing a root module from a remote git/http(s)/code-hosting location rather than a local path or the Terraform Registry. (7) brew_untrusted_tapbrew install given a raw URL instead of a formula name (High), or brew tap pointed at an explicit non-GitHub git remote (Medium). All rules see through a single leading sudo / doas wrapper (and its value-taking flags) and tolerate shell quoting. Detection is pure pattern matching — no registry or network calls on the hot path. Each rule has full tirith explain documentation, a tier-1 PATTERN_TABLE entry, and golden fixtures covering both the attack shape and the benign baseline.

  • tirith ecosystem scan — project dependency-manifest supply-chain scan — the directory-level companion to tirith package risk: tirith ecosystem scan [path] walks a project, discovers and parses dependency manifests (npm package.json / package-lock.json, Python requirements*.txt / pyproject.toml, Rust Cargo.toml, Go go.mod, Ruby Gemfile), and scores every declared dependency through the package_risk engine — offline by default, --online adds the registry-API provenance signals. It also folds in slopsquat detection — AI-hallucinated package names: a conservative three-layer heuristic (the name is unknown to the threat DB, and shaped like an LLM hallucination, and sits near a real popular name) flags dependencies an attacker may have registered to catch a hallucinated import. Findings flow through the normal Verdict / Finding model, are explainable, respect the policy allowlist, and support --format json; slopsquat is integrated here, not shipped as a separate crate. Manifest parsers are total — a malformed manifest yields no findings, never a panic.

  • tirith install — safe-install transactiontirith install <npm|pip|cargo|url> <args…> wraps a real package install with pre-execution supply-chain risk analysis: it scores the package(s) with the package_risk engine and the install command with the install-command rules before anything runs, presents one explainable Verdict (a block refuses with bypass-per-policy, a warn requires acknowledgement, an allow proceeds), records the transaction (a working-directory checkpoint plus an audit-log entry), then runs the real npm / pip / cargo install — or, for the url form, the downloaded script via the existing safe-download path. --no-exec analyzes and records without running the install; --online adds registry-API provenance, --offline / TIRITH_OFFLINE force offline; --format json carries an explicit sandboxed: false. This is pre-execution install-risk analysis plus a recorded transaction — it does not sandbox or isolate the install (runtime sandboxing is an explicit tirith non-goal); the real install runs with the user's full privileges.

  • CI / repo supply-chain scanning — tirith scan covers your CI and infrastructure filestirith scan now inspects the files a repository checks in to describe its own build and deploy pipeline, not just AI-config files. It detects the dangerous pattern, not the tool, so a hardened workflow, a digest-pinned image, a local Terraform module, and a normal package.json all stay clean — every detection ships with benign fixtures proving a legitimate file does not fire. Six new file-content scan rules, run on the tirith scan file-walk path (no network, no registry calls): (1) workflow_unpinned_action (Medium) — a GitHub Actions uses: reference in .github/workflows/*.yml pinned to a mutable ref (a branch like @main or a tag like @v3) instead of an immutable 40-character commit SHA; a SHA-pinned action and a local ./ action do not fire, and a workflow with many unpinned steps yields one folded finding. (2) workflow_dangerous_trigger (High) — the pull_request_target trigger, which runs with repository secrets and a read/write token in the context of an untrusted fork's PR; the safe pull_request trigger does not fire. (3) workflow_curl_pipe_shell (High) — a curl … | bash / wget … | sh pipe-to-shell inside a workflow run: step (single-line or | block scalar); a curl -o file download or a benign echo | grep does not fire. (4) workflow_untrusted_input (High) — an attacker-controllable ${{ github.event.* }} expression (PR title, issue body, branch name, comment, …) interpolated directly into a run: shell step — the classic Actions script-injection sink; a trusted context value (github.sha) and the same expression in a non-run: with: block do not fire. (5) dockerfile_unpinned_image (Medium) — a Dockerfile FROM on the mutable latest tag or with no tag at all and no @sha256: digest pin; a digest-pinned image, a specific version tag, an earlier-build-stage reference, and a build-arg-templated image do not fire. (6) package_script_dangerous (High) — an npm package.json preinstall/install/postinstall lifecycle hook (the hooks that run automatically on npm install) whose command is a pipe-to-shell, a base64-decode-and-execute payload, an inline interpreter one-liner that shells out or opens a network connection, or a download-and-run sequence; a benign node-gyp rebuild / tsc build hook, and the prepare hook (commonly a benign husky install), do not fire. Terraform module blocks with a remote/untrusted source in a *.tf file and Helm chart dependencies from an untrusted repository in Chart.yaml are also detected — these reuse the existing terraform_remote_module / helm_untrusted_repo rule IDs, since a remote module or untrusted chart repo is the same risk class whether named on a command line or in a checked-in file. Each new rule has full tirith explain documentation. tirith scan also gains three built-in --profile values that tune which checks and severities apply: ci-hardening (every supply-chain check at full strength, fail-on high, for hardening a CI/CD pipeline), ai-agent-repo (keeps the injection / dangerous-trigger / dangerous-script findings, suppresses low-value pinning-hygiene noise, for a repo an AI agent operates in), and oss-maintainer (emphasises contributor-controllable attack surface — script injection, dangerous triggers, dangerous lifecycle scripts — and downgrades pinning-hygiene findings, for reviewing a contributed change). A built-in profile sets a default fail_on and a small explicit per-rule overlay that can suppress or re-grade a finding but never invent one; a policy scan.profiles.<name> entry of the same name overrides the built-in. tirith scan --format json exposes the new findings unchanged.

  • AI-relevant file hidden-content scanning — tirith scan catches content smuggled past a human reviewertirith scan now inspects file types an AI coding agent (or a renderer) reads and acts on, looking specifically for hidden / smuggled content — content a human reviewing the file would not see, but an agent or a renderer still processes. It extends the existing FileScan architecture (the same module pattern as the CI/repo cifile rules) with a new aifile rule module; false positives are the explicit design priority, so a normal notebook, an ordinary CLAUDE.md with visible instructions, and a plain SVG image all stay clean — every detection ships with benign fixtures proving a legitimate file does not fire. No network, no registry calls. Five new file-content scan rules across three file kinds: (1) notebook_hidden_content — a Jupyter notebook (*.ipynb) cell with content hidden from the rendered view: invisible / bidirectional / zero-width characters in the cell source (High), a long base64-encoded blob embedded in the source (Medium), or a cell hidden via metadata.jupyter.source_hidden or a hide_input tag (Medium). (2) notebook_suspicious_output — a stored cell output carrying smuggled content: invisible characters in a saved stream / text/plain output (High), or an embedded <script>, an inline event handler, a javascript: URI, or CSS-hidden content in a saved text/html output (Medium). A normal computed output — a number, a pandas DataFrame HTML <table>, a plain-text result — does not fire. (3) agent_instruction_hidden (High) — an AI agent-instruction file (CLAUDE.md, AGENTS.md, .cursorrules, and similar) with a hidden directive: an instruction inside an HTML comment (Markdown renders an HTML comment to nothing) or a visually-hidden HTML element (hidden, aria-hidden, display:none). These files legitimately contain visible instructions, so ordinary visible instructions — and benign developer comments (<!-- TODO -->, prettier-ignore) — never fire; only hidden directives with an instruction-shaped phrase do. (4) svg_script_embedded (High) — an SVG image (*.svg) carrying executable content: an embedded <script> element, an inline on* event-handler attribute, or a javascript: URI; a static SVG image (paths, shapes, gradients, text) does not fire. (5) svg_external_reference (Medium) — an SVG that references content outside itself: a remote xlink:href / href, or an XXE external-entity declaration (<!ENTITY … SYSTEM "…">); an internal xlink:href="#id" fragment reference does not fire. .svg is no longer treated as a binary/skip extension by the directory walk — an SVG is XML text and is now scanned. Invisible-character detection reuses tirith's existing bidi / zero-width / Unicode-tag classification rather than reimplementing it. Each new rule has full tirith explain documentation and golden fixtures covering both the attack shape and the benign baseline; the four golden_fixtures.rs tier-1 safeguard tests pass. tirith scan --format json exposes the new findings unchanged. DOCX / PPTX / ODT are deliberately out of scop

Note

PR body was truncated to here.


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR has been generated by Mend Renovate.

@github-actions

Copy link
Copy Markdown

Site preview

Preview: https://947965b0-site.fullsend-ai.workers.dev

Commit: 70c50e0c8ea19f8fe30bd913292334f05154f3f2

@codecov

codecov Bot commented Jul 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@renovate-fullsend
renovate-fullsend Bot force-pushed the renovate/sheeki03-tirith-0.x branch 5 times, most recently from d68e995 to 15071d3 Compare August 1, 2026 04:20
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 1, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 4:20 AM UTC · Completed 4:31 AM UTC
Commit: 15071d3 · View workflow run →

@fullsend-ai-review

fullsend-ai-review Bot commented Aug 1, 2026

Copy link
Copy Markdown

Review

Findings

High

  • [checksum mismatch] images/sandbox/Containerfile:148TIRITH_VERSION was bumped from 0.3.1 to 0.3.3 but the SHA256 checksums (TIRITH_SHA256_AMD64 on line 148 and TIRITH_SHA256_ARM64 on line 149) were not updated. The RUN block downloads v0.3.3 tarballs and verifies them against the stale v0.3.1 hashes, so sha256sum -c will fail and the container build will abort. This issue was flagged in the prior review and remains unfixed.
    Remediation: Update the checksum ARGs to the v0.3.3 values from checksums.txt.

  • [protected-path] images/sandbox/Containerfile — This file is under images/, a protected path requiring human approval. The PR has no linked issue providing authorization for modifying governance or infrastructure files. Human review is required before merge.


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run

Review

Findings

High

  • [checksum mismatch] images/sandbox/Containerfile:148TIRITH_VERSION was bumped from 0.3.1 to 0.3.3 but the SHA256 checksums (TIRITH_SHA256_AMD64 on line 148 and TIRITH_SHA256_ARM64 on line 149) were not updated. The RUN block downloads v0.3.3 tarballs and verifies them against the stale v0.3.1 hashes, so sha256sum -c will fail and the container build will abort. This is a known Renovate limitation — the regex manager only captures the version string, and automerge is explicitly disabled for tirith because checksums must be updated manually. This issue was flagged in the prior review and remains unfixed.
    Remediation: Update the checksum ARGs to the v0.3.3 values from checksums.txt.

  • [protected-path] images/sandbox/Containerfile — This file is under images/, a protected path requiring human approval. The PR has no linked issue providing authorization for modifying governance or infrastructure files. Human review is required before merge.


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run (2)

Review

Findings

High

  • [checksum mismatch] images/sandbox/Containerfile:148TIRITH_VERSION was bumped from 0.3.1 to 0.3.3 but the SHA256 checksums (TIRITH_SHA256_AMD64 on line 148 and TIRITH_SHA256_ARM64 on line 149) were not updated. The checksums still correspond to v0.3.1 artifacts. The RUN block (starting at line 150) downloads v0.3.3 tarballs and verifies them against the stale v0.3.1 hashes, so sha256sum -c will fail and the container build will abort. This is confirmed by: (1) the Containerfile’s own inline comments on lines 145–146 documenting that both the version and checksums must be updated together, and (2) the renovate.json configuration explicitly stating checksums must be refreshed manually, with automerge disabled precisely because of this manual step. This issue was flagged in the prior review and remains unfixed.
    Remediation: Update the checksum ARGs to the v0.3.3 values from checksums.txt.

  • [protected-path] images/sandbox/Containerfile — This file is under images/, a protected path requiring human approval. The PR has no linked issue providing authorization for modifying governance or infrastructure files. Human review is required before merge.


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run (3)

Review

Findings

High

  • [checksum mismatch] images/sandbox/Containerfile:148TIRITH_VERSION was bumped from 0.3.1 to 0.3.3 but the SHA256 checksums (TIRITH_SHA256_AMD64 and TIRITH_SHA256_ARM64) were not updated. The checksums still correspond to v0.3.1 artifacts. The RUN block downloads v0.3.3 tarballs and verifies them against the stale v0.3.1 hashes, so sha256sum -c will fail and the container build will abort. The Containerfile's own comments (lines 145–146) document that both the version and checksums must be updated together. This issue was flagged in the prior review and remains unfixed.
    Remediation: Update the checksum ARGs to the v0.3.3 values from checksums.txt.

  • [protected-path] images/sandbox/Containerfile — This file is under images/, a protected path requiring human approval. The PR has no linked issue providing authorization for modifying governance or infrastructure files. Human review is required before merge.


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run (4)

Review

Findings

High

  • [checksum mismatch] images/sandbox/Containerfile:148TIRITH_VERSION was bumped from 0.3.1 to 0.3.3 but the SHA256 checksums (TIRITH_SHA256_AMD64 and TIRITH_SHA256_ARM64) were not updated. The checksums still correspond to v0.3.1 artifacts. The RUN block downloads v0.3.3 tarballs and verifies them against the stale v0.3.1 hashes, so sha256sum -c will fail and the container build will abort. The Containerfile's own comments (lines 145–146) document that both the version and checksums must be updated together. This issue was flagged in the prior review and remains unfixed.
    Remediation: Update the checksum ARGs to the v0.3.3 values from checksums.txt. The prior review identified these as:
    TIRITH_SHA256_AMD64=6cdbe35e8f9ccf42e70ad95b501c93cd218ac18201c3df958d54f6ba0d995ce2
    TIRITH_SHA256_ARM64=c784233083003a6a1533db9ebba30b1a7bb7cefaa239db6ca121598b384cca1a

  • [protected-path] images/sandbox/Containerfile — This file is under images/, a protected path requiring human approval. The PR has no linked issue providing authorization for modifying governance or infrastructure files. Human review is required before merge.


Labels: PR modifies sandbox container image (images/sandbox/Containerfile) and is a Renovate dependency update


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run (5)

Review

Findings

High

  • [checksum mismatch] images/sandbox/Containerfile:148TIRITH_VERSION was bumped from 0.3.1 to 0.3.3 but the SHA256 checksums (TIRITH_SHA256_AMD64 and TIRITH_SHA256_ARM64) were not updated. The checksums still correspond to v0.3.1 artifacts. The RUN block downloads v0.3.3 tarballs and verifies them against the stale v0.3.1 hashes, so sha256sum -c will fail and the container build will abort. The Containerfile's own comments (lines 145–146) document that both the version and checksums must be updated together. This issue was flagged in the prior review and remains unfixed.
    Remediation: Update the checksum ARGs to the v0.3.3 values from checksums.txt. The prior review identified these as:
    TIRITH_SHA256_AMD64=6cdbe35e8f9ccf42e70ad95b501c93cd218ac18201c3df958d54f6ba0d995ce2
    TIRITH_SHA256_ARM64=c784233083003a6a1533db9ebba30b1a7bb7cefaa239db6ca121598b384cca1a

  • [protected-path] images/sandbox/Containerfile — This file is under images/, a protected path requiring human approval. The PR has no linked issue providing authorization for modifying governance or infrastructure files. Human review is required before merge.


Labels: PR modifies sandbox container image (images/sandbox/Containerfile) and is a Renovate dependency update


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run (6)

Review

Findings

High

  • [checksum mismatch] images/sandbox/Containerfile:148TIRITH_VERSION was bumped from 0.3.1 to 0.3.3 but the SHA256 checksums (TIRITH_SHA256_AMD64 and TIRITH_SHA256_ARM64) were not updated. The checksums still correspond to v0.3.1 artifacts (verified against the v0.3.3 GitHub release). The RUN block downloads v0.3.3 tarballs and verifies them against the stale v0.3.1 hashes, so sha256sum -c will fail and the container build will abort. The Containerfile's own comments (lines 145–146) document that both the version and checksums must be updated together. This issue was flagged in the prior review and remains unfixed.
    Remediation: Update the checksum ARGs to the v0.3.3 values from checksums.txt:
    TIRITH_SHA256_AMD64=6cdbe35e8f9ccf42e70ad95b501c93cd218ac18201c3df958d54f6ba0d995ce2
    TIRITH_SHA256_ARM64=c784233083003a6a1533db9ebba30b1a7bb7cefaa239db6ca121598b384cca1a

  • [protected-path] images/sandbox/Containerfile — This file is under images/, a protected path requiring human approval. The PR has no linked issue providing authorization for modifying governance or infrastructure files. Human review is required before merge.


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run (7)

Review

Findings

High

  • [checksum mismatch] images/sandbox/Containerfile:148TIRITH_VERSION was bumped from 0.3.1 to 0.3.3 but the SHA256 checksums (TIRITH_SHA256_AMD64 and TIRITH_SHA256_ARM64) were not updated. The checksums still correspond to v0.3.1 artifacts. The RUN block downloads v0.3.3 tarballs and verifies them against the old v0.3.1 hashes, so sha256sum -c will fail and the container build will abort. The Containerfile's own comments (lines 145–146) document that both the version and checksums must be updated together. This issue was flagged in the prior review and remains unfixed.
    Remediation: Download checksums.txt from the v0.3.3 release, extract the sha256 hashes for tirith-x86_64-unknown-linux-gnu.tar.gz and tirith-aarch64-unknown-linux-gnu.tar.gz, and update TIRITH_SHA256_AMD64 and TIRITH_SHA256_ARM64 accordingly.

  • [protected-path] images/sandbox/Containerfile — This file is under images/, a protected path requiring human approval. The PR has no linked issue providing authorization for modifying governance or infrastructure files. Human review is required before merge.


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run (8)

Review

Findings

High

  • [checksum mismatch] images/sandbox/Containerfile:148TIRITH_VERSION was bumped from 0.3.1 to 0.3.3 but the SHA256 checksums (TIRITH_SHA256_AMD64 and TIRITH_SHA256_ARM64) were not updated. The checksums 571e6a3... (amd64) and 0462fe5... (arm64) correspond to v0.3.1 artifacts. The build downloads v0.3.3 tarballs and verifies them against these stale checksums, causing sha256sum -c to fail and the build to abort. This issue was flagged in the prior review and remains unfixed.
    Remediation: Fetch checksums.txt from the v0.3.3 release, extract the sha256 hashes for tirith-x86_64-unknown-linux-gnu.tar.gz and tirith-aarch64-unknown-linux-gnu.tar.gz, and update TIRITH_SHA256_AMD64 and TIRITH_SHA256_ARM64 accordingly.

  • [protected-path] images/sandbox/Containerfile — This file is under images/, a protected path requiring human approval. The PR has no linked issue providing authorization for modifying governance or infrastructure files. Human review is required before merge.


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run (9)

Review

Findings

High

  • [supply-chain integrity] images/sandbox/Containerfile:148TIRITH_VERSION was bumped from 0.3.1 to 0.3.3 but TIRITH_SHA256_AMD64 (line 148) and TIRITH_SHA256_ARM64 (line 149) still contain the v0.3.1 hashes. The build downloads v0.3.3 tarballs but verifies them against stale v0.3.1 checksums, causing the sha256sum -c step to fail. This issue was flagged in the prior review and remains unfixed.
    Remediation: Download checksums.txt from the v0.3.3 release, extract the sha256 hashes for tirith-x86_64-unknown-linux-gnu.tar.gz and tirith-aarch64-unknown-linux-gnu.tar.gz, and update TIRITH_SHA256_AMD64 and TIRITH_SHA256_ARM64 accordingly.

  • [protected-path] images/sandbox/Containerfile — This file is under images/, a protected path requiring human approval. The PR has no linked issue providing authorization for modifying governance or infrastructure files. Human review is required before merge.


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run (10)

Review

Findings

High

  • [supply-chain integrity] images/sandbox/Containerfile:148TIRITH_VERSION was bumped from 0.3.1 to 0.3.3 but the SHA256 checksums on lines 148–149 (TIRITH_SHA256_AMD64 and TIRITH_SHA256_ARM64) were not updated. They still contain the hashes for the v0.3.1 tarballs. The build will fail at the sha256sum -c step because the downloaded v0.3.3 tarballs will not match the stale v0.3.1 hashes. This is confirmed by the build-base CI check, which is currently failing. The inline comment on lines 145–146 documents the required procedure: bump both TIRITH_VERSION and TIRITH_SHA256_{AMD64,ARM64} together from the release's checksums.txt. This issue was flagged in the prior review and remains unfixed.
    Remediation: Download checksums.txt from the v0.3.3 release and update TIRITH_SHA256_AMD64 and TIRITH_SHA256_ARM64 to the correct checksums.

  • [protected-path] images/sandbox/Containerfile — This file is under images/, a protected path requiring human approval. The PR has no linked issue providing authorization for modifying governance or infrastructure files. Human review is required before merge.


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run (11)

Review

Findings

High

  • [supply-chain integrity] images/sandbox/Containerfile:148TIRITH_VERSION was bumped from 0.3.1 to 0.3.3 but the SHA256 checksums for both amd64 (line 148) and arm64 (line 149) were not updated. The checksums still correspond to the v0.3.1 binaries. The build will fail at the sha256sum -c step because the downloaded v0.3.3 tarball will not match the stale hashes. The inline comment on lines 145–146 documents the required procedure: bump both TIRITH_VERSION and TIRITH_SHA256_{AMD64,ARM64} together from the release's checksums.txt. This issue was flagged in the prior review and remains unfixed.
    Remediation: Update TIRITH_SHA256_AMD64 and TIRITH_SHA256_ARM64 to the correct checksums from the v0.3.3 release.

  • [protected-path] images/sandbox/Containerfile — This file is under images/, a protected path requiring human approval. The PR has no linked issue providing authorization for modifying governance or infrastructure files. Human review is required before merge.


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run (12)

Review

Findings

High

  • [supply-chain integrity] images/sandbox/Containerfile:148TIRITH_VERSION was bumped from 0.3.1 to 0.3.3 but the SHA256 checksums for both amd64 (line 148) and arm64 (line 149) were not updated. The checksums still correspond to v0.3.1 binaries. The build will fail at the sha256sum -c step because the downloaded v0.3.3 tarball will not match the stale hash. The inline comment on lines 145–146 documents the required procedure: bump both TIRITH_VERSION and TIRITH_SHA256_{AMD64,ARM64} together from the release's checksums.txt.
    Remediation: Update TIRITH_SHA256_AMD64 and TIRITH_SHA256_ARM64 to the correct checksums from the v0.3.3 release.

  • [protected-path] images/sandbox/Containerfile — This file is under images/, a protected path requiring human approval. The PR has no linked issue providing authorization for modifying governance or infrastructure files. Human review is required before merge.


Labels: PR modifies sandbox container image and is a dependency update


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR

fullsend-ai-review[bot]

This comment was marked as outdated.

@fullsend-ai-review fullsend-ai-review Bot added component/sandbox OpenShell sandbox environment dependencies Pull requests that update a dependency file labels Aug 1, 2026
@renovate-fullsend
renovate-fullsend Bot force-pushed the renovate/sheeki03-tirith-0.x branch from 15071d3 to b9976b0 Compare August 1, 2026 15:35
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 1, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 3:37 PM UTC · Completed 3:47 PM UTC
Commit: b9976b0 · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

@renovate-fullsend
renovate-fullsend Bot force-pushed the renovate/sheeki03-tirith-0.x branch from b9976b0 to 9526609 Compare August 2, 2026 04:20
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 2, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 4:21 AM UTC · Completed 4:34 AM UTC
Commit: 9526609 · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

@renovate-fullsend
renovate-fullsend Bot force-pushed the renovate/sheeki03-tirith-0.x branch from 9526609 to 23abe7c Compare August 2, 2026 15:36
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 2, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 3:37 PM UTC · Completed 3:49 PM UTC
Commit: 23abe7c · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

@renovate-fullsend
renovate-fullsend Bot force-pushed the renovate/sheeki03-tirith-0.x branch from 23abe7c to 196ef1d Compare August 3, 2026 04:23
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 3, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 4:23 AM UTC · Completed 4:34 AM UTC
Commit: 196ef1d · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

@renovate-fullsend

Copy link
Copy Markdown
Contributor Author

⚠️ Artifact update problem

Renovate failed to update artifacts related to this branch. You probably do not want to merge this PR as-is.

♻ Renovate will retry this branch, including artifacts, only when one of the following happens:

  • any of the package files in this branch needs updating, or
  • the branch becomes conflicted, or
  • you click the rebase/retry checkbox if found above, or
  • you rename this PR's title to start with "rebase!" to trigger it manually

The artifact failure details are included below:

File name: images/sandbox/Containerfile
Command failed: bash scripts/renovate/update-tirith-checksums.sh
bash: scripts/renovate/update-tirith-checksums.sh: No such file or directory

File name: images/sandbox/Containerfile
Command failed: bash scripts/renovate/update-tirith-checksums.sh
bash: scripts/renovate/update-tirith-checksums.sh: No such file or directory

@fullsend-ai-review

fullsend-ai-review Bot commented Aug 3, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 1:44 PM UTC · Completed 1:56 PM UTC
Commit: b00f9af · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

@renovate-fullsend
renovate-fullsend Bot force-pushed the renovate/sheeki03-tirith-0.x branch from b00f9af to 739989b Compare August 3, 2026 16:04
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 3, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 4:05 PM UTC · Completed 4:16 PM UTC
Commit: 739989b · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

@renovate-fullsend
renovate-fullsend Bot force-pushed the renovate/sheeki03-tirith-0.x branch from 739989b to 91bbf9a Compare August 4, 2026 04:18
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 4, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 4:19 AM UTC · Completed 4:30 AM UTC
Commit: 91bbf9a · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

@renovate-fullsend
renovate-fullsend Bot force-pushed the renovate/sheeki03-tirith-0.x branch from 91bbf9a to df3c18c Compare August 4, 2026 16:00
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 4, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 4:01 PM UTC · Completed 4:11 PM UTC
Commit: df3c18c · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

@renovate-fullsend
renovate-fullsend Bot force-pushed the renovate/sheeki03-tirith-0.x branch from df3c18c to 840986c Compare August 5, 2026 04:18
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 5, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 4:19 AM UTC · Completed 4:31 AM UTC
Commit: 840986c · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

@renovate-fullsend
renovate-fullsend Bot force-pushed the renovate/sheeki03-tirith-0.x branch from 840986c to e49d9c4 Compare August 5, 2026 15:52
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 5, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 3:53 PM UTC · Completed 4:06 PM UTC
Commit: e49d9c4 · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

@renovate-fullsend
renovate-fullsend Bot force-pushed the renovate/sheeki03-tirith-0.x branch from e49d9c4 to df93994 Compare August 6, 2026 04:18
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 6, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 4:19 AM UTC · Completed 4:30 AM UTC
Commit: df93994 · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

@renovate-fullsend
renovate-fullsend Bot force-pushed the renovate/sheeki03-tirith-0.x branch from df93994 to a8a5a2b Compare August 7, 2026 04:06
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 7, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 4:07 AM UTC · Completed 4:16 AM UTC
Commit: a8a5a2b · View workflow run →

@fullsend-ai-review fullsend-ai-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the review comment for full details.

# in the GitHub release: https://github.com/sheeki03/tirith/releases
ARG TIRITH_VERSION=0.3.1
ARG TIRITH_VERSION=0.3.3
ARG TIRITH_SHA256_AMD64=571e6a300e4c444293476537a322666069e561c7f05283d6650f5b8ef83db3ac

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[high] checksum mismatch

TIRITH_VERSION was bumped from 0.3.1 to 0.3.3 but the SHA256 checksums (TIRITH_SHA256_AMD64 on line 148 and TIRITH_SHA256_ARM64 on line 149) were not updated. They still contain the v0.3.1 hashes. The RUN block downloads v0.3.3 tarballs and verifies them with sha256sum -c against these stale hashes, so the container build will unconditionally fail. This issue was flagged in the prior review and remains unfixed.

Suggested fix: Fetch the v0.3.3 checksums from https://github.com/sheeki03/tirith/releases/download/v0.3.3/checksums.txt and update TIRITH_SHA256_AMD64 and TIRITH_SHA256_ARM64 on lines 148-149 to the correct values for the x86_64 and aarch64 tarballs respectively.

@fullsend-ai-retro

fullsend-ai-retro Bot commented Aug 7, 2026

Copy link
Copy Markdown

🤖 Finished Retro · ✅ Success · Started 1:08 PM UTC · Completed 1:23 PM UTC

Commit: a8a5a2b · View workflow run →

@fullsend-ai-retro

Copy link
Copy Markdown

Retro: PR #5618 — Renovate tirith bump with 13 redundant review cycles

What happened

PR #5618 was a Renovate bot PR bumping sheeki03/tirith from 0.3.1 to 0.3.3 in images/sandbox/Containerfile. The version ARG was updated but the SHA256 checksums were not — a known Renovate limitation for this dependency (automerge is explicitly disabled and the Containerfile itself documents that checksums must be updated manually).

Over 7 days (Aug 1–7), Renovate rebased the branch 13 times due to frequent merges to main (~2/day). Each rebase triggered a new review agent run, and each run found the same two findings: (1) checksum mismatch (high) and (2) protected-path requiring human approval (high). The review agent correctly identified the issue on the first run and provided actionable remediation including the correct v0.3.3 checksums. However, the same findings were repeated verbatim 12 more times.

The fix agent ran once but was blocked by a bug: reusable-fix.yml uses gh pr view --json author (GraphQL format: app/renovate-fullsend) and checks [bot]$, which doesn't match the app/ prefix format. The PR author was misclassified as human, and without a fullsend-fix label, the fix agent exited. No comment was posted to the PR. The PR was eventually closed and a separate manual PR #5851 fixed the checksums.

Review quality

The review agent performed well on the substance: it correctly identified the checksum mismatch as a build-breaking issue on the very first review, researched the upstream release, and provided the exact remediation including correct SHA256 values. The protected-path finding was also appropriate.

Evidence for existing issues

This PR provides strong supporting evidence for several open issues:

  • #4596 / #4401: 13 reviews of an unchanged effective diff across rebases — the core rebase-dedup proposal would have reduced this to 1 review.
  • #2587: Without a hard cap, the review count grew to 13 over 7 days. A cap of 3–5 would have stopped the waste.
  • #5360: Skipping review/retro for bot-authored dependency PRs entirely would eliminate this class of waste.
  • #324 (agents): The review comment accumulated 12 collapsed "Previous run" sections, demonstrating unbounded comment growth.
  • #5863: The fix agent was blocked but posted no comment — the PR author and human reviewers had no visibility into why auto-fix didn't run.
  • #5185: The [bot]$ regex pattern for bot detection failed for the app/ login prefix format — same root cause as identified for the retro agent, now confirmed in the fix agent guard path as well.

Token cost

Conservatively, 12 of the 13 review runs were redundant (the first review found everything). Each run took ~10 minutes. This represents significant wasted compute for findings that were already known and unactionable by the bot PR author.

Proposals filed

@renovate-fullsend

Copy link
Copy Markdown
Contributor Author

Renovate Ignore Notification

Because you closed this PR without merging, Renovate will ignore this update (0.3.3). You will get a PR once a newer version is released. To ignore this dependency forever, add it to the ignoreDeps array of your Renovate config.

If you accidentally closed this PR, or if you changed your mind: rename this PR to get a fresh replacement PR.

@renovate-fullsend
renovate-fullsend Bot deleted the renovate/sheeki03-tirith-0.x branch August 7, 2026 15:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component/sandbox OpenShell sandbox environment dependencies Pull requests that update a dependency file

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants