fix(doctor): report Kiro IDE ignore sources that hide .kiro/ - #1161
Conversation
|
Thank you for picking this up — it is the detection half of #1146, and evaluating each ignore source on its own is the right shape for it. I am working on #1157 at the moment, which serves Kiro IDE and Kiro CLI from one distribution. It rewrites So: once #1157 is merged and this is rebased on it, I will review this properly. |
Fixes #1146. On Kiro IDE, a `.kiro/` rule in git's global excludes file makes the IDE's fs_read guard deny every stage, agent, and protocol read, so no stage can run. The IDE compiles each ignore file into its own matcher, so a `!.kiro/` in the project .gitignore cannot undo it even though `git check-ignore` reports the path as not ignored; and Kiro applies deny-overrides across scopes, so a permissions.yaml fs_read allow cannot clear it either. `--doctor` reported 0 problems because its reads run in a subprocess, not through fs_read. Add a doctor check for the Kiro harness when the IDE conductor (agents/aidlc.md) is present. It evaluates each ignore source Kiro IDE honours on its own - git's global excludes file (in a git repo), ~/.kiro/settings/ kiroignore, the project .gitignore, and .kiroignore - by running `git -c core.excludesFile=<source> check-ignore -v --no-index` in a scratch repository, so only that one file applies and gitignore semantics are git's own rather than a hand-rolled matcher. A directly matched negation exits 0 in verbose mode, so a leading `!` in the reported pattern counts as not hidden. Global-source matches fail, naming file:line and the pattern with the remedy (remove or narrow the rule; a negation elsewhere or a permissions allow does not help; per-repo personal ignores belong in .git/info/exclude). Workspace matches warn, because whether those files apply is governed by the IDE's kiroAgent.agentIgnoreFiles setting, which doctor cannot read. Missing git degrades to a passing advisory row. Docs: doctor check table, a Kiro IDE Read Denials troubleshooting section with the exact denial text, and the doctor command summary. t340 pins the global-rule detection despite a repo negation, same-file negation (directory and direct-file), the global-fail/workspace-warn split, and that the row is emitted only for the IDE conductor surface.
t340-kiro-ide-ignore-sources-doctor spawns the doctor CLI, so the coverage registry classes it as a cli-mechanism claim. Regenerate tests/.coverage-registry.json and add the file to EXPECTED_NONE_TO_CLI so gen-coverage-registry and t134 mechanism-honesty pass.
fb5939c to
c8dcc09
Compare
AIDA findings ledger
Open blocking findings (P0/P1): 0. Accepted and rejected findings never count toward the next action. Maintainer commands (repository write access) — put them on the first lines of a comment, one per line, several ids per line allowed: ledger.json{
"version": 4,
"pullRequest": 1161,
"nextId": 9,
"findings": [
{
"id": "F1",
"priority": "P1",
"category": "security",
"title": "Repository ignore patterns are relayed into model context verbatim",
"anchors": [
{
"kind": "line",
"path": "core/tools/aidlc-utility.ts",
"side": "RIGHT",
"sha256": "255df0934183f48ef205704c08a74a076353802ff767e32314c1c60d922f5b6f"
},
{
"kind": "line",
"path": "core/tools/aidlc-utility.ts",
"side": "RIGHT",
"sha256": "08e4dbe6fdc3fff9b48b32690bc13f1fb6ba6d35093654ec50d61f03566632d3"
}
],
"status": "resolved",
"firstSeen": {
"head": "c8dcc096e8b63948f44c0cd08e105d143862288d",
"at": "2026-09-24T22:29:19.004Z"
},
"lastSeen": {
"head": "500e918e7858f8b60272435551b0565aa573884f",
"at": "2026-09-24T23:22:31.054Z"
}
},
{
"id": "F2",
"priority": "P1",
"category": "contracts",
"title": "Symlinked nested workspaces still suppress the global-ignore warning",
"anchors": [
{
"kind": "line",
"path": "core/tools/aidlc-utility.ts",
"side": "RIGHT",
"sha256": "ed0ad791a84431f8b6719f150ba3b5d54f7e5841078877622df83f8aba61b389"
},
{
"kind": "line",
"path": "core/tools/aidlc-utility.ts",
"side": "RIGHT",
"sha256": "ce485bf74fdb929eab57321bf0326666390fc87878c839e50d4a3bfd3af03395"
},
{
"kind": "line",
"path": "core/tools/aidlc-utility.ts",
"side": "RIGHT",
"sha256": "f0f92229f4bae485b4018011672f8de685c5975f2066af0b22af3ff45f48dd9d"
},
{
"kind": "line",
"path": "docs/guide/12-cli-commands.md",
"side": "RIGHT",
"sha256": "8565eff617168b26fe730d0d83cb0a53c9b0088356e52ed30f80a8b779f4d2ad"
},
{
"kind": "line",
"path": "core/tools/aidlc-utility.ts",
"side": "RIGHT",
"sha256": "ad67cd3f32f9ef848e797cdb60e5d9e97c72cd1735a4241ca8bb502bdf074ddb"
},
{
"kind": "line",
"path": "core/tools/aidlc-utility.ts",
"side": "RIGHT",
"sha256": "1bacc5d7193efd0afc8b3a14d304ce2c486ba6c27a4e6b436b8fc9d9db7db488"
},
{
"kind": "line",
"path": "docs/guide/12-cli-commands.md",
"side": "RIGHT",
"sha256": "e94db79ccd93f83f1beaf41ec0b835852484ac3ed1aa50006a0e9170c6c3e743"
},
{
"kind": "line",
"path": "core/tools/aidlc-utility.ts",
"side": "RIGHT",
"sha256": "f9881fb66f4cbddc872aa975d87f8277baf3006e84cf896c8c6edd9bf4bf8292"
},
{
"kind": "line",
"path": "core/tools/aidlc-utility.ts",
"side": "RIGHT",
"sha256": "ac3416c8bc74c00ab7fbf3bd6aff563febeb429dd6aeb20d3c7844cb17e675da"
},
{
"kind": "line",
"path": "docs/guide/12-cli-commands.md",
"side": "RIGHT",
"sha256": "f0bd3179d6db26b1d2ef0969eb1bdf4039a7f2da465fa104061d9e8d258f9e8d"
}
],
"status": "resolved",
"firstSeen": {
"head": "c8dcc096e8b63948f44c0cd08e105d143862288d",
"at": "2026-09-24T22:29:19.004Z"
},
"lastSeen": {
"head": "ec7e1e3e452505b59c316b330849fa76f7e7d292",
"at": "2026-09-25T01:04:58.823Z"
}
},
{
"id": "F3",
"priority": "P1",
"category": "correctness",
"title": "Empty XDG_CONFIG_HOME skips Git's actual global ignore file",
"anchors": [
{
"kind": "line",
"path": "core/tools/aidlc-utility.ts",
"side": "RIGHT",
"sha256": "5be59815fbadcc9d2c92e8ba6a975514b5d094803fd2f105f4ec015cc22f58af"
}
],
"status": "resolved",
"firstSeen": {
"head": "c8dcc096e8b63948f44c0cd08e105d143862288d",
"at": "2026-09-24T22:29:19.004Z"
},
"lastSeen": {
"head": "500e918e7858f8b60272435551b0565aa573884f",
"at": "2026-09-24T23:22:31.054Z"
}
},
{
"id": "F4",
"priority": "P1",
"category": "security",
"title": "Ignore-source filenames remain a model prompt-injection channel",
"anchors": [
{
"kind": "line",
"path": "core/tools/aidlc-utility.ts",
"side": "RIGHT",
"sha256": "3bfd46e0f531ed4faa8904fa63a637a313d17fc232f0392220428ad61a422a01"
},
{
"kind": "line",
"path": "core/tools/aidlc-utility.ts",
"side": "RIGHT",
"sha256": "82a664518ba93f7dd521dea0003cb87b60f3f862fae479c191f56d4daff6d14e"
}
],
"status": "resolved",
"firstSeen": {
"head": "500e918e7858f8b60272435551b0565aa573884f",
"at": "2026-09-24T23:22:31.054Z"
},
"lastSeen": {
"head": "2a9b8cc86774799f6e53b6792b024d8c1555c23a",
"at": "2026-09-25T00:02:01.899Z"
}
},
{
"id": "F5",
"priority": "P1",
"category": "correctness",
"title": "Blank HOME bypasses the Windows user-profile fallback",
"anchors": [
{
"kind": "line",
"path": "core/tools/aidlc-utility.ts",
"side": "RIGHT",
"sha256": "7e5fa7e3891dbde8afb585c2e6d6f5450e6d6f065918f38c32209ded2b6a1ef6"
}
],
"status": "resolved",
"firstSeen": {
"head": "500e918e7858f8b60272435551b0565aa573884f",
"at": "2026-09-24T23:22:31.054Z"
},
"lastSeen": {
"head": "2a9b8cc86774799f6e53b6792b024d8c1555c23a",
"at": "2026-09-25T00:02:01.899Z"
}
},
{
"id": "F6",
"priority": "P2",
"category": "user-experience",
"title": "Git-refusal warnings do not provide a working recovery path",
"anchors": [
{
"kind": "line",
"path": "core/tools/aidlc-utility.ts",
"side": "RIGHT",
"sha256": "83663270630379e76e9e96842b422e819b8e991883f5eea2adec4ec70f9715a0"
},
{
"kind": "line",
"path": "docs/guide/15-troubleshooting.md",
"side": "RIGHT",
"sha256": "9d8839380b59e72a172b13ac2bc2e95dd915acf11e194e02ce0fba1aca175b82"
}
],
"status": "resolved",
"firstSeen": {
"head": "83a7157e3f3889c0f61f580385d4f4aaf9de6be7",
"at": "2026-09-25T00:39:47.616Z"
},
"lastSeen": {
"head": "ec7e1e3e452505b59c316b330849fa76f7e7d292",
"at": "2026-09-25T01:04:58.823Z"
}
},
{
"id": "F7",
"priority": "P2",
"category": "user-experience",
"title": "No-Git recovery omits supported global configuration locations",
"anchors": [
{
"kind": "line",
"path": "core/tools/aidlc-utility.ts",
"side": "RIGHT",
"sha256": "13d89de1a1473e9c72ed607723ae436081a6506a85a1386f1d7fe106782ffb24"
},
{
"kind": "line",
"path": "core/tools/aidlc-utility.ts",
"side": "RIGHT",
"sha256": "7f6027c6b4b8c083ecafa66a25bfff123954e67e4cdd1aa033009b17e6444c5c"
},
{
"kind": "line",
"path": "docs/guide/15-troubleshooting.md",
"side": "RIGHT",
"sha256": "f0da6e1fc311652b6909b10f4218c9f2fe670f315ec8dc04dfef2a5ae32ad4d4"
}
],
"status": "open",
"firstSeen": {
"head": "ec7e1e3e452505b59c316b330849fa76f7e7d292",
"at": "2026-09-25T01:04:58.823Z"
},
"lastSeen": {
"head": "ec7e1e3e452505b59c316b330849fa76f7e7d292",
"at": "2026-09-25T01:04:58.823Z"
}
},
{
"id": "F8",
"priority": "P3",
"category": "user-experience",
"title": "Repository fallback crosses filesystem discovery boundaries",
"anchors": [
{
"kind": "line",
"path": "core/tools/aidlc-utility.ts",
"side": "RIGHT",
"sha256": "41c58d633c95e6d7042537bf253088e02d33d868de0c7090c89303dbff918f6d"
},
{
"kind": "line",
"path": "core/tools/aidlc-utility.ts",
"side": "RIGHT",
"sha256": "59f370435ae055102bcd549baef9895562ecf850bba9c0ac67e20a39d34e6a5c"
}
],
"status": "open",
"firstSeen": {
"head": "ec7e1e3e452505b59c316b330849fa76f7e7d292",
"at": "2026-09-25T01:04:58.823Z"
},
"lastSeen": {
"head": "ec7e1e3e452505b59c316b330849fa76f7e7d292",
"at": "2026-09-25T01:04:58.823Z"
}
}
],
"events": [
{
"at": "2026-09-24T22:29:19.004Z",
"kind": "opened",
"by": "aida",
"id": "F1",
"head": "c8dcc096e8b63948f44c0cd08e105d143862288d"
},
{
"at": "2026-09-24T22:29:19.004Z",
"kind": "opened",
"by": "aida",
"id": "F2",
"head": "c8dcc096e8b63948f44c0cd08e105d143862288d"
},
{
"at": "2026-09-24T22:29:19.004Z",
"kind": "opened",
"by": "aida",
"id": "F3",
"head": "c8dcc096e8b63948f44c0cd08e105d143862288d"
},
{
"at": "2026-09-24T23:22:31.054Z",
"kind": "seen",
"by": "aida",
"id": "F2",
"head": "500e918e7858f8b60272435551b0565aa573884f"
},
{
"at": "2026-09-24T23:22:31.054Z",
"kind": "resolved",
"by": "aida",
"id": "F1",
"head": "500e918e7858f8b60272435551b0565aa573884f",
"reason": "declared corrected by the judge; a cited line is gone"
},
{
"at": "2026-09-24T23:22:31.054Z",
"kind": "resolved",
"by": "aida",
"id": "F3",
"head": "500e918e7858f8b60272435551b0565aa573884f",
"reason": "declared corrected by the judge; a cited line is gone"
},
{
"at": "2026-09-24T23:22:31.054Z",
"kind": "opened",
"by": "aida",
"id": "F4",
"head": "500e918e7858f8b60272435551b0565aa573884f"
},
{
"at": "2026-09-24T23:22:31.054Z",
"kind": "opened",
"by": "aida",
"id": "F5",
"head": "500e918e7858f8b60272435551b0565aa573884f"
},
{
"at": "2026-09-25T00:02:01.899Z",
"kind": "seen",
"by": "aida",
"id": "F2",
"head": "2a9b8cc86774799f6e53b6792b024d8c1555c23a"
},
{
"at": "2026-09-25T00:02:01.899Z",
"kind": "resolved",
"by": "aida",
"id": "F4",
"head": "2a9b8cc86774799f6e53b6792b024d8c1555c23a",
"reason": "declared corrected by the judge; a cited line is gone"
},
{
"at": "2026-09-25T00:02:01.899Z",
"kind": "resolved",
"by": "aida",
"id": "F5",
"head": "2a9b8cc86774799f6e53b6792b024d8c1555c23a",
"reason": "declared corrected by the judge; a cited line is gone"
},
{
"at": "2026-09-25T00:39:47.616Z",
"kind": "seen",
"by": "aida",
"id": "F2",
"head": "83a7157e3f3889c0f61f580385d4f4aaf9de6be7"
},
{
"at": "2026-09-25T00:39:47.616Z",
"kind": "opened",
"by": "aida",
"id": "F6",
"head": "83a7157e3f3889c0f61f580385d4f4aaf9de6be7"
},
{
"at": "2026-09-25T01:04:58.823Z",
"kind": "resolved",
"by": "aida",
"id": "F2",
"head": "ec7e1e3e452505b59c316b330849fa76f7e7d292",
"reason": "declared corrected by the judge; a cited line is gone"
},
{
"at": "2026-09-25T01:04:58.823Z",
"kind": "resolved",
"by": "aida",
"id": "F6",
"head": "ec7e1e3e452505b59c316b330849fa76f7e7d292",
"reason": "declared corrected by the judge; a cited line is gone"
},
{
"at": "2026-09-25T01:04:58.823Z",
"kind": "opened",
"by": "aida",
"id": "F7",
"head": "ec7e1e3e452505b59c316b330849fa76f7e7d292"
},
{
"at": "2026-09-25T01:04:58.823Z",
"kind": "opened",
"by": "aida",
"id": "F8",
"head": "ec7e1e3e452505b59c316b330849fa76f7e7d292"
}
],
"review": {
"head": "ec7e1e3e452505b59c316b330849fa76f7e7d292",
"readiness": 4,
"risk": 2,
"decision": "merge"
}
} |
There was a problem hiding this comment.
Reviewed c8dcc096e8b63948f44c0cd08e105d143862288d against 057b13bee16bb255719c4c462452a240e4c03ee1 and current repository behavior.
Inspection: 7 changed files. Scope: full head (first review of this pull request).
Final Assessment
Human decision aid only: Readiness 5/5 is best; Risk 1/5 is best. These scores inform the maintainer; the next action below follows finding severity (any open P0/P1 → author/change) and does not approve or merge the PR.
Readiness: 2/5 — Major correction is required: three P1 defects leave the diagnostic unsafe or falsely healthy in supported environments.
Risk: 4/5 — The Kiro IDE recovery path can remain completely blocked, and raw repository-controlled text reaches model-consumed diagnostic output.
Decision required: Author — make changes before this PR proceeds. The three surviving P1 security and correctness defects must be corrected before the PR proceeds.
Validation performed:
- Inspected the complete diff and all seven changed-file snapshots.
- Inspected PR metadata, discussion, full review scope, specialist candidates, and the empty findings ledger.
- Traced doctor rendering and Kiro IDE dispatch, packaging projection, native prerequisites, tests, and Git ignore-path semantics.
- Repository code and tests were not executed, as required by the read-only review contract.
Findings: 3 blocking, 0 advisory.
Ledger: 3 open, 0 retained blocking, 0 accepted, 0 suppressed as rejected by a maintainer. Maintainers act on findings with /aida commands in the ledger comment.
Security & Trust
P1 [F1]: Repository ignore patterns are relayed into model context verbatim
Evidence: core/tools/aidlc-utility.ts:2802, core/tools/aidlc-utility.ts:2804.
Problem: A repository can place instruction-shaped text inside a glob character class while the pattern still matches the fixed stage probe. Git returns that complete pattern, and these lines interpolate it directly into doctor output. The Kiro dispatch path supplies doctor output verbatim to the model, so attacker-controlled repository prose crosses the prompt trust boundary.
Impact: Running the recommended diagnostic in a malicious repository can expose the Kiro IDE agent to persistent prompt or tool-abuse instructions. This is a reachable prompt-injection path and therefore P1.
Required correction: Do not emit raw ignore patterns or other repository-controlled prose into model-consumed output. Use a fixed description with safely normalized source and line metadata, and add an adversarial test using an instruction-shaped pattern that still matches the probe.
Contracts & Compatibility
P1 [F2]: Ignore-source evaluation failures are counted as healthy
Evidence: core/tools/aidlc-utility.ts:2808, core/tools/aidlc-utility.ts:2817.
Problem: On a supported native Kiro IDE installation without external Git, a rule in ~/.kiro/settings/kiroignore can hide .kiro while the first Git invocation fails and the catch returns pass:true. Doctor counts that row as passed and hides it in normal output, so it can report zero problems or readiness while framework reads remain denied. Other non-0/1 Git failures follow the same false-pass path.
Impact: The supported no-Git workflow remains completely unusable while the diagnostic introduced specifically for this condition reports health, contradicting the documented native prerequisite contract.
Required correction: Evaluate the Kiro-owned ignore source without requiring external Git, or surface inability to evaluate as a visible non-passing warning or failure. Cover no-Git and per-source Git-error paths and reconcile prerequisite documentation if Git becomes required.
Correctness & Reliability
P1 [F3]: Empty XDG_CONFIG_HOME skips Git's actual global ignore file
Evidence: core/tools/aidlc-utility.ts:2747.
Problem: Git treats an empty XDG_CONFIG_HOME as unset and falls back to HOME/.config/git/ignore. The new nullish-coalescing expression instead constructs the relative path git/ignore, which is then resolved beneath the project. With a blocking rule in the real fallback file, that source is never checked and doctor reports no match.
Impact: A valid environment configuration can leave every Kiro workflow read blocked while doctor misses the exact global-ignore condition this change promises to detect.
Required correction: Treat empty XDG_CONFIG_HOME as absent when resolving the fallback path, and add regression coverage with an empty value and a matching HOME/.config/git/ignore file.
User Experience
User experience change: Kiro IDE users running doctor receive a new diagnosis for ignore rules that hide framework files.
Before: Doctor could report no relevant problem while every read under .kiro was denied.
After: Doctor is intended to name the matching source and remediation, but some supported configurations still produce a false healthy result.
Example: Before: no relevant problem. Intended after: a Kiro IDE ignore-source failure naming the source and recovery action.
Assessment: The change improves discoverability in covered cases, but the surviving false negatives and prompt-injection path make the recovery incomplete and unsafe.
Residual risk: Static inspection was complete, but runtime tests and packaging determinism checks were not executed under the mandated read-only review constraints.
Reviewed by AIDA (AI-DLC Developer Agent).
[AI-PR-REVIEWED] c8dcc09
…a source is not evaluated Addresses AIDA F1 to F3 on the Kiro IDE ignore-sources check. F1: an ignore pattern is repository text, and doctor output reaches the model. A character class such as `.kir[o SYSTEM ...]/` still matches .kiro/, so the pattern was relayed verbatim in the label and fix. Rows now name only file:line. check-ignore runs with -z --stdin, so git's NUL-separated source, line, and pattern fields cannot be shifted by a pattern containing ":<digits>:", and the pattern is used only to detect a directly matching negation. F2: a git failure returned a passing "check skipped" row, so on a native install without git a ~/.kiro/settings/kiroignore rule that hides .kiro/ reported healthy. Every path where doctor cannot evaluate a present source (git missing, git config/rev-parse/init errors, a per-source check-ignore exit other than 0 or 1) now warns as "not evaluated", naming the files to check by hand. With no ignore files present it still passes as "none present". F3: an empty XDG_CONFIG_HOME built a relative git/ignore path under the project. Git treats empty as unset and falls back to $HOME/.config/git/ignore; doctor now does the same. t340 adds an instruction-shaped pattern test, a no-git test, a per-source git-failure test (a git shim, skipped on Windows), and an empty XDG_CONFIG_HOME test. Docs drop the pattern from the sample output and describe the not-evaluated warning.
There was a problem hiding this comment.
Reviewed 500e918e7858f8b60272435551b0565aa573884f against 057b13bee16bb255719c4c462452a240e4c03ee1 and current repository behavior.
Inspection: 7 changed files. Scope: incremental — 4 files with lines changed since the review at c8dcc096; the security lenses reviewed the full head. Findings on lines unchanged since that review are deferred, not decisive.
Final Assessment
Human decision aid only: Readiness 5/5 is best; Risk 1/5 is best. These scores inform the maintainer; the next action below follows finding severity (any open P0/P1 → author/change) and does not approve or merge the PR.
Readiness: 2/5 — Major correction remains: three P1 paths can expose untrusted instructions or leave a fully blocked Kiro IDE workflow falsely undiagnosed.
Risk: 4/5 — The affected diagnostic crosses a model trust boundary and can report health while every framework read remains denied. The impact covers supported native and Windows environments.
Decision required: Author — make changes before this PR proceeds. The surviving P1 security, contract, and correctness defects require correction before the PR proceeds.
Validation performed:
- Inspected the complete diff and all seven changed-file snapshots.
- Applied incremental scope to non-security findings and reviewed security across the full head.
- Traced ignore-source discovery, home-path fallback, doctor rendering, Kiro IDE model-context dispatch, packaging, prerequisites, tests, and documentation.
- Established that the original raw-pattern and empty-XDG defects were corrected; the evaluation-failure defect remains partially unresolved.
- Repository code and tests were not executed under the read-only review contract.
Findings: 3 blocking, 0 advisory.
Ledger: 3 open, 0 retained blocking, 0 accepted, 0 suppressed as rejected by a maintainer, resolved F1, F3 (F1, F3 declared corrected by the judge). Maintainers act on findings with /aida commands in the ledger comment.
Security & Trust
P1 [F4]: Ignore-source filenames remain a model prompt-injection channel
Evidence: core/tools/aidlc-utility.ts:2756, core/tools/aidlc-utility.ts:2813.
Problem: An instruction-shaped checkout or configured excludes filename is returned by Git or retained in `source`, interpolated into doctor output, and then placed inside Kiro IDE's SYSTEM-wrapped terminal context with an instruction to relay it verbatim. Removing raw pattern text therefore does not close the model trust boundary.
Impact: Running doctor with a maliciously named source can expose the conductor to role-override or tool-abuse instructions. This is a reachable prompt-injection path.
Required correction: Render fixed source identifiers and validated line numbers instead of arbitrary filesystem paths or Git diagnostics in model-consumed output. Add adversarial filename and error-text coverage.
Contracts & Compatibility
P1 [F2]: Undiscoverable custom global excludes still pass as healthy
Evidence: core/tools/aidlc-utility.ts:2833, docs/guide/12-cli-commands.md:684.
Problem: On a supported native installation without Git, doctor cannot discover a custom `core.excludesFile`. When the default candidate files are absent, the catch returns `none present` even though the custom file may hide `.kiro/`, contradicting the documented not-evaluated warning contract and the native no-Git prerequisite.
Impact: Every Kiro IDE stage read can remain denied while doctor reports a passing row, leaving the primary workflow unusable without recovery guidance.
Required correction: Treat failed source discovery as not evaluated even when no default candidate exists, or discover configured global excludes without external Git. Cover no-Git custom-excludes and repository-probe failure paths.
Correctness & Reliability
P1 [F5]: Blank HOME bypasses the Windows user-profile fallback
Evidence: core/tools/aidlc-utility.ts:2733.
Problem: When Windows supplies `HOME=""` and a valid `USERPROFILE`, nullish coalescing selects the blank value. The user Kiro ignore and default global-ignore paths then resolve relative to the project instead of the user profile, so a blocking user rule is missed.
Impact: A supported Windows Kiro IDE workflow can remain completely blocked while the new diagnostic reports no matching source.
Required correction: Treat blank HOME as absent and fall back to USERPROFILE or `homedir()`. Add a regression test with blank HOME and a blocking user-profile ignore file.
User Experience
User experience change: Kiro IDE users running doctor now receive source-specific diagnostics for ignore rules that hide framework files.
Before: Doctor could report no relevant problem while every read under .kiro was denied.
After: Known matching or unevaluable sources are reported, but custom global excludes without Git and blank HOME environments can still appear healthy.
Example: Intended: Kiro IDE ignore sources: <source>:<line> hides .kiro/. Remaining failure: none present despite an active blocking source.
Assessment: The diagnostic improves recovery in covered cases, but surviving false negatives and unsafe filename rendering make it incomplete.
Residual risk: Static inspection was complete, but runtime tests and packaging determinism checks were not executed under the mandated read-only contract.
Reviewed by AIDA (AI-DLC Developer Agent).
[AI-PR-REVIEWED] 500e918
Superseded by AI review of 500e918
…iscovery fails Addresses AIDA round 2 (F2, F4, F5) on the Kiro IDE ignore-sources check. F4: doctor output reaches the model verbatim (the Kiro IDE skill prints utility output as-is), so a checkout directory, a configured excludes path, or git's stderr could carry instruction-shaped text. Rows now name each source by a fixed identifier (~/.config/git/ignore or $XDG_CONFIG_HOME/git/ignore, core.excludesFile, ~/.kiro/settings/kiroignore, .gitignore, .kiroignore) with a validated line number, and every not-evaluated reason is fixed text such as "git config exit 3". Because a row now attributes a match to the source under test, the scratch repository is created with --template=, so a templated info/exclude cannot match on that source's behalf. F2: without git, doctor cannot learn where a custom core.excludesFile points. In a git repository that source is now reported as not evaluated even when no default ignore file exists. Git still answers the repository question when available (0 = repo, 128 = not a repo, anything else = unknown, which warns); without git, a .git holding HEAD or a gitdir: pointer stands in, so outside a repository a no-git run with no ignore files still passes as "none present". F5: a blank HOME now falls back to USERPROFILE, then homedir(). t340 adds adversarial coverage for an instruction-shaped custom excludes filename, checkout name, and git error text; custom core.excludesFile discovery; no-git in and outside a repository; a templated info/exclude; and a blank HOME. Docs describe the fixed source names and when a source is not evaluated.
There was a problem hiding this comment.
Reviewed 2a9b8cc86774799f6e53b6792b024d8c1555c23a against 057b13bee16bb255719c4c462452a240e4c03ee1 and current repository behavior.
Inspection: 7 changed files. Scope: incremental — 4 files with lines changed since the review at 500e918e; the security lenses reviewed the full head. Findings on lines unchanged since that review are deferred, not decisive.
Final Assessment
Human decision aid only: Readiness 5/5 is best; Risk 1/5 is best. These scores inform the maintainer; the next action below follows finding severity (any open P0/P1 → author/change) and does not approve or merge the PR.
Readiness: 2/5 — A P1 false-healthy diagnostic path remains and requires correction before the bug fix is complete.
Risk: 4/5 — The affected condition can leave every Kiro IDE framework read blocked while the prescribed recovery command reports health.
Decision required: Author — make changes before this PR proceeds. The remaining P1 diagnostic contract failure must be corrected before the PR proceeds.
Validation performed:
- Inspected all seven changed-file snapshots and the SHA-anchored diff.
- Applied incremental scope to non-security findings and reviewed security across the full head.
- Inspected repository instructions, PR metadata, discussion, ledger, prior reviews, specialist outputs, doctor rendering, Kiro dispatch, packaging, tests, and documentation.
- Confirmed the filename prompt-injection and blank-HOME findings were corrected.
- Repository code and tests were not executed under the read-only review contract.
Findings: 1 blocking, 0 advisory.
Ledger: 1 open, 0 retained blocking, 0 accepted, 0 suppressed as rejected by a maintainer, resolved F4, F5 (F4, F5 declared corrected by the judge). Maintainers act on findings with /aida commands in the ledger comment.
Contracts & Compatibility
P1 [F2]: Git probe failures suppress the global-ignore warning
Evidence: core/tools/aidlc-utility.ts:2785, core/tools/aidlc-utility.ts:2881, docs/guide/12-cli-commands.md:684.
Problem: When a real worktree's `git rev-parse` exits 128 for a repository error such as dubious ownership or an invalid ambient Git-directory setting, line 2785 treats it as definitively outside Git. Global-exclude discovery and its not-evaluated warning are skipped, allowing the final branch to return `none present` even when that source hides `.kiro/`. This contradicts the documented warning contract.
Impact: Kiro IDE can deny every stage, agent, and protocol read while doctor reports a passing row, leaving the primary workflow unusable without recovery guidance.
Required correction: Treat repository-probe failures as unknown unless repository absence is independently established, sanitize repository-redirecting Git variables, fall back to physical worktree detection where appropriate, and add regression coverage for exit 128 and ambient Git-directory variables.
User Experience
User experience change: Kiro IDE users running doctor receive source-specific diagnostics for ignore rules that hide framework files.
Before: Doctor could report no relevant problem while every read under .kiro was denied.
After: Doctor identifies matching or unevaluable ignore sources, but some Git repository-probe failures can still produce a false healthy result.
Example: Expected: Kiro IDE ignore sources: <source>:<line> hides .kiro/. Remaining failure: none present after a Git repository probe exits 128.
Assessment: Recovery improves for covered configurations, but the remaining false-negative path can strand users without actionable guidance.
Residual risk: Static inspection was complete, but runtime tests and packaging determinism checks were not executed under the mandated read-only contract.
Reviewed by AIDA (AI-DLC Developer Agent).
[AI-PR-REVIEWED] 2a9b8cc
There was a problem hiding this comment.
Reviewed 83a7157e3f3889c0f61f580385d4f4aaf9de6be7 against 057b13bee16bb255719c4c462452a240e4c03ee1 and current repository behavior.
Inspection: 7 changed files. Scope: incremental — 4 files with lines changed since the review at 2a9b8cc8; the security lenses reviewed the full head. Findings on lines unchanged since that review are deferred, not decisive.
Final Assessment
Human decision aid only: Readiness 5/5 is best; Risk 1/5 is best. These scores inform the maintainer; the next action below follows finding severity (any open P0/P1 → author/change) and does not approve or merge the PR.
Readiness: 2/5 — A P1 false-healthy path remains, and Git-refusal recovery guidance is incomplete.
Risk: 4/5 — A supported symlinked workspace can remain fully blocked while doctor reports no relevant issue.
Decision required: Author — make changes before this PR proceeds. The remaining P1 repository-detection defect must be corrected before the PR proceeds.
Validation performed:
- Inspected the complete diff and all seven changed-file snapshots.
- Applied incremental scope to non-security findings and reviewed security across the full head.
- Inspected repository instructions, PR metadata, discussion, prior reviews, ledger, specialist outputs, doctor rendering, project-directory resolution, Kiro IDE dispatch, packaging, tests, and documentation.
- Confirmed the previous prompt-injection, empty-XDG, blank-HOME, and no-Git custom-excludes defects are corrected.
- Repository code and tests were not executed under the read-only review contract.
Findings: 1 blocking, 1 advisory.
Ledger: 2 open, 0 retained blocking, 0 accepted, 0 suppressed as rejected by a maintainer. Maintainers act on findings with /aida commands in the ledger comment.
Contracts & Compatibility
P1 [F2]: Symlinked nested workspaces still suppress the global-ignore warning
Evidence: core/tools/aidlc-utility.ts:2775, core/tools/aidlc-utility.ts:2802, docs/guide/12-cli-commands.md:684.
Problem: When projectDir is a symlink to a subdirectory of a worktree and Git refuses the repository, the fallback walks lexical parents and cannot see the real ancestor's .git. onDisk remains false, the failed probe is treated as outside Git, global excludes are skipped, and doctor can return "none present" contrary to the documented not-evaluated contract. resolveProjectDir and the dispatcher preserve symlink spellings, and repository tests support such aliases.
Impact: A global rule can still deny every Kiro IDE stage, agent, and protocol read while the prescribed diagnostic reports health, leaving the primary workflow unusable.
Required correction: Perform fallback discovery from the canonical project path with Git-equivalent ceiling handling, or treat any failed probe as unknown unless repository absence is conclusive. Add a symlinked nested-worktree regression test where rev-parse fails.
User Experience
User experience change: Kiro IDE users running doctor receive source-specific diagnostics for ignore rules hiding framework files.
Before: Doctor could report no relevant problem while reads under .kiro were denied.
After: Most matching or unevaluable sources are reported, but a symlinked nested workspace can still appear healthy after Git refuses repository access, and refusal warnings lack a working recovery step.
Example: Expected: global excludes not evaluated. Remaining result: Kiro IDE ignore sources: none present.
Assessment: Discoverability improves in common configurations, but recovery remains unreliable in supported edge cases.
P2 [F6]: Git-refusal warnings do not provide a working recovery path
Evidence: core/tools/aidlc-utility.ts:2804, docs/guide/15-troubleshooting.md:209.
Problem: When Git is installed but repository inspection is refused, doctor emits an exit-status warning, but the generated fix still says Git is needed on PATH and the troubleshooting guide only says to check files by hand. For a custom core.excludesFile, the suggested context-sensitive config command can fail for the same reason, so the user cannot locate the blocking source.
Impact: Users receive a warning but may remain stranded with all framework reads denied and no actionable recovery.
Required correction: Distinguish missing Git from repository/config refusal. For refusal, explain how to resolve ownership or inspect global configuration safely from a neutral context, identify the default fallback, and add assertions for the resulting recovery text.
Residual risk: Static inspection was complete, but runtime tests and packaging determinism checks were not executed under the mandated read-only contract.
Reviewed by AIDA (AI-DLC Developer Agent).
[AI-PR-REVIEWED] 83a7157
Superseded by AI review of 83a7157
…fusals a recovery Addresses AIDA round 4 (F2, F6) on the Kiro IDE ignore-sources check. F2: the on-disk repository search walked a symlinked project's lexical parents, so a project path that aliases a subdirectory of a worktree never reached the real .git; when git also refused the repository, doctor skipped git's global excludes file and could report "none present". The search now starts from the canonical project path, and GIT_CEILING_DIRECTORIES is handled as git handles it: entries must be absolute and are canonicalized until an empty entry. F6: every not-evaluated row told the user to put git on PATH, even when git was installed and refusing the project. Rows now carry a recovery by kind: git missing (install it; until then the global excludes file is core.excludesFile in ~/.gitconfig, else the default), git refusing the project (run `git status` to see why, run the safe.directory command git prints for dubious ownership, and find the global excludes file with `git config --get core.excludesFile` outside the project), or one evaluation failing (check that file by hand). The default named in both hints follows XDG_CONFIG_HOME. t340 adds a symlinked nested-workspace case where rev-parse fails, asserts the recovery text for each kind, and shares one git shim helper. The troubleshooting guide lists the recovery for each reason.
There was a problem hiding this comment.
Reviewed ec7e1e3e452505b59c316b330849fa76f7e7d292 against 057b13bee16bb255719c4c462452a240e4c03ee1 and current repository behavior.
Inspection: 7 changed files. Scope: incremental — 3 files with lines changed since the review at 83a7157e; the security lenses reviewed the full head. Findings on lines unchanged since that review are deferred, not decisive.
Final Assessment
Human decision aid only: Readiness 5/5 is best; Risk 1/5 is best. These scores inform the maintainer; the next action below follows finding severity (any open P0/P1 → author/change) and does not approve or merge the PR.
Readiness: 4/5 — The primary false-healthy paths are corrected and focused regression coverage was added. Two limited recovery and repository-discovery gaps remain.
Risk: 2/5 — Remaining defects produce incomplete or misleading warnings rather than false health or security-boundary violations. Impact is limited to Git-free or cross-filesystem configurations.
Decision required: Maintainer — decide whether to merge this PR. No P0 or P1 finding survives; the remaining P2 and P3 gaps are advisory under the review contract.
Validation performed:
- Inspected the immutable diff and all seven changed-file snapshots.
- Applied incremental scope to non-security findings and reviewed security across the full head.
- Inspected repository instructions, PR metadata, discussion, ledger, prior reviews, specialist outputs, doctor rendering, Kiro dispatch, packaging, tests, and documentation.
- Confirmed the symlinked-workspace detection and Git-refusal recovery defects were corrected.
- Ran read-only Git diff and whitespace checks; repository code and tests were not executed as required.
Findings: 0 blocking, 2 advisory.
Ledger: 2 open, 0 retained blocking, 0 accepted, 0 suppressed as rejected by a maintainer, resolved F2, F6 (F2, F6 declared corrected by the judge). Maintainers act on findings with /aida commands in the ledger comment.
User Experience
User experience change: Kiro IDE users running doctor now receive source-specific diagnostics when ignore rules can hide the framework directory.
Before: Doctor could report no relevant problem while every framework read was denied.
After: Doctor identifies matching or unevaluable ignore sources and provides differentiated recovery guidance, although some uncommon configurations remain incompletely handled.
Example: Before: no relevant problem. After: Kiro IDE ignore sources: git's global excludes file not evaluated - git is not available.
Assessment: The change materially improves diagnosis and recovery, with the remaining gaps confined to manual no-Git recovery and cross-filesystem repository discovery.
P2 [F7]: No-Git recovery omits supported global configuration locations
Evidence: core/tools/aidlc-utility.ts:2908, core/tools/aidlc-utility.ts:2915, docs/guide/15-troubleshooting.md:209.
Problem: When Git is unavailable, the manual recovery identifies ~/.gitconfig as the global configuration location. Git may instead read $XDG_CONFIG_HOME/git/config or a file selected through GIT_CONFIG_GLOBAL, so users following the fallback can miss the custom core.excludesFile that is blocking Kiro reads.
Impact: A Git-free Kiro IDE user can remain unable to read any framework file after following the advertised manual recovery, although installing Git and rerunning doctor remains a working path.
Required correction: Mention every supported global configuration surface without rendering environment values, and add no-Git coverage for XDG and GIT_CONFIG_GLOBAL configurations.
P3 [F8]: Repository fallback crosses filesystem discovery boundaries
Evidence: core/tools/aidlc-utility.ts:2793, core/tools/aidlc-utility.ts:2805.
Problem: The fallback walks all canonical parents without stopping when the device changes. Git normally stops repository discovery at a filesystem boundary unless GIT_DISCOVERY_ACROSS_FILESYSTEM is enabled, so a project mounted beneath an unrelated ancestor repository is incorrectly classified as a refused repository.
Impact: Doctor emits a persistent global-ignore warning and inappropriate ownership/refusal recovery for a workspace where Git does not consider the ancestor repository applicable.
Required correction: Stop fallback discovery at device boundaries unless cross-filesystem discovery is enabled, and add coverage using injectable device identities or a distinct filesystem.
Residual risk: Static review could not execute the new platform-sensitive tests or packaging determinism checks under the read-only contract.
Reviewed by AIDA (AI-DLC Developer Agent).
[AI-PR-REVIEWED] ec7e1e3
Superseded by AI review of ec7e1e3
Self-review after the AIDA loopRebased onto Fixed on this branch
t340 now has 19 tests; each round's new tests fail against the previous round's code. Local runs per round: t340, t148, Still openAIDA advisory (non-blocking)
From my own review
|
* origin/main: fix(doctor): report Kiro IDE ignore sources that hide .kiro/ (awslabs#1161) chore(ci): run the cross-OS jobs in the merge queue, not on every PR push (awslabs#1389) feat(plan-approval): auto-resolve --session from the invoking conversation (awslabs#1379) fix: always sort audit rows before deriving the stage run floor (awslabs#1314) fix(sensor): route a sensor's path argument from its declared input_schema (awslabs#1239) # Conflicts: # tests/.coverage-ratchet.json # tests/.coverage-registry.json
* origin/main: (41 commits) chore(ci): supersede Full Suite verification across branch heads (awslabs#1390) fix: never record an unreadable review findings table as no findings (awslabs#1163) fix(doctor): report Kiro IDE ignore sources that hide .kiro/ (awslabs#1161) chore(ci): run the cross-OS jobs in the merge queue, not on every PR push (awslabs#1389) feat(plan-approval): auto-resolve --session from the invoking conversation (awslabs#1379) fix: always sort audit rows before deriving the stage run floor (awslabs#1314) fix(sensor): route a sensor's path argument from its declared input_schema (awslabs#1239) fix(onboarding): render user-typed skill names with the harness skill prefix (awslabs#1368) fix(dispatch): route the three team-mode state verbs the engine calls (awslabs#1309) test(kiro-ide): pin the legacy execute_pwsh populated-command approval flip (awslabs#1051) chore(release): prepare v2.10.0 (awslabs#1380) fix: normalize Windows drive letters so Kiro IDE artifact writes are audited (awslabs#1201) fix: make the guards a fence for the agents and a gate the human holds the key to (awslabs#1262) fix: correct session-skill command references and document CLI fallback (awslabs#1363) fix(ci): preload system modules for Windows Codex readiness (awslabs#1367) fix(ci): correct Codex readiness and composed scope checks (awslabs#1365) fix: name a working next step in the refusals operators actually hit (awslabs#1322) fix(ci): tolerate unsupported AIDA repository evidence (awslabs#1364) fix(ci): require live coverage and parallelize platform tests (awslabs#1311) fix(aida): a folded higher-severity duplicate publishes its own body; deferral rationale never stacks explanations (awslabs#1359) ...
…k-json-output * origin/main: (42 commits) fix(windows): repair the cross-OS test failures on Windows (#1393) fix(doctor): compare the audit against the per-stage checkboxes (#1272) fix(sensor): drop a superseded detail file when the sensor passes (#1266) chore(ci): supersede Full Suite verification across branch heads (#1390) fix: never record an unreadable review findings table as no findings (#1163) fix(doctor): report Kiro IDE ignore sources that hide .kiro/ (#1161) chore(ci): run the cross-OS jobs in the merge queue, not on every PR push (#1389) feat(plan-approval): auto-resolve --session from the invoking conversation (#1379) fix: always sort audit rows before deriving the stage run floor (#1314) fix(sensor): route a sensor's path argument from its declared input_schema (#1239) fix(onboarding): render user-typed skill names with the harness skill prefix (#1368) fix(dispatch): route the three team-mode state verbs the engine calls (#1309) test(kiro-ide): pin the legacy execute_pwsh populated-command approval flip (#1051) chore(release): prepare v2.10.0 (#1380) fix: normalize Windows drive letters so Kiro IDE artifact writes are audited (#1201) fix: make the guards a fence for the agents and a gate the human holds the key to (#1262) fix: correct session-skill command references and document CLI fallback (#1363) fix(ci): preload system modules for Windows Codex readiness (#1367) fix(ci): correct Codex readiness and composed scope checks (#1365) fix: name a working next step in the refusals operators actually hit (#1322) ...
Absorbs the 13 commits from 057b13b (#1309) through e71c60a (#1398). Conflicts: - core/tools/aidlc-orchestrate.ts: import list. This branch added currentDistribution and main added entrySkillInvocation; both are used, so both are kept. - core/tools/aidlc-utility.ts: Kiro doctor wiring. This branch replaced the agent-v1 cli.json check with an unconditional one; main added the Kiro IDE ignore-source checks (#1161) inside the Markdown-agent branch. Kept the unconditional check and run the ignore-source checks whenever agents/aidlc.md is present, since the one Markdown conductor now serves CLI and IDE alike. t340 (new on main) asserted the retired agents/aidlc.{json,md} label and that an aidlc.json-only project skips the ignore rows. With the JSON row retired, the test now checks the unwired and wired Markdown conductor. t260 (4 cases) and t27 (#67, #68) fail identically on main e71c60a and are not caused by this merge.
Summary
Fixes #1146.
On Kiro IDE, a
.kiro/rule in git's global excludes file makes the IDE'sfs_readguard deny every stage, agent, and protocol read, so no stage can run. The IDE compiles each ignore file into its own matcher, so a!.kiro/in the project.gitignorecannot undo it even thoughgit check-ignorereports the path as not ignored; and Kiro applies deny-overrides across scopes, so apermissions.yamlfs_readallow cannot clear it either./aidlc --doctorreported0 problemsbecause its reads run in a subprocess, not throughfs_read.The guard itself is a Kiro IDE defect and is not patchable here; this change gives
--doctora deterministic detection with a remedy, plus the troubleshooting entry.Changes
core/tools/aidlc-utility.ts: new exportedkiroIdeIgnoreSourceChecks(projectDir, harness, env), wired intocollectDoctorReportfor the Kiro harness when the IDE conductor (agents/aidlc.md) is present. It evaluates each ignore source Kiro IDE honours on its own - git's global excludes file (only inside a git repo, as Kiro does),~/.kiro/settings/kiroignore, the project.gitignore, and.kiroignore- by runninggit -c core.excludesFile=<source> check-ignore -v --no-indexagainst a stage path in a scratch repository. Only that one file applies, and the gitignore semantics are git's own rather than a hand-rolled matcher. Verbosecheck-ignoreexits 0 for a directly matched negation, so a leading!in the reported pattern counts as not hidden.file:lineand the pattern, with the remedy: remove or narrow the rule; a negation in another file or a permissions allow does not help; per-repo personal ignores belong in that repo's.git/info/exclude. Workspace-source matches warn, because whether those files apply is governed by the IDE'skiroAgent.agentIgnoreFilessetting, which doctor cannot read. Missing git degrades to a passing advisory row.docs/guide/12-cli-commands.md), a new Kiro IDE Read Denials troubleshooting section with the exact denial text and a quick-fix row (docs/guide/15-troubleshooting.md), doctor summary indocs/reference/06-hooks-and-tools.md.tests/unit/t340-kiro-ide-ignore-sources-doctor.test.ts: global rule detected and named despite a repo!.kiro/; same-file negation clears it (directory and direct-file forms); global-fail/workspace-warn split; row emitted only for the IDE conductor surface.User experience
Before: on the reporter's setup doctor reports
0 problems, 2 warningswhile every stage read is denied. After, against the packageddist/kiro-idewith a repo!.kiro/and a global.kiro/(git's owncheck-ignoreexits 1 = not ignored):After removing the rule:
ok Kiro IDE ignore sources: none hide .kiro/ (1 file(s) checked).No release metadata changes (version, badge, changelog) per policy.
Checklist
Test plan
bun test tests/unit/t340-kiro-ide-ignore-sources-doctor.test.ts- 5 passbun test tests/smoke/t148-kiro-file-structure.test.ts- 20 pass (existing Kiro doctor shape test)bun scripts/package.ts --check- deterministic across all 7 harnessesdist/kiro-idewith an isolatedHOME/XDG_CONFIG_HOME/GIT_CONFIG_GLOBALNot verified: whether Kiro IDE reads
.git/info/exclude. Kiro documents its sources as named workspace files plus the two global files, so the remedy text treats it as invisible to the IDE.Acknowledgment
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of the project license.