From 1dd935a7c32bbe660dc8526bdf5aed84fb07a122 Mon Sep 17 00:00:00 2001 From: Codex Automation Date: Sat, 8 Aug 2026 00:29:26 -0500 Subject: [PATCH 1/9] fix(gate): dedupe in-flight issue formatting --- .../workflows/agents-issue-format-guard.yml | 18 ++++++++++-------- .github/workflows/agents-issue-optimizer.yml | 4 ++-- config/template-drift-allowlist.txt | 6 +++--- .../workflows/agents-issue-format-guard.yml | 18 ++++++++++-------- .../workflows/agents-issue-optimizer.yml | 4 ++-- ...st_agents_issue_optimizer_format_trigger.py | 7 ++++++- 6 files changed, 33 insertions(+), 24 deletions(-) diff --git a/.github/workflows/agents-issue-format-guard.yml b/.github/workflows/agents-issue-format-guard.yml index a4b692e27..c734fb140 100644 --- a/.github/workflows/agents-issue-format-guard.yml +++ b/.github/workflows/agents-issue-format-guard.yml @@ -143,24 +143,26 @@ jobs: if jq -e '[.labels[].name] | any(. == "agents:format")' live.json >/dev/null; then has_format_label=true fi - # Dedup completed handoffs, but retry when a prior dispatch/optimizer run - # left agents:format set (marker without a finished optimizer pass). + # The marker is written only after dispatch succeeds. Keep the label as + # the in-flight lease: a repeated guard run must not enqueue another + # optimizer while that lease is still present. If the label was removed, + # retry the dispatch because the earlier handoff no longer owns the work. dispatch=true - if [[ "$trusted_marker" == true && "$has_format_label" != true ]]; then - echo "Identical invalid body was already routed; skipping duplicate dispatch." + if [[ "$trusted_marker" == true && "$has_format_label" == true ]]; then + echo "Identical invalid body is already routed and in flight; skipping duplicate dispatch." dispatch=false - elif [[ "$trusted_marker" == true && "$has_format_label" == true ]]; then - echo "Prior format-guard marker present but agents:format still set — retrying optimizer dispatch." + elif [[ "$trusted_marker" == true ]]; then + echo "Prior format-guard marker present but agents:format is absent — retrying optimizer dispatch." fi if jq -e '[.labels[].name] | any(. == "agents:formatted")' live.json >/dev/null; then gh issue edit "$NUMBER" --repo "$GITHUB_REPOSITORY" --remove-label "agents:formatted" \ || echo "::warning::could not remove agents:formatted" fi - gh issue edit "$NUMBER" --repo "$GITHUB_REPOSITORY" --add-label "agents:format" \ - || echo "::warning::could not apply agents:format (label missing in this repo?)" if [[ "$dispatch" != true ]]; then exit 0 fi + gh issue edit "$NUMBER" --repo "$GITHUB_REPOSITORY" --add-label "agents:format" \ + || echo "::warning::could not apply agents:format (label missing in this repo?)" # GITHUB_TOKEN label edits do not start issues:labeled workflows; dispatch is explicit. # Persist the completion marker only after a successful workflow_dispatch so a # failed run remains retryable on the next guard pass. diff --git a/.github/workflows/agents-issue-optimizer.yml b/.github/workflows/agents-issue-optimizer.yml index 7d4ddbc2e..382433d0a 100644 --- a/.github/workflows/agents-issue-optimizer.yml +++ b/.github/workflows/agents-issue-optimizer.yml @@ -510,7 +510,7 @@ jobs: # Do not publish agents:formatted for apply-phase output that fails # the same fleet contract enforced by the issue-event guard. - python .github/scripts/issue_format.py /tmp/updated_body.md + python3 .github/scripts/issue_format.py /tmp/updated_body.md # Update issue body node - <<'NODE' @@ -580,7 +580,7 @@ jobs: # Do not advertise a formatted issue until it satisfies the same # fleet contract enforced by the issue-event guard. - python .github/scripts/issue_format.py /tmp/formatted_body.md + python3 .github/scripts/issue_format.py /tmp/formatted_body.md # Update issue body with formatted version node - <<'NODE' diff --git a/config/template-drift-allowlist.txt b/config/template-drift-allowlist.txt index 9a23c65a4..9f4b044aa 100644 --- a/config/template-drift-allowlist.txt +++ b/config/template-drift-allowlist.txt @@ -113,9 +113,9 @@ reason = Intentional divergence re-baselined 2026-06-30: root and consumer guard [pair.11] main = .github/workflows/agents-issue-optimizer.yml template = templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml -main_sha256 = d99f29c3433fa3430c68338cffe0c9ad7c6e22801303fea1916ddeab4040dc90 -template_sha256 = a4ab5b6f0039c1c20d3fb3133fed3a38902f7943cd46c951cf7695a0d3e41858 -reason = Intentional divergence re-baselined 2026-08-08: root and consumer issue-optimizer workflows keep different auth plumbing/action pin surfaces. Both validate format output before adding agents:formatted; the consumer explicitly sparse-checks out .github/scripts/issue_format.py plus config/scripts/langchain/tools from Workflows, while root runs those files in-tree. Do not align wholesale because that would strip consumer action pins/token setup. +main_sha256 = f3f6c4a885ff989c27de1ac032da092d4bc56dfa82f4c65e15624aa7b4273601 +template_sha256 = 617ff055673ec97fac8eaf9adf14630622ccb2ab8f45dfb651fd5ef725f29e20 +reason = Intentional divergence re-baselined 2026-08-08: root and consumer issue-optimizer workflows keep different auth plumbing/action pin surfaces. Both validate format output with python3 before adding agents:formatted; the consumer explicitly sparse-checks out .github/scripts/issue_format.py plus config/scripts/langchain/tools from Workflows, while root runs those files in-tree. Do not align wholesale because that would strip consumer action pins/token setup. [pair.12] main = .github/workflows/agents-keepalive-loop-reporter.yml diff --git a/templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml b/templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml index a4b692e27..c734fb140 100644 --- a/templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml +++ b/templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml @@ -143,24 +143,26 @@ jobs: if jq -e '[.labels[].name] | any(. == "agents:format")' live.json >/dev/null; then has_format_label=true fi - # Dedup completed handoffs, but retry when a prior dispatch/optimizer run - # left agents:format set (marker without a finished optimizer pass). + # The marker is written only after dispatch succeeds. Keep the label as + # the in-flight lease: a repeated guard run must not enqueue another + # optimizer while that lease is still present. If the label was removed, + # retry the dispatch because the earlier handoff no longer owns the work. dispatch=true - if [[ "$trusted_marker" == true && "$has_format_label" != true ]]; then - echo "Identical invalid body was already routed; skipping duplicate dispatch." + if [[ "$trusted_marker" == true && "$has_format_label" == true ]]; then + echo "Identical invalid body is already routed and in flight; skipping duplicate dispatch." dispatch=false - elif [[ "$trusted_marker" == true && "$has_format_label" == true ]]; then - echo "Prior format-guard marker present but agents:format still set — retrying optimizer dispatch." + elif [[ "$trusted_marker" == true ]]; then + echo "Prior format-guard marker present but agents:format is absent — retrying optimizer dispatch." fi if jq -e '[.labels[].name] | any(. == "agents:formatted")' live.json >/dev/null; then gh issue edit "$NUMBER" --repo "$GITHUB_REPOSITORY" --remove-label "agents:formatted" \ || echo "::warning::could not remove agents:formatted" fi - gh issue edit "$NUMBER" --repo "$GITHUB_REPOSITORY" --add-label "agents:format" \ - || echo "::warning::could not apply agents:format (label missing in this repo?)" if [[ "$dispatch" != true ]]; then exit 0 fi + gh issue edit "$NUMBER" --repo "$GITHUB_REPOSITORY" --add-label "agents:format" \ + || echo "::warning::could not apply agents:format (label missing in this repo?)" # GITHUB_TOKEN label edits do not start issues:labeled workflows; dispatch is explicit. # Persist the completion marker only after a successful workflow_dispatch so a # failed run remains retryable on the next guard pass. diff --git a/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml b/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml index d070e9202..149696d7c 100644 --- a/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml +++ b/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml @@ -468,7 +468,7 @@ jobs: " || exit 1 # Keep agents:formatted truthful for apply-phase output too. - python workflows-scripts/.github/scripts/issue_format.py /tmp/updated_body.md + python3 workflows-scripts/.github/scripts/issue_format.py /tmp/updated_body.md # Update issue body gh issue edit "${ISSUE_NUMBER}" --body-file /tmp/updated_body.md @@ -511,7 +511,7 @@ jobs: # Keep the format-result label truthful: the generated issue must # pass the canonical Workflows validator before it can be marked # agents:formatted below. - python workflows-scripts/.github/scripts/issue_format.py /tmp/formatted_body.md + python3 workflows-scripts/.github/scripts/issue_format.py /tmp/formatted_body.md # Update issue body with formatted version gh issue edit "${ISSUE_NUMBER}" --body-file /tmp/formatted_body.md diff --git a/tests/workflows/test_agents_issue_optimizer_format_trigger.py b/tests/workflows/test_agents_issue_optimizer_format_trigger.py index 4e4972f64..e75750713 100644 --- a/tests/workflows/test_agents_issue_optimizer_format_trigger.py +++ b/tests/workflows/test_agents_issue_optimizer_format_trigger.py @@ -32,14 +32,19 @@ def test_issue_optimizer_validates_format_and_apply_bodies() -> None: consumer_text = consumer.read_text(encoding="utf-8") assert "issue_format.py /tmp/formatted_body.md" in consumer_text assert "issue_format.py /tmp/updated_body.md" in consumer_text + assert "python3 .github/scripts/issue_format.py" in text + assert "python3 workflows-scripts/.github/scripts/issue_format.py" in consumer_text -def test_format_guard_retries_incomplete_optimizer_dispatch() -> None: +def test_format_guard_deduplicates_inflight_optimizer_dispatch() -> None: guard = Path(".github/workflows/agents-issue-format-guard.yml").read_text(encoding="utf-8") assert "Re-fetch before side effects" in guard assert "no completion marker written so later runs can retry" in guard assert 'marker=""' in guard + assert '"$trusted_marker" == true && "$has_format_label" == true' in guard + assert "already routed and in flight; skipping duplicate dispatch" in guard consumer = Path( "templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml" ).read_text(encoding="utf-8") assert "no completion marker written so later runs can retry" in consumer + assert '"$trusted_marker" == true && "$has_format_label" == true' in consumer From c47b48b63ce9d365375b3f750d51d412b6cffd45 Mon Sep 17 00:00:00 2001 From: Codex Automation Date: Sat, 8 Aug 2026 02:35:28 -0500 Subject: [PATCH 2/9] fix(agents): make format lease failure-safe --- .../workflows/agents-issue-format-guard.yml | 8 ++++++-- .github/workflows/agents-issue-optimizer.yml | 11 +++++++++++ config/template-drift-allowlist.txt | 6 +++--- .../workflows/agents-issue-format-guard.yml | 8 ++++++-- .../workflows/agents-issue-optimizer.yml | 11 +++++++++++ ...st_agents_issue_optimizer_format_trigger.py | 18 ++++++++++++++++++ 6 files changed, 55 insertions(+), 7 deletions(-) diff --git a/.github/workflows/agents-issue-format-guard.yml b/.github/workflows/agents-issue-format-guard.yml index c734fb140..ff2515abf 100644 --- a/.github/workflows/agents-issue-format-guard.yml +++ b/.github/workflows/agents-issue-format-guard.yml @@ -161,8 +161,12 @@ jobs: if [[ "$dispatch" != true ]]; then exit 0 fi - gh issue edit "$NUMBER" --repo "$GITHUB_REPOSITORY" --add-label "agents:format" \ - || echo "::warning::could not apply agents:format (label missing in this repo?)" + # Acquiring the label is the handoff lease. Do not dispatch without it: + # otherwise a trusted marker alone could repeat the optimizer dispatch. + if ! gh issue edit "$NUMBER" --repo "$GITHUB_REPOSITORY" --add-label "agents:format"; then + echo "::error::could not acquire agents:format lease; refusing optimizer dispatch" + exit 1 + fi # GITHUB_TOKEN label edits do not start issues:labeled workflows; dispatch is explicit. # Persist the completion marker only after a successful workflow_dispatch so a # failed run remains retryable on the next guard pass. diff --git a/.github/workflows/agents-issue-optimizer.yml b/.github/workflows/agents-issue-optimizer.yml index 382433d0a..f49fdab84 100644 --- a/.github/workflows/agents-issue-optimizer.yml +++ b/.github/workflows/agents-issue-optimizer.yml @@ -718,3 +718,14 @@ jobs: NODE echo "Labels updated: removed format, added formatted" fi + + - name: Release failed format lease + if: failure() && steps.check.outputs.should_run == 'true' && steps.check.outputs.phase == 'format' + env: + GH_TOKEN: ${{ github.token }} + ISSUE_NUMBER: ${{ steps.check.outputs.issue_number }} + run: | + set -euo pipefail + # A guard retry may proceed only after the failed format run releases its lease. + gh issue edit "$ISSUE_NUMBER" --remove-label "agents:format" \ + || echo "::warning::could not release failed agents:format lease" diff --git a/config/template-drift-allowlist.txt b/config/template-drift-allowlist.txt index 9f4b044aa..da6f42cb0 100644 --- a/config/template-drift-allowlist.txt +++ b/config/template-drift-allowlist.txt @@ -113,9 +113,9 @@ reason = Intentional divergence re-baselined 2026-06-30: root and consumer guard [pair.11] main = .github/workflows/agents-issue-optimizer.yml template = templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml -main_sha256 = f3f6c4a885ff989c27de1ac032da092d4bc56dfa82f4c65e15624aa7b4273601 -template_sha256 = 617ff055673ec97fac8eaf9adf14630622ccb2ab8f45dfb651fd5ef725f29e20 -reason = Intentional divergence re-baselined 2026-08-08: root and consumer issue-optimizer workflows keep different auth plumbing/action pin surfaces. Both validate format output with python3 before adding agents:formatted; the consumer explicitly sparse-checks out .github/scripts/issue_format.py plus config/scripts/langchain/tools from Workflows, while root runs those files in-tree. Do not align wholesale because that would strip consumer action pins/token setup. +main_sha256 = 3ad86a30a866167dc78ec21150fc2dba475dc70b2504cfe3373906ed95a2502d +template_sha256 = 3f76718542ab27978fc819118a9e671a9f34439e388fa0ea6f0359937e7bbb57 +reason = Intentional divergence re-baselined 2026-08-08: root and consumer issue-optimizer workflows keep different auth plumbing/action pin surfaces. Both validate format output with python3, require the agents:format lease before dispatch, and release that lease on a failed format run; the consumer explicitly sparse-checks out .github/scripts/issue_format.py plus config/scripts/langchain/tools from Workflows, while root runs those files in-tree. Do not align wholesale because that would strip consumer action pins/token setup. [pair.12] main = .github/workflows/agents-keepalive-loop-reporter.yml diff --git a/templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml b/templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml index c734fb140..ff2515abf 100644 --- a/templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml +++ b/templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml @@ -161,8 +161,12 @@ jobs: if [[ "$dispatch" != true ]]; then exit 0 fi - gh issue edit "$NUMBER" --repo "$GITHUB_REPOSITORY" --add-label "agents:format" \ - || echo "::warning::could not apply agents:format (label missing in this repo?)" + # Acquiring the label is the handoff lease. Do not dispatch without it: + # otherwise a trusted marker alone could repeat the optimizer dispatch. + if ! gh issue edit "$NUMBER" --repo "$GITHUB_REPOSITORY" --add-label "agents:format"; then + echo "::error::could not acquire agents:format lease; refusing optimizer dispatch" + exit 1 + fi # GITHUB_TOKEN label edits do not start issues:labeled workflows; dispatch is explicit. # Persist the completion marker only after a successful workflow_dispatch so a # failed run remains retryable on the next guard pass. diff --git a/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml b/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml index 149696d7c..f9aea4acf 100644 --- a/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml +++ b/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml @@ -537,6 +537,17 @@ jobs: echo "Labels updated: removed format, added formatted" fi + - name: Release failed format lease + if: failure() && steps.check.outputs.should_run == 'true' && steps.check.outputs.phase == 'format' + env: + GH_TOKEN: ${{ steps.token.outputs.token || github.token }} + ISSUE_NUMBER: ${{ steps.check.outputs.issue_number }} + run: | + set -euo pipefail + # A guard retry may proceed only after the failed format run releases its lease. + gh issue edit "$ISSUE_NUMBER" --remove-label "agents:format" \ + || echo "::warning::could not release failed agents:format lease" + - name: Report workflow failure if: failure() env: diff --git a/tests/workflows/test_agents_issue_optimizer_format_trigger.py b/tests/workflows/test_agents_issue_optimizer_format_trigger.py index e75750713..282f50fe3 100644 --- a/tests/workflows/test_agents_issue_optimizer_format_trigger.py +++ b/tests/workflows/test_agents_issue_optimizer_format_trigger.py @@ -48,3 +48,21 @@ def test_format_guard_deduplicates_inflight_optimizer_dispatch() -> None: ).read_text(encoding="utf-8") assert "no completion marker written so later runs can retry" in consumer assert '"$trusted_marker" == true && "$has_format_label" == true' in consumer + + +def test_format_lease_is_required_and_released_after_failure() -> None: + guard = Path(".github/workflows/agents-issue-format-guard.yml").read_text(encoding="utf-8") + consumer_guard = Path( + "templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml" + ).read_text(encoding="utf-8") + for text in (guard, consumer_guard): + assert "could not acquire agents:format lease" in text + assert text.index("could not acquire agents:format lease") < text.index( + "gh workflow run agents-issue-optimizer.yml" + ) + consumer_optimizer = Path( + "templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml" + ).read_text(encoding="utf-8") + for text in (WORKFLOW_PATH.read_text(encoding="utf-8"), consumer_optimizer): + assert "Release failed format lease" in text + assert "failure() && steps.check.outputs.should_run == 'true'" in text From 1b121b75f8b48183f4e083a33f98d6fbe21fb980 Mon Sep 17 00:00:00 2001 From: Codex Automation Date: Sat, 8 Aug 2026 05:38:27 -0500 Subject: [PATCH 3/9] fix(agents): tighten format-guard trust and cancel-safe lease Require exact github-actions[bot] identity (id 41898282) for trusted markers, release agents:format on failure or cancellation, and harden format-trigger assertions for both workflow copies. Co-authored-by: Cursor --- .../workflows/agents-issue-format-guard.yml | 10 ++- .github/workflows/agents-issue-optimizer.yml | 2 +- .../workflows/agents-issue-format-guard.yml | 10 ++- .../workflows/agents-issue-optimizer.yml | 2 +- ...t_agents_issue_optimizer_format_trigger.py | 81 ++++++++++++------- 5 files changed, 66 insertions(+), 39 deletions(-) diff --git a/.github/workflows/agents-issue-format-guard.yml b/.github/workflows/agents-issue-format-guard.yml index ff2515abf..921206e22 100644 --- a/.github/workflows/agents-issue-format-guard.yml +++ b/.github/workflows/agents-issue-format-guard.yml @@ -132,10 +132,14 @@ jobs: fi fingerprint="$(sha256sum body.md | cut -c1-12)" marker="" - # Only trust exact HTML markers authored by automation bots (not user text). + # Only trust exact HTML markers authored by github-actions[bot] + # (immutable account id 41898282 when the REST payload includes user.id). trusted_marker=false - if gh issue view "$NUMBER" --repo "$GITHUB_REPOSITORY" --json comments \ - --jq '.comments[] | select((.author.login // "") | test("\\[bot\\]$|github-actions"; "i")) | .body' \ + if gh api "repos/${GITHUB_REPOSITORY}/issues/${NUMBER}/comments" \ + --jq '.[] | select( + (.user.login // "") == "github-actions[bot]" + and ((.user.id == null) or (.user.id == 41898282)) + ) | .body' \ | grep -qF "$marker"; then trusted_marker=true fi diff --git a/.github/workflows/agents-issue-optimizer.yml b/.github/workflows/agents-issue-optimizer.yml index f49fdab84..018fe295a 100644 --- a/.github/workflows/agents-issue-optimizer.yml +++ b/.github/workflows/agents-issue-optimizer.yml @@ -720,7 +720,7 @@ jobs: fi - name: Release failed format lease - if: failure() && steps.check.outputs.should_run == 'true' && steps.check.outputs.phase == 'format' + if: (failure() || cancelled()) && steps.check.outputs.should_run == 'true' && steps.check.outputs.phase == 'format' env: GH_TOKEN: ${{ github.token }} ISSUE_NUMBER: ${{ steps.check.outputs.issue_number }} diff --git a/templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml b/templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml index ff2515abf..921206e22 100644 --- a/templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml +++ b/templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml @@ -132,10 +132,14 @@ jobs: fi fingerprint="$(sha256sum body.md | cut -c1-12)" marker="" - # Only trust exact HTML markers authored by automation bots (not user text). + # Only trust exact HTML markers authored by github-actions[bot] + # (immutable account id 41898282 when the REST payload includes user.id). trusted_marker=false - if gh issue view "$NUMBER" --repo "$GITHUB_REPOSITORY" --json comments \ - --jq '.comments[] | select((.author.login // "") | test("\\[bot\\]$|github-actions"; "i")) | .body' \ + if gh api "repos/${GITHUB_REPOSITORY}/issues/${NUMBER}/comments" \ + --jq '.[] | select( + (.user.login // "") == "github-actions[bot]" + and ((.user.id == null) or (.user.id == 41898282)) + ) | .body' \ | grep -qF "$marker"; then trusted_marker=true fi diff --git a/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml b/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml index f9aea4acf..be6e87489 100644 --- a/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml +++ b/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml @@ -538,7 +538,7 @@ jobs: fi - name: Release failed format lease - if: failure() && steps.check.outputs.should_run == 'true' && steps.check.outputs.phase == 'format' + if: (failure() || cancelled()) && steps.check.outputs.should_run == 'true' && steps.check.outputs.phase == 'format' env: GH_TOKEN: ${{ steps.token.outputs.token || github.token }} ISSUE_NUMBER: ${{ steps.check.outputs.issue_number }} diff --git a/tests/workflows/test_agents_issue_optimizer_format_trigger.py b/tests/workflows/test_agents_issue_optimizer_format_trigger.py index 282f50fe3..fd1172617 100644 --- a/tests/workflows/test_agents_issue_optimizer_format_trigger.py +++ b/tests/workflows/test_agents_issue_optimizer_format_trigger.py @@ -3,6 +3,13 @@ import yaml WORKFLOW_PATH = Path(".github/workflows/agents-issue-optimizer.yml") +CONSUMER_WORKFLOW_PATH = Path( + "templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml" +) +GUARD_PATH = Path(".github/workflows/agents-issue-format-guard.yml") +CONSUMER_GUARD_PATH = Path( + "templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml" +) def _load_workflow() -> dict: @@ -26,43 +33,55 @@ def test_issue_optimizer_checks_for_format_label() -> None: def test_issue_optimizer_validates_format_and_apply_bodies() -> None: text = WORKFLOW_PATH.read_text(encoding="utf-8") - assert "issue_format.py /tmp/formatted_body.md" in text - assert "issue_format.py /tmp/updated_body.md" in text - consumer = Path("templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml") - consumer_text = consumer.read_text(encoding="utf-8") - assert "issue_format.py /tmp/formatted_body.md" in consumer_text - assert "issue_format.py /tmp/updated_body.md" in consumer_text - assert "python3 .github/scripts/issue_format.py" in text - assert "python3 workflows-scripts/.github/scripts/issue_format.py" in consumer_text + consumer_text = CONSUMER_WORKFLOW_PATH.read_text(encoding="utf-8") + assert "python3 .github/scripts/issue_format.py /tmp/formatted_body.md" in text + assert "python3 .github/scripts/issue_format.py /tmp/updated_body.md" in text + assert ( + "python3 workflows-scripts/.github/scripts/issue_format.py /tmp/formatted_body.md" + in consumer_text + ) + assert ( + "python3 workflows-scripts/.github/scripts/issue_format.py /tmp/updated_body.md" + in consumer_text + ) def test_format_guard_deduplicates_inflight_optimizer_dispatch() -> None: - guard = Path(".github/workflows/agents-issue-format-guard.yml").read_text(encoding="utf-8") - assert "Re-fetch before side effects" in guard - assert "no completion marker written so later runs can retry" in guard - assert 'marker=""' in guard - assert '"$trusted_marker" == true && "$has_format_label" == true' in guard - assert "already routed and in flight; skipping duplicate dispatch" in guard - consumer = Path( - "templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml" - ).read_text(encoding="utf-8") - assert "no completion marker written so later runs can retry" in consumer - assert '"$trusted_marker" == true && "$has_format_label" == true' in consumer + guard = GUARD_PATH.read_text(encoding="utf-8") + consumer = CONSUMER_GUARD_PATH.read_text(encoding="utf-8") + for text in (guard, consumer): + assert "Re-fetch before side effects" in text + assert "no completion marker written so later runs can retry" in text + assert 'marker=""' in text + assert '(.user.login // "") == "github-actions[bot]"' in text + assert "(.user.id == null) or (.user.id == 41898282)" in text + assert '"$trusted_marker" == true && "$has_format_label" == true' in text + assert "already routed and in flight; skipping duplicate dispatch" in text + # Trusted marker is written only after a successful workflow_dispatch. + assert text.index("gh workflow run agents-issue-optimizer.yml") < text.index( + 'echo "$marker"' + ) def test_format_lease_is_required_and_released_after_failure() -> None: - guard = Path(".github/workflows/agents-issue-format-guard.yml").read_text(encoding="utf-8") - consumer_guard = Path( - "templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml" - ).read_text(encoding="utf-8") + guard = GUARD_PATH.read_text(encoding="utf-8") + consumer_guard = CONSUMER_GUARD_PATH.read_text(encoding="utf-8") for text in (guard, consumer_guard): assert "could not acquire agents:format lease" in text - assert text.index("could not acquire agents:format lease") < text.index( - "gh workflow run agents-issue-optimizer.yml" - ) - consumer_optimizer = Path( - "templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml" - ).read_text(encoding="utf-8") - for text in (WORKFLOW_PATH.read_text(encoding="utf-8"), consumer_optimizer): + lease_idx = text.index("could not acquire agents:format lease") + dispatch_idx = text.index("gh workflow run agents-issue-optimizer.yml") + assert lease_idx < dispatch_idx + assert "exit 1" in text[lease_idx:dispatch_idx] + # Dispatch must stay inside the success path after lease acquisition. + assert "--add-label \"agents:format\"" in text[:dispatch_idx] + + for text in ( + WORKFLOW_PATH.read_text(encoding="utf-8"), + CONSUMER_WORKFLOW_PATH.read_text(encoding="utf-8"), + ): assert "Release failed format lease" in text - assert "failure() && steps.check.outputs.should_run == 'true'" in text + assert ( + "(failure() || cancelled()) && steps.check.outputs.should_run == 'true' " + "&& steps.check.outputs.phase == 'format'" + ) in text + assert 'gh issue edit "$ISSUE_NUMBER" --remove-label "agents:format"' in text From f5f677d55f133cdc562571b784b0a91c8e2052c8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 8 Aug 2026 10:43:40 +0000 Subject: [PATCH 4/9] chore(autofix): formatting/lint --- tests/workflows/test_agents_issue_optimizer_format_trigger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/workflows/test_agents_issue_optimizer_format_trigger.py b/tests/workflows/test_agents_issue_optimizer_format_trigger.py index fd1172617..d891f57b1 100644 --- a/tests/workflows/test_agents_issue_optimizer_format_trigger.py +++ b/tests/workflows/test_agents_issue_optimizer_format_trigger.py @@ -73,7 +73,7 @@ def test_format_lease_is_required_and_released_after_failure() -> None: assert lease_idx < dispatch_idx assert "exit 1" in text[lease_idx:dispatch_idx] # Dispatch must stay inside the success path after lease acquisition. - assert "--add-label \"agents:format\"" in text[:dispatch_idx] + assert '--add-label "agents:format"' in text[:dispatch_idx] for text in ( WORKFLOW_PATH.read_text(encoding="utf-8"), From b7f8e7fc7057d99287bfe3a3d9f8c940e11fc50c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 8 Aug 2026 10:44:26 +0000 Subject: [PATCH 5/9] chore(codex-autofix): apply updates (PR #2981) --- langsmith-fleet-worker-attempt.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/langsmith-fleet-worker-attempt.json b/langsmith-fleet-worker-attempt.json index 51f4e9cbe..e3061d62d 100644 --- a/langsmith-fleet-worker-attempt.json +++ b/langsmith-fleet-worker-attempt.json @@ -1,13 +1,13 @@ { "agent": "codex", "cli_version": "0.144.1", - "emitted_at": "2026-08-08T05:39:15.569084Z", + "emitted_at": "2026-08-08T10:44:25.864057Z", "execution_profile": "codex-default", "fallback_models": [ "gpt-5.5" ], "operation_role": "worker", - "pr_number": "2982", + "pr_number": "2981", "requested_model": "gpt-5.6-terra", "runner": "reusable-codex-run", "schema": "langsmith-fleet/v1", From 1391adfac8f0d6fd8b7972ec4f643981e64e0d8c Mon Sep 17 00:00:00 2001 From: Codex Automation Date: Sat, 8 Aug 2026 06:26:03 -0500 Subject: [PATCH 6/9] fix(agents): paginate format guard comments safely --- .../workflows/agents-issue-format-guard.yml | 45 +- .../workflows/agents-issue-format-guard.yml | 45 +- .../workflows/agents-issue-optimizer.yml | 435 ++++++++++++------ ...t_agents_issue_optimizer_format_trigger.py | 18 +- 4 files changed, 377 insertions(+), 166 deletions(-) diff --git a/.github/workflows/agents-issue-format-guard.yml b/.github/workflows/agents-issue-format-guard.yml index 921206e22..b39c66c26 100644 --- a/.github/workflows/agents-issue-format-guard.yml +++ b/.github/workflows/agents-issue-format-guard.yml @@ -39,6 +39,12 @@ jobs: with: persist-credentials: false + - name: Setup API client + uses: ./.github/actions/setup-api-client + with: + secrets: ${{ toJSON(secrets) }} + github_token: ${{ github.token }} + - name: Resolve issue id: issue env: @@ -134,15 +140,36 @@ jobs: marker="" # Only trust exact HTML markers authored by github-actions[bot] # (immutable account id 41898282 when the REST payload includes user.id). - trusted_marker=false - if gh api "repos/${GITHUB_REPOSITORY}/issues/${NUMBER}/comments" \ - --jq '.[] | select( - (.user.login // "") == "github-actions[bot]" - and ((.user.id == null) or (.user.id == 41898282)) - ) | .body' \ - | grep -qF "$marker"; then - trusted_marker=true - fi + trusted_marker="$(FORMAT_GUARD_MARKER="$marker" node - <<'NODE' + (async () => { + const { Octokit } = require('@octokit/rest'); + const { createTokenAwareRetry } = require('./.github/scripts/github-api-with-retry.js'); + const github = new Octokit({ auth: process.env.GH_TOKEN }); + const core = { info: () => {}, warning: console.warn, debug: () => {} }; + const { paginateWithRetry } = await createTokenAwareRetry({ + github, + core, + env: process.env, + task: 'issue-format-guard', + capabilities: ['issues:read'], + }); + const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); + const comments = await paginateWithRetry( + github.rest.issues.listComments, + { owner, repo, issue_number: Number(process.env.NUMBER), per_page: 100 } + ); + const trusted = comments.some((comment) => + comment.user?.login === 'github-actions[bot]' + && (comment.user?.id == null || comment.user.id === 41898282) + && (comment.body || '').includes(process.env.FORMAT_GUARD_MARKER) + ); + process.stdout.write(trusted ? 'true' : 'false'); + })().catch((error) => { + console.error(error); + process.exit(1); + }); + NODE + )" has_format_label=false if jq -e '[.labels[].name] | any(. == "agents:format")' live.json >/dev/null; then has_format_label=true diff --git a/templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml b/templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml index 921206e22..b39c66c26 100644 --- a/templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml +++ b/templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml @@ -39,6 +39,12 @@ jobs: with: persist-credentials: false + - name: Setup API client + uses: ./.github/actions/setup-api-client + with: + secrets: ${{ toJSON(secrets) }} + github_token: ${{ github.token }} + - name: Resolve issue id: issue env: @@ -134,15 +140,36 @@ jobs: marker="" # Only trust exact HTML markers authored by github-actions[bot] # (immutable account id 41898282 when the REST payload includes user.id). - trusted_marker=false - if gh api "repos/${GITHUB_REPOSITORY}/issues/${NUMBER}/comments" \ - --jq '.[] | select( - (.user.login // "") == "github-actions[bot]" - and ((.user.id == null) or (.user.id == 41898282)) - ) | .body' \ - | grep -qF "$marker"; then - trusted_marker=true - fi + trusted_marker="$(FORMAT_GUARD_MARKER="$marker" node - <<'NODE' + (async () => { + const { Octokit } = require('@octokit/rest'); + const { createTokenAwareRetry } = require('./.github/scripts/github-api-with-retry.js'); + const github = new Octokit({ auth: process.env.GH_TOKEN }); + const core = { info: () => {}, warning: console.warn, debug: () => {} }; + const { paginateWithRetry } = await createTokenAwareRetry({ + github, + core, + env: process.env, + task: 'issue-format-guard', + capabilities: ['issues:read'], + }); + const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); + const comments = await paginateWithRetry( + github.rest.issues.listComments, + { owner, repo, issue_number: Number(process.env.NUMBER), per_page: 100 } + ); + const trusted = comments.some((comment) => + comment.user?.login === 'github-actions[bot]' + && (comment.user?.id == null || comment.user.id === 41898282) + && (comment.body || '').includes(process.env.FORMAT_GUARD_MARKER) + ); + process.stdout.write(trusted ? 'true' : 'false'); + })().catch((error) => { + console.error(error); + process.exit(1); + }); + NODE + )" has_format_label=false if jq -e '[.labels[].name] | any(. == "agents:format")' live.json >/dev/null; then has_format_label=true diff --git a/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml b/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml index be6e87489..018fe295a 100644 --- a/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml +++ b/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml @@ -18,6 +18,13 @@ on: - apply - format +concurrency: + group: >- + agents-issue-optimizer-${{ + github.repository }}-${{ + github.event.issue.number || github.run_id }} + cancel-in-progress: false + jobs: optimize_issue: runs-on: ubuntu-latest @@ -89,55 +96,29 @@ jobs: echo "should_run=false" >> "$GITHUB_OUTPUT" fi - - name: Generate App Token - id: app_token - if: steps.check.outputs.should_run == 'true' - continue-on-error: true - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3 - with: - app-id: ${{ secrets.WORKFLOWS_APP_ID }} - private-key: ${{ secrets.WORKFLOWS_APP_PRIVATE_KEY }} - - - name: Select Token - id: token - if: steps.check.outputs.should_run == 'true' - env: - APP_TOKEN: ${{ steps.app_token.outputs.token }} - GITHUB_TOKEN_FALLBACK: ${{ github.token }} - run: | - if [ -n "$APP_TOKEN" ]; then - echo "Using GitHub App token (5000/hr pool)" - echo "token=$APP_TOKEN" >> "$GITHUB_OUTPUT" - echo "source=app" >> "$GITHUB_OUTPUT" - else - echo "Falling back to GITHUB_TOKEN (1000/hr shared pool)" - echo "token=$GITHUB_TOKEN_FALLBACK" >> "$GITHUB_OUTPUT" - echo "source=github_token" >> "$GITHUB_OUTPUT" - fi - - name: Checkout repository if: steps.check.outputs.should_run == 'true' uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Checkout Workflows repository for scripts + - name: Set up Node.js if: steps.check.outputs.should_run == 'true' - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 with: - repository: stranske/Workflows - path: workflows-scripts - sparse-checkout: | - .github/scripts/issue_format.py - config - scripts/langchain - tools - sparse-checkout-cone-mode: false + node-version: 24 + + - name: Install load balancer dependencies + if: steps.check.outputs.should_run == 'true' + run: | + set -euo pipefail + npm install --no-save --no-package-lock @octokit/rest @octokit/auth-app - name: Setup API client if: steps.check.outputs.should_run == 'true' uses: ./.github/actions/setup-api-client with: secrets: ${{ toJSON(secrets) }} - github_token: ${{ steps.token.outputs.token }} + github_token: ${{ github.token }} + - name: Set up Python if: steps.check.outputs.should_run == 'true' @@ -149,13 +130,13 @@ jobs: if: steps.check.outputs.should_run == 'true' run: | python -m pip install --upgrade pip - python -m pip install -r workflows-scripts/tools/requirements-llm.txt + python -m pip install -r tools/requirements-llm.txt - name: Check optimizer recursion guard if: steps.check.outputs.should_run == 'true' id: recursion_guard env: - GH_TOKEN: ${{ steps.token.outputs.token }} + GH_TOKEN: ${{ github.token }} ISSUE_NUMBER: ${{ steps.check.outputs.issue_number }} run: | # Check how many optimizer runs for this issue in last hour @@ -217,29 +198,38 @@ jobs: if: steps.check.outputs.should_run == 'true' id: get_issue env: - GH_TOKEN: ${{ steps.token.outputs.token }} + GH_TOKEN: ${{ github.token }} ISSUE_NUMBER: ${{ steps.check.outputs.issue_number }} - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 - with: - github-token: ${{ steps.token.outputs.token }} - script: | + run: | + node - <<'NODE' + (async () => { const fs = require('fs'); + const { Octokit } = require('@octokit/rest'); const { createTokenAwareRetry } = require('./.github/scripts/github-api-with-retry.js'); - const { github: retryGithub, withRetry } = await createTokenAwareRetry({ + const core = { info: () => {}, warning: console.warn, debug: () => {} }; + const github = new Octokit({ auth: process.env.GITHUB_TOKEN }); + const { withRetry } = await createTokenAwareRetry({ github, core, env: process.env, task: 'issue-optimizer', capabilities: ['issues:read'], }); + const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); const issueNumber = Number(process.env.ISSUE_NUMBER); - const { owner, repo } = context.repo; - const { data } = await withRetry((client) => - client.rest.issues.get({ owner, repo, issue_number: issueNumber }) - ); + const { data } = await withRetry((client) => client.rest.issues.get({ + owner, + repo, + issue_number: issueNumber, + })); fs.writeFileSync('/tmp/issue.json', JSON.stringify(data, null, 2)); fs.writeFileSync('/tmp/issue_body.md', data.body || ''); - core.info('Issue body saved to /tmp/issue_body.md'); + console.log('Issue body saved to /tmp/issue_body.md'); + })().catch((error) => { + console.error(error); + process.exit(1); + }); + NODE - name: Phase 1 - Analyze Issue if: steps.check.outputs.should_run == 'true' && steps.check.outputs.phase == 'analyze' @@ -251,10 +241,11 @@ jobs: CLAUDE_API_STRANSKE: ${{ secrets.CLAUDE_API_STRANSKE }} LANGCHAIN_PROVIDER: anthropic LANGCHAIN_MODEL: claude-sonnet-4-5-20250929 - PYTHONPATH: ${{ github.workspace }}/workflows-scripts + PYTHONPATH: ${{ github.workspace }} + ISSUE_PR_CONTEXT_WORKFLOW: agents-issue-optimizer run: | echo "Running analysis on issue #${ISSUE_NUMBER}" - python workflows-scripts/scripts/langchain/issue_optimizer.py \ + python scripts/langchain/issue_optimizer.py \ --input-file /tmp/issue_body.md \ --json > /tmp/suggestions.json @@ -262,7 +253,7 @@ jobs: python -c " import json import sys - sys.path.insert(0, 'workflows-scripts/scripts/langchain') + sys.path.insert(0, 'scripts/langchain') from issue_optimizer import IssueOptimizationResult, format_suggestions_comment with open('/tmp/suggestions.json') as f: @@ -287,34 +278,57 @@ jobs: } # Post comment - gh issue comment "${ISSUE_NUMBER}" --body-file /tmp/comment.md + node - <<'NODE' + (async () => { + const fs = require('fs'); + const { Octokit } = require('@octokit/rest'); + const { createTokenAwareRetry } = require('./.github/scripts/github-api-with-retry.js'); + const core = { info: () => {}, warning: console.warn, debug: () => {} }; + const github = new Octokit({ auth: process.env.GITHUB_TOKEN }); + const { withRetry } = await createTokenAwareRetry({ + github, + core, + env: process.env, + task: 'issue-optimizer', + capabilities: ['issues:write'], + }); + const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); + const issueNumber = Number(process.env.ISSUE_NUMBER); + const body = fs.readFileSync('/tmp/comment.md', 'utf8'); + await withRetry((client) => client.rest.issues.createComment({ + owner, + repo, + issue_number: issueNumber, + body, + })); + })().catch((error) => { + console.error(error); + process.exit(1); + }); + NODE - echo "Analysis complete." - echo "Review suggestions and add 'agents:apply-suggestions' label to apply." + echo "Analysis complete. Review suggestions" \ + "and add 'agents:apply-suggestions'" \ + "label to apply." - name: Advisory issue dedup check if: steps.check.outputs.should_run == 'true' && steps.check.outputs.phase == 'analyze' env: - GH_TOKEN: ${{ steps.token.outputs.token }} + GH_TOKEN: ${{ github.token }} ISSUE_NUMBER: ${{ steps.check.outputs.issue_number }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} CLAUDE_API_STRANSKE: ${{ secrets.CLAUDE_API_STRANSKE }} - PYTHONPATH: ${{ github.workspace }}/workflows-scripts + PYTHONPATH: ${{ github.workspace }} run: | echo "Checking for potential duplicate issues (advisory)" - node - <<'NODE' - const fs = require('fs'); - const { Octokit } = require('@octokit/rest'); - const { createTokenAwareRetry } = require('./.github/scripts/github-api-with-retry.js'); - - const issueNumber = Number(process.env.ISSUE_NUMBER); - const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); - const github = new Octokit({ auth: process.env.GH_TOKEN }); - const core = { info: console.log, warning: console.warn, debug: () => {} }; - (async () => { + const fs = require('fs'); + const { Octokit } = require('@octokit/rest'); + const { createTokenAwareRetry } = require('./.github/scripts/github-api-with-retry.js'); + const core = { info: () => {}, warning: console.warn, debug: () => {} }; + const github = new Octokit({ auth: process.env.GITHUB_TOKEN }); const { paginateWithRetry } = await createTokenAwareRetry({ github, core, @@ -322,17 +336,16 @@ jobs: task: 'issue-optimizer', capabilities: ['issues:read'], }); - + const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); + const issueNumber = Number(process.env.ISSUE_NUMBER); const openIssues = await paginateWithRetry( github.rest.issues.listForRepo, { owner, repo, state: 'open', per_page: 100 } ); - const comments = await paginateWithRetry( github.rest.issues.listComments, { owner, repo, issue_number: issueNumber, per_page: 100 } ); - fs.writeFileSync('/tmp/open_issues.json', JSON.stringify(openIssues, null, 2)); fs.writeFileSync('/tmp/dedup_comments.json', JSON.stringify(comments, null, 2)); })().catch((error) => { @@ -343,44 +356,74 @@ jobs: python - <<'PY' || true import json - import sys - sys.path.insert(0, 'workflows-scripts/scripts/langchain') - import issue_dedup + from scripts.langchain import issue_dedup with open('/tmp/issue.json', encoding='utf-8') as f: issue = json.load(f) with open('/tmp/open_issues.json', encoding='utf-8') as f: open_issues = json.load(f) with open('/tmp/dedup_comments.json', encoding='utf-8') as f: - comments = json.load(f) + comments = json.load(f) marker = issue_dedup.SIMILAR_ISSUES_MARKER for comment in comments or []: - body = (comment or {}).get('body') or '' - if marker in body: - raise SystemExit(0) + body = (comment or {}).get('body') or '' + if marker in body: + raise SystemExit(0) # Conservative defaults; can be tuned later. threshold = 0.82 store = issue_dedup.build_issue_vector_store(open_issues) if store is None: - raise SystemExit(0) + raise SystemExit(0) title = (issue.get('title') or '').strip() body = (issue.get('body') or '').strip() query = f"{title}\n{body}".strip() if body else title if not query: - raise SystemExit(0) + raise SystemExit(0) matches = issue_dedup.find_similar_issues(store, query, threshold=threshold, k=5) comment = issue_dedup.format_similar_issues_comment(matches, max_items=5) if comment: - with open('/tmp/dedup_comment.md', 'w', encoding='utf-8') as out: - out.write(comment) + with open('/tmp/dedup_comment.md', 'w', encoding='utf-8') as out: + out.write(comment) PY if [[ -f /tmp/dedup_comment.md ]]; then - gh issue comment "${ISSUE_NUMBER}" --body-file /tmp/dedup_comment.md || true + node - <<'NODE' + (async () => { + const fs = require('fs'); + const { Octokit } = require('@octokit/rest'); + const { createTokenAwareRetry } = + require('./.github/scripts/github-api-with-retry.js'); + const core = { info: () => {}, warning: console.warn, debug: () => {} }; + const github = new Octokit({ auth: process.env.GITHUB_TOKEN }); + const { withRetry } = await createTokenAwareRetry({ + github, + core, + env: process.env, + task: 'issue-optimizer', + capabilities: ['issues:write'], + }); + const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); + const issueNumber = Number(process.env.ISSUE_NUMBER); + const body = fs.readFileSync('/tmp/dedup_comment.md', 'utf8'); + try { + await withRetry((client) => client.rest.issues.createComment({ + owner, + repo, + issue_number: issueNumber, + body, + })); + } catch (error) { + console.warn(`Dedup comment failed: ${error.message}`); + } + })().catch((error) => { + console.error(error); + process.exit(1); + }); + NODE else echo "No likely duplicates detected." fi @@ -390,27 +433,25 @@ jobs: id: apply env: ISSUE_NUMBER: ${{ steps.check.outputs.issue_number }} - GH_TOKEN: ${{ steps.token.outputs.token }} + GH_TOKEN: ${{ github.token }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} CLAUDE_API_STRANSKE: ${{ secrets.CLAUDE_API_STRANSKE }} LANGCHAIN_PROVIDER: anthropic LANGCHAIN_MODEL: claude-sonnet-4-5-20250929 - PYTHONPATH: ${{ github.workspace }}/workflows-scripts + PYTHONPATH: ${{ github.workspace }} + ISSUE_PR_CONTEXT_WORKFLOW: agents-issue-optimizer run: | echo "Extracting suggestions from comments on issue #${ISSUE_NUMBER}" + # Get all comments and find the one with suggestions JSON node - <<'NODE' - const fs = require('fs'); - const { Octokit } = require('@octokit/rest'); - const { createTokenAwareRetry } = require('./.github/scripts/github-api-with-retry.js'); - - const issueNumber = Number(process.env.ISSUE_NUMBER); - const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); - const github = new Octokit({ auth: process.env.GH_TOKEN }); - const core = { info: console.log, warning: console.warn, debug: () => {} }; - (async () => { + const fs = require('fs'); + const { Octokit } = require('@octokit/rest'); + const { createTokenAwareRetry } = require('./.github/scripts/github-api-with-retry.js'); + const core = { info: () => {}, warning: console.warn, debug: () => {} }; + const github = new Octokit({ auth: process.env.GITHUB_TOKEN }); const { paginateWithRetry } = await createTokenAwareRetry({ github, core, @@ -418,12 +459,12 @@ jobs: task: 'issue-optimizer', capabilities: ['issues:read'], }); - + const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); + const issueNumber = Number(process.env.ISSUE_NUMBER); const comments = await paginateWithRetry( github.rest.issues.listComments, { owner, repo, issue_number: issueNumber, per_page: 100 } ); - fs.writeFileSync('/tmp/comments.json', JSON.stringify(comments, null, 2)); })().catch((error) => { console.error(error); @@ -436,7 +477,7 @@ jobs: import json import sys import re - sys.path.insert(0, 'workflows-scripts/scripts/langchain') + sys.path.insert(0, 'scripts/langchain') from issue_optimizer import _extract_suggestions_json, apply_suggestions with open('/tmp/comments.json') as f: @@ -467,11 +508,39 @@ jobs: print('Suggestions applied successfully') " || exit 1 - # Keep agents:formatted truthful for apply-phase output too. - python3 workflows-scripts/.github/scripts/issue_format.py /tmp/updated_body.md + # Do not publish agents:formatted for apply-phase output that fails + # the same fleet contract enforced by the issue-event guard. + python3 .github/scripts/issue_format.py /tmp/updated_body.md # Update issue body - gh issue edit "${ISSUE_NUMBER}" --body-file /tmp/updated_body.md + node - <<'NODE' + (async () => { + const fs = require('fs'); + const { Octokit } = require('@octokit/rest'); + const { createTokenAwareRetry } = require('./.github/scripts/github-api-with-retry.js'); + const core = { info: () => {}, warning: console.warn, debug: () => {} }; + const github = new Octokit({ auth: process.env.GITHUB_TOKEN }); + const { withRetry } = await createTokenAwareRetry({ + github, + core, + env: process.env, + task: 'issue-optimizer', + capabilities: ['issues:write'], + }); + const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); + const issueNumber = Number(process.env.ISSUE_NUMBER); + const body = fs.readFileSync('/tmp/updated_body.md', 'utf8'); + await withRetry((client) => client.rest.issues.update({ + owner, + repo, + issue_number: issueNumber, + body, + })); + })().catch((error) => { + console.error(error); + process.exit(1); + }); + NODE echo "Issue body updated with applied suggestions" @@ -480,16 +549,17 @@ jobs: id: format env: ISSUE_NUMBER: ${{ steps.check.outputs.issue_number }} - GH_TOKEN: ${{ steps.token.outputs.token }} + GH_TOKEN: ${{ github.token }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} CLAUDE_API_STRANSKE: ${{ secrets.CLAUDE_API_STRANSKE }} - PYTHONPATH: ${{ github.workspace }}/workflows-scripts + PYTHONPATH: ${{ github.workspace }} + ISSUE_PR_CONTEXT_WORKFLOW: agents-issue-optimizer run: | echo "Formatting issue #${ISSUE_NUMBER} into AGENT_ISSUE_TEMPLATE structure" # Format the issue using issue_formatter.py - python workflows-scripts/scripts/langchain/issue_formatter.py \ + python scripts/langchain/issue_formatter.py \ --input-file /tmp/issue_body.md \ --json > /tmp/format_result.json @@ -508,65 +578,154 @@ jobs: print('Issue formatted successfully') " || exit 1 - # Keep the format-result label truthful: the generated issue must - # pass the canonical Workflows validator before it can be marked - # agents:formatted below. - python3 workflows-scripts/.github/scripts/issue_format.py /tmp/formatted_body.md + # Do not advertise a formatted issue until it satisfies the same + # fleet contract enforced by the issue-event guard. + python3 .github/scripts/issue_format.py /tmp/formatted_body.md # Update issue body with formatted version - gh issue edit "${ISSUE_NUMBER}" --body-file /tmp/formatted_body.md + node - <<'NODE' + (async () => { + const fs = require('fs'); + const { Octokit } = require('@octokit/rest'); + const { createTokenAwareRetry } = require('./.github/scripts/github-api-with-retry.js'); + const core = { info: () => {}, warning: console.warn, debug: () => {} }; + const github = new Octokit({ auth: process.env.GITHUB_TOKEN }); + const { withRetry } = await createTokenAwareRetry({ + github, + core, + env: process.env, + task: 'issue-optimizer', + capabilities: ['issues:write'], + }); + const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); + const issueNumber = Number(process.env.ISSUE_NUMBER); + const body = fs.readFileSync('/tmp/formatted_body.md', 'utf8'); + await withRetry((client) => client.rest.issues.update({ + owner, + repo, + issue_number: issueNumber, + body, + })); + })().catch((error) => { + console.error(error); + process.exit(1); + }); + NODE echo "Issue body updated with formatted structure" - name: Manage labels if: steps.check.outputs.should_run == 'true' env: - GH_TOKEN: ${{ steps.token.outputs.token || github.token }} + GH_TOKEN: ${{ github.token }} ISSUE_NUMBER: ${{ steps.check.outputs.issue_number }} PHASE: ${{ steps.check.outputs.phase }} run: | if [[ "$PHASE" == "apply" ]]; then - # Only remove agents:optimize, keep agents:apply-suggestions for state tracking - gh issue edit "${ISSUE_NUMBER}" --remove-label "agents:optimize" || true - gh issue edit "${ISSUE_NUMBER}" --add-label "agents:formatted" + # Remove optimization label but keep apply-suggestions (used for state tracking) + node - <<'NODE' + (async () => { + const { Octokit } = require('@octokit/rest'); + const { createTokenAwareRetry } = + require('./.github/scripts/github-api-with-retry.js'); + const core = { info: () => {}, warning: console.warn, debug: () => {} }; + const github = new Octokit({ auth: process.env.GITHUB_TOKEN }); + const { withRetry } = await createTokenAwareRetry({ + github, + core, + env: process.env, + task: 'issue-optimizer', + capabilities: ['issues:write'], + }); + const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); + const issueNumber = Number(process.env.ISSUE_NUMBER); + // Only remove agents:optimize, keep agents:apply-suggestions for next steps + const labelsToRemove = ['agents:optimize']; + for (const label of labelsToRemove) { + try { + await withRetry((client) => client.rest.issues.removeLabel({ + owner, + repo, + issue_number: issueNumber, + name: label, + })); + } catch (error) { + if (!String(error.message || '').includes('Label does not exist')) { + console.warn(`Failed to remove label ${label}: ${error.message}`); + } + } + } + try { + await withRetry((client) => client.rest.issues.addLabels({ + owner, + repo, + issue_number: issueNumber, + labels: ['agents:formatted'], + })); + } catch (error) { + console.warn(`Failed to add formatted label: ${error.message}`); + } + })().catch((error) => { + console.error(error); + process.exit(1); + }); + NODE echo "Labels updated: removed optimize, kept apply-suggestions for state tracking" elif [[ "$PHASE" == "format" ]]; then # Remove format trigger label and add formatted result label - gh issue edit "${ISSUE_NUMBER}" --remove-label "agents:format" - gh issue edit "${ISSUE_NUMBER}" --add-label "agents:formatted" + node - <<'NODE' + (async () => { + const { Octokit } = require('@octokit/rest'); + const { createTokenAwareRetry } = + require('./.github/scripts/github-api-with-retry.js'); + const core = { info: () => {}, warning: console.warn, debug: () => {} }; + const github = new Octokit({ auth: process.env.GITHUB_TOKEN }); + const { withRetry } = await createTokenAwareRetry({ + github, + core, + env: process.env, + task: 'issue-optimizer', + capabilities: ['issues:write'], + }); + const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); + const issueNumber = Number(process.env.ISSUE_NUMBER); + try { + await withRetry((client) => client.rest.issues.removeLabel({ + owner, + repo, + issue_number: issueNumber, + name: 'agents:format', + })); + } catch (error) { + if (!String(error.message || '').includes('Label does not exist')) { + console.warn(`Failed to remove format label: ${error.message}`); + } + } + try { + await withRetry((client) => client.rest.issues.addLabels({ + owner, + repo, + issue_number: issueNumber, + labels: ['agents:formatted'], + })); + } catch (error) { + console.warn(`Failed to add formatted label: ${error.message}`); + } + })().catch((error) => { + console.error(error); + process.exit(1); + }); + NODE echo "Labels updated: removed format, added formatted" fi - name: Release failed format lease if: (failure() || cancelled()) && steps.check.outputs.should_run == 'true' && steps.check.outputs.phase == 'format' env: - GH_TOKEN: ${{ steps.token.outputs.token || github.token }} + GH_TOKEN: ${{ github.token }} ISSUE_NUMBER: ${{ steps.check.outputs.issue_number }} run: | set -euo pipefail # A guard retry may proceed only after the failed format run releases its lease. gh issue edit "$ISSUE_NUMBER" --remove-label "agents:format" \ || echo "::warning::could not release failed agents:format lease" - - - name: Report workflow failure - if: failure() - env: - GH_TOKEN: ${{ steps.token.outputs.token || github.token }} - ISSUE_NUMBER: ${{ steps.check.outputs.issue_number }} - RUN_URL: >- - ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - run: | - if [ -n "${ISSUE_NUMBER}" ]; then - body=$(cat <<'COMMENT' - ⚠️ **Workflow failed** - - The agents-issue-optimizer workflow encountered an error. - - **Details**: [View workflow run](RUN_URL_PLACEHOLDER) - - Please check the logs and retry if needed. - COMMENT - ) - body="${body//RUN_URL_PLACEHOLDER/${RUN_URL}}" - gh issue comment "${ISSUE_NUMBER}" --body "$body" || true - fi diff --git a/tests/workflows/test_agents_issue_optimizer_format_trigger.py b/tests/workflows/test_agents_issue_optimizer_format_trigger.py index d891f57b1..a17723b51 100644 --- a/tests/workflows/test_agents_issue_optimizer_format_trigger.py +++ b/tests/workflows/test_agents_issue_optimizer_format_trigger.py @@ -36,14 +36,8 @@ def test_issue_optimizer_validates_format_and_apply_bodies() -> None: consumer_text = CONSUMER_WORKFLOW_PATH.read_text(encoding="utf-8") assert "python3 .github/scripts/issue_format.py /tmp/formatted_body.md" in text assert "python3 .github/scripts/issue_format.py /tmp/updated_body.md" in text - assert ( - "python3 workflows-scripts/.github/scripts/issue_format.py /tmp/formatted_body.md" - in consumer_text - ) - assert ( - "python3 workflows-scripts/.github/scripts/issue_format.py /tmp/updated_body.md" - in consumer_text - ) + assert "python3 .github/scripts/issue_format.py /tmp/formatted_body.md" in consumer_text + assert "python3 .github/scripts/issue_format.py /tmp/updated_body.md" in consumer_text def test_format_guard_deduplicates_inflight_optimizer_dispatch() -> None: @@ -53,8 +47,12 @@ def test_format_guard_deduplicates_inflight_optimizer_dispatch() -> None: assert "Re-fetch before side effects" in text assert "no completion marker written so later runs can retry" in text assert 'marker=""' in text - assert '(.user.login // "") == "github-actions[bot]"' in text - assert "(.user.id == null) or (.user.id == 41898282)" in text + assert "comment.user?.login === 'github-actions[bot]'" in text + assert "comment.user?.id == null || comment.user.id === 41898282" in text + assert "createTokenAwareRetry" in text + assert "paginateWithRetry" in text + assert "github.rest.issues.listComments" in text + assert "per_page: 100" in text assert '"$trusted_marker" == true && "$has_format_label" == true' in text assert "already routed and in flight; skipping duplicate dispatch" in text # Trusted marker is written only after a successful workflow_dispatch. From 70c8340078a039cede5f94796827b604188f5f64 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 8 Aug 2026 11:32:34 +0000 Subject: [PATCH 7/9] chore(codex-autofix): apply updates (PR #2981) --- langsmith-fleet-worker-attempt.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/langsmith-fleet-worker-attempt.json b/langsmith-fleet-worker-attempt.json index e3061d62d..336c7a2e8 100644 --- a/langsmith-fleet-worker-attempt.json +++ b/langsmith-fleet-worker-attempt.json @@ -1,7 +1,7 @@ { "agent": "codex", "cli_version": "0.144.1", - "emitted_at": "2026-08-08T10:44:25.864057Z", + "emitted_at": "2026-08-08T11:32:33.483036Z", "execution_profile": "codex-default", "fallback_models": [ "gpt-5.5" From 30908dfcbe37c9c65e0c4a7062621bfb8ee45eec Mon Sep 17 00:00:00 2001 From: Codex Automation Date: Sat, 8 Aug 2026 06:39:43 -0500 Subject: [PATCH 8/9] fix(agents): restore consumer optimizer and harden format dedupe Restore the consumer issue-optimizer sparse-checkout contract after a root-copy sync broke LLM-client discovery, and share concurrency, cancel-safe lease release, dedup indentation, and stderr retry logging. Co-authored-by: Cursor --- .github/scripts/github-api-with-retry.js | 4 +- .github/workflows/agents-issue-optimizer.yml | 41 +- config/template-drift-allowlist.txt | 6 +- .../.github/scripts/github-api-with-retry.js | 4 +- .../workflows/agents-issue-optimizer.yml | 448 ++++++------------ ...t_agents_issue_optimizer_format_trigger.py | 11 +- 6 files changed, 186 insertions(+), 328 deletions(-) diff --git a/.github/scripts/github-api-with-retry.js b/.github/scripts/github-api-with-retry.js index 9a13c47e6..99231c2e1 100755 --- a/.github/scripts/github-api-with-retry.js +++ b/.github/scripts/github-api-with-retry.js @@ -170,7 +170,7 @@ function logWithCore(core, level, message) { core[level](message); return; } - const logFn = level === 'error' ? console.error : level === 'warning' ? console.warn : console.log; + const logFn = level === 'error' ? console.error : level === 'warning' ? console.warn : console.error; logFn(message); } @@ -428,7 +428,7 @@ async function withRetry(fn, options = {}) { ? 'rate limit' : 'transient error'; - console.log( + console.error( `${retryReason} (attempt ${attempt + 1}/${maxRetries + 1}). ` + `Retrying in ${Math.round(actualDelay / 1000)}s...` ); diff --git a/.github/workflows/agents-issue-optimizer.yml b/.github/workflows/agents-issue-optimizer.yml index 018fe295a..501bccb86 100644 --- a/.github/workflows/agents-issue-optimizer.yml +++ b/.github/workflows/agents-issue-optimizer.yml @@ -22,7 +22,7 @@ concurrency: group: >- agents-issue-optimizer-${{ github.repository }}-${{ - github.event.issue.number || github.run_id }} + github.event.issue.number || inputs.issue_number || github.run_id }} cancel-in-progress: false jobs: @@ -106,11 +106,6 @@ jobs: with: node-version: 24 - - name: Install load balancer dependencies - if: steps.check.outputs.should_run == 'true' - run: | - set -euo pipefail - npm install --no-save --no-package-lock @octokit/rest @octokit/auth-app - name: Setup API client if: steps.check.outputs.should_run == 'true' @@ -354,7 +349,7 @@ jobs: }); NODE - python - <<'PY' || true + python - <<'PY' import json from scripts.langchain import issue_dedup @@ -362,33 +357,37 @@ jobs: issue = json.load(f) with open('/tmp/open_issues.json', encoding='utf-8') as f: open_issues = json.load(f) - with open('/tmp/dedup_comments.json', encoding='utf-8') as f: + with open('/tmp/dedup_comments.json', encoding='utf-8') as f: comments = json.load(f) - marker = issue_dedup.SIMILAR_ISSUES_MARKER - for comment in comments or []: + marker = issue_dedup.SIMILAR_ISSUES_MARKER + for comment in comments or []: body = (comment or {}).get('body') or '' if marker in body: - raise SystemExit(0) + raise SystemExit(0) # Conservative defaults; can be tuned later. threshold = 0.82 - store = issue_dedup.build_issue_vector_store(open_issues) - if store is None: + store = issue_dedup.build_issue_vector_store(open_issues) + if store is None: raise SystemExit(0) - title = (issue.get('title') or '').strip() - body = (issue.get('body') or '').strip() - query = f"{title}\n{body}".strip() if body else title - if not query: + title = (issue.get('title') or '').strip() + body = (issue.get('body') or '').strip() + query = f"{title}\n{body}".strip() if body else title + if not query: raise SystemExit(0) - matches = issue_dedup.find_similar_issues(store, query, threshold=threshold, k=5) - comment = issue_dedup.format_similar_issues_comment(matches, max_items=5) - if comment: + matches = issue_dedup.find_similar_issues(store, query, threshold=threshold, k=5) + comment = issue_dedup.format_similar_issues_comment(matches, max_items=5) + if comment: with open('/tmp/dedup_comment.md', 'w', encoding='utf-8') as out: - out.write(comment) + out.write(comment) PY + dedup_rc=$? + if [[ $dedup_rc -ne 0 ]]; then + echo "::warning::issue dedup python exited with $dedup_rc; continuing without similar-issues comment" + fi if [[ -f /tmp/dedup_comment.md ]]; then node - <<'NODE' diff --git a/config/template-drift-allowlist.txt b/config/template-drift-allowlist.txt index da6f42cb0..a669a5967 100644 --- a/config/template-drift-allowlist.txt +++ b/config/template-drift-allowlist.txt @@ -113,9 +113,9 @@ reason = Intentional divergence re-baselined 2026-06-30: root and consumer guard [pair.11] main = .github/workflows/agents-issue-optimizer.yml template = templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml -main_sha256 = 3ad86a30a866167dc78ec21150fc2dba475dc70b2504cfe3373906ed95a2502d -template_sha256 = 3f76718542ab27978fc819118a9e671a9f34439e388fa0ea6f0359937e7bbb57 -reason = Intentional divergence re-baselined 2026-08-08: root and consumer issue-optimizer workflows keep different auth plumbing/action pin surfaces. Both validate format output with python3, require the agents:format lease before dispatch, and release that lease on a failed format run; the consumer explicitly sparse-checks out .github/scripts/issue_format.py plus config/scripts/langchain/tools from Workflows, while root runs those files in-tree. Do not align wholesale because that would strip consumer action pins/token setup. +main_sha256 = ccf1cd3ccdba84c54743d2950367308df15c5928b95c1e7400a5d2858b7c1fa5 +template_sha256 = a4d50beb165724ff9266a18390d738105538fe0c13a5eb3a620fb8c9297fe80f +reason = Intentional divergence re-baselined 2026-08-08b: root remains in-tree (scripts/langchain + .github/scripts/issue_format.py); consumer vendors those via Workflows sparse-checkout under workflows-scripts/. Shared behavioral contract this round: concurrency includes inputs.issue_number for workflow_dispatch dedupe, cancel-safe (failure()||cancelled()) agents:format lease release, and fixed issue_dedup Python indentation with visible non-zero exit warnings. Do not align wholesale — that would strip consumer action pins/token setup. [pair.12] main = .github/workflows/agents-keepalive-loop-reporter.yml diff --git a/templates/consumer-repo/.github/scripts/github-api-with-retry.js b/templates/consumer-repo/.github/scripts/github-api-with-retry.js index 9a13c47e6..99231c2e1 100755 --- a/templates/consumer-repo/.github/scripts/github-api-with-retry.js +++ b/templates/consumer-repo/.github/scripts/github-api-with-retry.js @@ -170,7 +170,7 @@ function logWithCore(core, level, message) { core[level](message); return; } - const logFn = level === 'error' ? console.error : level === 'warning' ? console.warn : console.log; + const logFn = level === 'error' ? console.error : level === 'warning' ? console.warn : console.error; logFn(message); } @@ -428,7 +428,7 @@ async function withRetry(fn, options = {}) { ? 'rate limit' : 'transient error'; - console.log( + console.error( `${retryReason} (attempt ${attempt + 1}/${maxRetries + 1}). ` + `Retrying in ${Math.round(actualDelay / 1000)}s...` ); diff --git a/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml b/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml index 018fe295a..ab2f44db1 100644 --- a/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml +++ b/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml @@ -22,7 +22,7 @@ concurrency: group: >- agents-issue-optimizer-${{ github.repository }}-${{ - github.event.issue.number || github.run_id }} + github.event.issue.number || inputs.issue_number || github.run_id }} cancel-in-progress: false jobs: @@ -96,29 +96,55 @@ jobs: echo "should_run=false" >> "$GITHUB_OUTPUT" fi + - name: Generate App Token + id: app_token + if: steps.check.outputs.should_run == 'true' + continue-on-error: true + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3 + with: + app-id: ${{ secrets.WORKFLOWS_APP_ID }} + private-key: ${{ secrets.WORKFLOWS_APP_PRIVATE_KEY }} + + - name: Select Token + id: token + if: steps.check.outputs.should_run == 'true' + env: + APP_TOKEN: ${{ steps.app_token.outputs.token }} + GITHUB_TOKEN_FALLBACK: ${{ github.token }} + run: | + if [ -n "$APP_TOKEN" ]; then + echo "Using GitHub App token (5000/hr pool)" + echo "token=$APP_TOKEN" >> "$GITHUB_OUTPUT" + echo "source=app" >> "$GITHUB_OUTPUT" + else + echo "Falling back to GITHUB_TOKEN (1000/hr shared pool)" + echo "token=$GITHUB_TOKEN_FALLBACK" >> "$GITHUB_OUTPUT" + echo "source=github_token" >> "$GITHUB_OUTPUT" + fi + - name: Checkout repository if: steps.check.outputs.should_run == 'true' uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Set up Node.js + - name: Checkout Workflows repository for scripts if: steps.check.outputs.should_run == 'true' - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - node-version: 24 - - - name: Install load balancer dependencies - if: steps.check.outputs.should_run == 'true' - run: | - set -euo pipefail - npm install --no-save --no-package-lock @octokit/rest @octokit/auth-app + repository: stranske/Workflows + path: workflows-scripts + sparse-checkout: | + .github/scripts/issue_format.py + config + scripts/langchain + tools + sparse-checkout-cone-mode: false - name: Setup API client if: steps.check.outputs.should_run == 'true' uses: ./.github/actions/setup-api-client with: secrets: ${{ toJSON(secrets) }} - github_token: ${{ github.token }} - + github_token: ${{ steps.token.outputs.token }} - name: Set up Python if: steps.check.outputs.should_run == 'true' @@ -130,13 +156,13 @@ jobs: if: steps.check.outputs.should_run == 'true' run: | python -m pip install --upgrade pip - python -m pip install -r tools/requirements-llm.txt + python -m pip install -r workflows-scripts/tools/requirements-llm.txt - name: Check optimizer recursion guard if: steps.check.outputs.should_run == 'true' id: recursion_guard env: - GH_TOKEN: ${{ github.token }} + GH_TOKEN: ${{ steps.token.outputs.token }} ISSUE_NUMBER: ${{ steps.check.outputs.issue_number }} run: | # Check how many optimizer runs for this issue in last hour @@ -198,38 +224,29 @@ jobs: if: steps.check.outputs.should_run == 'true' id: get_issue env: - GH_TOKEN: ${{ github.token }} + GH_TOKEN: ${{ steps.token.outputs.token }} ISSUE_NUMBER: ${{ steps.check.outputs.issue_number }} - run: | - node - <<'NODE' - (async () => { + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + with: + github-token: ${{ steps.token.outputs.token }} + script: | const fs = require('fs'); - const { Octokit } = require('@octokit/rest'); const { createTokenAwareRetry } = require('./.github/scripts/github-api-with-retry.js'); - const core = { info: () => {}, warning: console.warn, debug: () => {} }; - const github = new Octokit({ auth: process.env.GITHUB_TOKEN }); - const { withRetry } = await createTokenAwareRetry({ + const { github: retryGithub, withRetry } = await createTokenAwareRetry({ github, core, env: process.env, task: 'issue-optimizer', capabilities: ['issues:read'], }); - const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); const issueNumber = Number(process.env.ISSUE_NUMBER); - const { data } = await withRetry((client) => client.rest.issues.get({ - owner, - repo, - issue_number: issueNumber, - })); + const { owner, repo } = context.repo; + const { data } = await withRetry((client) => + client.rest.issues.get({ owner, repo, issue_number: issueNumber }) + ); fs.writeFileSync('/tmp/issue.json', JSON.stringify(data, null, 2)); fs.writeFileSync('/tmp/issue_body.md', data.body || ''); - console.log('Issue body saved to /tmp/issue_body.md'); - })().catch((error) => { - console.error(error); - process.exit(1); - }); - NODE + core.info('Issue body saved to /tmp/issue_body.md'); - name: Phase 1 - Analyze Issue if: steps.check.outputs.should_run == 'true' && steps.check.outputs.phase == 'analyze' @@ -241,11 +258,10 @@ jobs: CLAUDE_API_STRANSKE: ${{ secrets.CLAUDE_API_STRANSKE }} LANGCHAIN_PROVIDER: anthropic LANGCHAIN_MODEL: claude-sonnet-4-5-20250929 - PYTHONPATH: ${{ github.workspace }} - ISSUE_PR_CONTEXT_WORKFLOW: agents-issue-optimizer + PYTHONPATH: ${{ github.workspace }}/workflows-scripts run: | echo "Running analysis on issue #${ISSUE_NUMBER}" - python scripts/langchain/issue_optimizer.py \ + python workflows-scripts/scripts/langchain/issue_optimizer.py \ --input-file /tmp/issue_body.md \ --json > /tmp/suggestions.json @@ -253,7 +269,7 @@ jobs: python -c " import json import sys - sys.path.insert(0, 'scripts/langchain') + sys.path.insert(0, 'workflows-scripts/scripts/langchain') from issue_optimizer import IssueOptimizationResult, format_suggestions_comment with open('/tmp/suggestions.json') as f: @@ -278,57 +294,34 @@ jobs: } # Post comment - node - <<'NODE' - (async () => { - const fs = require('fs'); - const { Octokit } = require('@octokit/rest'); - const { createTokenAwareRetry } = require('./.github/scripts/github-api-with-retry.js'); - const core = { info: () => {}, warning: console.warn, debug: () => {} }; - const github = new Octokit({ auth: process.env.GITHUB_TOKEN }); - const { withRetry } = await createTokenAwareRetry({ - github, - core, - env: process.env, - task: 'issue-optimizer', - capabilities: ['issues:write'], - }); - const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); - const issueNumber = Number(process.env.ISSUE_NUMBER); - const body = fs.readFileSync('/tmp/comment.md', 'utf8'); - await withRetry((client) => client.rest.issues.createComment({ - owner, - repo, - issue_number: issueNumber, - body, - })); - })().catch((error) => { - console.error(error); - process.exit(1); - }); - NODE + gh issue comment "${ISSUE_NUMBER}" --body-file /tmp/comment.md - echo "Analysis complete. Review suggestions" \ - "and add 'agents:apply-suggestions'" \ - "label to apply." + echo "Analysis complete." + echo "Review suggestions and add 'agents:apply-suggestions' label to apply." - name: Advisory issue dedup check if: steps.check.outputs.should_run == 'true' && steps.check.outputs.phase == 'analyze' env: - GH_TOKEN: ${{ github.token }} + GH_TOKEN: ${{ steps.token.outputs.token }} ISSUE_NUMBER: ${{ steps.check.outputs.issue_number }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} CLAUDE_API_STRANSKE: ${{ secrets.CLAUDE_API_STRANSKE }} - PYTHONPATH: ${{ github.workspace }} + PYTHONPATH: ${{ github.workspace }}/workflows-scripts run: | echo "Checking for potential duplicate issues (advisory)" + node - <<'NODE' + const fs = require('fs'); + const { Octokit } = require('@octokit/rest'); + const { createTokenAwareRetry } = require('./.github/scripts/github-api-with-retry.js'); + + const issueNumber = Number(process.env.ISSUE_NUMBER); + const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); + const github = new Octokit({ auth: process.env.GH_TOKEN }); + const core = { info: console.log, warning: console.warn, debug: () => {} }; + (async () => { - const fs = require('fs'); - const { Octokit } = require('@octokit/rest'); - const { createTokenAwareRetry } = require('./.github/scripts/github-api-with-retry.js'); - const core = { info: () => {}, warning: console.warn, debug: () => {} }; - const github = new Octokit({ auth: process.env.GITHUB_TOKEN }); const { paginateWithRetry } = await createTokenAwareRetry({ github, core, @@ -336,16 +329,17 @@ jobs: task: 'issue-optimizer', capabilities: ['issues:read'], }); - const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); - const issueNumber = Number(process.env.ISSUE_NUMBER); + const openIssues = await paginateWithRetry( github.rest.issues.listForRepo, { owner, repo, state: 'open', per_page: 100 } ); + const comments = await paginateWithRetry( github.rest.issues.listComments, { owner, repo, issue_number: issueNumber, per_page: 100 } ); + fs.writeFileSync('/tmp/open_issues.json', JSON.stringify(openIssues, null, 2)); fs.writeFileSync('/tmp/dedup_comments.json', JSON.stringify(comments, null, 2)); })().catch((error) => { @@ -354,76 +348,50 @@ jobs: }); NODE - python - <<'PY' || true + python - <<'PY' import json - from scripts.langchain import issue_dedup + import sys + sys.path.insert(0, 'workflows-scripts/scripts/langchain') + import issue_dedup with open('/tmp/issue.json', encoding='utf-8') as f: issue = json.load(f) with open('/tmp/open_issues.json', encoding='utf-8') as f: open_issues = json.load(f) - with open('/tmp/dedup_comments.json', encoding='utf-8') as f: + with open('/tmp/dedup_comments.json', encoding='utf-8') as f: comments = json.load(f) - marker = issue_dedup.SIMILAR_ISSUES_MARKER - for comment in comments or []: + marker = issue_dedup.SIMILAR_ISSUES_MARKER + for comment in comments or []: body = (comment or {}).get('body') or '' if marker in body: - raise SystemExit(0) + raise SystemExit(0) # Conservative defaults; can be tuned later. threshold = 0.82 - store = issue_dedup.build_issue_vector_store(open_issues) - if store is None: + store = issue_dedup.build_issue_vector_store(open_issues) + if store is None: raise SystemExit(0) - title = (issue.get('title') or '').strip() - body = (issue.get('body') or '').strip() - query = f"{title}\n{body}".strip() if body else title - if not query: + title = (issue.get('title') or '').strip() + body = (issue.get('body') or '').strip() + query = f"{title}\n{body}".strip() if body else title + if not query: raise SystemExit(0) - matches = issue_dedup.find_similar_issues(store, query, threshold=threshold, k=5) - comment = issue_dedup.format_similar_issues_comment(matches, max_items=5) - if comment: + matches = issue_dedup.find_similar_issues(store, query, threshold=threshold, k=5) + comment = issue_dedup.format_similar_issues_comment(matches, max_items=5) + if comment: with open('/tmp/dedup_comment.md', 'w', encoding='utf-8') as out: - out.write(comment) + out.write(comment) PY + dedup_rc=$? + if [[ $dedup_rc -ne 0 ]]; then + echo "::warning::issue dedup python exited with $dedup_rc; continuing without similar-issues comment" + fi if [[ -f /tmp/dedup_comment.md ]]; then - node - <<'NODE' - (async () => { - const fs = require('fs'); - const { Octokit } = require('@octokit/rest'); - const { createTokenAwareRetry } = - require('./.github/scripts/github-api-with-retry.js'); - const core = { info: () => {}, warning: console.warn, debug: () => {} }; - const github = new Octokit({ auth: process.env.GITHUB_TOKEN }); - const { withRetry } = await createTokenAwareRetry({ - github, - core, - env: process.env, - task: 'issue-optimizer', - capabilities: ['issues:write'], - }); - const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); - const issueNumber = Number(process.env.ISSUE_NUMBER); - const body = fs.readFileSync('/tmp/dedup_comment.md', 'utf8'); - try { - await withRetry((client) => client.rest.issues.createComment({ - owner, - repo, - issue_number: issueNumber, - body, - })); - } catch (error) { - console.warn(`Dedup comment failed: ${error.message}`); - } - })().catch((error) => { - console.error(error); - process.exit(1); - }); - NODE + gh issue comment "${ISSUE_NUMBER}" --body-file /tmp/dedup_comment.md || true else echo "No likely duplicates detected." fi @@ -433,25 +401,27 @@ jobs: id: apply env: ISSUE_NUMBER: ${{ steps.check.outputs.issue_number }} - GH_TOKEN: ${{ github.token }} + GH_TOKEN: ${{ steps.token.outputs.token }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} CLAUDE_API_STRANSKE: ${{ secrets.CLAUDE_API_STRANSKE }} LANGCHAIN_PROVIDER: anthropic LANGCHAIN_MODEL: claude-sonnet-4-5-20250929 - PYTHONPATH: ${{ github.workspace }} - ISSUE_PR_CONTEXT_WORKFLOW: agents-issue-optimizer + PYTHONPATH: ${{ github.workspace }}/workflows-scripts run: | echo "Extracting suggestions from comments on issue #${ISSUE_NUMBER}" - # Get all comments and find the one with suggestions JSON node - <<'NODE' + const fs = require('fs'); + const { Octokit } = require('@octokit/rest'); + const { createTokenAwareRetry } = require('./.github/scripts/github-api-with-retry.js'); + + const issueNumber = Number(process.env.ISSUE_NUMBER); + const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); + const github = new Octokit({ auth: process.env.GH_TOKEN }); + const core = { info: console.log, warning: console.warn, debug: () => {} }; + (async () => { - const fs = require('fs'); - const { Octokit } = require('@octokit/rest'); - const { createTokenAwareRetry } = require('./.github/scripts/github-api-with-retry.js'); - const core = { info: () => {}, warning: console.warn, debug: () => {} }; - const github = new Octokit({ auth: process.env.GITHUB_TOKEN }); const { paginateWithRetry } = await createTokenAwareRetry({ github, core, @@ -459,12 +429,12 @@ jobs: task: 'issue-optimizer', capabilities: ['issues:read'], }); - const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); - const issueNumber = Number(process.env.ISSUE_NUMBER); + const comments = await paginateWithRetry( github.rest.issues.listComments, { owner, repo, issue_number: issueNumber, per_page: 100 } ); + fs.writeFileSync('/tmp/comments.json', JSON.stringify(comments, null, 2)); })().catch((error) => { console.error(error); @@ -477,7 +447,7 @@ jobs: import json import sys import re - sys.path.insert(0, 'scripts/langchain') + sys.path.insert(0, 'workflows-scripts/scripts/langchain') from issue_optimizer import _extract_suggestions_json, apply_suggestions with open('/tmp/comments.json') as f: @@ -508,39 +478,11 @@ jobs: print('Suggestions applied successfully') " || exit 1 - # Do not publish agents:formatted for apply-phase output that fails - # the same fleet contract enforced by the issue-event guard. - python3 .github/scripts/issue_format.py /tmp/updated_body.md + # Keep agents:formatted truthful for apply-phase output too. + python workflows-scripts/.github/scripts/issue_format.py /tmp/updated_body.md # Update issue body - node - <<'NODE' - (async () => { - const fs = require('fs'); - const { Octokit } = require('@octokit/rest'); - const { createTokenAwareRetry } = require('./.github/scripts/github-api-with-retry.js'); - const core = { info: () => {}, warning: console.warn, debug: () => {} }; - const github = new Octokit({ auth: process.env.GITHUB_TOKEN }); - const { withRetry } = await createTokenAwareRetry({ - github, - core, - env: process.env, - task: 'issue-optimizer', - capabilities: ['issues:write'], - }); - const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); - const issueNumber = Number(process.env.ISSUE_NUMBER); - const body = fs.readFileSync('/tmp/updated_body.md', 'utf8'); - await withRetry((client) => client.rest.issues.update({ - owner, - repo, - issue_number: issueNumber, - body, - })); - })().catch((error) => { - console.error(error); - process.exit(1); - }); - NODE + gh issue edit "${ISSUE_NUMBER}" --body-file /tmp/updated_body.md echo "Issue body updated with applied suggestions" @@ -549,17 +491,16 @@ jobs: id: format env: ISSUE_NUMBER: ${{ steps.check.outputs.issue_number }} - GH_TOKEN: ${{ github.token }} + GH_TOKEN: ${{ steps.token.outputs.token }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} CLAUDE_API_STRANSKE: ${{ secrets.CLAUDE_API_STRANSKE }} - PYTHONPATH: ${{ github.workspace }} - ISSUE_PR_CONTEXT_WORKFLOW: agents-issue-optimizer + PYTHONPATH: ${{ github.workspace }}/workflows-scripts run: | echo "Formatting issue #${ISSUE_NUMBER} into AGENT_ISSUE_TEMPLATE structure" # Format the issue using issue_formatter.py - python scripts/langchain/issue_formatter.py \ + python workflows-scripts/scripts/langchain/issue_formatter.py \ --input-file /tmp/issue_body.md \ --json > /tmp/format_result.json @@ -578,151 +519,62 @@ jobs: print('Issue formatted successfully') " || exit 1 - # Do not advertise a formatted issue until it satisfies the same - # fleet contract enforced by the issue-event guard. - python3 .github/scripts/issue_format.py /tmp/formatted_body.md + # Keep the format-result label truthful: the generated issue must + # pass the canonical Workflows validator before it can be marked + # agents:formatted below. + python workflows-scripts/.github/scripts/issue_format.py /tmp/formatted_body.md # Update issue body with formatted version - node - <<'NODE' - (async () => { - const fs = require('fs'); - const { Octokit } = require('@octokit/rest'); - const { createTokenAwareRetry } = require('./.github/scripts/github-api-with-retry.js'); - const core = { info: () => {}, warning: console.warn, debug: () => {} }; - const github = new Octokit({ auth: process.env.GITHUB_TOKEN }); - const { withRetry } = await createTokenAwareRetry({ - github, - core, - env: process.env, - task: 'issue-optimizer', - capabilities: ['issues:write'], - }); - const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); - const issueNumber = Number(process.env.ISSUE_NUMBER); - const body = fs.readFileSync('/tmp/formatted_body.md', 'utf8'); - await withRetry((client) => client.rest.issues.update({ - owner, - repo, - issue_number: issueNumber, - body, - })); - })().catch((error) => { - console.error(error); - process.exit(1); - }); - NODE + gh issue edit "${ISSUE_NUMBER}" --body-file /tmp/formatted_body.md echo "Issue body updated with formatted structure" - name: Manage labels if: steps.check.outputs.should_run == 'true' env: - GH_TOKEN: ${{ github.token }} + GH_TOKEN: ${{ steps.token.outputs.token || github.token }} ISSUE_NUMBER: ${{ steps.check.outputs.issue_number }} PHASE: ${{ steps.check.outputs.phase }} run: | if [[ "$PHASE" == "apply" ]]; then - # Remove optimization label but keep apply-suggestions (used for state tracking) - node - <<'NODE' - (async () => { - const { Octokit } = require('@octokit/rest'); - const { createTokenAwareRetry } = - require('./.github/scripts/github-api-with-retry.js'); - const core = { info: () => {}, warning: console.warn, debug: () => {} }; - const github = new Octokit({ auth: process.env.GITHUB_TOKEN }); - const { withRetry } = await createTokenAwareRetry({ - github, - core, - env: process.env, - task: 'issue-optimizer', - capabilities: ['issues:write'], - }); - const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); - const issueNumber = Number(process.env.ISSUE_NUMBER); - // Only remove agents:optimize, keep agents:apply-suggestions for next steps - const labelsToRemove = ['agents:optimize']; - for (const label of labelsToRemove) { - try { - await withRetry((client) => client.rest.issues.removeLabel({ - owner, - repo, - issue_number: issueNumber, - name: label, - })); - } catch (error) { - if (!String(error.message || '').includes('Label does not exist')) { - console.warn(`Failed to remove label ${label}: ${error.message}`); - } - } - } - try { - await withRetry((client) => client.rest.issues.addLabels({ - owner, - repo, - issue_number: issueNumber, - labels: ['agents:formatted'], - })); - } catch (error) { - console.warn(`Failed to add formatted label: ${error.message}`); - } - })().catch((error) => { - console.error(error); - process.exit(1); - }); - NODE + # Only remove agents:optimize, keep agents:apply-suggestions for state tracking + gh issue edit "${ISSUE_NUMBER}" --remove-label "agents:optimize" || true + gh issue edit "${ISSUE_NUMBER}" --add-label "agents:formatted" echo "Labels updated: removed optimize, kept apply-suggestions for state tracking" elif [[ "$PHASE" == "format" ]]; then # Remove format trigger label and add formatted result label - node - <<'NODE' - (async () => { - const { Octokit } = require('@octokit/rest'); - const { createTokenAwareRetry } = - require('./.github/scripts/github-api-with-retry.js'); - const core = { info: () => {}, warning: console.warn, debug: () => {} }; - const github = new Octokit({ auth: process.env.GITHUB_TOKEN }); - const { withRetry } = await createTokenAwareRetry({ - github, - core, - env: process.env, - task: 'issue-optimizer', - capabilities: ['issues:write'], - }); - const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); - const issueNumber = Number(process.env.ISSUE_NUMBER); - try { - await withRetry((client) => client.rest.issues.removeLabel({ - owner, - repo, - issue_number: issueNumber, - name: 'agents:format', - })); - } catch (error) { - if (!String(error.message || '').includes('Label does not exist')) { - console.warn(`Failed to remove format label: ${error.message}`); - } - } - try { - await withRetry((client) => client.rest.issues.addLabels({ - owner, - repo, - issue_number: issueNumber, - labels: ['agents:formatted'], - })); - } catch (error) { - console.warn(`Failed to add formatted label: ${error.message}`); - } - })().catch((error) => { - console.error(error); - process.exit(1); - }); - NODE + gh issue edit "${ISSUE_NUMBER}" --remove-label "agents:format" + gh issue edit "${ISSUE_NUMBER}" --add-label "agents:formatted" echo "Labels updated: removed format, added formatted" fi + - name: Report workflow failure + if: failure() + env: + GH_TOKEN: ${{ steps.token.outputs.token || github.token }} + ISSUE_NUMBER: ${{ steps.check.outputs.issue_number }} + RUN_URL: >- + ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + run: | + if [ -n "${ISSUE_NUMBER}" ]; then + body=$(cat <<'COMMENT' + ⚠️ **Workflow failed** + + The agents-issue-optimizer workflow encountered an error. + + **Details**: [View workflow run](RUN_URL_PLACEHOLDER) + + Please check the logs and retry if needed. + COMMENT + ) + body="${body//RUN_URL_PLACEHOLDER/${RUN_URL}}" + gh issue comment "${ISSUE_NUMBER}" --body "$body" || true + fi + - name: Release failed format lease if: (failure() || cancelled()) && steps.check.outputs.should_run == 'true' && steps.check.outputs.phase == 'format' env: - GH_TOKEN: ${{ github.token }} + GH_TOKEN: ${{ steps.token.outputs.token || github.token }} ISSUE_NUMBER: ${{ steps.check.outputs.issue_number }} run: | set -euo pipefail diff --git a/tests/workflows/test_agents_issue_optimizer_format_trigger.py b/tests/workflows/test_agents_issue_optimizer_format_trigger.py index a17723b51..5c95df014 100644 --- a/tests/workflows/test_agents_issue_optimizer_format_trigger.py +++ b/tests/workflows/test_agents_issue_optimizer_format_trigger.py @@ -36,8 +36,15 @@ def test_issue_optimizer_validates_format_and_apply_bodies() -> None: consumer_text = CONSUMER_WORKFLOW_PATH.read_text(encoding="utf-8") assert "python3 .github/scripts/issue_format.py /tmp/formatted_body.md" in text assert "python3 .github/scripts/issue_format.py /tmp/updated_body.md" in text - assert "python3 .github/scripts/issue_format.py /tmp/formatted_body.md" in consumer_text - assert "python3 .github/scripts/issue_format.py /tmp/updated_body.md" in consumer_text + # Consumer template vendors issue_format.py from the Workflows sparse checkout. + assert ( + "python workflows-scripts/.github/scripts/issue_format.py /tmp/formatted_body.md" + in consumer_text + ) + assert ( + "python workflows-scripts/.github/scripts/issue_format.py /tmp/updated_body.md" + in consumer_text + ) def test_format_guard_deduplicates_inflight_optimizer_dispatch() -> None: From 22e9ef34c2c2715de67c776273a49d808968ce8b Mon Sep 17 00:00:00 2001 From: Codex Automation Date: Sat, 8 Aug 2026 07:23:55 -0500 Subject: [PATCH 9/9] fix(agents): scope format guard API secrets --- .github/workflows/agents-issue-format-guard.yml | 3 ++- .../.github/workflows/agents-issue-format-guard.yml | 3 ++- tests/workflows/test_agents_issue_optimizer_format_trigger.py | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/agents-issue-format-guard.yml b/.github/workflows/agents-issue-format-guard.yml index b39c66c26..3acb8f601 100644 --- a/.github/workflows/agents-issue-format-guard.yml +++ b/.github/workflows/agents-issue-format-guard.yml @@ -42,7 +42,8 @@ jobs: - name: Setup API client uses: ./.github/actions/setup-api-client with: - secrets: ${{ toJSON(secrets) }} + # This guard only reads issue comments with the workflow token. Do not + # expose the repository-wide secret bundle to the composite action. github_token: ${{ github.token }} - name: Resolve issue diff --git a/templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml b/templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml index b39c66c26..3acb8f601 100644 --- a/templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml +++ b/templates/consumer-repo/.github/workflows/agents-issue-format-guard.yml @@ -42,7 +42,8 @@ jobs: - name: Setup API client uses: ./.github/actions/setup-api-client with: - secrets: ${{ toJSON(secrets) }} + # This guard only reads issue comments with the workflow token. Do not + # expose the repository-wide secret bundle to the composite action. github_token: ${{ github.token }} - name: Resolve issue diff --git a/tests/workflows/test_agents_issue_optimizer_format_trigger.py b/tests/workflows/test_agents_issue_optimizer_format_trigger.py index 5c95df014..021aa25fc 100644 --- a/tests/workflows/test_agents_issue_optimizer_format_trigger.py +++ b/tests/workflows/test_agents_issue_optimizer_format_trigger.py @@ -60,6 +60,8 @@ def test_format_guard_deduplicates_inflight_optimizer_dispatch() -> None: assert "paginateWithRetry" in text assert "github.rest.issues.listComments" in text assert "per_page: 100" in text + assert "github_token: ${{ github.token }}" in text + assert "secrets: ${{ toJSON(secrets) }}" not in text assert '"$trusted_marker" == true && "$has_format_label" == true' in text assert "already routed and in flight; skipping duplicate dispatch" in text # Trusted marker is written only after a successful workflow_dispatch.