From a0d91ac0e43f76f70e31ec20206a9b9e2877fe1e Mon Sep 17 00:00:00 2001 From: elamaran shanmugam Date: Thu, 30 Jul 2026 17:50:21 -0400 Subject: [PATCH 1/2] feat(coder): emit a PR change-description alongside verification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per reviewer request: the coder now writes a concise, reviewer-facing description of WHAT it changed (and why) to artifacts/description.md as part of its run, and the PR body renders it as a '### 📝 Changes' section ABOVE the existing verification block. Falls back to a neutral line if absent so the body is never empty. - claude path: description instruction appended to the prompt. - kiro path: same instruction appended to SPEC.md (kiro reads --spec). - PR body: new Changes section placed before the marker, so status.js (which rewrites from the marker down) preserves it on every update. node --check passes. --- examples/dark-factory/coder/entrypoint.js | 24 ++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/examples/dark-factory/coder/entrypoint.js b/examples/dark-factory/coder/entrypoint.js index 79b421cf..d7e87bc0 100644 --- a/examples/dark-factory/coder/entrypoint.js +++ b/examples/dark-factory/coder/entrypoint.js @@ -256,11 +256,25 @@ function runCoder(repoDir) { // Inherit stdio so the coder CLI's own output + errors stream into the pod // logs (kubectl logs), instead of being swallowed by execFileSync's exception. const opts = { cwd: repoDir, env, stdio: "inherit", maxBuffer: 64 * 1024 * 1024 }; - const prompt = `Implement the change described in ${WORKSPACE}/SPEC.md. Build and run unit tests until green. Commit your work.`; + // The coder also writes a concise, human-readable summary of WHAT it changed to + // artifacts/description.md — this becomes the "Changes" section of the PR body + // (in addition to the verification section). Keep it short: what changed + why, + // as reviewer-facing markdown bullets. + const descPath = `${WORKSPACE}/artifacts/description.md`; + const prompt = + `Implement the change described in ${WORKSPACE}/SPEC.md. Build and run unit tests until green. Commit your work. ` + + `Then write a concise description of the changes you made (what changed and why, as a few markdown bullet points, ` + + `reviewer-facing — no preamble) to ${descPath}.`; if (ENGINE === "kiro") { // Kiro CLI headless — the coder image carries the `kiro` binary; it reads the // same Bifrost/Bedrock env above. --headless drives it non-interactively. + // Append the description instruction so kiro produces the same artifact. console.log("[coder] engine=kiro (kiro run --headless)"); + try { + fs.appendFileSync(`${WORKSPACE}/SPEC.md`, + `\n\n---\n\n## After implementing\n\nWrite a concise description of the changes you made ` + + `(what changed and why, a few reviewer-facing markdown bullets, no preamble) to ${descPath}.\n`); + } catch { /* non-fatal */ } return execFileSync("kiro", ["run", "--headless", "--spec", `${WORKSPACE}/SPEC.md`], opts); } console.log("[coder] engine=claude (claude -p)"); @@ -429,9 +443,17 @@ async function main() { ? "- ⏳ **Security review (AWS Security Agent):** _queued (DevOps cleared)…_" : "- ⬜ **Security review (AWS Security Agent):** _waiting on DevOps clearance_"; } + // Coder-authored description of the changes (artifacts/description.md). Shown + // as a "Changes" section ahead of the verification block. Falls back to a + // neutral line if the coder didn't produce one, so the PR body is never empty. + const desc = readSecret(`${WORKSPACE}/artifacts/description.md`); + const changesSection = desc + ? ["### 📝 Changes", "", desc, ""] + : ["### 📝 Changes", "", "_Implemented per the linked issue; see the diff for details._", ""]; const prBody = [ `Closes #${ISSUE}.`, "", + ...changesSection, "", "### 🏭 Dark Factory — verification", `- ✅ **Build + unit tests:** ${test.summary}`, From 1a4df9be67bc147c64724324a5c99fce345350b5 Mon Sep 17 00:00:00 2001 From: elamaran shanmugam Date: Thu, 30 Jul 2026 17:53:21 -0400 Subject: [PATCH 2/2] fix(security-agent): early-exit when findings ready + graceful timeout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two fixes for the 'security review waits ~15 min while the PR already shows a result' problem: 1. Early-exit: the code-review job's status field flips to COMPLETED long AFTER the AWS Security Agent App bot has already posted its findings on the PR. So in addition to polling status, each iteration now probes list-findings; the moment it returns a well-formed result (findingsSummaries present) we proceed — no waiting for the status flip. Reuses those findings for the report (no re-fetch). 2. Graceful timeout: this step is advisory (the App bot posts the authoritative result regardless), so exceeding the poll timeout now posts a neutral 'pending' status + a pointer to the bot comment, instead of a misleading red 'error'. This also fixes the stale sticky board: the sticky-status step depends on security-agent (runs once, after it), so a fast security step means the board is rewritten with accurate rows within seconds instead of ~15 min later. sh -n passes. --- .../dark-factory/scripts/security-agent.sh | 38 ++++++++++++++++--- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/gitops/addons/charts/dark-factory/scripts/security-agent.sh b/gitops/addons/charts/dark-factory/scripts/security-agent.sh index 8dc938bb..9601df42 100644 --- a/gitops/addons/charts/dark-factory/scripts/security-agent.sh +++ b/gitops/addons/charts/dark-factory/scripts/security-agent.sh @@ -95,27 +95,53 @@ JOBID="$(aws securityagent start-code-review-job --region "$AWS_REGION" \ log "codeReviewJobId=${JOBID} — polling (timeout ${POLL_TIMEOUT}s)..." # ── 4. Poll to completion ──────────────────────────────────────────────────── +# The job's `status` field lags well behind the actual analysis: the AWS Security +# Agent GitHub App posts its findings comment on the PR (e.g. "No issues identified") +# minutes before batch-get-code-review-jobs flips to COMPLETED. Polling status alone +# therefore blocks this (advisory) step for the full timeout even though the result +# is already known. So we ALSO probe list-findings each iteration: once it returns a +# well-formed result (findingsSummaries key present), the review has produced output +# and we can proceed immediately — this is the early-exit that avoids the long wait. DEADLINE=$(( $(date +%s) + POLL_TIMEOUT )) STATUS="IN_PROGRESS" +DONE="" +: > "$WORK/findings.json" while [ "$(date +%s)" -lt "$DEADLINE" ]; do STATUS="$(aws securityagent batch-get-code-review-jobs --region "$AWS_REGION" \ --agent-space-id "$AGENT_SPACE_ID" --code-review-job-ids "$JOBID" \ --query 'codeReviewJobs[0].status' --output text 2>/dev/null || echo IN_PROGRESS)" log "job status=${STATUS}" case "$STATUS" in - COMPLETED|SUCCEEDED) break ;; + COMPLETED|SUCCEEDED) DONE="status"; break ;; FAILED|STOPPED|ERROR) log "review job ${STATUS}"; post_status "error" "security: review job ${STATUS}"; exit 0 ;; esac + # Early-exit: findings ready before status flips? (App bot already posted them.) + if aws securityagent list-findings --region "$AWS_REGION" \ + --agent-space-id "$AGENT_SPACE_ID" --code-review-job-id "$JOBID" \ + > "$WORK/findings.try.json" 2>/dev/null \ + && python3 -c 'import json,sys; sys.exit(0 if "findingsSummaries" in json.load(open(sys.argv[1])) else 1)' "$WORK/findings.try.json" 2>/dev/null; then + mv "$WORK/findings.try.json" "$WORK/findings.json" + DONE="findings"; log "findings ready (status=${STATUS}) — proceeding without waiting for status flip"; break + fi sleep 20 done -if [ "$STATUS" != "COMPLETED" ] && [ "$STATUS" != "SUCCEEDED" ]; then - log "timed out waiting for review (last=${STATUS})"; post_status "error" "security: review timed out"; exit 0 +if [ -z "$DONE" ]; then + # Advisory step: the App bot posts the authoritative result on the PR regardless, + # so a slow job-status flip is NOT a failure. Post a neutral pending status (not + # error) so the PR check isn't a misleading red, and continue. + log "review still running past ${POLL_TIMEOUT}s (last status=${STATUS}) — see the AWS Security Agent bot comment on the PR for the authoritative result" + post_status "pending" "security: review still running — see AWS Security Agent PR comment" + exit 0 fi # ── 5. Fetch findings, render report + verdict (python3, no node) ──────────── -aws securityagent list-findings --region "$AWS_REGION" \ - --agent-space-id "$AGENT_SPACE_ID" --code-review-job-id "$JOBID" \ - > "$WORK/findings.json" 2>/dev/null || echo '{"findingsSummaries":[]}' > "$WORK/findings.json" +# Reuse the findings we already fetched during the early-exit probe; only re-fetch +# if we broke on the status flip (findings not yet captured). +if [ "$DONE" = "status" ] || [ ! -s "$WORK/findings.json" ]; then + aws securityagent list-findings --region "$AWS_REGION" \ + --agent-space-id "$AGENT_SPACE_ID" --code-review-job-id "$JOBID" \ + > "$WORK/findings.json" 2>/dev/null || echo '{"findingsSummaries":[]}' > "$WORK/findings.json" +fi python3 - "$WORK/findings.json" "$BLOCK_LEVEL" "$WORK/report.md" > "$WORK/verdict.env" <<'PY' import json, sys