refactor: correct false comments and flatten conditionals in service - #8305
Conversation
|
The shard's 5 failures are all in with Evidence it is not attributable to this PR:
Root cause, for whoever picks it up: Per this repo's conventions I have neither weakened the assertions nor added a re-run, and fixing it here is out of scope (one module per PR, and it is not this module). Flagging for a maintainer: this reds shard 1 for every open PR until it is fixed on Disposition: |
Design Review (Fable 5) — 🟡 CONCERNSDesign-level review of The verification checks out: Design-Verdict: CONCERNS Corrections are accurate and verified, but the repo now states two contradictory accounts of the same escalation boundary, with the false one in the owning module. Watch
Suggestions
[DESIGN-REVIEWED] 7173cf6 |
Opus 4.8 Review — ✅ no blocking findingsReviewed Verdict parsed from the review's SHA-scoped output markers for commit False positive or not applicable? A repository writer can comment: |
GPT 5.6 Review — ✅ no blocking findingsGPT 5.6 completed its review of This comment is updated in place on each push. Review detailsFINDING -- src/kiro_crew/service/linux.py:39 -- False positive or not applicable? A repository writer can comment: |
First Principles Review (Fable 5) — ✅ PASSPremise-level review of All claims verified. First-Principles-Verdict: PASS Corrects three provably false comments on a sudo boundary and removes the drift mechanism that produced one of them; every item is verified behavior-identical. What this change shipsIntent: make the service module's comments tell an auditor the truth about what runs as root, per the AGENTS.md comment rules — a FIX.
WatchTwo declared deferrals a human should see, both counted: [FIRST-PRINCIPLES-REVIEWED] 7173cf6 |
d232d9c to
874671f
Compare
Legitimate and in scope. The sentence was literally true — The docstring now separates the two claims instead of conflating them: The guarantee, stated on what actually secures it — the escalated interpreter is root-owned, resolved from a fixed list of trusted system directories, never Scope note: the underlying behaviour — |
366e893 to
9589701
Compare
Legitimate, and the sharpest reading of the four rounds this paragraph has now taken. The sentence opened by asserting a safety property and the next three sentences withdrew it — so the paragraph argued against itself, which is worse than either half alone. Not point-patched, because this span has now absorbed four rounds and the wording fix would have been the fourth patch. Every finding on it has had the same shape rather than four different causes: an affirmative safety claim broader than the code supports. Round 1 read So the invariant, not the sentence, is what changed: the paragraph now makes no safety claim at all, which is what makes the whole class unreachable rather than moving it one clause further along. It states what each mechanism buys and stops there — trusted resolution rules out escalating the user-writable venv interpreter and says nothing about what that interpreter then loads; The cause-level fix — passing Diff is comment text only: the module's AST is byte-identical to |
9589701 to
8dcfb79
Compare
Legitimate on both counts, and verified against the code rather than accepted on the reviewer's word:
This is the fifth round on this span, and the previous four all had one shape: a claim broader than the code supports. Round 4's restructure removed the affirmative safety claims but then over-corrected into the opposite overstatement — the reviewer's own warning that widening a fix is itself a change needing a check for the OPPOSITE failure mode, walked into directly. A third site is fixed here that the finding does not name, because the invariant demanded it: the hooks sentence said the planted code "runs as root" with no path qualifier, which is false on the default path for exactly the reason the The invariant now holding, which is what makes the class unreachable rather than moving it one clause along: every claim about a mechanism in this section names the install path it holds on. The section is reorganized around that axis and separates two questions that were tangled — WHAT gets loaded (trusted resolution says nothing about it, on either path) from WHOSE privileges it gets ( The cause-level fix — passing Diff is comment text only: |
`service/linux.py` claimed `tee` writes the unit file and that `uninstall()` probes with a non-sudo `test -e`. Neither is true: the writer is `sudo install`, and the probe is `Path.exists()`. Both are read by anyone auditing what this module runs as root, so a wrong list produces a wrong audit — and `docs/system-specs/modules/cli.md` had already copied the narrow claim. Replace them with the real escalated set, and state the mechanism the claim rests on rather than a list to be trusted: what makes the AppArmor probe's interpreter safe to escalate is WHICH interpreter it is — root-owned, resolved from a fixed list of trusted system directories, running a constant stdlib snippet, never `sys.executable` — and not `setpriv`, which reuids to the account the installer was invoked as and so is still root under `sudo kirocrew service install`. Scope every claim to the install path it holds on, because there are two and both are live: the payload imports no `kiro_crew`, so no MCP / LLM / agent code is reached deliberately on either — but the interpreter is not isolated. Without `-I`/`-S`, CPython prepends the caller's working directory to `sys.path` and imports `site`, so the working directory, `PYTHONPATH`, a user-site `.pth` line, `sitecustomize` or `usercustomize` runs before or during the payload's own first import of `ctypes`. WHOSE privileges that code gets is `setpriv`'s to decide, and it reuids to the account the installer was invoked as: as an ordinary user (the default, where this module escalates individual commands through `sudo`) it drops sudo's root back to that user and the loaded code stays unprivileged; under `sudo kirocrew service install` it reuids to 0, a no-op, and only there does that code run as root. Measured, not assumed: a planted `ctypes.py` on the working directory IS what that import resolves to, and `-I` restores the stdlib one. The invocation lives in `apparmor.py` and is left alone (see below); this records the boundary rather than moving it. `cli.md` points at the module docstring beside the call sites instead of keeping a second copy of the escalated set to drift, and its own claim narrows to the elevated EXECUTABLES being stock system programs. `macos.py`'s `_write_plist_atomic` enumerated the interruption outcomes as "the old plist or no plist", omitting the new complete plist an interruption after `os.replace` leaves. Name all three, so the docstring describes what the atomic rename actually guarantees. Drop the four `#NNNN` task-log citations and four historical narrations AGENTS.md prohibits, restating each in present tense with its constraint intact. Behaviour-preserving structural work, five sites: flatten a `print()` built from a conditional expression around a nested ternary; invert four double-negated warning-prefix ternaries to test `ok` positively, preserving each prefix's trailing width; replace a set comprehension built for one membership test with `any()`; and route `_require_privilege`'s open-coded root check through `_privilege_prefix()`, whose non-empty return already means "this call escalates", so the two cannot drift apart. `service/apparmor.py` is deliberately untouched: it is the module's security- control generator, and its citations carry a design-failure narrative that deserves its own review rather than a line in a readability sweep. Co-authored-by: Kiro Crew <noreply@kirodotdev.github.io>
8dcfb79 to
7173cf6
Compare
Legitimate, and measured rather than taken on the reviewer's word —
Fixed by stating the dependency rather than swapping the one word the finding suggested. A second site in the same docstring is fixed here that the finding does not name, applying the lesson from this PR's other span rather than waiting for a round to find it: the crash-outcome sentence opened with Diff is comment text only: |
| ``sudo kirocrew service install`` it reuids to 0, which is a no-op, and only on | ||
| that path does the loaded code run as root. |
There was a problem hiding this comment.
and only on that path is under-inclusive — sudo kirocrew sandbox install-profile is a second live root path.
Both AppArmor entry points hand os.getuid() to the same setpriv probe, and neither is modified by this PR:
install_apparmor_profile(L585) →apparmor.install(..., os.getuid(), os.getgid(), ...)(L631) — reached fromservice installinstall_launcher_profile(L643) →apparmor.install_launcher(..., os.getuid(), os.getgid(), ...)(L658) — reached fromkirocrew sandbox install-profileviacli_server.py→service/controller.py::install_launcher_profile
Both converge on the one invocation in apparmor.py:
sudo aa-exec -p <profile> -- setpriv --reuid={uid} --regid={gid} --clear-groups -- python3 -c <snippet>
So the reuid is 0 whenever the installer process is root, and sandbox install-profile is a sudo command by its own --help: "Attach the userns AppArmor profile to this app (sudo on Linux)".
What makes this worth fixing rather than a nit: the paragraph opens by saying the setpriv guarantee "depends on which install path is running" and that "both install paths are live", then names only one as reaching uid 0 — so the omission lands exactly on the distinction the paragraph exists to draw. install_launcher_profile's own docstring further down this file already records that it is invoked explicitly rather than from service install, so the module docstring and that function currently disagree about how many escalating paths there are.
Suggested wording:
started under
sudo— eithersudo kirocrew service installorsudo kirocrew sandbox install-profile— it reuids to 0, which is a no-op, and on those paths the loaded code runs as root.
Flagging it because this PR's stated purpose is correcting false comments in a module people read to audit what runs as root, which makes a newly-introduced narrow claim here costlier than elsewhere.
chenmingwei23
left a comment
There was a problem hiding this comment.
Approving: PR Readiness green (the repo's only required check), no failing lanes, MERGEABLE.
Problem / Motivation
src/kiro_crew/service/carries comment debt thatAGENTS.md§ Code styleexplicitly forbids, and two of the comments are outright false — which is
worse than stale, because a reader auditing the sudo surface from them reaches
the wrong conclusion:
service/linux.py's module docstring andinstall()docstring both claimedthe privileged writer is
tee.teeappears nowhere in the module; theunit is written with
sudo install. A reader tracing "what runs as root here"was being pointed at a program that does not exist on the path.
service/linux.py'suninstall()said it used a "non-sudotest -e". Thecode calls
Path.exists(); the only privilegedtest -ein the module is_seed_env_file's, for a different reason.#3463×2,#5285×2) and four"previously / used to / the previous implementation" narrations, both of which
AGENTS.mdnames as prohibited comment content.Alongside that, the module had a handful of small readability items: a
double-negated ternary idiom written four different ways, one
print()builtfrom a conditional expression wrapping a nested ternary inside an f-string, a
set comprehension materialised for a single membership test, and a root check
open-coded in two functions that must never disagree.
Why it matters
A false comment on a privilege boundary is a security-review hazard: it is
exactly the text a reviewer or an auditor reads instead of re-deriving the
sudo surface, so an incomplete list becomes an incorrect audit. The
teeclaimhad already survived long enough that the spec (
docs/system-specs/modules/cli.md)had copied the same narrow claim.
The task-log citations are the reason
AGENTS.mdbans them:#3463tells areader nothing at the point of use, while the rationale it stands in for is
already written out two lines away.
What changed (motivation → approach → change)
One module, one commit, behaviour-preserving throughout. Nothing in
service/apparmor.pyis touched (see Scope below).Comment accuracy — 3 false claims corrected:
linux.pymodule docstring: replaced thesystemctl/teeclaim with theactual escalated set —
systemctl,install,mkdir,rm,rmdir,testdirectly, plus
apparmor_parser,aa-exec, and thesetpriv+ trustedsystem
python3thatservice/apparmor.pyruns through the privilegedhelpers this module lends it. The load-bearing part is stated as the
mechanism rather than as a list to be trusted, and it is pinned to the thing
that actually secures the escalation: WHICH interpreter runs — root-owned,
resolved from a fixed list of trusted system directories, never
sys.executable, and running a constant stdlib snippet that does not importkiro_crew, so no MCP / LLM / agent code is reached deliberately — and thedocstring now stops the claim exactly there, because the interpreter is not
isolated. Invoked without
-I/-S, CPython prepends the caller's workingdirectory to
sys.pathand importssite, so code from that workingdirectory,
PYTHONPATH, a user-site.pthline,sitecustomizeorusercustomizecan run as root before or during the payload's own first importof
ctypes. That is measured rather than assumed (see Local review), and theinvocation itself lives in
service/apparmor.py, which this commit leavesalone (see Scope) — the docstring records the boundary rather than moving it.
setprivis stated separately and without any de-privileging implication: itreuids to the account the installer was invoked as, which under
sudo kirocrew service installis root, so it does not by itself make theprobe unprivileged. Cites
docs/system-specs/modules/security.mdfor the reasoning behind the AppArmorstep's four tools.
linux.pyinstall(): drops its own (stale) enumeration and defers to thatparagraph.
linux.pyuninstall(): names the check that actually runs, and states theoperative permission — a stock
/etc/systemd/systemis traversable, so aplain stat answers without escalating — and contrasts it with
_seed_env_file's privileged probe, which exists becausePath.exists()raises
PermissionErroron a locked-down directory rather than answering.docs/system-specs/modules/cli.mdcarried the same narrow "Onlyinstallandsystemctlinvocations are elevated" claim. Corrected in this commit: fixingone half of a duplicated false claim and leaving the other is how it comes
back. It now defers to the
linux.pymodule docstring that sits beside thecall sites rather than keeping a second copy of the set to drift — the same
mechanism-plus-pointer form
install()was given — and its own claim narrowsto the elevated executables being stock system programs, which is what is
actually true of them.
Comment hygiene — the 4
#NNNNcitations and the 4 historical narrations(
macos.py_write_plist_atomic/write_live_program/restart,live_target.pywrite_target/restore) are restated in present tense. Eachrewritten comment keeps its constraint and drops only the ticket number or the
"what it used to be": the
atomic_writeguarantees, therestrict_to_ownerordering versus the planted-link check, the
mode-before-content property, andthe reason
unload+loadcannot restart the agent from inside it are allstill there.
Structural — 5 sites, all behaviour-identical:
controller.pyremove_launcher_profile:print(X if cond else Y)with anested ternary inside
X→ a plainif/else, matching its siblinginstall_launcher_profile.controller.py×4: the warning-prefix ternaries all readA if not ok else B;inverted to test
okpositively. The two prefix spellings differ in trailingwidth (
'⚠️ 'two spaces vs'⚠️ 'one), and each stayed on its own side ofthe flipped condition — verified byte-for-byte.
controller.pyinstalled_service_has_managed_marker: a set comprehensionbuilt solely for one
intest →any(line.strip() == expected for line in …).linux.py_require_privilege: the open-codedos.geteuidroot check nowasks
_privilege_prefix(), whose non-empty return is "this call will shellout through sudo". The two functions can no longer drift into disagreeing
about whether escalation is needed. Equivalence holds in all four input states
(
geteuidabsent →["sudo"]→ truthy, matching the oldnot is_root;geteuid() == 0→[]→ falsy;geteuid() != 0→ truthy; non-Linux hits theunchanged early
returnabove).os.geteuidis still reached through thismodule's global
os, which is what the existing tests monkeypatch, andshutil.whichis still short-circuited away when already root — so aroot-with-no-sudo container still does not raise.
Scope
service/apparmor.pyis deliberately untouched, though it holds 12 of themodule's
#NNNNcitations. It is the module's one security-control generator,and there the ticket numbers carry a design-failure narrative (two earlier
attachment designs and why each was wrong) rather than being bare task-log
noise — rewriting that prose is a judgment call that deserves its own review,
not a line item in a readability sweep. The criterion is a property of the file,
so it is applied to the file as a whole rather than hunk by hunk.
The mechanical detector (shadow-import / chained-ternary) reports 0
actionable sites in this module on current
origin/main, so everything here isjudgment-class work under the campaign's rules.
Tests
No test changes. This is a behaviour-preserving sweep, so the existing tests are
the assertion that nothing moved — in particular
test/test_service.py's four_privilege_prefix/_require_privilegecases, which patchsvc_linux.os.geteuidand therefore still drive the real logic through the new indirection.
test_service.py,test_live_target.py,test_spawn_audit.py,test_host_service_guard.py,test_doctor_sandbox_verdict.py,test_pod_launchd.py— 474 passed, and 365 passed again on the finaltree after the review fixes.
pre-existing on this host and none is in
service/. Attribution was done byfailure set, not count: the same 13 files fail identically on a pristine
detached
origin/mainworktree (87 failed there). The single set difference(
auto_improvement/tests/test_github_profile.py::TestSuiteMeasurement::test_canary_produces_a_correctly_signed_win)passes standalone on both trees and did not fail in the branch's own full
run, so it is order-dependent on this host and not attributable to the diff.
The host lacks a usable user-namespace sandbox, which is what reds the
subprocess-spawning families listed.
Manual verification
N/A — unit coverage sufficient. There is no reachable behaviour change to
exercise: after stripping docstrings,
live_target.pyandmacos.pyareAST-identical to
origin/main, and the five remaining rewrites areexpression-level and output-identical.
Local review
Four parallel reviewers ran before this PR opened, each on a distinct lens
(AUTOSDE blocking rules; behaviour equivalence; comment accuracy; security
keystone / boot path / import semantics).
Acted on — 3 findings, all in text this PR itself introduced:
linux.pysudo-scope paragraph asserted anexhaustive list that omitted
aa-exec,apparmor_parser,setprivandpython3. Raised independently by three of the four lenses, verified againstapparmor.py'sverify_enforcementargv andsecurity.md, and fixed — theparagraph now names them and states the de-privileging mechanism, which is
the part the incomplete list was hiding. Replacing one wrong claim with a
differently-wrong one would have been the worst outcome here.
uninstall()comment said "world-readable" where the operativepermission is the traverse bit, and did not acknowledge that
Path.exists()propagates
PermissionError. Corrected.docs/system-specs/modules/cli.mdmirrored the same stale claim. Correctedin this commit rather than deferred.
A verifier then re-checked those three fixes and found two new inaccuracies
that the fixes themselves had introduced, both confirmed against the code and
both fixed in the same commit:
security.mdwas "the authoritative list". It is not:it names the four AppArmor tools and
sudo install/sudo systemctl, andnever
mkdir,rmdirortest. Both new pointers (linux.pyandcli.md)now cite it for the reasoning, which is what it actually carries. Pointing a
reader at a subset while calling it authoritative is the same defect class as
the
teeclaim this PR started from._seed_env_file's own docstringscopes the
PermissionErrorclaim to Python 3.12, and on 3.14Path.exists()swallows the error and answers
Falseinstead — so the unscoped restatementwas false on a supported interpreter (
requires-python = ">=3.12"). Rewordedto state the consequence ("cannot answer trustworthily") and defer the
mechanism to that docstring.
Dropped — none. Both behaviour lenses returned no findings with per-rewrite
equivalence proofs (independently confirming the byte-width of the two
⚠️prefixes and the four-state truth table for
_require_privilege), and theAUTOSDE lens returned no findings.
One finding I initially deferred and then fixed. The verifier noted that
setpriv --reuid=<uid>does not actually drop privilege undersudo kirocrew service install, whereos.getuid()is already 0, so"setpriv drops back to the invoking uid/gid" reads as a de-privileging
guarantee it does not give. I first deferred it as pre-existing (the same claim
sits unchanged in
apparmor.py,install_apparmor_profile, andsecurity.md).GPT 5.6 then raised it independently on the PR against text this PR wrote —
which settles it the other way: rebutting an accuracy finding on a technicality,
in a PR whose entire premise is making these comments true, would have been
inconsistent. The docstring now separates the guarantee (stated on what actually
secures it: a root-owned, trusted-directory interpreter that is never
sys.executable, running a constant snippet that does not importkiro_crew)from
setpriv(stated without the implication). The underlying behaviour —that
apparmor.py's "the probe must run unprivileged" constraint is unmet undera
sudo-invoked install — is a real pre-existing defect flagged for amaintainer; fixing it is a behaviour change and does not belong in a
behaviour-preserving sweep.
Round 2 — 3 more findings in this PR's own text, all fixed. GPT 5.6 passed
the previous head with no blocking findings but left two advisory ones, and both
were legitimate on exactly the axis this PR exists to fix, so both were fixed
rather than rebutted:
linux.pyasserted"no user-writable code ... ever runs as root". False:the escalated interpreter runs without
-I/-S, so CPython's own startupimports
site. Measured on/usr/bin/python3: with asitecustomize.pyand a
usercustomize.pyplanted on a relocated per-user site path, bothexecuted before the
-cpayload, and adding-S -Isuppressed both.macos.py_write_plist_atomicenumerated the interruption outcomes as"either the old plist or no plist at all", omitting the complete new plist
that an interruption after
os.replaceleaves. All three are now named.A re-review of fix (6) then found it still overstated — the same
one-wrong-claim-for-another trap as (1) and (4):
first line is
import ctypes. Withsys.path[0] == ''under-c, a plantedctypes.pyin the caller's working directory is what that importresolves to — measured, and
-Irestores the stdlib module — and a user-site.pthline is a further omitted hook. The docstring now names all fourvectors (working directory,
PYTHONPATH,.pth,sitecustomize/usercustomize) and claims only that no MCP / LLM / agent code is reacheddeliberately.
cli.md's "never kirocrew code" narrowed with it.Both behaviour lenses again returned no findings on the final tree, one of them
re-deriving the
_require_privilege/_privilege_prefixequivalenceindependently, and both judged that disclosing the residual exposure is the
right call for a comment-accuracy PR rather than an obligation to change the
invocation.
Round 3 — the paragraph was restructured, not patched again. GPT passed the
next head with no blocking findings and one advisory: the phrase
"safe to escalate"contradicts the root execution the same paragraph goes on toacknowledge. Correct — and it was the fourth round on that one paragraph
(
span=95458d4eeff1, whose identity is path + lane, so all four share it).All four had one shape rather than four causes: an affirmative safety claim
broader than the code supports. Round 1 read
setprivas a de-privilegingguarantee; round 2 asserted no user-writable code ever runs as root; round 3
scoped that to the payload, missing that the payload's own first line is
import ctypes; round 4 was the wordsafe. So the invariant changed ratherthan the sentence: the paragraph now makes no safety claim at all, stating
only what each mechanism buys — trusted resolution rules out escalating the
user-writable venv interpreter and says nothing about what it then loads,
setprivbuys nothing under a sudo-invoked install, the payload is what isbounded — with the four open import hooks named as facts rather than as caveats
on a promise.
Flagging for a maintainer, second item. The working-directory vector is a
concrete unprivileged trigger, unlike the site-path ones:
_sudo_capturepinsno
cwd, socd /tmp && sudo kirocrew service installresolves the probe'simport ctypesagainst a world-writable directory. Passing-Ito the trustedpython3inapparmor.verify_enforcementcloses all four vectors in one tokenand the payload is pure stdlib, but that edits a file this PR declares out of
scope and changes a security control's invocation, so it wants its own commit,
its own test, and its own review — not a line in a behaviour-preserving sweep.
CI
Backend Tests (Windows)was red on an earlier head for a reason that wasmain's, not this diff's — all 5 failures were intest/test_autonudge_stop_auth.py,reproducing byte-identically in a pristine detached
origin/mainworktree. All fourWindows shards are green on the current head after the rebase, so nothing is
outstanding there and nothing was weakened, skipped, or re-run to get it.
Dependency Audit / Audit Production Dependenciesis the one red left, and itis not this diff's. Every attempt fails identically on
npm audit timed out after 120s for website/package-lock.json— a tool timeout that the gate turnsinto a failure by failing closed, never a reported advisory. Three independent
lines of evidence put it on
main:four modules under
src/kiro_crew/service/— and nopackage.json,package-lock.json, or Python dependency manifest. The audited tree ismain's own; this PR's merge ref is a strict subset of it (it predateshtml-to-image, whichmainadded after this branch's base).and test(autonudge): pin the gate premise the paused-loop tests rely on #8321 all carry the identical failure, and the successes on fix(electron): grant the dashboard the notifications permission so its OS toasts work #8312, feat(agents): template selector becomes the definition panel's header with private fork-on-edit #8307
and fix(snapshot): report a refused cron merge to the import caller #8315 all land inside one good 01:00–01:26 window. Identical input,
different outcome, is timing.
(
npm audit --omit=dev --package-lock-only --ignore-scripts --audit-level=high) against this merge ref's lockfile and against currentmain's produces the same result — both exceed even a 220s budget. So the120s ceiling is marginal for this lockfile against the live registry, which is
what makes the gate flaky for everyone rather than wrong about this PR.
The job was re-run 10 times rather than touched. The two things that would turn
it green from here — raising the timeout, or adding a
.vulnerability-exceptions.jsonentry — both weaken a security gate, so neitherbelongs in a behaviour-preserving comment sweep. Flagging for a maintainer: this
ceiling needs raising (or the audit needs a retry) in its own change.
Screenshots / video
Why no screenshot: backend-only — the diff touches four Python files under
src/kiro_crew/service/plus one spec markdown file, renders no UI, and changesno user-visible string; the four
print()rewrites are byte-identical in output.Related Issues
no linked issue: this is a scheduled module-simplification sweep, not the fix for
a tracked report, so nothing here should close on merge.
It files one, though: #8414 tracks the cause-level fix for the escalation
boundary this PR only documents (
deferred-finding, assignee @bolichen97,Due: 2026-09-18). It must not be closed by this PR — the remedy it namesedits
service/apparmor.py, which this commit declares out of scope.Checklist
docs/system-specs/modules/cli.md