Skip to content

ci: fix the release's Python setup and harden workflows to the repo standard - #1008

Open
zeevmoney wants to merge 25 commits into
masterfrom
zeev/per-18920-release-python-311
Open

zeevmoney wants to merge 25 commits into
masterfrom
zeev/per-18920-release-python-311

Conversation

@zeevmoney

@zeevmoney zeevmoney commented Nov 8, 2026 •

Copy link
Copy Markdown
Member

Summary

Fixes the release workflow, which failed for 0.10.0-rc.6, and brings the GitHub Actions setup up to Permit's repo standard: pinned actions, least-privilege tokens, workflow linting, Dependabot, secret scanning on PRs, and a scheduled security scan. The setup follows permitio/permit-golang#78.

Changelog

Fixed

  • The release workflow sets up Python 3.11 instead of 3.11.8, which Ubuntu 26.04 runners don't have. This fixes the failed 0.10.0-rc.6 publish.
  • This closes the five code-scanning alerts "Workflow does not contain permissions" (alerts 1, 2, 3, 4 and 11).

Added

  • actionlint, zizmor, gitleaks, shellcheck and shfmt as hooks. CI runs them with a sha256-pinned prek.
  • A secret scan of each PR's commits, run by gitleaks as part of the required CI check.
  • Dependency review on PRs. It fails when a change adds a high or critical vulnerability.
  • Dependabot version updates for pip, npm (docs), docker, GitHub Actions and pre-commit hooks. The config comes from ci: add Dependabot version updates (PER-15358) #957 by @EliMoshkovich.
  • A scheduled security scan on Monday and Thursday and a weekly digest, both reported to Slack. The scan covers dependency trees, the published images, Dependabot alerts and the git history.

Changed

  • Every action is pinned to a full commit SHA. The release workflow keeps the exact action versions it ran before.
  • Every workflow and job has least-privilege permissions, and no checkout persists its credentials.
  • Release: the PyPI job runs in the pypi environment, and image builds no longer use a registry cache. The unused token env and the unused docker-compose v1 download are removed.
  • CI:
    • Runners are pinned to ubuntu-24.04.
    • A new push cancels the PR's older run.
    • The required CI check also runs on stacked PRs.
    • Tool versions are pinned exactly.

Release fix

ubuntu-latest is now Ubuntu 26.04, and actions/setup-python has no 3.11.8 build for it, so every publish job of 0.10.0-rc.6 failed at "Python setup":

The version '3.11.8' with architecture 'x64' was not found for Ubuntu 26.04.

Both publish jobs now set up python-version: '3.11'. The failed run stopped before any build, so nothing was published under 0.10.0-rc.6.

on_release.yml: every behavior change

Each action is pinned to the exact commit the 0.10.0-rc.5 and rc.6 runs downloaded, so the action code is unchanged: checkout v2.8.0, setup-python v5.6.0, login v2.2.0, setup-qemu v3.7.0, setup-buildx v3.12.0, build-push v6.19.2, upload-release-asset v1.7.5, pypi-publish v1.14.3.

  • permissions: {} at the top, and each job gets only what it uses:
    • validate_release: none.
    • build_and_test and publish_docker_images: contents: read.
    • publish_python_packages: contents: write, for the release assets.
    • The id-token and pull-requests grants are removed. The PyPI steps pass a password, so the publish action never asks for an OIDC token.
  • persist-credentials: false on every checkout.
  • Release and matrix values reach run: blocks through env:.
  • The publish job runs in the pypi environment. The environment has no protection rules, so this adds no approval step.
  • Release image builds no longer read or write a registry cache, so each release builds every layer.
  • Removed:
    • the unused TOKEN_GITHUB env;
    • the unused docker-compose 1.29.2 download (the job runs docker compose, the v2 plugin).
  • pip install versions are pinned to those the rc.5 run installed (semver 3.1.0, packaging 26.3, wheel 0.48.0).
  • Unchanged: the triggers, the runner, the matrix, the tag logic and the version checks.

Workflows

In tests.yml, pre-commit.yml and docs-build.yml:

  • every action is pinned to a full commit SHA with its version;
  • every job has an explicit permissions block;
  • every checkout has persist-credentials: false;
  • runners are pinned to ubuntu-24.04;
  • the redis service image and the pip-installed tools are pinned exactly;
  • the shellcheck findings are fixed.

tests.yml also changes how its checks run:

  • A newer push to a PR cancels the older run.
  • The pull_request trigger has no base-branch filter, so the required CI check runs on stacked PRs too.
  • The CI aggregate checks its jobs through .github/scripts/ci-aggregate.sh.

This closes the five code-scanning alerts "Workflow does not contain permissions" (alerts 1, 2, 3, 4 and 11).

Hooks

.pre-commit-config.yaml adds actionlint, zizmor (with .github/zizmor.yml), gitleaks, and shellcheck and shfmt for .github/scripts. Every hook's rev is frozen to its tag's commit.

The pre-commit job runs the hooks with prek 0.5.9, which it installs from .github/binaries.lock and checks by sha256. The job fails unless all 12 hooks pass. Locally, prek 0.5.5 or later is needed.

Secret scanning and dependency review on PRs

  • secrets job (part of CI): runs .github/scripts/gitleaks-range.sh, a checksum-verified gitleaks 8.30.1 over the PR's commit range, redacted.
    • It fails on a finding, and when the scan did not run (an empty range, or 0 commits scanned).
    • .gitleaks.toml adds a permit-api-key rule. It allowlists, with a comment each, the placeholder values in docs and tests.
  • dependency-review job: fails on high or critical vulnerabilities that a PR's dependency changes add.

Dependabot

.github/dependabot.yml comes from #957 by @EliMoshkovich (his three commits, kept as authored), plus follow-up commits.

  • Ecosystems: pip, npm (documentation), docker (/docker and the git-leak seed image), github-actions and pre-commit.
  • Schedule: weekly on Monday, at most 5 open PRs, a 7-day cooldown, and 14 days for majors where the ecosystem supports it.
  • Grouping: pip, npm and docker group their minor and patch updates. GitHub Actions and pre-commit hooks each get one tooling group.
  • pip: uses increase-if-necessary, so the packages' minimum versions are not raised to the newest release.
  • Every ignore carries its reason.

Scheduled security scan

security.yml runs .github/scripts/security-scan.sh twice a week and digest.sh weekly, and can be started by hand. The scan covers:

  • the lowest and highest versions the requires files allow (resolved with uv, scanned with Trivy);
  • the newest PyPI release and the published opal-server and opal-client images;
  • open Dependabot alerts;
  • a full-history gitleaks scan;
  • TruffleHog with verified results, on manual runs only.

The report goes to the job summary and to Slack. The scan reads the Dependabot alerts with a per-run installation token from a GitHub App that has only "Dependabot alerts: read". No personal access token is used. Until these secrets exist, each part skips and says so in the summary:

  • SECURITY_SLACK_WEBHOOK_URL, in the security-scan environment. Both jobs run in that environment, so the webhook is available only to runs from master. A manual run must start from master.
  • OPAL_CI_APP_CLIENT_ID and OPAL_CI_APP_PRIVATE_KEY (the permitio-opal-ci App), in the security-scan environment.
  • GITLEAKS_HISTORY_ACCEPT_SHA256, in the security-scan environment. A dependency-vulnerability gate on PRs is not added yet, because the lowest allowed versions currently have known vulnerabilities.

Testing

  • prek over every file: 12 of 12 hooks pass. That includes zizmor with online audits ("No findings to report") and actionlint (exit 0).
  • check-jsonschema passes every workflow and dependabot.yml.
  • gitleaks-range.sh over this PR's commits: 0 findings.
  • Tests for the scripts behind the required checks run in CI. .github/scripts/tests/ci-aggregate.test.sh (23 cases) and prek-count.test.sh (12 cases) run in the pre-commit job. gitleaks-range.test.sh (14 cases, with keys generated at run time) runs in the secrets job. Bugs planted in the scripts make these tests fail.
  • CONTRIBUTING.md now tells contributors to use prek 0.5.5 or later.
  • Failure paths tested:
    • the secret scan fails on a committed key, even with a gitleaks:allow comment, on an empty range and on the zero SHA;
    • ci-aggregate fails on skipped, failed or cancelled jobs and on a wrong job count;
    • the security scan fails when it did not run.
  • A local run of the scheduled scan without secrets completes, and reports findings in the dependency trees, the images and history.

Supersedes #957 and #898.

🤖 Generated with Claude Code

…on Ubuntu 26.04

ubuntu-latest is now Ubuntu 26.04, and actions/setup-python has no
3.11.8 build for it, so every publish job of the 0.10.0-rc.6 release
failed at "Python setup" before building anything. '3.11' takes the
newest 3.11 the runner has, as tests.yml already does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings November 8, 2026 20:18
@netlify

netlify Bot commented Nov 8, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for opal-docs canceled.

Name Link
🔨 Latest commit 2e8ed35
🔍 Latest deploy log https://app.netlify.com/projects/opal-docs/deploys/6af226814bd01c10898c6162

@linear-code

linear-code Bot commented Nov 8, 2026 •

Copy link
Copy Markdown

PER-18920

PER-18261

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

EliMoshkovich and others added 13 commits November 8, 2026 23:29
This repo had no dependency automation. It matters beyond OPAL itself, because
OPAL is the upstream that downstream consumers inherit: permitio/pdp-v2 installs
opal-client and opal-common, so the floors and caps declared here decide what a
PDP image can resolve. Several CVE waivers in the PDP exist purely because a cap
here forbids the fixed version.

Ecosystems: pip (/), npm (/documentation), docker (/docker), github-actions (/) -
weekly, Monday. Shape mirrors the PDP config so
every repo behaves alike. cooldown is supply-chain defence rather than noise
reduction (GitHub made a 3-day cooldown the platform default in July 2026);
security updates are never delayed by it. Only semver-strict ecosystems support
the semver-specific knobs, so pip/npm get semver-major-days and
docker/github-actions get default-days only.

A SCOPE LIMIT worth stating plainly, because it is easy to assume otherwise: the
pip entry does NOT cover OPAL's library dependencies. Those live in
packages/requires.txt and packages/*/requires.txt, and each setup.py loads them
at runtime with a plain open() inside get_install_requires(). Dependabot's pip
parser reads standard manifests and cannot resolve a dynamic file read, so those
files are invisible to it. Bumping OPAL's actual caps therefore stays manual
until they become a pyproject.toml - which is the highest-value follow-up here
and deserves its own PR. What the entry does cover is still useful: two pins in
the root requirements.txt already carry the comment "pinned by Snyk to avoid a
vulnerability", so someone was doing this by hand.

Real work the other entries will surface:

  docker/Dockerfile builds on python:3.10-bookworm and python:3.10-slim-bookworm,
  and Python 3.10 reaches END OF LIFE in October 2026. The PDP already moved off
  python:3.10 for that reason plus four CPython CVEs that only had 3.13 fixes. It
  also pulls alpine:latest twice - a floating tag with no reproducibility - and
  hand-pins openpolicyagent/opa:1.9.0-static and permitio/cedar-agent:0.2.1.

  The workflows mix actions/checkout@v2, @V3, @v4 and a bare commit SHA;
  actions/setup-python@v2, @v4, @v5; docker/build-push-action@v2 and @v6;
  docker/setup-buildx-action@v1 and @V3; docker/setup-qemu-action@v1 and @V3. The
  @v1/@v2 generations are years old and run on Node runtimes GitHub has already
  deprecated.

The config ends with a DOWNSTREAM NOTE recording the three caps that force PDP
waivers - starlette<1, ddtrace<4, and gitpython's >=3.1.32 floor - so the next
person to touch requires.txt sees why they matter to a consumer. The gitpython
one is the sharpest: 3.1.59 fixes CVE-2026-78676, a CRITICAL (CVSS 9.8)
argument-injection RCE, and a floor of 3.1.32 lets any consumer resolve a
vulnerable version. pdp-v2:0.9.14 shipped 3.1.57 and had to add its own floor.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- The starlette <1 cap is gone (raised to >=1.3.1,<2 by #959), so drop it from
  the downstream note; ddtrace <4 and the gitpython 3.1.32 floor still stand.
- The workflow action-version inventory now matches master (no checkout@v4;
  login-action@v2 added).
- Drop an unverifiable claim about GitHub's default cooldown, the OPA version
  pin that #906 changes, and prefix-development on github-actions (no dev deps).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r, fix notes

Review follow-ups:
- Dependabot's pip fetcher reads any *.txt whose lines parse as requirements
  in a configured directory and its immediate subdirectories, so
  packages/requires.txt is covered from '/' and the per-package requires.txt
  files via 'directories'. The old comment said they were invisible to it.
- Hold python minor/major tag bumps: the Dockerfile hard-codes the 3.10
  site-packages path and opal-server caps python <3.13, so they'd only be red.
- Add the test-only app-tests seed image; say which images Dependabot can
  see (FROM lines) and can't (OPA via skopeo ARG, EOPA via wget).
- Correct the action inventory and the 'mirrors other configs' claim.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- pip: versioning-strategy increase-if-necessary. Requirement .txt
  files otherwise get `increase`, which raises every `>=` floor to the
  latest release; these are the published packages' ranges.
- pip: a shared-majors group for aiohttp, click, gitpython, pyjwt and
  tenacity, which sit in more than one requires.txt, so a major update
  is one PR instead of one per directory.
- Every entry: weekly on Monday, limit 5, 7-day cooldown (plus 14 days
  for semver-major on pip and npm), minor-and-patch and security
  groups, deps / deps-dev prefixes, the existing `dependencies` label.
- docker: split /docker from the git-leak seed image so the python
  minor hold applies to /docker only, and say that the floating
  python:3.12 bases get no PRs while it is held.
- pre-commit: new entry for the hook revs; black, isort and docformatter
  are ignored because a bump reformats the tree.
- Drop the downstream note (ddtrace is >=4.8.2 and gitpython >=3.2.1
  now), the python:3.10 notes, the hand-kept action inventory, tracker
  IDs and the references to non-public repositories.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tests.yml and docs-build.yml:
- Every action pinned to a commit SHA with its version, one version per
  action across both files (checkout v7.0.1, setup-python v7.1.0,
  setup-node v7.1.0, setup-qemu v4.4.0, setup-buildx v4.4.1,
  build-push v7.4.0), each checkout with persist-credentials: false.
- permissions: contents: read for the whole workflow.
- A push to a PR cancels that PR's older runs; master and release
  branch runs are never cancelled.
- Run steps use bash -euo pipefail; runners pinned to ubuntu-24.04.

tests.yml only:
- The pull_request trigger loses its base-branch filter, so a PR
  stacked on another branch gets the full CI.
- redis service pinned to 8.10.3 (the floating tag resolves to it
  today); pip, flake8 and the 3.13 leg's pytest tools pinned exactly.
- matrix values reach run: through env:, and the App Tests step quotes
  the key path (shellcheck SC2086, SC2155).
- Drop the docker-compose 1.29.2 binary download from both E2E jobs:
  it was fetched unverified and nothing calls it (the steps and
  app-tests/run.sh use the `docker compose` plugin).
- DOCKER_BUILD_RECORD_UPLOAD=false: build-push-action v6+ uploads a
  build record with the provenance, the same data that
  BUILDX_METADATA_PROVENANCE keeps out of the logs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each action is pinned to the commit its current major tag points at
(the commits the 0.10.0-rc.5 and rc.6 runs downloaded), so the same
code runs: checkout v2.8.0, setup-python v5.6.0, login-action v2.2.0,
setup-qemu v3.7.0, setup-buildx v3.12.0, build-push v6.19.2,
actions-upload-release-asset v1.7.5, gh-action-pypi-publish v1.14.3
(the release/v1 branch head).

- permissions: {} for the workflow; validate_release gets none,
  build_and_test and publish_docker_images contents: read,
  publish_python_packages contents: write for the release assets.
  Nothing used id-token or pull-requests: the PyPI steps pass a token,
  so the action never requests an OIDC token.
- publish_python_packages runs in the pypi environment (no protection
  rules); the misplaced step-level env name/url is gone.
- Drop the unused TOKEN_GITHUB env and the unverified, unused
  docker-compose 1.29.2 download.
- Release tag, prerelease flag and matrix values reach run: through
  env:; quote $version_tag; cd ... || exit 1.
- Pin semver 3.1.0, packaging 26.3 and wheel 0.48.0, the versions the
  rc.5 run installed.
- Image builds no longer read or write a registry cache, so layers from
  an earlier image (such as a stale apt-get upgrade) cannot reach a
  release.
- checkouts set persist-credentials: false.
- use-trusted-publishing stays ignored inline until PyPI trusted
  publishing is set up.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- .pre-commit-config.yaml: add actionlint v1.7.12, zizmor v1.31.1 and
  gitleaks v8.30.1 (staged changes); every rev, the existing hooks
  included, is now the tag's commit SHA with a `# frozen:` comment, at
  the same versions.
- .gitleaks.toml: the default rules plus a permit-api-key rule for
  permit_key_[A-Za-z0-9]{20,}, which GitHub secret scanning does not
  detect. Allowlists cover the false positives a full-history scan
  finds (doc placeholders and samples, the docs search widget key, test
  fixtures, the app tests' local Gitea), each limited to the rules that
  fire on it.
- pre-commit.yml: pre-commit 4.7.0 (was `<4`) so the hooks run in CI;
  zizmor runs in its own step with the job token for its online audits
  (impostor commits, known-vulnerable actions, ref and version-comment
  mismatches), the other hooks without it. Actions pinned by SHA,
  persist-credentials: false, contents: read, a 20-minute timeout,
  ubuntu-24.04, bash -euo pipefail, and older PR runs cancelled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A secret-scan job in tests.yml, required through the CI job, runs
gitleaks 8.30.1 (checksum-verified binary, .gitleaks.toml rules) over
the commits the run brings in: base..head for a PR, before..sha for a
push, the head commit for a new branch or a manual run. Older history is
out of scope, so it cannot block an unrelated PR.

The job fails on findings (printed redacted), when gitleaks does not
complete, when the range has no commits, and when gitleaks reports 0
commits scanned: a shallow clone, or a git log format it cannot parse,
would otherwise pass having checked nothing. Its output runs inside
::stop-commands:: because it quotes lines from the commits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Follows permit-golang's tools/binaries.lock, fetch-tool.sh and
prek-count.sh:

- .github/binaries.lock pins release binaries by version and sha256 for
  darwin and linux, amd64 and arm64: gitleaks 8.30.1, prek 0.5.9,
  trivy 0.76.1, trufflehog 3.99.7, uv 0.13.6, each the newest release
  at least 7 days old, with the sums from the release's own checksum
  files. .github/scripts/fetch-tool.sh <name> checks the sha256 before
  unpacking and installs bin/<name>, which .gitignore now ignores. It
  deletes nothing: the download stays under RUNNER_TEMP or TMPDIR.
- pre-commit.yml (job still named pre-commit, the required check)
  installs prek that way and runs .github/scripts/prek-count.sh, which
  runs every hook on every file and fails unless EXPECTED_HOOKS (12)
  hooks passed or had nothing to check, so a skipped or dropped hook
  cannot pass unnoticed. zizmor gets GH_TOKEN for its online audits.
- .pre-commit-config.yaml: minimum_prek_version 0.5.5, prek update
  with a 7-day cooldown and frozen SHAs, zizmor reads .github/zizmor.yml
  (every action pinned to a full SHA, GitHub's included), and
  shellcheck 0.11.0.1 and shfmt 3.14.1 check .github/scripts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A header that states the rules every entry follows.
- No labels: Dependabot's defaults (dependencies plus the ecosystem)
  apply, and it creates them when missing.
- Version groups say applies-to: version-updates with patterns "*".
- deps for what the packages and images install (pip, /docker);
  deps-dev for actions, hooks, the docs site and the test-only seed
  image. The actions and hooks group is named tooling.
- No security group on docker and pre-commit entries: Dependabot has
  no security updates for either.

The entries, the pip strategy, the shared-majors group and the reasoned
ignores are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ports permit-golang's PR-time secret scan, dependency review and
aggregate check to tests.yml:

- secrets (was secret-scan) installs gitleaks with fetch-tool.sh and
  runs .github/scripts/gitleaks-range.sh: base..head for a PR,
  before..after for a push (origin/master..after for a new branch),
  origin/master..HEAD for a manual run. gitleaks gets .gitleaks.toml by
  path, runs from an empty directory with an empty ignore file, no
  GITLEAKS_ variables and no user or system git config, reports lines
  marked gitleaks:allow, reads binary-looking files as text and scans
  what merge commits change. The commit count comes from git rev-list,
  and an empty range fails on a PR. Exit 1 for findings (redacted), 2
  when the scan did not run.
- .gitleaks.toml: fake keys that start with permit_key_FAKE are allowed
  anywhere.
- dependency-review (pull requests only): actions/dependency-review-
  action v5.0.0 fails on a new dependency with a high or critical
  vulnerability and comments on failure.
- The CI job decides with .github/scripts/ci-aggregate.sh: every job
  must succeed in the runs that select it (dependency-review on pull
  requests only), and the count of needed jobs must be EXPECTED_JOBS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ports permit-golang's security-scan.sh, digest.sh, trivy.sh and vuln.sh
to OPAL, with a new security.yml (schedule plus a manual mode input)
instead of modes in the CI workflow, and notify.sh in place of the Go
notify and secreport tools.

- vuln.sh resolves the published packages' requires files with uv pip
  compile (CPython 3.12, manylinux, wheels only) into a floor (lowest
  direct versions) and a ceiling (newest), and with --prepare leaves
  the trees for security-scan.sh. Without it, it runs trivy.sh block
  on both.
- trivy.sh scans a pinned requirements file (Trivy must list one
  package per pin) or a published image (at least one package), from
  an empty directory with no Trivy config or TRIVY_ variables, and
  writes findings as JSON lines.
- security-scan.sh (Mon and Thu, or mode security): floor, ceiling,
  the latest opal-client and opal-server from PyPI, the
  permitio/opal-server and opal-client :latest images, the open
  Dependabot alerts, gitleaks over the full history with accepted
  fingerprint digests, and TruffleHog --results=verified on manual
  runs. Findings are reported and pass; a source that did not complete
  or a verified secret fails. Private findings are counted in the job
  summary and listed in Slack only.
- digest.sh (Mon, or mode weekly): open Dependabot pull requests, the
  last security scan, and newer releases of .github/binaries.lock
  entries that are at least 7 days old.
- A missing DEPENDABOT_ALERTS_TOKEN skips the alerts source and a
  missing SECURITY_SLACK_WEBHOOK_URL skips the post, each with a line in
  the job summary; without GITLEAKS_HISTORY_ACCEPT_SHA256 every history
  finding is reported as new.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every job in tests.yml, pre-commit.yml and docs-build.yml now states
contents: read, next to the workflow-level block, as on_release.yml and
security.yml already do. This closes CodeQL's "Workflow does not
contain permissions" (actions/missing-workflow-permissions) alerts on
tests.yml (build, e2e-tests, e2e-tests-alpine) and pre-commit.yml; the
on_release.yml alert is closed by the permissions blocks of the release
commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings November 8, 2026 21:32
@zeevmoney zeevmoney changed the title ci(release): set up Python 3.11, not 3.11.8, so the publish jobs run on Ubuntu 26.04 ci: fix the release's Python setup and harden workflows to the repo standard Nov 8, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

The security scan mints a per-run installation token from the security
GitHub App (SECURITY_APP_CLIENT_ID, SECURITY_APP_PRIVATE_KEY in the
security-scan environment), scoped to this repository with only
"Dependabot alerts: read", instead of taking a stored token.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings November 8, 2026 22:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings November 8, 2026 22:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

zeevmoney and others added 8 commits November 9, 2026 00:36
SECURITY_SLACK_WEBHOOK_URL is a secret of the security-scan environment,
not of the repository, so the digest job, which ran outside it, read an
empty webhook: notify.sh then skips the post with a warning and the job
stays green. The digest job now runs in the environment too, which keeps
the webhook limited to master.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The group was keyed on inputs.mode or github.event.schedule, so a
scheduled scan ("security-23 4 * * 1,4") and a manual scan
("security-security") were in different groups and could run at the
same time, which the comment said they would not. The group is now
security-scan or security-digest, whichever way the run started.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The comment said the pypi environment scopes the PyPI token to the
publish job. PYPI_TOKEN is a repository secret and the environment holds
no secrets, so every workflow can still read it. The comment now says
so, and that moving the secret into the environment would scope it.
Comment only; the workflow is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tests.yml never sets ADVISORY_JOBS, so the option that let a listed job
fail without failing CI had no user here. It is removed with its docs;
every result other than success, or a skip in a run that selects the
job, fails CI as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The two scripts decide the required CI and pre-commit checks, and their
failure paths were tested only by hand. Each test runs its script on
made-up results (job results for ci-aggregate.sh, a fake prek for
prek-count.sh) and checks the exit code of every case: success, a
failed, cancelled or skipped job, a hook skipped by SKIP, a wrong
count, malformed input and wrong arguments. The pre-commit job runs
both after the hooks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The secret scan's failure paths were tested only by hand. The test
builds a throwaway repository with the scan's files, commits random
Permit API keys made at run time, and checks gitleaks-range.sh's exit
code for a clean range, a range that adds a key (also on a line with
gitleaks:allow), an empty range with and without --if-empty notice, the
zero SHA, revisions that are not commits and wrong arguments. It checks
that the finding comes from the permit-api-key rule of .gitleaks.toml
and that no output shows a key. The secrets job runs it before the scan.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
notify.sh exits 2 when SECURITY_SLACK_WEBHOOK_URL is not an https URL,
and security-scan.sh and digest.sh pass that code on, but neither
header listed it. security-scan.sh's header also named jq alone,
though the script checks for jq, gh and curl. Comments only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
.pre-commit-config.yaml now sets minimum_prek_version 0.5.5 and the
pre-commit job runs the hooks with prek, but CONTRIBUTING.md still told
contributors to run pre-commit install and pre-commit run. It now names
prek and the version the config needs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings November 8, 2026 22:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

Copilot AI balanced review requested due to automatic review settings November 9, 2026 20:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

This branch has not been deployed

No deployments
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.

4 participants