From 1c0b924bb8956d433013a91a21b0ea1c71ec3ef9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Topi=20J=C3=A4rvinen?= Date: Sun, 2 Aug 2026 22:01:29 +0300 Subject: [PATCH] fix: give the remediation search a route when the runtime exposes no search tool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Found by running the step for real, on cs-toolkit, rather than by reading it. The step said to search the archives with "your runtime's own file-search facility, passing the subject as a parameter". A session with no such tool exposed — only MCP search for unrelated systems — has no route at all: the preferred one is unavailable and the stated fallback is to read #241 and treat building a shell command as its own problem. That is a description of a hazard, not an instruction. The withdrawal in #241 was right about the shell and wrong about its scope. It treated every subject as equally dangerous. In practice the risk is a property of WHERE THE SUBJECT CAME FROM: - a cron job name, a branch, a path, a scope — from your own repo or config, operator-controlled, and an ordinary shell search is fine - an issue or PR title — from a tracker that may accept issues from outside, which is the attacker-influenceable case #241 is actually about That distinction restores a usable route for the majority of candidates without reopening anything. The three recipes #241 records were all defeated by *title* inputs — an apostrophe, a quote, a delimiter line — and none of those arrive in a job name you wrote in your own automations.yaml. For the tracker case the step now also says to match on the candidate's ID rather than its title where possible. An id is the part whose shape you control, and it is what actually identifies the item: the live run that found this defect matched `CUS-1107` and `nightly-fixer`, never a free-text title. MEASURED, not assumed. Running the step on cs-toolkit exercised three different branches of it: `nightly-fixer` (dropped — a dated diagnosis in the archive plus a "DISABLED … monthly spend cap" note in its own status line), `weekly-slides` (candidate stands — the archive hits were about something else, which is the generic-subject case the step warns about), and `CUS-1107` (replaced by CUS-1110, the residual follow-up rule firing). Every subject that worked was an id or a config-derived name. VERIFIED: `make test` 721 passed; `python scripts/kit_doctor.py` 32 unchanged, 0 differ, 0 missing. Neither executes this prose; the run on cs-toolkit is the only thing that did, and it is what produced the finding. --- docs/agentic-dev-kit/workflows/session-start.md | 17 ++++++++++++++++- kit-manifest.json | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/docs/agentic-dev-kit/workflows/session-start.md b/docs/agentic-dev-kit/workflows/session-start.md index a89bf1b..a8bcd0e 100644 --- a/docs/agentic-dev-kit/workflows/session-start.md +++ b/docs/agentic-dev-kit/workflows/session-start.md @@ -167,7 +167,22 @@ something already classified 🟡 is later raised to 🔴, it gets the check the Search them **per candidate**, by job / ticket / subject name, using **your runtime's own file-search facility** — the subject passed as a *parameter*, the - two archives as the scope. + two archives as the scope. A parameter is never parsed as shell syntax, which is + what makes this the preferred route. + + **If your runtime exposes no such tool, the deciding question is where the + subject came from**, not whether you are using a shell: + + - **From your own repository or config** — a cron job name, a branch, a file + path, a scope. Operator-controlled, and an ordinary shell search is fine. + - **From your tracker or forge** — an issue title, a PR title. On any project + that accepts issues from outside, that is attacker-influenceable text, and + building a shell command around it is a problem three separate attempts here + failed to solve; see + [`#241`](https://github.com/topij/agentic-dev-kit/issues/241) before trying a + fourth. Prefer matching such a candidate by its **id** (`CUS-1107`, `#143`), + which is the part you control the shape of, and search the title only through + a parameter-passing tool. **Skip a candidate whose subject is empty or whitespace-only** rather than searching for it. An empty pattern matches every line of both archives, which is diff --git a/kit-manifest.json b/kit-manifest.json index a778faf..7e2fb6b 100644 --- a/kit-manifest.json +++ b/kit-manifest.json @@ -44,7 +44,7 @@ }, "docs/agentic-dev-kit/workflows/session-start.md": { "role": "workflow", - "sha256": "00cae6afe47b6817f92d012c6dcac4447a3e7114d403e7fae03891c35a01d3d6" + "sha256": "535a391e491d5371ba1b4930d75323a6ec9b46a636d0b89b59d239934e7aaf2c" }, "docs/agentic-dev-kit/workflows/wrap-up.md": { "role": "workflow",