Skip to content

ci: wire no-infra-g1 into CI (caller half) - #6009

Merged
renecannao merged 1 commit into
v3.0from
ci/wire-no-infra-g1-caller
Aug 9, 2026
Merged

ci: wire no-infra-g1 into CI (caller half)#6009
renecannao merged 1 commit into
v3.0from
ci/wire-no-infra-g1-caller

Conversation

@renecannao

@renecannao renecannao commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Caller for ci-no-infra-g1.yml. See the companion PR against GH-Actions for the callee — that one must merge first, otherwise this caller resolves to a missing workflow.

no-infra-g1 was the only group flagged NEW by lint_group_coverage.py; its five tests have never run in CI, including reg_test_5363_admin_monitor_caching_sha2-t.

With the pair in place:

group coverage lint: 94 groups | phantom-infra=0 | missing-workflow NEW=0 known=41

Closes the pending "wire no-infra-g1 into CI" item. Tracking for the 41 remaining (deliberately allowlisted) families: #6007.

Summary by CodeRabbit

  • Chores
    • Added an automated CI workflow that can run manually or after successful CI completion.
    • Prevents redundant workflow runs by canceling older runs for the same branch and workflow.
    • Enables coverage reporting through secure workflow authentication.

Caller for the ci-no-infra-g1.yml reusable workflow. no-infra-g1 was the
only group flagged NEW by lint_group_coverage.py -- its five tests have
never run in CI, including reg_test_5363_admin_monitor_caching_sha2-t, the
regression test for the Admin/Monitor caching_sha2 work.

After this pair lands the lint reports:

    group coverage lint: 94 groups | phantom-infra=0 | missing-workflow NEW=0 known=41

infras.lst for the group is empty, so no backend containers start; the group
costs ~73s locally.

Requires the callee at ci-no-infra-g1.yml@GH-Actions to be merged first,
otherwise this caller resolves to a missing workflow.
@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The pull request adds the CI-no-infra-g1 GitHub Actions workflow. The workflow supports manual dispatch and successful CI-trigger completion, applies concurrency controls, and invokes reusable CI with inherited secrets and the full event context.

Changes

CI workflow orchestration

Layer / File(s) Summary
Workflow triggers and reusable invocation
.github/workflows/CI-no-infra-g1.yml
The workflow supports manual and successful CI-trigger executions. It cancels competing runs, applies conditional execution, grants write-all permissions, inherits secrets, and passes the serialized GitHub event context to the reusable CI workflow.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Poem

A rabbit hops through Actions bright,
Dispatch by day, CI by night.
Secrets pass, the context flows,
OIDC helps the upload grow.
One workflow bounds the run—
Carrots for everyone! 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the CI integration for the no-infra-g1 caller workflow.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/wire-no-infra-g1-caller

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@sonarqubecloud

sonarqubecloud Bot commented Aug 9, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
C Security Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@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: 5

🤖 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/workflows/CI-no-infra-g1.yml:
- Line 24: Update the reusable workflow reference in the CI workflow to replace
the mutable GH-Actions branch with the reviewed immutable commit SHA from that
branch, preserving the existing called workflow path.
- Line 25: Replace secrets: inherit in the reusable workflow invocation with an
explicit named-secrets mapping, passing only the GITHUB_TOKEN and secrets
declared by the called workflow; preserve the existing workflow permissions and
other invocation settings.
- Line 16: Update the workflow_run job condition near the existing conclusion
check to require that github.event.workflow_run.head_repository.full_name
matches github.repository, while preserving the current
success-or-no-workflow_run behavior. Ensure fork-derived runs are rejected
before the privileged callee is invoked.
- Around line 17-23: Replace the broad permissions setting in the caller
workflow with an explicit minimal permissions map, retaining id-token: write and
adding only scopes required by the called jobs; update the corresponding
permissions declaration in the reusable ci-<group>.yml workflow to the same
least-privilege set so checkout, Codecov, and other actions receive only
necessary access.
- Around line 10-12: Update the concurrency group in the workflow’s concurrency
configuration to use a callee-specific key, such as a workflow name with a
callee prefix and github.run_id, instead of the caller-derived branch/ref
expression. Keep cancel-in-progress enabled while ensuring reusable workflow
runs cannot share or cancel the caller’s group.
🪄 Autofix

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: CHILL

Plan: Pro Plus

Run ID: bad58f60-2cbc-4e37-9678-66377034ce40

📥 Commits

Reviewing files that changed from the base of the PR and between 2bd3c17 and ac39ee5.

📒 Files selected for processing (1)
  • .github/workflows/CI-no-infra-g1.yml
📜 Review details
🧰 Additional context used
🪛 zizmor (1.29.0)
.github/workflows/CI-no-infra-g1.yml

[error] 23-23: overly broad permissions (excessive-permissions): uses write-all permissions

(excessive-permissions)


[error] 4-8: use of fundamentally insecure workflow trigger (dangerous-triggers): workflow_run is almost always used insecurely

(dangerous-triggers)


[warning] 24-24: secrets unconditionally inherited by called workflow (secrets-inherit): this reusable workflow

(secrets-inherit)

🔇 Additional comments (2)
.github/workflows/CI-no-infra-g1.yml (2)

1-2: LGTM!


26-27: 🗄️ Data Integrity & Integration

Verify the callee contract and minimize the shared github payload.

Line [27] passes the full github context string to .github/workflows/ci-<callee>.yml@GH-Actions. If the callee declares a reusable workflow_call.trigger string input, ensure it applies the same parsing/validation for workflow_dispatch and workflow_run events. Treat branch names, commit messages, and PR fields as untrusted, and pass only the fields the callee needs to avoid exposing unfiltered github.context data across the reusable workflow boundary.

Comment on lines +10 to +12
concurrency:
group: ${{ github.workflow }}-${{ github.event.workflow_run && github.event.workflow_run.head_branch || github.ref_name }}
cancel-in-progress: true

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

callee=.github/workflows/ci-no-infra-g1.yml
git show "GH-Actions:$callee" |
  rg -n -C 5 'concurrency|cancel-in-progress|github.workflow|ref_name|head_branch' || true

Repository: sysown/proxysql

Length of output: 194


🏁 Script executed:

#!/bin/bash
set -u

echo "--- available workflow files ---"
git ls-files '.github/workflows/*' | sed -n '1,120p'

echo "--- matching filenames ---"
git ls-files '.github/workflows/*' | rg -i 'ci-no-infra-g1|call|callable|caller|trigger' || true

echo "--- current file excerpt (if present) ---"
if [ -f .github/workflows/CI-no-infa-g1.yml ]; then
  cat -n .github/workflows/CI-no-infa-g1.yml | sed -n '1,80p'
elif [ -f .github/workflows/CI-no-infra-g1.yml ]; then
  cat -n .github/workflows/CI-no-infra-g1.yml | sed -n '1,80p'
fi

echo "--- workflow_run and reusable usages ---"
rg -n "workflow_run|uses:|concurrency:|cancel-in-progress|ref_name|head_branch|github.workflow" .github/workflows || true

Repository: sysown/proxysql

Length of output: 50372


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "--- call-target metadata files ---"
git ls-files '.github/workflows/ci-no-infra-g1.yml'

echo "--- ci-no-infra-g1.yml excerpt (current) ---"
if [ -f .github/workflows/ci-no-infra-g1.yml ]; then
  cat -n .github/workflows/ci-no-infra-g1.yml | sed -n '1,120p'
fi

echo "--- ci-no-infra-g1.yml remote references ---"
git ls-remote https://github.com/sysown/proxysql refs/tags/GH-Actions --symref 2>/dev/null || true
git ls-remote https://github.com/sysown/proxysql refs/heads/GH-Actions --symref 2>/dev/null || true

echo "--- caller and callable concurrency groups for CI-no-infra-g1 ---"
python3 - <<'PY'
import json, pathlib, re
callers = [p for p in pathlib.Path('.github/workflows').glob('CI-no-infra-g1.yml') if p.name == 'CI-no-infra-g1.yml']
for caller in callers:
    text = caller.read_text()
    print(f'CALLER {caller}')
    for m in re.finditer(r'(^[\s]{0,2}uses:\s*sysown\/proxysql\.github\.workflows\/[\S]+(?:@[\S]+)?|^\s*concurrency:|^\s{2,4}group:\s*|^\s{4,6}cancel-in-progress:\s*)', text, re.M):
        line = text.count('\n', 0, m.start()) + 1
        print(f'{line}: {m.group(0).strip()}')

# Read only remote Git references (not repo code).
import subprocess
for ref in ['refs/tags/GH-Actions', 'refs/heads/GH-Actions']:
    out = subprocess.run(['git','ls-remote','https://github.com/sysown/proxysql', ref], text=True, capture_output=True)
    print(f'REMOTE {ref}: {out.stdout.strip() if out.returncode == 0 else f'ERR {out.returncode}: {out.stderr.strip()}'}')
PY

Repository: sysown/proxysql

Length of output: 671


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "--- fetch ci-no-infra-g1.yml from GH-Actions ---"
url="https://raw.githubusercontent.com/sysown/proxysql/GH-Actions/.github/workflows/ci-no-infra-g1.yml"
python3 - <<'PY'
import urllib.request
url = "https://raw.githubusercontent.com/sysown/proxysql/GH-Actions/.github/workflows/ci-no-infra-g1.yml"
try:
    data = urllib.request.urlopen(url, timeout=20).read().decode()
    print(data)
except Exception as e:
    print(type(e).__name__, e)
PY

echo "--- fetch remote commits from GH-Actions for relevant workflows ---"
python3 - <<'PY'
import urllib.request, urllib.error
sha = "GH-Actions"
url = f"https://raw.githubusercontent.com/sysown/proxysql/{sha}/.github/workflows/ci-no-infra-g1.yml"
try:
    data = urllib.request.urlopen(url, timeout=20).read().decode()
except urllib.error.HTTPError as e:
    print("fetch_error", e.code, e.url, str(e.reason)[:200])
else:
    print("fetched", url, len(data))
PY

echo "--- parse caller concurrency with simple Python ---"
python3 - <<'PY'
import pathlib, re
caller = pathlib.Path(".github/workflows/CI-no-infra-g1.yml")
text = caller.read_text()
print("caller", caller, "exists", caller.exists())
for m in re.finditer(r'(^[\s]{0,2}uses:\s*sysown\/proxysql\.github\.workflows\/[\S]+(?:@[\S]+)?|^\s*concurrency:|^\s{2,4}group:\s*|^\s{4,6}cancel-in-progress:\s*)', text, re.M):
    line = text.count('\n', 0, m.start()) + 1
    print(f'{line}: {m.group(0).strip()}')
PY

Repository: sysown/proxysql

Length of output: 2700


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "--- list remote ref GH-Actions metadata ---"
git ls-remote --symref https://github.com/sysown/proxysql refs/heads/GH-Actions refs/tags/GH-Actions

echo "--- find ci-no-infra-g1.yml in remote archive ---"
git ls-tree --name-only -r "GH-Actions" ".github/workflows" | rg -n '(^|[[:space:]])ci-no-infra-g1\.yml$' || true

echo "--- stream selected file from remote repository archive ---"
git show "GH-Actions:.github/workflows/ci-no-infra-g1.yml" 2>/dev/null | sed -n '1,120p'

echo "--- parser comparison for caller and callee concurrency groups ---"
python3 - <<'PY'
import re, pathlib, subprocess

def extract_concurrency(path):
    data = subprocess.check_output(["git", "show", f"GH-Actions:{path}"], text=True)
    out = {}
    in_conc = False
    for i, line in enumerate(data.splitlines(), 1):
        if re.match(r'^\s*concurrency:', line):
            in_conc = True
            out["concurrency"] = i
            continue
        if not in_conc:
            continue
        m_conc = re.match(r'^\s+group:\s*(.+)', line)
        m_cancel = re.match(r'^\s+cancel-in-progress:\s*(.+)', line)
        if m_conc:
            out["group_value"] = m_conc.group(1).strip()
        if m_cancel:
            out["cancel"] = m_cancel.group(1).strip()
            break
    return out

caller = extract_concurrency(".github/workflows/CI-no-infra-g1.yml")
callee = extract_concurrency(".github/workflows/ci-no-infra-g1.yml")
print("caller", caller)
print("callee", callee)
print("caller group equals callee group:", caller.get("group_value") == callee.get("group_value"))
print("both disable cancellations:", caller.get("cancel") == "false" and callee.get("cancel") == "false")
PY

Repository: sysown/proxysql

Length of output: 416


🌐 Web query:

GitHub Actions reusable workflows reusable workflow configurations matching caller and callee concurrency groups cancel caller

💡 Result:

In GitHub Actions, using concurrency groups across caller and reusable (callee) workflows requires caution because ${{ github.workflow }} in a called workflow resolves to the name of the caller workflow, not the reusable workflow itself [1][2]. If both the caller and the callee use the same concurrency group name derived from ${{ github.workflow }}, they may inadvertently target the same group, causing the caller to cancel itself when the callee runs, or causing callees to cancel each other [1][3][2]. To manage concurrency correctly and avoid unwanted cancellations: 1. Avoid ${{ github.workflow }} in reusable workflows: Since the callee inherits the caller's workflow name, using ${{ github.workflow }} as part of a concurrency group key in both locations creates a collision [1][2][4]. 2. Use unique, hardcoded identifiers: To distinguish between caller and callee or prevent collisions between multiple reusable workflows, use distinct, hardcoded prefixes or identifiers within the concurrency group strings [2][4]. For example, use group: caller-name-${{ github.ref }} in the caller and group: callee-name-${{ github.run_id }} or a specific prefix in the callee [2]. 3. Understanding cancel-in-progress: If cancel-in-progress: true is set, any workflow or job already running in the same concurrency group will be cancelled when a new run in that group starts [5][6]. If a caller and callee share a group, the act of starting the callee can trigger the cancellation of the caller [1][3]. 4. Context availability: Note that ${{ github.run_id }} is unique to each individual workflow run, making it a reliable way to isolate concurrency groups if you want to avoid collisions entirely between concurrent executions [2]. In summary, GitHub explicitly advises against using the same concurrency group value for both caller and called workflows if cancel-in-progress: true is enabled, as the shared context causes the caller to be cancelled by its own called workflow [1]. Always use unique, explicit group identifiers in the callee to prevent this inheritance-related conflict [2][4].

Citations:


Use distinct concurrency groups for caller and callee.

The caller uses group: ${{ github.workflow }}-${{ github.event.workflow_run && github.event.workflow_run.head_branch || github.ref_name }} with cancel-in-progress: true; avoid the reusable workflow using the same caller-derived group. This can cancel the caller run when the callee starts; use a unique callee-prefixed key such as ${{ github.workflow }}-callee-${{ github.run_id }}.

🤖 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/CI-no-infra-g1.yml around lines 10 - 12, Update the
concurrency group in the workflow’s concurrency configuration to use a
callee-specific key, such as a workflow name with a callee prefix and
github.run_id, instead of the caller-derived branch/ref expression. Keep
cancel-in-progress enabled while ensuring reusable workflow runs cannot share or
cancel the caller’s group.


jobs:
run:
if: ${{ github.event.workflow_run && github.event.workflow_run.conclusion == 'success' || ! github.event.workflow_run }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

: "${REPO:?Set REPO=OWNER/REPO}"

gh api --paginate \
  "repos/${REPO}/actions/workflows/CI-trigger.yml/runs?event=pull_request&per_page=100" \
  --jq '.workflow_runs[]
    | select(.head_repository != null and .head_repository.full_name != .repository.full_name)
    | [.id, .conclusion, .head_repository.full_name, .repository.full_name]
    | `@tsv`'

Repository: sysown/proxysql

Length of output: 193


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf 'Repo: %s\n' "${GITHUB_REPOSITORY:-<GITHUB_REPOSITORY not set>}"

printf '\nRelevant workflow files:\n'
git ls-files '.github/workflows/CI*.yml' '.github/workflows/CI*.yaml' | sed -n '1,50p'

printf '\nCI-trigger.yml contents:\n'
if [ -f .github/workflows/CI-trigger.yml ]; then
  cat -n .github/workflows/CI-trigger.yml | sed -n '1,220p'
fi

printf '\nCI-no-infra-g1.yml relevant contents:\n'
if [ -f .github/workflows/CI-no-infra-g1.yml ]; then
  cat -n .github/workflows/CI-no-infra-g1.yml | sed -n '1,220p'
fi

printf '\nSearch for reusable workflow references and workflow_run conditions:\n'
rg -n "uses:|workflow_run|github.repository|head_repository|conclusion" .github/workflows || true

Repository: sysown/proxysql

Length of output: 50372


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf 'Repository: %s\n' "${GITHUB_REPOSITORY:-<GITHUB_REPOSITORY not set>}"

printf '\nCI-trigger.yml relevant contents:\n'
cat -n .github/workflows/CI-trigger.yml | sed -n '1,240p'

printf '\nCI-no-infra-g1.yml relevant contents:\n'
cat -n .github/workflows/CI-no-infra-g1.yml | sed -n '1,220p'

printf '\nOther workflow_run runners with same condition pattern:\n'
python3 - <<'PY'
import pathlib
for p in pathlib.Path('.github/workflows').glob('CI*'):
    text = p.read_text()
    if 'workflow_run.conclusion == \'success\' || ! github.event.workflow_run' in text:
        print(p)
        for i, line in enumerate(text.splitlines(), 1), None:
            print(f'  line {line}')
PY

Repository: sysown/proxysql

Length of output: 2787


🌐 Web query:

GitHub Actions workflow_run event skipped conclusion head_repository.full_name

💡 Result:

When using the workflow_run event in GitHub Actions, you can access the conclusion and repository details of the triggering workflow via the github.event.workflow_run context [1][2][3][4]. Key points regarding your query: Conclusion and Skipped Status: The workflow_run event triggers regardless of whether the previous workflow passed, failed, or was skipped [2]. If your workflow is being skipped unexpectedly, it is often due to an if conditional in your workflow file that explicitly checks for a specific conclusion (e.g., if: ${{ github.event.workflow_run.conclusion == 'success' }}) [1]. To have your workflow run regardless of the outcome, ensure any such conditional is either removed or adjusted to include all desired statuses (e.g., if: ${{ contains(fromJSON('["success", "failure", "skipped"]'), github.event.workflow_run.conclusion) }}) [1][5]. Accessing Repository Information: You can access the repository of the triggering workflow using the head_repository.full_name property within the event context [3][4]. This is frequently used for security gating, such as ensuring that privileged workflows only run when the triggering event originated from the same repository (e.g., github.event.workflow_run.head_repository.full_name == github.repository) [3][4]. Example Usage: on: workflow_run: workflows: [Previous Workflow Name] types: [completed] jobs: on-complete: runs-on: ubuntu-latest # This ensures the job runs even if the previous workflow was skipped or failed if: ${{ github.event.workflow_run.conclusion!= 'cancelled' }} steps: - run: echo "The previous workflow from ${{ github.event.workflow_run.head_repository.full_name }} finished with conclusion: ${{ github.event.workflow_run.conclusion }}"

Citations:


Reject fork-derived runs before invoking the privileged callee.

.github/workflows/CI-trigger.yml skips its job for fork pull requests, but this workflow_run job accepts any completed run with conclusion == 'success'. Add a source-repository check in this job, such as comparing github.event.workflow_run.head_repository.full_name or repository ID with github.repository, because the fork guard stops the job, not the workflow-run event from arriving.

🤖 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/CI-no-infra-g1.yml at line 16, Update the workflow_run job
condition near the existing conclusion check to require that
github.event.workflow_run.head_repository.full_name matches github.repository,
while preserving the current success-or-no-workflow_run behavior. Ensure
fork-derived runs are rejected before the privileged callee is invoked.

Source: Linters/SAST tools

Comment on lines +17 to +23
# `write-all` is required for the callee's `use_oidc: true` Codecov
# upload step to mint a GitHub OIDC token. Reusable-workflow
# permissions are the intersection of caller + callee, so the
# caller has to grant id-token:write (and everything else included
# in write-all) for the callee's declaration to take effect. The
# callee at ci-<group>.yml@GH-Actions also declares write-all.
permissions: write-all

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== workflow files =="
git ls-files '.github/workflows/*' | sort

echo
echo "== target workflow excerpt =="
if [ -f .github/workflows/CI-no-infra-g1.yml ]; then
  cat -n .github/workflows/CI-no-infra-g1.yml | sed -n '1,120p'
else
  echo "missing target workflow"
fi

echo
echo "== related workflow permission snippets =="
for f in $(git ls-files '.github/workflows/*' | sort); do
  echo "--- $f"
  cat -n "$f" | sed -n '1,80p' | grep -nE 'permissions:|id-token:|write-all|codecov|ci-|reuse|uses:' || true
done

echo
echo "== search codecov / id-token / write-all in workflows =="
rg -n "codecov|id-token|write-all|permissions:" .github/workflows || true

Repository: sysown/proxysql

Length of output: 50372


🌐 Web query:

GitHub reusable workflow caller permissions intersection GITHUB_TOKEN id-token writeall documentation

💡 Result:

In GitHub Actions, reusable workflows inherit the permissions of the calling job [1][2][3]. The following rules govern the interaction between caller and called workflow permissions: 1. Permission Downgrading: The GITHUB_TOKEN permissions passed from a caller workflow can only be downgraded, never elevated, by a called (reusable) workflow [1][2]. If a caller workflow assigns specific permissions to a job that calls a reusable workflow, the reusable workflow cannot request or exercise permissions beyond that set [1][2][4]. 2. Inheritance and Defaults: If a caller job does not explicitly define permissions, the called (reusable) workflow defaults to the repository's configured default permissions for the GITHUB_TOKEN [1][2]. 3. Security Hardening and "write-all": While the "write-all" permission set exists, it is strongly discouraged in security-sensitive contexts. Because reusable workflows inherit the caller's permission context, if a caller job grants "write-all," the reusable workflow also gains those extensive privileges, which contradicts the principle of least privilege [5][3]. Best practice is to explicitly define the minimum required permissions (e.g., contents: read) at the job or workflow level in both the caller and the reusable workflow [5][3]. 4. ID Token Permissions: If a reusable workflow requires the use of OpenID Connect (OIDC) for cloud authentication, the caller job must grant the id-token: write permission [6]. The reusable workflow will then inherit this ability [6]. OIDC tokens generated for jobs within a reusable workflow include a custom claim, job_workflow_ref, which identifies the specific reusable workflow being executed, allowing cloud providers to apply granular trust conditions [7]. Summary of Interaction: - Caller permissions act as an upper bound (a ceiling) for all nested jobs in the reusable workflow [2][8]. - If you attempt to use more permissions in a called workflow than are granted by the caller job, the workflow will fail at runtime [3]. - For maximum security, define explicit, minimal permissions in both the caller and the called workflow [5][3]. Top Results: [1], [7], [2], [3]

Citations:


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== CI-no-infra branch candidate files =="
git ls-remote --heads origin gh-actions 2>/dev/null | sed -n '1,120p' || true
git ls-remote --tags origin gh-actions 2>/dev/null | sed -n '1,120p' || true

echo
echo "== fetch caller file from gh-actions, if available =="
tmp="$(mktemp -d)"
git ls-remote refs/remotes/origin/gh-actions sysown/proxysql/.github/workflows/CI-no-infra-g1.yml 2>/dev/null | while read -r ref path; do
  [ -n "$path" ] || continue
  git cat-file -p "$ref" -o "$tmp/CI-no-infra-g1.yml"
  echo "--- $path"
  cat -n "$tmp/CI-no-infra-g1.yml" | sed -n '1,160p'
done

echo
echo "== fetch same branch reusable callee if present =="
git ls-remote refs/remotes/origin/gh-actions sysown/proxysql/.github/workflows/ci-no-infra-g1.yml 2>/dev/null | while read -r ref path; do
  [ -n "$path" ] || continue
  git cat-file -p "$ref" -o "$tmp/ci-no-infra-g1.yml"
  echo "--- $path permissions/content snippets"
  cat -n "$tmp/ci-no-infra-g1.yml" | sed -n '1,180p' | grep -nE 'permissions:|id-token:|write-all|use_oidc|codecov|jobs:|workflow_call|uses:' || cat -n "$tmp/ci-no-infra-g1.yml" | sed -n '1,180p'
done

echo
echo "== local GH-Actions branch availability =="
git branch -r 2>/dev/null | grep 'origin/gh-actions' || true

Repository: sysown/proxysql

Length of output: 253


🌐 Web query:

GH-Actions write-all id-token write reuse_workflow_permissions documentation

💡 Result:

In GitHub Actions, the id-token: write permission is required to request and use an OpenID Connect (OIDC) JSON Web Token (JWT) for authenticating with external cloud providers [1][2]. This permission does not grant write access to repository contents or any other resources; it strictly enables the generation and use of the OIDC token [1][3]. Key aspects regarding permissions and reusable workflows include: Explicit Requirement: When using reusable workflows (especially those outside your enterprise or organization), you must explicitly set permissions: id-token: write at the caller workflow or job level to allow the token to be generated and consumed [1][4]. Permission Hierarchy: Permissions can be defined at the workflow level (applying to all jobs) or the job level (overriding workflow-level settings) [5][6]. If you specify any permissions, all unspecified permissions are set to none [5][6]. Security Best Practices: Avoid write-all: The write-all permission grants broad, often unnecessary access [7]. It is a security best practice to follow the principle of least privilege by explicitly defining only the minimal permissions required for each job [8][7][9]. Default Settings: GitHub now defaults new repositories and organizations to restricted (read-only) GITHUB_TOKEN permissions, though workflows may inherit broader settings depending on existing repository configurations [10][8][11]. If your workflow fails with permission errors, verify that you have not inadvertently restricted required access or omitted necessary permissions (like contents: read or id-token: write) [11][9].

Citations:


Narrow the caller job permissions.

permissions: write-all grants every write-capable token scope. OIDC Codecov uploads need id-token: write, and the reusable workflow calls can still be elevated to broader actions such as actions/checkout or codecov/codecov-action unless permission caps are set. Declare only the permissions called jobs require in both the caller and the reusable GH-Actions workflow.

🧰 Tools
🪛 zizmor (1.29.0)

[error] 23-23: overly broad permissions (excessive-permissions): uses write-all permissions

(excessive-permissions)

🤖 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/CI-no-infra-g1.yml around lines 17 - 23, Replace the broad
permissions setting in the caller workflow with an explicit minimal permissions
map, retaining id-token: write and adding only scopes required by the called
jobs; update the corresponding permissions declaration in the reusable
ci-<group>.yml workflow to the same least-privilege set so checkout, Codecov,
and other actions receive only necessary access.

Source: Linters/SAST tools

# in write-all) for the callee's declaration to take effect. The
# callee at ci-<group>.yml@GH-Actions also declares write-all.
permissions: write-all
uses: sysown/proxysql/.github/workflows/ci-no-infra-g1.yml@GH-Actions

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

git ls-remote --heads --tags origin GH-Actions

Repository: sysown/proxysql

Length of output: 216


Pin the called workflow to an immutable ref.

GH-Actions resolves to refs/heads/GH-Actions, a mutable branch. Use the reviewed commit SHA from that branch for the callee ref after the companion PR merges, so future workflow changes require a review.

🧰 Tools
🪛 zizmor (1.29.0)

[warning] 24-24: secrets unconditionally inherited by called workflow (secrets-inherit): this reusable workflow

(secrets-inherit)

🤖 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/CI-no-infra-g1.yml at line 24, Update the reusable
workflow reference in the CI workflow to replace the mutable GH-Actions branch
with the reviewed immutable commit SHA from that branch, preserving the existing
called workflow path.

# callee at ci-<group>.yml@GH-Actions also declares write-all.
permissions: write-all
uses: sysown/proxysql/.github/workflows/ci-no-infra-g1.yml@GH-Actions
secrets: inherit

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Tracked workflow files:\n'
git ls-files '.github/workflows/*' | sort

printf '\nTarget file with line numbers around secrets usage:\n'
sed -n '1,80p' .github/workflows/CI-no-infra-g1.yml 2>/dev/null || true

printf '\nAll uses of ci-no-infra-g1 / CI-no-infra-g1 workflow files:\n'
rg -n "ci-no-infra-g1|CI-no-infra-g1|secrets:\s*inherit|secrets:" .github/workflows || true

printf '\nWorkflow dispatch/run triggers mentioning secrets or workflow_run:\n'
rg -n "workflow_dispatch|workflow_run|repository_dispatch|schedule|workflow_call|secrets:\s*inherit" .github/workflows || true

Repository: sysown/proxysql

Length of output: 50371


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Callee workflow header and secrets declaration:\n'
cat -n .github/workflows/ci-no-infra-g1.yml | sed -n '1,80p'

printf '\nAll secret references in callee:\n'
rg -n "\$\{\{\s* secrets\.[A-Za-z0-9_-]+\s*\}\}" .github/workflows/ci-no-infra-g1.yml || true

printf '\nAll reusable-workflow uses in root workflows with job-local permissions/secrets:\n'
python3 - <<'PY'
from pathlib import Path
import re, yaml, sys

for p in sorted(Path('.github/workflows').glob('*.yml')):
    text = p.read_text()
    if 'uses: sysown/proxysql/.github/workflows/ci-no-infra-g1.yml@GH-Actions' not in text:
        continue
    lines = text.splitlines()
    start = 0
    while start < len(lines) and 'uses: sysown/proxysql/.github/workflows/ci-no-infra-g1.yml@GH-Actions' not in lines[start]:
        start += 1
    indent = re.match(r'^(\s*)', lines[start]).group(1)
    end = len(lines)
    for i in range(start+1, len(lines)):
        if re.match(r'^\S', lines[i]):
            end = i
            break
    block = lines[start:end]
    sec = next((s.strip() for s in block if s.startswith('secrets:')), '')
    perm = next((s.strip() for s in block if s.startswith ('permissions:')), '')
    print(p)
    print('  '.join(block[:18]))
    print('  permissions:', perm)
    print('  secrets:', sec)
PY

Repository: sysown/proxysql

Length of output: 270


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Locate ci-no-infra-g1 workflow files exactly:\n'
fd -a '^ci-no-infra-g1\.yml$|^CI-no-infra-g1\.yml$' . || true
git ls-files | rg '(^|/)ci-no-infra-g1\.yml$|(^|/)CI-no-infra-g1\.yml$' || true

printf '\nGit tracked diff for CI-no-infra-g1.yml if available:\n'
git diff -- .github/workflows/CI-no-infra-g1.yml .github/workflows/ci-no-infra-g1.yml 2>/dev/null | sed -n '1,180p' || true

printf '\nTracked reusable workflows with named secrets or call references to ci-no-infra-g1:\n'
rg -n "ci-no-infra-g1.yml|name:\s*\$.*|on:\s*\{\}|uses:\s*[^@]+@[^\\n]*secrets:" .github/workflows 2>/dev/null | sed -n '1,200p' || true

Repository: sysown/proxysql

Length of output: 490


Pass only named secrets to the reusable workflow.

Line 25 uses secrets: inherit, which passes every secret available to this caller to the reusable workflow. The caller also grants permissions: write-all; because workflow_run workflows can access secrets and use tokens, this broad call makes the reusable workflow available for secret exfiltration if it is compromised. Use secrets: [ ... ] and the specific GITHUB_TOKEN/secrets that this reusable workflow declares.

🤖 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/CI-no-infra-g1.yml at line 25, Replace secrets: inherit in
the reusable workflow invocation with an explicit named-secrets mapping, passing
only the GITHUB_TOKEN and secrets declared by the called workflow; preserve the
existing workflow permissions and other invocation settings.

Source: Linters/SAST tools

@renecannao
renecannao merged commit e2293b0 into v3.0 Aug 9, 2026
10 of 11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant