Repository navigation
ci: add Dependabot version updates (PER-15358) - #957
EliMoshkovich wants to merge 4 commits into
Conversation
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 agent-security, PDP and permit-opa configs 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>
✅ Deploy Preview for opal-docs canceled.
|
The Waivers section closed by claiming every waiver exists because opal-common caps the dependency. That stopped being true when the two x/crypto/ssh waivers landed - those are blocked by an unreleased Go 1.26, not by OPAL. Replaced with a table that names the actual blocker and retirement condition for all five. Added where each class of finding really lives, so the next person does not re-derive it: - OPAL owns the dependency caps (packages/requires.txt, packages/opal-common/requires.txt): starlette<1, ddtrace<4, and gitpython>=3.1.32. The gitpython FLOOR is the sharpest of the three - 3.1.32 lets any consumer resolve a version carrying the CRITICAL CVE-2026-78676 RCE, which is how 0.9.14 shipped 3.1.57 and why this repo needed its own floor. Also notes that Dependabot cannot see those files at all: setup.py loads requires.txt with a runtime open(), which its pip parser cannot resolve, so OPAL's caps stay manual until they become a pyproject.toml. - permit-opa owns every Go CVE in /app/bin/opa, and had neither a CVE gate nor dependency automation - which is why its drift surfaced in OUR scans. Both now have Dependabot PRs (permitio/opal#957, permitio/permit-opa#50), same shape as this repo's and agent-security's. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The Waivers section closed by claiming every waiver exists because opal-common caps the dependency. That stopped being true when the two x/crypto/ssh waivers landed - those are blocked by an unreleased Go 1.26, not by OPAL. Replaced with a table that names the actual blocker and retirement condition for all five. Added where each class of finding really lives, so the next person does not re-derive it: - OPAL owns the dependency caps (packages/requires.txt, packages/opal-common/requires.txt): starlette<1, ddtrace<4, and gitpython>=3.1.32. The gitpython FLOOR is the sharpest of the three - 3.1.32 lets any consumer resolve a version carrying the CRITICAL CVE-2026-78676 RCE, which is how 0.9.14 shipped 3.1.57 and why this repo needed its own floor. Also notes that Dependabot cannot see those files at all: setup.py loads requires.txt with a runtime open(), which its pip parser cannot resolve, so OPAL's caps stay manual until they become a pyproject.toml. - permit-opa owns every Go CVE in /app/bin/opa, and had neither a CVE gate nor dependency automation - which is why its drift surfaced in OUR scans. Both now have Dependabot PRs (permitio/opal#957, permitio/permit-opa#50), same shape as this repo's and agent-security's. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The Waivers section closed by claiming every waiver exists because opal-common caps the dependency. That stopped being true when the two x/crypto/ssh waivers landed - those are blocked by an unreleased Go 1.26, not by OPAL. Replaced with a table that names the actual blocker and retirement condition for all five. Added where each class of finding really lives, so the next person does not re-derive it: - OPAL owns the dependency caps (packages/requires.txt, packages/opal-common/requires.txt): starlette<1, ddtrace<4, and gitpython>=3.1.32. The gitpython FLOOR is the sharpest of the three - 3.1.32 lets any consumer resolve a version carrying the CRITICAL CVE-2026-78676 RCE, which is how 0.9.14 shipped 3.1.57 and why this repo needed its own floor. Also notes that Dependabot cannot see those files at all: setup.py loads requires.txt with a runtime open(), which its pip parser cannot resolve, so OPAL's caps stay manual until they become a pyproject.toml. - permit-opa owns every Go CVE in /app/bin/opa, and had neither a CVE gate nor dependency automation - which is why its drift surfaced in OUR scans. Both now have Dependabot PRs (permitio/opal#957, permitio/permit-opa#50), same shape as this repo's and agent-security's. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The Waivers section closed by claiming every waiver exists because opal-common caps the dependency. That stopped being true when the two x/crypto/ssh waivers landed - those are blocked by an unreleased Go 1.26, not by OPAL. Replaced with a table that names the actual blocker and retirement condition for all five. Added where each class of finding really lives, so the next person does not re-derive it: - OPAL owns the dependency caps (packages/requires.txt, packages/opal-common/requires.txt): starlette<1, ddtrace<4, and gitpython>=3.1.32. The gitpython FLOOR is the sharpest of the three - 3.1.32 lets any consumer resolve a version carrying the CRITICAL CVE-2026-78676 RCE, which is how 0.9.14 shipped 3.1.57 and why this repo needed its own floor. Also notes that Dependabot cannot see those files at all: setup.py loads requires.txt with a runtime open(), which its pip parser cannot resolve, so OPAL's caps stay manual until they become a pyproject.toml. - permit-opa owns every Go CVE in /app/bin/opa, and had neither a CVE gate nor dependency automation - which is why its drift surfaced in OUR scans. Both now have Dependabot PRs (permitio/opal#957, permitio/permit-opa#50), same shape as this repo's and agent-security's. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The Waivers section closed by claiming every waiver exists because opal-common caps the dependency. That stopped being true when the two x/crypto/ssh waivers landed - those are blocked by an unreleased Go 1.26, not by OPAL. Replaced with a table that names the actual blocker and retirement condition for all five. Added where each class of finding really lives, so the next person does not re-derive it: - OPAL owns the dependency caps (packages/requires.txt, packages/opal-common/requires.txt): starlette<1, ddtrace<4, and gitpython>=3.1.32. The gitpython FLOOR is the sharpest of the three - 3.1.32 lets any consumer resolve a version carrying the CRITICAL CVE-2026-78676 RCE, which is how 0.9.14 shipped 3.1.57 and why this repo needed its own floor. Also notes that Dependabot cannot see those files at all: setup.py loads requires.txt with a runtime open(), which its pip parser cannot resolve, so OPAL's caps stay manual until they become a pyproject.toml. - permit-opa owns every Go CVE in /app/bin/opa, and had neither a CVE gate nor dependency automation - which is why its drift surfaced in OUR scans. Both now have Dependabot PRs (permitio/opal#957, permitio/permit-opa#50), same shape as this repo's and agent-security's. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Nice, this covers a lot. One gap I noticed while testing: Dependabot's docker ecosystem doesn't update images tagged Pinning them gives Dependabot something to track: FROM alpine:3.24@sha256:294b683cb724975bec92580e1e685676bd4b50bda910ddb8c51d4cabeaec77e6 AS opa-extractor FROM alpine:3.24@sha256:294b683cb724975bec92580e1e685676bd4b50bda910ddb8c51d4cabeaec77e6 AS eopa-extractor (That's the multi-arch index digest for alpine 3.24.2.) I built Happy to open that as a small follow-up PR once this lands, or feel free to fold it in here. Separately, |
- 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>
| ignore: | ||
| - dependency-name: "python" | ||
| update-types: ["version-update:semver-minor", "version-update:semver-major"] |
zeevmoney
left a comment
There was a problem hiding this comment.
Changes requested — 1 HIGH, 1 MEDIUM, 4 LOW.
Blocking:
- HIGH
.github/dependabot.yml:26— the default pip strategy raises every>=floor to the latest release, which contradicts the comment and the description
Non-blocking:
- MEDIUM
.github/dependabot.yml:88— with the pythonignore, the python base images get no Dependabot PRs at all - LOW
.github/dependabot.yml:43— a major bump of a shared dependency opens one PR per directory - LOW
.github/dependabot.yml:113— the workflow action inventory is already out of date - LOW
.github/dependabot.yml:10— the header's cross-references can't be followed publicly, and the labels claim is wrong - LOW
.github/dependabot.yml:147— CVE-2026-78676 is described as an argument injection
Details are in the inline comments on each line.
| # "/" covers requirements.txt (dev/test toolchain) and, one level | ||
| # down, packages/requires.txt (fastapi, starlette, pydantic, ...) | ||
| # "/packages/opal-*" covers each package's own requires.txt (ddtrace, gitpython) | ||
| # These are library RANGES, so expect PRs that widen a cap (`<4` -> `<5`); raising a |
There was a problem hiding this comment.
[HIGH] The default pip strategy raises every >= floor to the latest release, which is the opposite of what this comment says
Problem: This entry doesn't set versioning-strategy. For requirement .txt files, Dependabot then uses increase. The widen default applies only when it updates a pyproject.toml that it identifies as a library (UpdateChecker#requirements_update_strategy and #library? in dependabot-core's python/lib/dependabot/python/update_checker.rb).
Under increase, RequirementsUpdater#updated_requirement_string sends any requirement with a >/>= bound to bump_requirements_range. That method rewrites the floor to the latest resolvable version, even when the current range already allows that version. For a range with no resolved version, requirements_up_to_date? compares the floor (for example 3.1.32) with the latest release, so nearly every line in these files gets an update.
On the first run, expect the minor-and-patch group to raise floors such as gitpython>=3.1.32,<4 → >=<latest 3.1.x>,<4 and pydantic[email]>=2.9.0,<3 → >=<latest 2.x>,<3. Separate major PRs will move both bounds, for example ddtrace>=3.0.0,<4 → >=<latest 4.x>,<5. These files are the published packages' install_requires, so each merged update narrows what downstream installs can resolve. L26-27, L139-140 and the PR description all say the opposite: "expect PRs that widen a cap; raising a floor stays manual".
Dependabot security updates won't raise these floors either. UpdateChecker#vulnerable? returns false for a dependency with no resolved version, and every range-only line here has none.
Suggestion: If the comments describe the intent (move caps only when a release falls outside the range, and raise floors by hand), set the strategy explicitly:
- package-ecosystem: "pip"
directories: [...]
versioning-strategy: increase-if-necessaryWith increase-if-necessary, Dependabot leaves an in-range requirement alone and widens only the < bound, when a new release falls outside it. If you want floors raised automatically instead, keep the default and rewrite L26-27 and L139-140 to say so.
| # The python minor is held: the Dockerfile hard-codes /usr/local/lib/python3.10 and | ||
| # opal-server declares python_requires <3.13, so an automatic 3.10 -> 3.1x tag bump | ||
| # would only produce a red PR. Move off 3.10 (EOL Oct 2026) deliberately, then drop | ||
| # the ignore. Patch-level 3.10.x digest/tag updates still come through. |
There was a problem hiding this comment.
[MEDIUM] With this ignore, Dependabot opens no PRs for any python base image
Problem: Every python base in docker/Dockerfile is a floating two-part tag with no digest: python:3.10-bookworm (L4), python:3.10-slim-bookworm (L17) and python:3.10-alpine (L247, L284). Three things combine:
- Dependabot's docker update checker never moves a two-part tag to a three-part one (
remove_more_precise_tagsindocker/lib/dependabot/docker/update_checker.rb), so it never offers3.10.x-bookwormfor3.10-bookworm. - The only other candidates (
3.11-*and up) are minor or major updates, and thisignorefilters them out. - Without an
@sha256:pin, there is no digest to refresh.
So "Patch-level 3.10.x digest/tag updates still come through" (L88) doesn't hold. In /docker, the entry effectively tracks only permitio/cedar-agent (L164). Patch releases reach the images only because a rebuild re-pulls the floating tag.
The inventory at L75-76 also leaves out the python:3.10-alpine stages. L85 misses the second hard-coded /usr/local/lib/python3.10, at L285.
Suggestion: Pick one:
- Pin the python bases by digest (
python:3.10-slim-bookworm@sha256:...) so Dependabot has a digest to refresh. - Reword L81 and L85-88 to say the python bases get no Dependabot PRs while the minor is held.
Either way, add python:3.10-alpine to L75-76.
| cooldown: | ||
| default-days: 7 | ||
| semver-major-days: 14 | ||
| groups: |
There was a problem hiding this comment.
[LOW] A major bump of a dependency shared across directories opens one PR per directory
Problem: The minor-and-patch group spans all four directories, but major updates fall outside it, and Dependabot raises ungrouped updates per directory. Several dependencies appear in more than one of these requires.txt files:
aiohttpandtenacity: opal-common and opal-clientclick,gitpythonandpyjwt: opal-common and opal-server
tenacity already has a 9.x release above the <9 cap. The first run should therefore open two separate tenacity PRs, and they have to be merged together to keep the packages consistent.
Suggestion: Add a group for major updates of the shared packages so each lands in one PR:
groups:
minor-and-patch:
update-types: ["minor", "patch"]
shared-majors:
patterns: ["aiohttp", "tenacity", "click", "gitpython", "pyjwt"]
update-types: ["major"]| # Note: cooldown.semver-major-days is not supported for github-actions. | ||
| # | ||
| # This is the entry with the most immediate payoff. The workflows currently mix | ||
| # actions/checkout@v2 and @v3 (plus one SHA-pinned v7.0.0); actions/setup-python@v2, |
There was a problem hiding this comment.
[LOW] The workflow action inventory is already out of date
Problem: L112-116 say the workflows use actions/checkout @v2 and @V3 "plus one SHA-pinned v7.0.0". master now has two SHA-pinned checkouts: v7.0.0 in docs-build.yml and v7.0.1 in tests.yml. The list also leaves out actions/setup-node (SHA-pinned), actions/cache@v4 and shogo82148/actions-upload-release-asset@v1.7.5. This entry's own PRs will change these versions every week, so a hand-kept list goes stale again right away.
Suggestion: Drop the per-action version list and keep only what stays true:
- some workflows still use @v1/@v2 majors, which run on deprecated Node runtimes;
pypa/gh-action-pypi-publish@release/v1is a branch ref, which Dependabot does not bump.
| # (see the note at the bottom of this file). See PER-15358. | ||
| # | ||
| # The cooldown/group/limit shape, commit prefixes and labels match the configs proposed | ||
| # for permitio/permit-opa (#50) and permitio/PDP (#338), so reviewers learn one convention. |
There was a problem hiding this comment.
[LOW] Readers of this public repo can't follow the header's cross-references, and the claim that labels match is wrong
Problem:
- L7, L78 and L135 cite an internal tracker ID that readers of this repo can't open.
- L10 points at a pull request in a repository that isn't public, and that PR is still open, so nobody outside can check the reference.
- The config that landed in permitio/PDP doesn't set
labels. It also differs in other ways: it usesuvrather thanpip, and it schedules its main docker entry daily. So "the ... commit prefixes and labels match" isn't accurate.
Suggestion: Remove the tracker IDs and the reference to the non-public repo. If a cross-reference helps, say "cooldown, grouping and commit prefixes follow permitio/PDP's .github/dependabot.yml".
| # works around it by dropping "baggage" from | ||
| # DD_TRACE_PROPAGATION_STYLE_EXTRACT. | ||
| # gitpython>=3.1.32,<4 - the FLOOR is the problem here, not the cap. 3.1.59 fixes | ||
| # CVE-2026-78676, a CRITICAL (CVSS 9.8) argument-injection RCE |
There was a problem hiding this comment.
[LOW] CVE-2026-78676 is described as an argument injection
Problem: GHSA-284h-m62q-gf8w (CVE-2026-78676) is a git-config injection, not an argument injection. When GitConfigParser writes any unrelated change, dormant multi-line config values are re-serialized as live directives such as core.hooksPath, which enables RCE. Separately, L143-145 and L149-151 describe a downstream project's images and workarounds, not OPAL's own state. That detail goes stale as the downstream images change.
Suggestion: Describe the CVE as "a git-config injection leading to RCE via core.hooksPath (fixed in 3.1.59)". Limit the note to OPAL-side facts:
- the
ddtrace<4cap excludes the CVE-2026-50271 fix (4.8.2); - the
gitpython>=3.1.32floor admits versions affected by CVE-2026-78676.
|
Thanks @EliMoshkovich. Your three commits are in #1008, with you as their author, so I'm closing this PR in favor of it. On top of them, #1008 does the following:
|
…tandard (#1008) Fixes the release workflow, which failed for 0.10.0-rc.6, and brings the GitHub Actions setup up to Permit's repo standard. Fixed - Release: Python setup uses 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. - Every workflow and job has least-privilege permissions. This closes the five "Workflow does not contain permissions" code-scanning alerts. Added - actionlint, zizmor, gitleaks, shellcheck and shfmt as pre-commit hooks. CI runs them with a sha256-pinned prek. - A gitleaks scan of each PR's commits, 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, grouped, with a 7-day cooldown. - A security scan on Monday and Thursday and a weekly digest, both reported to Slack. The scan covers the dependency trees, the published images, Dependabot alerts and the git history. It reads Dependabot alerts with a GitHub App token, not a personal access token. - Tests for the scripts behind the required checks. Changed - Every action is pinned to a full commit SHA. The release workflow keeps the exact action versions it ran before. - 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, and tool versions are pinned exactly. - A new push to a PR cancels its older CI run, and the required CI check also runs on stacked PRs. - CONTRIBUTING.md asks for prek 0.5.5 or later. The Dependabot config comes from #957 by Eli Moshkovich. Supersedes #957 and #898. Co-authored-by: eli <eli@permit.io> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>


This repo has no dependency automation. This adds Dependabot version updates for
pip,npm(docs site),dockerandgithub-actions.Why it matters beyond OPAL
permitio/pdp-v2installsopal-clientandopal-common, so the floors and caps declared here decide what a PDP image can resolve. Some PDP CVE waivers exist only because a pin here forbids the fixed version.What the
pipentry coversOPAL's library pins live in
packages/requires.txtandpackages/opal-*/requires.txt. Dependabot's pip fetcher reads any*.txtfile in a configured directory and its immediate subdirectories whose lines parse as requirements (dependabot-core/python/lib/dependabot/python/shared_file_fetcher.rb). So:/covers the rootrequirements.txtandpackages/requires.txt;directoriesalso lists/packages/opal-common,/packages/opal-clientand/packages/opal-server, which hold the ddtrace and gitpython pins.These are library ranges, so expect PRs that widen caps. Raising a security floor, such as gitpython, stays a manual change. This comes from reading dependabot-core's source, so confirm on the first run under Insights → Dependency graph → Dependabot.
What the other entries will surface (as of
mastertoday)docker/Dockerfile(and the test-onlyapp-tests/git-leak/seedimage):python:3.10-*bases; 3.10 reaches end of life in Oct 2026. The python minor is held by anignore: the Dockerfile hard-codes the 3.10 site-packages path and opal-server capspython_requires <3.13, so an automatic bump would only be red. Patch updates still come through.alpine:latestis used twice.FROMlines (the python bases,cedar-agent). It can't see the OPA tag (an ARG fed toskopeo) or the EOPA tag (awgetURL); the OPA bump itself is in PER-14697: fix(docker): bump OPA to 1.21.4 (digest-pinned) and EOPA to v1.45.1 (verified download) to address CVEs #906.actions/checkout@v2/@v3/SHA,setup-python@v2/@v4/@v5,build-push-action@v2/@v6,setup-buildx-action@v1/@v3,setup-qemu-action@v1/@v3, andlogin-action@v2. The@v1/@v2generations run on deprecated Node runtimes.Downstream note in the config
The file ends with a comment recording the pins that still force PDP waivers:
ddtrace>=3.0.0,<4gitpython>=3.1.32,<4>=3.1.59is a one-line follow-up.The
starlette <1cap that used to be on this list was lifted to>=1.3.1,<2by #959.Config details
cooldown(7 days, 14 for semver-major) is supply-chain defence; security updates aren't delayed by it.pipandnpmalso getsemver-major-days, whichdockerandgithub-actionsdon't support. Minor and patch updates are grouped. The cooldown and grouping follow permitio/PDP's Dependabot config (permitio/PDP#338). The schema passes GitHub's dependabot.yml validation check.Verified: the YAML parses, and every claim in the comments was re-checked against
masteron 2026-10-01.Description updated during review to match 998a36f (removed internal tracker links, dropped the stale "up to date with master" line, and fixed cross-repo PR references that auto-linked to this repo).
🤖 Generated with Claude Code