Skip to content

feat(workflows): add no-build opt-out input to all reusable workflows#112

Merged
williaby merged 5 commits into
mainfrom
claude/no-build-opt-out-0
May 15, 2026
Merged

feat(workflows): add no-build opt-out input to all reusable workflows#112
williaby merged 5 commits into
mainfrom
claude/no-build-opt-out-0

Conversation

@williaby
Copy link
Copy Markdown
Collaborator

@williaby williaby commented May 15, 2026

Problem

Repos using a build backend (hatchling, setuptools) fail CI with errors like:

error: Distribution `gleif==0.1.0 @ editable+file:///home/runner/work/gleif/gleif`
can't be installed because it is not a wheel and --no-build is set

The cause: uv sync --no-build was hardcoded into every reusable workflow. That flag is correct for repos that are pure scripts with no build step, but it prevents repos with a proper package build from using the shared workflow library at all.

Root Cause

There are two distinct uses of --no-build in these workflows:

  1. uv pip install --no-build 'pkg==version' (security fix from PR fix(workflows): replace unsafe pip installs with uv pip install --no-build #110) -- refuses to download and execute arbitrary sdist build scripts from PyPI. This is an S8541/S8544 control and must stay.

  2. uv sync --no-build / uv run --frozen --no-build (pre-existing) -- refuses to build the calling repo's own package. This breaks repos with hatchling/setuptools.

PR #110 fixed #1 but did not address #2.

Solution

Add a no-build boolean input (default: true) to all 11 affected workflows. Callers with a build backend opt out with no-build: false:

jobs:
  ci:
    uses: ByronWilliamsCPA/.github/.github/workflows/python-ci.yml@v1
    with:
      no-build: false   # repo has hatchling build backend

Implementation: each job exports NO_BUILD_FLAG at the job env: level so the variable is available to every step without per-step changes:

env:
  NO_BUILD_FLAG: ${{ inputs.no-build && '--no-build' || '' }}

Then all uv sync/run commands reference $NO_BUILD_FLAG unquoted -- an empty string word-splits away cleanly, passing no extra argument.

Files Changed

Commit 1 -- pre-existing unrelated fixes bundled with the pre-commit run:

  • SECURITY.md -- adds Security Surface Areas section
  • .pre-commit-config.yaml -- upgrades TruffleHog hook to upstream repo (v3.92.3, SHA-pinned) instead of local script; adds pragma: allowlist secret for SHA false positive
  • python-scorecard.yml -- adds SCORECARD_TOKEN absence warning so callers get an actionable message when Branch-Protection scores 0; adds pragma: allowlist secret for false positive

Commit 2 -- the no-build fix:

  • python-ci.yml -- 2 jobs patched (quality-checks, matrix-testing)
  • python-compatibility.yml -- 1 job patched (test-matrix)
  • python-docs.yml -- 1 job patched (build)
  • python-fips-compatibility.yml -- 2 jobs patched (fips-check, fips-runtime-test)
  • python-mutation.yml -- 1 job patched (mutation-testing)
  • python-performance-regression.yml -- 1 job patched (performance-regression)
  • python-precommit.yml -- 1 job patched (pre-commit)
  • python-release.yml -- 2 jobs patched (test, release)
  • python-sbom.yml -- 1 job patched (generate-sbom)
  • python-security-analysis.yml -- 2 jobs patched (codeql, python-security)
  • python-sonarcloud.yml -- 1 job patched (sonarcloud-analysis)

Test Plan

  • Verify a repo with hatchling/setuptools passes CI with no-build: false
  • Verify a repo without a build backend passes CI with the default no-build: true
  • Confirm uv pip install --no-build lines (S8541/S8544 security controls) are untouched in all files

Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Reusable workflows now support a configurable no-build input parameter (default: enabled).
  • Chores

    • Updated TruffleHog pre-commit hook configuration to official repository, pinned to v3.92.3.
    • GitHub Actions workflows now emit warning when security token is missing.
  • Documentation

    • Expanded security policy with new "Security Surface Areas" section describing workflow attack vectors and mitigation strategies.

Review Change Stack

Copilot AI review requested due to automatic review settings May 15, 2026 22:32
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 15, 2026

Warning

Rate limit exceeded

@williaby has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 34 minutes and 37 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ac91d17d-8cc4-4df5-a455-b3a0a1dfcc2c

📥 Commits

Reviewing files that changed from the base of the PR and between 2e3e3dd and fc7142c.

📒 Files selected for processing (16)
  • .github/workflows/python-ci.yml
  • .github/workflows/python-compatibility.yml
  • .github/workflows/python-docs.yml
  • .github/workflows/python-fips-compatibility.yml
  • .github/workflows/python-mutation.yml
  • .github/workflows/python-performance-regression.yml
  • .github/workflows/python-precommit.yml
  • .github/workflows/python-release.yml
  • .github/workflows/python-sbom.yml
  • .github/workflows/python-scorecard.yml
  • .github/workflows/python-security-analysis.yml
  • .github/workflows/python-sonarcloud.yml
  • .pre-commit-config.yaml
  • .secrets.baseline
  • CHANGELOG.md
  • SECURITY.md
📝 Walkthrough

Walkthrough

This PR adds a no-build boolean input to 12 reusable GitHub Actions workflows, enabling callers to control whether uv commands include the --no-build flag. It replaces hardcoded --no-build usage with a conditional $NO_BUILD_FLAG environment variable across dependency installation and command execution steps. Additionally, it updates pre-commit configuration to use a dedicated TruffleHog hook, adds GitHub Actions security surface documentation, and includes a scorecard token warning.

Changes

Configurable no-build Input Threading Across Workflows

Layer / File(s) Summary
Input definitions and environment variable setup across all workflows
.github/workflows/python-ci.yml, python-compatibility.yml, python-docs.yml, python-fips-compatibility.yml, python-mutation.yml, python-performance-regression.yml, python-precommit.yml, python-release.yml, python-sbom.yml, python-scorecard.yml, python-security-analysis.yml, python-sonarcloud.yml
All 12 reusable workflows add a workflow_call.inputs.no-build boolean input (default true) and define a corresponding NO_BUILD_FLAG environment variable computed from the input, establishing the baseline for conditional flag expansion.
Dependency installation and quality check flag threading
.github/workflows/python-ci.yml, python-compatibility.yml, python-docs.yml, python-precommit.yml
Python-ci, python-compatibility, python-docs, and python-precommit workflows update uv sync and core build/lint/format steps to use $NO_BUILD_FLAG, removing hardcoded --no-build from formatter, linter, type-checker, and dependency installation paths.
Security and FIPS compliance scanning flag threading
.github/workflows/python-security-analysis.yml, python-fips-compatibility.yml
Python-security-analysis and python-fips-compatibility workflows update uv sync and security scanning commands (CodeQL, Bandit, Safety, FIPS checks) to use $NO_BUILD_FLAG instead of hardcoded --no-build in both job dependencies and scan execution.
Test execution and mutation testing flag threading
.github/workflows/python-ci.yml, python-mutation.yml, python-sonarcloud.yml, python-compatibility.yml
Python-ci (matrix testing), python-mutation, python-sonarcloud, and python-compatibility workflows update dependency installation, pytest execution, and mutmut command paths to use $NO_BUILD_FLAG conditionally, replacing previously hardcoded --no-build across all test variants.
Performance regression and release workflow flag threading
.github/workflows/python-performance-regression.yml, python-release.yml
Python-performance-regression and python-release workflows update dependency installation, benchmark execution, and release job steps to use $NO_BUILD_FLAG, including synthetic test data generation, benchmark script capability detection, and both PR and baseline benchmark runs.

Supporting Configuration, Documentation, and Diagnostic Updates

Layer / File(s) Summary
Scorecard token warning, TruffleHog hook migration, and security surface documentation
.github/workflows/python-scorecard.yml, .pre-commit-config.yaml, SECURITY.md
Adds a runtime check for missing SCORECARD_TOKEN with explicit warning, migrates TruffleHog pre-commit hook from local to remote repository with pinned version (v3.92.3), and documents GitHub Actions workflow security attack surfaces (input injection, token permissions, mutable action refs, unchecked inputs) and mitigations.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • ByronWilliamsCPA/.github#48: Both PRs touch the reusable .github/workflows/python-precommit.yml, with the main PR adding a no-build input/NO_BUILD_FLAG that changes the uv sync and uv run pre-commit command arguments, directly building on the pre-commit workflow introduced in #48.
  • ByronWilliamsCPA/.github#4: Both PRs touch the FIPS reusable workflow: the main PR updates .github/workflows/python-fips-compatibility.yml to introduce a no-build input and thread NO_BUILD_FLAG through the existing uv sync/FIPS report + runtime test commands, replacing previously hardcoded --no-build behavior.
  • ByronWilliamsCPA/.github#96: The retrieved PR #96 modifies the same reusable workflow commands (e.g., uv sync/uv run) to add --no-build (and related hardening) in many of the same workflow files that the main PR now makes conditional via a workflow_call no-build/NO_BUILD_FLAG input.

Poem

🐰 A rabbit hops through workflows grand,
Where --no-build once was hardcoded in hand.
Now inputs control the flow,
With NO_BUILD_FLAG steal the show—
Flexibility blooms across the land! 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the primary change: adding a no-build opt-out input to reusable workflows, which is the main objective of this PR.
Description check ✅ Passed The description is comprehensive and well-structured, covering Problem, Root Cause, Solution, Files Changed, and Test Plan sections that align well with the template's Type of Change and Changes Made sections.
Linked Issues check ✅ Passed The PR fully implements the feature to add no-build input to all affected reusable workflows across 11 files, addressing the core objective of enabling repos with build backends to opt out of --no-build constraints.
Out of Scope Changes check ✅ Passed Changes to SECURITY.md, .pre-commit-config.yaml, and python-scorecard.yml are pre-existing unrelated fixes bundled with the pre-commit run and documented as Commit 1, while Commit 2 focuses on the no-build feature across 11 workflow files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/no-build-opt-out-0

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 and usage tips.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the org-level reusable GitHub Actions workflow library to make uv sync and uv run optionally use --no-build, so downstream repos with build backends (hatchling, setuptools, etc.) can opt out while preserving the default behavior for script-only repos.

Changes:

  • Add a no-build boolean input (default true) to reusable Python workflows and thread it through via a job-level NO_BUILD_FLAG.
  • Replace hardcoded --no-build in uv sync and uv run commands with $NO_BUILD_FLAG across the affected workflows (keeping uv pip install --no-build ... security controls intact).
  • Update repo security and tooling files (SECURITY surface area documentation, TruffleHog hook source pinning, Scorecard token warning).

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
SECURITY.md Documents security surface areas relevant to a reusable workflow library.
.pre-commit-config.yaml Switches TruffleHog hook to upstream repo with SHA pinning and updated configuration comments.
.github/workflows/python-ci.yml Adds no-build input and uses $NO_BUILD_FLAG for uv sync/run in CI jobs.
.github/workflows/python-compatibility.yml Adds no-build input and uses $NO_BUILD_FLAG in matrix testing workflow.
.github/workflows/python-docs.yml Adds no-build input and uses $NO_BUILD_FLAG for docs build steps.
.github/workflows/python-fips-compatibility.yml Adds no-build input and uses $NO_BUILD_FLAG in FIPS-related jobs.
.github/workflows/python-mutation.yml Adds no-build input and uses $NO_BUILD_FLAG for mutation testing commands.
.github/workflows/python-performance-regression.yml Adds no-build input and uses $NO_BUILD_FLAG for benchmark execution.
.github/workflows/python-precommit.yml Adds no-build input and uses $NO_BUILD_FLAG for uv sync/run pre-commit.
.github/workflows/python-release.yml Adds no-build input and uses $NO_BUILD_FLAG in test and release jobs.
.github/workflows/python-sbom.yml Adds no-build input and uses $NO_BUILD_FLAG for dependency sync before SBOM generation.
.github/workflows/python-scorecard.yml Adds a warning step when SCORECARD_TOKEN is not provided.
.github/workflows/python-security-analysis.yml Adds no-build input and uses $NO_BUILD_FLAG for uv sync/run in security jobs.
.github/workflows/python-sonarcloud.yml Adds no-build input and uses $NO_BUILD_FLAG for uv sync/run in SonarCloud analysis.


- name: Install dependencies
run: uv sync --all-extras --frozen --no-build
run: uv sync --all-extras --frozen $NO_BUILD_FLAG
To reproduce locally:
\`\`\`bash
uv run --frozen --no-build python ${benchmarkScript} --iterations 1000 ${benchmarkArgs}
uv run --frozen $NO_BUILD_FLAG python ${benchmarkScript} --iterations 1000 ${benchmarkArgs}
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
.pre-commit-config.yaml (1)

61-80: ⚡ Quick win

Remove duplicate comments explaining staged-file scanning.

The rationale for staged-file-only scanning is documented twice: once in the block comment (lines 61-66) and again in the hook description field (lines 73-76). This redundancy reduces maintainability.

📝 Consolidate documentation

Keep the block comment above the repo (lines 61-66) and remove the duplicate explanation from the hook entry:

       - id: trufflehog
         name: TruffleHog Secret Scanner
         description: Detect secrets in your data before committing
-        # Scan staged files only. The git-history mode (--since-commit HEAD) also
-        # traverses fetched remote branches in the local object store, producing
-        # false positives from unmerged branches. Staged-file scanning is the
-        # correct scope for a pre-commit hook; git history scanning belongs in CI.
         entry: bash -c 'command -v trufflehog >/dev/null 2>&1 && (git diff --cached -z --diff-filter=d --name-only 2>/dev/null | xargs -0 -r trufflehog filesystem --fail --no-update --results=verified,unknown --exclude-paths .trufflehog-exclude) || echo "TruffleHog not installed - skipping secret scan"'
         language: system
         pass_filenames: false
         stages: [pre-commit]
🤖 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 @.pre-commit-config.yaml around lines 61 - 80, The hook contains a duplicate
explanatory comment about staged-file-only scanning inside the trufflehog hook
entry; remove the repeated explanation from the hook's metadata (the
"description" or the inline comment in the entry for the hook with id
"trufflehog" and name "TruffleHog Secret Scanner") and keep the single block
comment above the repo definition (the existing block comment before repo:
https://github.com/trufflesecurity/trufflehog). Ensure only the top-level block
comment documents the rationale, leaving the hook entry (id: trufflehog, name:
TruffleHog Secret Scanner, entry: ...) free of the duplicated explanation.
SECURITY.md (1)

38-40: ⚡ Quick win

Replace double-hyphen with standard punctuation.

Line 39 uses a double-hyphen (--) as a sentence separator. Standard technical writing style prefers commas, semicolons, or sentence restructuring over double-hyphens.

✍️ Suggested rephrasing
-This repository is a GitHub Actions workflow library. Its security surface differs from
-application repos -- there is no deployed service, but the workflows run with elevated
-permissions in every downstream repo that calls them.
+This repository is a GitHub Actions workflow library. Its security surface differs from
+application repos; there is no deployed service, but the workflows run with elevated
+permissions in every downstream repo that calls them.

Or alternatively:

-This repository is a GitHub Actions workflow library. Its security surface differs from
-application repos -- there is no deployed service, but the workflows run with elevated
-permissions in every downstream repo that calls them.
+This repository is a GitHub Actions workflow library. Unlike application repos, there is
+no deployed service, but the workflows run with elevated permissions in every downstream
+repo that calls them.
🤖 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 `@SECURITY.md` around lines 38 - 40, Replace the double-hyphen in the sentence
"there is no deployed service, but the workflows run with elevated permissions
in every downstream repo that calls them." with standard punctuation or
restructure the sentence; e.g., use a comma or semicolon ("there is no deployed
service, but the workflows run with elevated permissions in every downstream
repo that calls them.") or split into two sentences to remove the `--` and keep
tone consistent in SECURITY.md.
🤖 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/python-compatibility.yml:
- Line 265: The run step that currently invokes "uv sync --all-extras --frozen
$NO_BUILD_FLAG" fails to expand NO_BUILD_FLAG on Windows PowerShell runners;
replace the shell-specific $NO_BUILD_FLAG usage with the GitHub Actions context
expansion (e.g., use ${{ env.NO_BUILD_FLAG }} or the appropriate job/matrix
context) so the flag is inserted consistently across all shells, and ensure the
run line references that context token (NO_BUILD_FLAG) instead of a shell
variable.

In @.github/workflows/python-scorecard.yml:
- Around line 103-107: The step "Warn if SCORECARD_TOKEN is absent" must not use
secrets in the step-level if; instead map secrets.SCORECARD_TOKEN into an
environment variable (e.g., SCORECARD_TOKEN: ${{ secrets.SCORECARD_TOKEN }}) on
the step and remove the if: that references secrets; then perform the emptiness
check inside the shell run block (for example, use a shell test like checking if
"$SCORECARD_TOKEN" is empty and echo the warning if so). Update the step that
currently references secrets.SCORECARD_TOKEN in its if to use the env variable
SCORECARD_TOKEN and move the conditional logic into the run script.

---

Nitpick comments:
In @.pre-commit-config.yaml:
- Around line 61-80: The hook contains a duplicate explanatory comment about
staged-file-only scanning inside the trufflehog hook entry; remove the repeated
explanation from the hook's metadata (the "description" or the inline comment in
the entry for the hook with id "trufflehog" and name "TruffleHog Secret
Scanner") and keep the single block comment above the repo definition (the
existing block comment before repo:
https://github.com/trufflesecurity/trufflehog). Ensure only the top-level block
comment documents the rationale, leaving the hook entry (id: trufflehog, name:
TruffleHog Secret Scanner, entry: ...) free of the duplicated explanation.

In `@SECURITY.md`:
- Around line 38-40: Replace the double-hyphen in the sentence "there is no
deployed service, but the workflows run with elevated permissions in every
downstream repo that calls them." with standard punctuation or restructure the
sentence; e.g., use a comma or semicolon ("there is no deployed service, but the
workflows run with elevated permissions in every downstream repo that calls
them.") or split into two sentences to remove the `--` and keep tone consistent
in SECURITY.md.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: cc38b384-aa25-4b6e-b003-ac3ae1f875e6

📥 Commits

Reviewing files that changed from the base of the PR and between 3d29e7c and 2e3e3dd.

📒 Files selected for processing (14)
  • .github/workflows/python-ci.yml
  • .github/workflows/python-compatibility.yml
  • .github/workflows/python-docs.yml
  • .github/workflows/python-fips-compatibility.yml
  • .github/workflows/python-mutation.yml
  • .github/workflows/python-performance-regression.yml
  • .github/workflows/python-precommit.yml
  • .github/workflows/python-release.yml
  • .github/workflows/python-sbom.yml
  • .github/workflows/python-scorecard.yml
  • .github/workflows/python-security-analysis.yml
  • .github/workflows/python-sonarcloud.yml
  • .pre-commit-config.yaml
  • SECURITY.md

Comment thread .github/workflows/python-compatibility.yml
Comment thread .github/workflows/python-scorecard.yml
@williaby
Copy link
Copy Markdown
Collaborator Author

PR Review

4 Critical | 1 Important | 4 Suggested | 2 Informational


Critical (must fix before merge)

  • Merge conflicts (mergeStateStatus: DIRTY): Branch conflicts with main due to PR fix(ci): remove --no-build from uv sync in all reusable workflows #107 (removed --no-build from uv sync) merging after this branch was cut. Rebase required before any fixes will land cleanly.

  • $NO_BUILD_FLAG PowerShell incompatibility (.github/workflows/python-compatibility.yml:265): Matrix includes Windows runners; PowerShell does not expand $VAR_NAME from env -- it uses $env:VAR_NAME. The --no-build flag will be silently ignored on Windows even when no-build: true. Fix: use ${{ env.NO_BUILD_FLAG }} (GitHub Actions evaluates this before any shell runs). Confirmed by CodeRabbit.

  • CHANGELOG.md not updated (CHANGELOG.md): PR has feat(workflows): and fix(security): commits; CLAUDE.md requires updating CHANGELOG.md. Not present in changed files.

  • if: ${{ secrets.SCORECARD_TOKEN == '' }} unreliable (.github/workflows/python-scorecard.yml:107): GitHub Actions does not reliably evaluate secret comparisons in if: conditions (runner issue #520). The warning step will never fire. Fix: remove the if:, add env: SCORECARD_TOKEN: ${{ secrets.SCORECARD_TOKEN }}, check [ -z "$SCORECARD_TOKEN" ] inside run:. Found by CodeRabbit.


Important (should fix)

  • TruffleHog hook: leftover entry: and language: system may be ignored (.pre-commit-config.yaml:62): When switching from repo: local to a remote repo, pre-commit reads entry: and language: from the upstream .pre-commit-hooks.yaml, not from the user config. The --results=verified,unknown, staged-file-only, and graceful-skip behaviors (defined in the local entry:) may be silently dropped depending on the upstream hook definition at SHA 05cccb53. Verify that the upstream hook preserves this behavior, or keep repo: local.

Suggested

  • SECURITY.md:39: Double-hyphen -- as clause separator; replace with ; per CLAUDE.md writing rules. (Found by CodeRabbit.)
  • python-ci.yml, python-precommit.yml, python-performance-regression.yml: Double space in error messages/step summaries when no-build: false and NO_BUILD_FLAG is empty (cosmetic).
  • Test plan items (3 of 3) are unchecked in the PR description.
  • PR fix(sonar): exclude S8541 hotspot for uv sync in reusable workflows #109 (fix(sonar): exclude S8541 hotspot) appears superseded by this PR; consider closing it.

Copilot review was not auto-requested (org ruleset rule not active). SonarCloud findings not checked (MCP not available).

🤖 Generated with Claude Code

williaby and others added 3 commits May 15, 2026 15:45
…ning, expand SECURITY.md

- Switch TruffleHog pre-commit hook from local script to upstream
  trufflesecurity/trufflehog repo hook (v3.92.3, SHA-pinned)
- Add SCORECARD_TOKEN absence warning step to python-scorecard workflow
  so callers get an actionable message when Branch-Protection scores 0
- Expand SECURITY.md with Security Surface Areas section covering
  workflows, secrets, and dependency supply chain
- Add pragma: allowlist secret to two detect-secrets false positives
  (TruffleHog SHA and SCORECARD_TOKEN comparison expression)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Repos using a build backend (hatchling, setuptools) fail with
"uv sync --no-build" because uv refuses to build the repo's own
package. Prior to this change, --no-build was hardcoded in every
workflow, making those repos unable to use the shared workflows.

Adds a no-build: boolean input (default: true) to all 11 affected
workflows. Callers with a build backend set no-build: false to let
uv build the local package while still refusing to build third-party
source distributions.

Implementation: each job exports NO_BUILD_FLAG at the job env level
(${{ inputs.no-build && '--no-build' || '' }}), then all uv sync/run
commands reference $NO_BUILD_FLAG unquoted so an empty value word-
splits away cleanly.

Workflows changed: python-ci, python-compatibility, python-docs,
python-fips-compatibility, python-mutation, python-performance-
regression, python-precommit, python-release, python-sbom,
python-security-analysis, python-sonarcloud.

Note: uv pip install --no-build lines (S8541/S8544 security fix from
PR #110) are intentionally untouched -- those guard against executing
arbitrary sdist build scripts from PyPI, not local package builds.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- python-compatibility.yml: add shell: bash to Install dependencies step
  to prevent $NO_BUILD_FLAG from silently expanding to nothing on
  Windows matrix legs where the default shell is PowerShell
- python-scorecard.yml: replace unreliable secrets-in-if expression with
  env var + shell check pattern (runner issue #520 causes direct secret
  comparison in if: to behave inconsistently)
- .pre-commit-config.yaml: remove language: system from TruffleHog hook
  (not overridable for remote repos; upstream uses language: golang which
  is the correct behavior); clarify comment about entry override intent
- CHANGELOG.md: add Unreleased entries for feat/fix commits in this PR
- SECURITY.md: replace double-hyphen clause separator with semicolon

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@williaby williaby force-pushed the claude/no-build-opt-out-0 branch from 2e3e3dd to 2b09280 Compare May 15, 2026 22:55
williaby and others added 2 commits May 15, 2026 15:56
…nce regression

The Post PR Comment step in python-performance-regression.yml uses
actions/github-script. The PR body template literal used $NO_BUILD_FLAG
which is a shell env var not accessible in JavaScript. Add NO_BUILD_FLAG
to the step env: block and reference it as ${noBuildFlag} (via
process.env.NO_BUILD_FLAG) in the template literal so the reproduce-locally
command in the PR comment reflects the actual flag used in CI.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@williaby
Copy link
Copy Markdown
Collaborator Author

Fix Summary

All findings from the pr-review have been addressed. The PR has been rebased onto main (resolving the conflict with PR #107 which removed --no-build from the same lines this PR replaces with $NO_BUILD_FLAG).

Critical fixes applied

python-compatibility.yml (PowerShell incompatibility)
Added shell: bash to the Install dependencies step. On Windows matrix legs the default shell is PowerShell, which does not expand $NO_BUILD_FLAG. Explicit shell: bash ensures consistent behavior across all OS matrix targets. Commit 2b09280.

python-scorecard.yml (unreliable secret check in if: expression)
Replaced if: ${{ secrets.SCORECARD_TOKEN == '' }} with an env-var mapping + shell check ([ -z "$HAS_SCORECARD_TOKEN" ]). Direct secret comparison in if: is unreliable per GitHub runner issue #520 because secrets are redacted before expression evaluation. Commit 2b09280.

python-performance-regression.yml (shell variable in JS template literal)
The Post PR Comment step uses actions/github-script (JavaScript), so $NO_BUILD_FLAG was appearing as a literal string in the PR comment body. Added NO_BUILD_FLAG to the step env: block and updated the template literal to use ${noBuildFlag} via process.env.NO_BUILD_FLAG. Commit 94eb392.

Other fixes

  • .pre-commit-config.yaml: Removed language: system from the TruffleHog hook. For remote repos, language: is not overridable; the upstream language: golang is used. The entry: override is honored and works correctly because pre-commit puts the Go-built binary in PATH when running the hook subprocess. Commit 2b09280.
  • SECURITY.md: Replaced -- clause separator with ;. Commit 2b09280.
  • CHANGELOG.md: Added [Unreleased] entries for all feat: and fix: commits in this PR. Commit 2b09280.

Pre-commit gate

All hooks pass: trim-whitespace, yamllint, markdownlint, detect-secrets, TruffleHog, no-em-dash, commitizen.

Merge state

PR is now MERGEABLE (rebased onto current main, no conflicts).

@sonarqubecloud
Copy link
Copy Markdown

@williaby williaby merged commit 4e0fd54 into main May 15, 2026
24 checks passed
@williaby williaby deleted the claude/no-build-opt-out-0 branch May 16, 2026 00:46
williaby pushed a commit that referenced this pull request May 16, 2026
The docs table did not list the public no-build boolean input
(default true) added by PR #112; consumers had no way to discover
how to opt out of --no-build for projects with a build backend
like hatchling. Inserted in canonical YAML order after the
system-deps-windows row.
williaby pushed a commit that referenced this pull request May 16, 2026
The docs table did not list the public no-build boolean input
(default true) added by PR #112; consumers had no way to discover
how to opt out of --no-build for projects with a build backend
like hatchling. Inserted in canonical YAML order after the
system-deps-windows row.
williaby added a commit that referenced this pull request May 16, 2026
* fix(workflow-templates): correct fips-compatibility reusable path and cifuzzy SHA tag

- python-fips-compatibility.yml: add missing .github/ path segment so the
  starter template resolves the reusable workflow at the actual location
  (ByronWilliamsCPA/.github/.github/workflows/python-fips-compatibility.yml);
  the previous path pointed to a non-existent file at repo root and would
  fail to load (PR #70, #94 review).
- python-cifuzzy.yml: change the SHA comment for github/codeql-action/upload-sarif
  from '# v4' to '# v4.35.4' to match every other usage of the same SHA in
  this repo (PR #103 review).

* docs(workflows): add system-deps inputs to python-compatibility table

Adds system-deps-ubuntu, system-deps-macos, and system-deps-windows rows to
the inputs table so the caller-facing documentation matches the actual
workflow_call interface (PR #105 review).

* docs(community): route vulnerability reports to private channels

- profile/README.md: link to the GitHub Security Advisory creation form
  (/security/advisories/new) instead of the advisories list page, so
  reporters land directly on the private submission UI (PR #104 review).
- SUPPORT.md: split the Contact section into general inquiries (Issues
  or Discussions) and security vulnerabilities (private reporting via
  Security Advisories), so the broad 'all inquiries' wording no longer
  routes vulnerability reports to public channels (PR #104 review).

* docs(agents): clarify that the Bats test suite under tests/ exists

CLAUDE.md and GEMINI.md previously stated 'no test suite' in the Repository
Purpose / Repository Context sections. The repo does have a Bats test suite
under tests/ (covered by .github/workflows/shell-tests.yml), so the
statement was misleading agents about validation steps. Narrows the
statement to 'no Python package' and points to the Bats suite (PR #98
review).

* docs(changelog): record fips path and cifuzzy SHA tag fixes

Adds two entries under [Unreleased] Fixed to surface the
workflow-templates fixes already on this branch so downstream
consumers know to re-copy the starter templates after the
fips path correction.

* docs(agents): scope Bats coverage claim to update-pinned-actions.sh

The previous wording 'covers the shell scripts in scripts/' implied
broader validation than exists; only update-pinned-actions.bats runs,
covering one of the six shell scripts in scripts/. Names the specific
covered script and notes that the others are not yet tested.

* docs(workflows): fill default cells for system-deps inputs

The three system-deps-{ubuntu,macos,windows} rows had empty Default
cells, while every other row in the table specifies an explicit
backtick-quoted default. The workflow YAML has no default: key for
these inputs, so the actual default is the empty string; '' makes
the table uniform and removes ambiguity between 'no documented
default' and 'unset'.

* docs(workflows): add no-build input row to python-compatibility table

The docs table did not list the public no-build boolean input
(default true) added by PR #112; consumers had no way to discover
how to opt out of --no-build for projects with a build backend
like hatchling. Inserted in canonical YAML order after the
system-deps-windows row.

---------

Co-authored-by: Claude <noreply@anthropic.com>
williaby added a commit that referenced this pull request May 18, 2026
…put json

Resolves SonarCloud rule `githubactions:S8541` (MAJOR / VULNERABILITY) on
`python-security-analysis.yml` which fired on the Safety Vulnerability Scan
step introduced in PR #138.

Root cause: the existing `$NO_BUILD_FLAG` env interpolation pattern (from
PR #112) is invisible to SonarCloud's S8541 regex, which scans for a
literal `--no-build` token on the `uv run` line. The rule cannot statically
prove the flag is set when it is passed via a variable.

Fix: use a literal `--no-build` for `safety scan`. The flag has no
practical effect on safety scan (which reads dependency metadata from
pyproject.toml/uv.lock and never runs setup scripts), but making it
visible to the static analyzer clears the Quality Gate.

Also drops `--output json` since stdout is not piped or redirected;
`--save-as json safety-report.json` writes the artifact directly.

Closes the SonarCloud Quality Gate fail on the safety-version-drift
chain (#136, #137, #138).
williaby added a commit that referenced this pull request May 18, 2026
* fix(security): migrate Safety check to safety 3.x scan command

`safety check` was deprecated by Safety upstream after 1 May 2024
and its CLI semantics drifted in safety 3.x. After #137 fixed the
`--output` flag handling, every consumer repo's Safety step still
fails with:

  HINT: [Errno 2] No such file or directory: '.safety-policy.yml'
  Process completed with exit code 2.

safety 3.x's legacy `check` command requires a `.safety-policy.yml`
in the project root, which is a per-consumer requirement that should
not be imposed by a shared reusable workflow.

Migration: replace `safety check --file requirements-scan.txt --json`
with the safety 3.x recommended invocation:

  safety scan --output json --save-as json safety-report.json

What changes:
- `safety scan` auto-discovers project files (pyproject.toml,
  requirements*.txt, uv.lock) -- no need to pre-generate
  requirements-scan.txt via `uv export`.
- `--output json` controls the stdout format (still propagates exit
  code on findings).
- `--save-as json safety-report.json` persists the same report to
  the artifact path. Two-arg form is the documented safety 3.x
  syntax: FORMAT FILE_PATH.

Side effects:
- The `uv export` line is dropped from the run step (safety scan
  reads pyproject/lock directly).
- `requirements-scan.txt` is removed from the Upload Security Reports
  artifact list (it is no longer produced).

This is the third and final fix in the safety-version-drift chain
(#136 egress-policy + #137 --output syntax + this PR). The deeper
fix would be pinning safety to 2.x in the workflow, but Safety
upstream has communicated that 2.x is end-of-life; the long-term
path is the scan command this PR adopts.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(quality): inline --no-build for safety scan; drop redundant --output json

Resolves SonarCloud rule `githubactions:S8541` (MAJOR / VULNERABILITY) on
`python-security-analysis.yml` which fired on the Safety Vulnerability Scan
step introduced in PR #138.

Root cause: the existing `$NO_BUILD_FLAG` env interpolation pattern (from
PR #112) is invisible to SonarCloud's S8541 regex, which scans for a
literal `--no-build` token on the `uv run` line. The rule cannot statically
prove the flag is set when it is passed via a variable.

Fix: use a literal `--no-build` for `safety scan`. The flag has no
practical effect on safety scan (which reads dependency metadata from
pyproject.toml/uv.lock and never runs setup scripts), but making it
visible to the static analyzer clears the Quality Gate.

Also drops `--output json` since stdout is not piped or redirected;
`--save-as json safety-report.json` writes the artifact directly.

Closes the SonarCloud Quality Gate fail on the safety-version-drift
chain (#136, #137, #138).

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
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.

2 participants