Skip to content

Add Actions workflow to update dependencies inside devcontainer#467

Closed
some-natalie wants to merge 2 commits into
gadievron:mainfrom
some-natalie:main
Closed

Add Actions workflow to update dependencies inside devcontainer#467
some-natalie wants to merge 2 commits into
gadievron:mainfrom
some-natalie:main

Conversation

@some-natalie
Copy link
Copy Markdown
Contributor

This PR adds a Python script and GitHub Actions workflow to update the hard-coded dependencies inside of .devcontainer/Dockerfile by opening a PR like a janky Dependabot. I use scripts like this to reduce toil on maintaining pinned deps.

⚠️ In order for this to work, you'll need to allow Actions to open PRs under "settings -> actions -> general" and scroll down to the checkbox toggle for it. This can increase the blast radius of a supply chain attack w/i Actions, but it seems like everything's squared away on pinning these too. :)

@danielcuthbert danielcuthbert self-assigned this May 11, 2026
@danielcuthbert danielcuthbert added the enhancement New feature or request label May 11, 2026
@grokjc
Copy link
Copy Markdown
Collaborator

grokjc commented May 11, 2026

Can we hold off until SCA lands please. 'latest' isn't necessarily the best/safest/compatible version and I'm 30+ commits deep into that journey at the moment 😄

@some-natalie
Copy link
Copy Markdown
Contributor Author

Can we hold off until SCA lands please. 'latest' isn't necessarily the best/safest/compatible version and I'm 30+ commits deep into that journey at the moment 😄

Of course! I just wanted to bump CodeQL forward myself and figured I'd contribute back.

LMK if you need help or a rubber duck on SCA stuff.

@grokjc
Copy link
Copy Markdown
Collaborator

grokjc commented May 11, 2026

Hey, appreciate the contribution and offer of support. I already have a CI component in the works but have added your devcontainer idea specifically. When the commit lands you will have a co-author credit on that front.

But you've also led me to ponder the question of can a GH action actually do a 'super-dependabot' upgrade whilst being safe vs potential supply chain attacks? And the answer is sort of, but some of the defences need an LLM to reason (e.g. 'does this thing look like it was backdoored?') - so hard to do in that environment. To that end I'm working on an advisory model rather than a fully-automated one (with fully auto being a toggle should it be within user risk appetite).

I'd definitely like some assistance once I get my dev branch off my local machine and onto GH. It is a huge area and I imagine there are a lot of things that will need tweaking/improving/iterating. In the meantime don't be surprised if a few random 'Co-Authored: by ' credits appear in your feed as I implement some of the precursors to your suggestion and they will likely land on main before the rest of the SCA branch.

@grokjc grokjc self-assigned this May 11, 2026
@some-natalie
Copy link
Copy Markdown
Contributor Author

some-natalie commented May 11, 2026

can a GH action actually do a 'super-dependabot' upgrade whilst being safe vs potential supply chain attacks?

There's a lot to unpack there on safety, partly because there's not a fantastic limit on how deep Actions will resolve dependencies (or if there's vendored dependencies) and each different types of Actions all have their quirks. My approach is usually to try and let Actions agent do the resolution, then look at the delta with binary capability diffs ... which has some limitations too.

I took a quick stab at this a while ago with malcontent from @tstromberg while we were both at Chainguard. Here's a workflow and PR it reviewed. My implementation of it is brittle, but I'm hoping to carve out some time to improve it soon. 😅

I'd imagine that a "super" type upgrade would be equally complex as trying to just tackle the Actions ecosystem. More food for thought!

edit - thank you, and I'm happy to help, just lmk how

grokjc added a commit that referenced this pull request May 11, 2026
Adapted from Natalie Somersall's PR #467 (dependabot-style upstream
version checker). Her work covered the GitHub releases / tags endpoint
shape and the cache-key + tag-stripping logic; this commit lifts that
core, refactors it onto an injected HttpClient + JsonCache substrate,
and adds the shared stable-semver filter that future resolvers (OCI,
Helm) will reuse.

First lift of a centralised "latest upstream version" lookup. Today
every consumer that needs to know "what's the current stable release
of $thing" reinvents the same dance: hit api.github.com/.../releases/
latest, filter out pre-release tags, strip the v prefix, cache for a
day. Done in three places already (cve-diff, agentic upstream checks,
the new SCA bumper) with three slightly different definitions of
"stable" — drift waiting to happen.

This commit adds:

* core/upstream_latest/github_releases.py — GitHub releases endpoint
  (latest_release), tags-list fallback for projects that don't cut
  formal releases (latest_tag), and the resolve_tag_to_sha primitive
  used by GHA-uses commit-SHA pinning.
* core/upstream_latest/_version_filter.py — single parse_stable /
  highest_stable implementation: regex
  ^v?(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:\.(\d+))?$ rejecting pre-release
  / nightly / variant tags. One source of truth shared by every
  resolver here and any future ones.
* core/upstream_latest/__init__.py — re-exports the public API.
  A follow-up lift extends this with OCI + Helm resolvers.

HttpClient + JsonCache are injected, so consumers control egress
policy (proxied / sandboxed) and cache locality. The lookup
gracefully falls through GitHub releases → tags-list when
/releases/latest returns a non-semver name like
"codeql-bundle-v2.25.4".

Origin: https://github.com/grokjc/raptor/pull/467

Co-Authored-By: Natalie Somersall <natalie.somersall@gmail.com>
@grokjc
Copy link
Copy Markdown
Collaborator

grokjc commented May 17, 2026

Making progress. Just landed #545 to help with this. Full SCA module waiting in the wings ... not long now 😄

grokjc added a commit that referenced this pull request May 23, 2026
Adds a third pass to ``parse_dockerfile`` that walks ``ARG`` lines
whose name ends in ``_VERSION`` and emits ``Dependency`` rows for
those that map to an SCA ecosystem. The rows flow through the
normal OSV / KEV / EPSS pipeline.

Mapping comes from two sources:

1. **Built-in allowlist** (``_BUILTIN_ARG_MAP``) — handles the
   common cases: ``SEMGREP_VERSION`` → ``PyPI:semgrep``,
   ``CLAUDE_CODE_VERSION`` → ``npm:@anthropic-ai/claude-code``,
   etc. Boilerplate ARGs that have no SCA ecosystem (CodeQL CLI,
   Python / Node / Go runtimes, base-image tags) are listed as
   ``None`` so they're silently skipped without needing per-line
   ``# raptor-sca: skip`` comments.

2. **Inline-comment override**:
       ARG VENDORED_LIB_VERSION=2.0  # raptor-sca: PyPI:vendored-lib
       ARG ALREADY_REVIEWED=1.0      # raptor-sca: skip

   The override wins over the built-in map (operator may have
   already accepted risk on a specific version).

The ARG pass runs FIRST in ``parse_dockerfile`` so that when a
Dockerfile both ``ARG FOO_VERSION=1.0`` AND
``RUN pip install foo==${FOO_VERSION}``, the concrete-version row
(``foo@1.0``) wins the canonical-dep dedup over the placeholder
row (``foo@${FOO_VERSION}``) emitted by the shell scanner. Pre-
sequence the placeholder won, causing OSV to return all-CVE
noise for the package.

ARG-derived deps carry ``source_kind="dockerfile_arg"`` and
``scope="build"`` so operators can tell them apart from runtime
app deps (same scope as Maven parent-POM coordinates).

The version regex accepts PEP440 pre-release / dev shapes
(``20.8b1``, ``20.8rc1``, ``20.8.dev0``) plus semver shapes
plus 4-part NuGet versions. Rejects ``latest``, ``main``,
branch refs, and shell expansions like ``${BASE}`` (can't query
OSV for those).

17 tests cover built-in extraction, npm scoped-name handling,
v-prefix stripping, skip-known-non-SCA, unknown-ARG silent skip,
inline override, override-skip wins, non-version rejection,
quoted values, multiple-ARGs Dockerfiles, the canonical-dedup
ordering (placeholder-vs-concrete), and PEP440 shapes.

This is the SCA-side complement to
#467 which adds a GHA
workflow that auto-bumps these same ARG pins to the latest
GitHub release. PR #467 keeps the versions current; this commit
keeps the operator informed of CVE exposure on whatever's
currently pinned. Suggested operator pattern: combine the two
— the GHA workflow refreshes versions, the next scan reports
any CVEs that the bump newly introduced (or any that the
previous pin was hiding).

Co-Authored-By: Natalie Somersall <natalie.somersall@gmail.com>
grokjc added a commit that referenced this pull request May 23, 2026
Phase 2.c: adds the rewriter registry that the bumper subcommand
will use to apply edits across opinion surfaces, and ships the
first rewriter — Dockerfile ARG version pins.

Registry shape (symmetric to ``packages/sca/parsers/``):

  * ``RewriteEdit(locator, old_value, new_value)`` — a single
    proposed edit. ``locator`` is rewriter-specific (ARG name
    for Dockerfile, dep name for npm, group:artifact for
    Maven).
  * ``RewriteResult(edit, applied, reason)`` — per-edit
    outcome. ``reason`` ∈ ``{"applied", "no_change",
    "not_found", "value_mismatch: ...", "error: ..."}``.
  * ``register(filenames=..., predicate=...)`` decorator —
    same shape parsers use.
  * ``rewrite(path, edits)`` dispatcher — picks the right
    rewriter for the path.

Dockerfile ARG rewriter behaviour:

  * ARG present at expected ``old_value`` → rewrite + applied.
  * ARG already at ``new_value`` → ``no_change`` (idempotent
    skip — re-running a successful plan doesn't churn the file).
  * ARG present at a DIFFERENT non-target value → ``value_
    mismatch``, file left alone. Operator probably bumped
    manually or the plan is stale; surface the discrepancy
    instead of silently overwriting.
  * ARG absent from file → ``not_found``.
  * I/O error → ``error: ...``.

Robustness features:

  * Atomic write (tempfile + rename) so an interrupted rewrite
    can't leave a half-written Dockerfile.
  * Whitespace-tolerant regex (handles ``ARG FOO = 1.2.3`` with
    spaces around ``=``).
  * Quote-preserving (``ARG FOO="1.2.3"`` rewrites to
    ``ARG FOO="1.2.4"``, not ``ARG FOO=1.2.4``).
  * Exact-name match — ``SEMGREP_VERSION`` doesn't accidentally
    match ``CUSTOM_SEMGREP_VERSION`` or
    ``SEMGREP_VERSION_FALLBACK``.

Partial-failure behaviour: when a multi-edit batch has some
successes and some failures, the successful edits are persisted
(atomic write of the partially-updated content), the failed
edits return their failure ``RewriteResult``. The bumper
surfaces the partial state in the PR comment so reviewers see
what landed and what didn't.

15 tests cover: happy path, idempotency (already-at-target),
not-found skip, value-mismatch refusal, multi-edit batch,
partial-failure keeps successes, whitespace tolerance, quote
preservation, exact-name match, registry dispatch (Dockerfile +
Dockerfile.dev / .Dockerfile / .dockerfile suffix variants),
unknown-file fallthrough, atomic-write preservation of
unrelated content, re-run idempotency.

Adapted from #467 by
Natalie Somersall — her ``update_dockerfile()`` ships the
``rf"^(ARG {arg}=)(\\S+)"`` regex + idempotent
skip-if-unchanged + change-tuple-return pattern. This module
generalises that into the ``RewriteEdit``/``RewriteResult``
registry interface used across all SCA rewriters. Phase 2.c of
the dependabot++ pattern in memory
project_sca_dependabot_plus_plus.md.

Co-Authored-By: Natalie Somersall <natalie.somersall@gmail.com>
grokjc added a commit that referenced this pull request May 23, 2026
Phase 2.d: the orchestrator + CLI that ties Phases 1.a-d and
2.a-c together. End-to-end flow:

  raptor-sca bump <target>
    walk every Dockerfile under target
    for each ARG with a known upstream source:
      query upstream-latest (GitHub releases / tags)
      if not already at latest → candidate
      evaluate bump-tier supply-chain verdict
        (recent_publish + maintainer_change + install_hook)
    print verdict table (default) or JSON (--json)
    optionally --apply Clean bumps in place

Pieces shipped this commit:

* ``packages/sca/bump/orchestrator.py`` — walker + verdict
  computer + rewriter driver. Caches upstream-latest lookups per
  (kind, coordinate) so two Dockerfiles pinning the same tool
  don't double-hit the GitHub API.
* ``packages/sca/bump/upstream_map.py`` — ARG name → upstream
  source mapping (GitHub releases / tags repos for each ARG in
  ``_BUILTIN_ARG_MAP``, plus CODEQL_VERSION which has no SCA
  ecosystem but does have a GitHub-releases coordinate).
* ``packages/sca/bump/cli.py`` — argparse + dispatch to
  orchestrator. ``--apply`` / ``--json`` / ``--no-cache`` /
  ``--cache-root`` / ``--github-token`` / ``-v``.
* CLI wire: ``bump`` added to SUBCOMMANDS in ``packages/sca/cli.py``.

Suggest-only policy (memory project_sca_dependabot_plus_plus.md):
``--apply`` writes Clean bumps in place but REFUSES to write
Review or Block bumps even when the operator passes ``--apply``.
Per-finding rationale (recent_publish detail, maintainer_change
diff) surfaces inline in the report so reviewers see WHY a
verdict isn't Clean without having to open another tool.

The orchestrator pattern is general dependabot/renovate
territory — no co-author trailer.

12 new tests cover: empty-target, unknown-ARG-skipped,
already-at-latest-no-candidate, below-latest-becomes-candidate,
recent_publish-as-Review-verdict, upstream-lookup-failure-recorded-
in-skipped, apply-writes-Clean, apply-doesn't-write-Review,
default-is-dry-run, render-report-shape, no-candidates-friendly-
message, cross-Dockerfile-upstream-dedup.

This makes Phase 2 complete — the bumper now produces operator-
useful output end-to-end. Phase 3 (additional surfaces: FROM
image refs, GHA uses, k8s image:, Helm chart deps) is each
~1-2 days of (walker + rewriter + upstream source) per surface.

End state: ``raptor-sca bump <target>`` works on raptor's own
.devcontainer/Dockerfile once Natalie's PR #467 doesn't beat us
to it — but more usefully, on any project that uses the same
ARG convention.
grokjc added a commit that referenced this pull request May 23, 2026
Phase 3.a: extends the bumper to recognize Dockerfile ``FROM
<image>:<tag>`` lines as bump candidates alongside ARG version
pins. Pulls together pieces from the prior phases:

* ``core/dockerfile/parser`` for parsing FROM instructions
* ``core/oci/image_ref.parse_image_ref`` for resolving the
  registry/repository/tag triple
* ``core/upstream_latest/oci_tags.latest_tag`` (Phase 2.b) for
  the upstream-latest lookup
* New ``packages/sca/rewriters/dockerfile_from.py`` for the
  in-place rewrite

The orchestrator now walks both ARG pins and FROM lines; the
``BumpCandidate`` dataclass got a ``kind`` discriminator
(``"arg"`` / ``"from_image"``) and a generic ``locator`` field
that's the ARG name for ARGs and ``"{registry}/{repository}"``
for images.

Filtering on the FROM-walker side:
* Variant tags (``python:3.12-bookworm``, ``ubuntu:jammy``) —
  silently skipped. We don't have a variant-tag equivalence
  map; an auto-bumper that flipped ``bookworm`` → ``trixie``
  would be making a non-trivial OS change without operator
  input.
* Digest-pinned (``image@sha256:...``) — immutable, not a bump
  target.
* Stage reuse (``FROM build AS runtime``) — references a prior
  build stage, not an image.
* Tag already at latest — not a candidate.

Verdict tier: FROM-image candidates currently fall through to
Clean (no bump-tier supply-chain signals available for OCI yet
— no per-tag publish-date API on most registries). The
suggest-only policy still applies: the candidate appears in
the PR with the proposed bump, human review catches anything
weird. A future commit could add OCI-tag publish-date
detection for Docker Hub specifically (it has a separate paginated
endpoint with dates).

Rewriter dispatch refactor: ``dockerfile_arg`` and
``dockerfile_from`` would both register against the Dockerfile
predicate, but the dispatcher resolves a single rewriter per
path. Resolved by making ``dockerfile_from`` the registered
entry point that splits edits by locator shape (``/`` → FROM,
else → ARG) and delegates ARG edits to the ``dockerfile_arg``
function internally. One predicate registration, both edit
types routed correctly. Tests for both rewriters AND a mixed-
batch test that exercises the dispatch.

Live verification on raptor's own .devcontainer/Dockerfile:
  FROM mcr.microsoft.com/devcontainers/python:1-3.12-bookworm
The variant tag (``1-3.12-bookworm``) correctly silent-skips —
not a stable-semver shape. Once raptor's Dockerfile uses a
pure-semver tag, the bumper would surface it as a candidate.

19 orchestrator tests + 10 FROM rewriter tests cover the new
paths. Total Phase 3.a delta: ~270 lines, no co-author trailer
(no prior art from PR #467 for FROM rewrites; ARG path was
the only piece her work shaped).
grokjc added a commit that referenced this pull request May 23, 2026
Closes PR #467's deferred 5th-Tier-1-signal item: when a dep
bumps from X to Y and the deliverable is a binary artifact
(Dockerfile FROM image, GHA Docker-action, pre-built release
pin), run ``BinaryUnderstand`` against current + target binaries
and flag the bump when target adds dangerous capabilities the
current didn't have.

Substrate
- ``packages/sca/bump/binary_capability_delta.py`` — three-layer
  module:
    * ``_bucket_imports(imports)`` — classify import set by the
      shared ``core.function_taxonomy`` capability buckets (exec,
      network, string_overflow, scan, memory_copy, format_string,
      alloc, parser, integer_parse, toctou). Ubiquitous funcs
      (``malloc`` / ``printf`` / ``read``) deliberately dropped —
      not signal.
    * ``diff_binary_capabilities(cur, tgt)`` — analyse both
      binaries via ``packages.binary_analysis.radare2_understand.
      analyse_binary_context``, return a ``CapabilityDelta``
      carrying new buckets + new reachable sinks. Returns None
      when radare2 unavailable or either binary unanalysable
      (graceful degradation); empty delta when both analyse but
      target adds nothing.
    * ``binary_capability_delta_finding(...)`` — wrap the delta
      in a ``SupplyChainFinding`` of kind
      ``"binary_capability_delta"`` (new entry in
      ``SupplyChainKind`` literal). Severity ladder:
        - new exec or network capability → ``high``
          (RCE / exfil-flavoured)
        - other dangerous capability → ``medium``
      Confidence ``medium`` — static signal only, no runtime
      confirmation.

What this isn't
- The wiring into ``run_bump`` / ``_evaluate_one_candidate``
  isn't done yet. Driving the detector for Dockerfile FROM
  bumps needs OCI image-config introspection (read CMD /
  ENTRYPOINT) + targeted binary extraction from the layer.
  That's a separate ~100 LOC and lives in a follow-up commit.
- Path resolution is the caller's responsibility — the detector
  takes already-extracted ``Path`` objects, doesn't pull /
  unpack images itself. Clean separation of concerns lets the
  same detector serve Docker-FROM, GHA-action, and
  binary-artifact-pin call sites with their own extractors.

Tests
- 19 unit tests via stubbed BinaryContextMap (no radare2
  required for the unit suite):
    * bucket classification (exec, network, string_overflow,
      ubiquitous dropped)
    * diff outcomes: no change, new exec, new network, new
      string_overflow, new sinks, removed capabilities ignored,
      multiple buckets
    * graceful degradation: radare2 unavailable, current
      analyse fail, target analyse fail
    * finding wrapper: high severity for exec, medium for
      string_overflow, no finding when unchanged, detail
      rendering
- 1 integration test gated on probe_capability() — diffs
  /bin/ls against itself, asserts empty delta (catches
  non-determinism). Skips on hosts without r2pipe.

Co-Authored-By: Natalie Somersall <natalie.somersall@gmail.com>
grokjc added a commit that referenced this pull request May 23, 2026
Closes the GHA half of PR #467's signal: ``uses: owner/repo@vX``
candidates that point at Docker-container actions now flow
through the same capability-diff machinery as Dockerfile FROM
bumps. This matches what Natalie's malcontent-actions workflow
covered.

What GHA actions look like
- JavaScript / composite actions (``runs.using: node20`` /
  ``composite``) — ship as a git repo of JS/YAML, no OCI image.
  Out of scope; the resolver returns None and the bumper emits
  no capability-delta finding (other signals still apply).
- Docker-container actions with a pre-built image
  (``runs.using: docker`` + ``runs.image: docker://image:tag``
  or ``image:tag``) — exactly the shape we can diff. Resolver
  returns an ``image_ref`` ready for ``fetch_image_binary``.
- Docker-container actions with a Dockerfile reference
  (``runs.image: Dockerfile`` / ``./Dockerfile`` / ``build/
  Dockerfile``) — image only exists post-build; we don't run
  builds. Resolver returns None.

Substrate
- ``packages/sca/bump/gha_action_image.py``:
    * ``resolve_gha_action_image(repo, ref, *, http)`` — fetch
      ``action.yml`` (fall back to ``action.yaml``) from
      raw.githubusercontent.com, parse the YAML, classify the
      ``runs`` shape, return a ``GhaActionImage`` carrying the
      cleaned OCI ref. Unauthenticated fetch — fine for public
      repos which are the capability-delta-relevant case.
    * ``_parse_docker_action_image(text)`` — pure-YAML parse
      function isolated for direct unit coverage. Handles all
      the GHA syntax variants: ``docker://`` URI prefix, plain
      ``image:`` form, case-insensitive ``using``, Dockerfile
      rejections (bare, relative path, subdir, ``.dockerfile``
      extension).
- ``_binary_capability_delta_for_candidate`` extended to dispatch
  on ``cand.kind == "gha_uses"`` via a new
  ``_resolve_gha_image_refs`` helper. Both halves must resolve
  cleanly — if the action SWITCHED between Docker and JS
  between versions, the resolver returns None on the
  mismatching side and the bumper bails (different shapes,
  can't capability-diff).
- ``_evaluate_one`` gains an ``http`` kwarg threaded through from
  ``run_bump`` so the resolver can make its raw-content fetches.
- ``run_bump``'s OCI-client lazy-construct gate now also fires
  for ``gha_uses`` candidates.

Out of scope this revision
- Sub-action paths (``uses: owner/repo/sub/dir@vX``): the
  existing GHA-uses enumerator drops the subpath when building
  candidates, so we read ``action.yml`` at the repo root only.
  Sub-action resolution requires a candidate-shape change;
  deferred until the enumerator carries the subpath.
- Private-repo authentication: raw.githubusercontent.com
  doesn't auth, which is fine for the public-action case
  (private actions aren't the supply-chain risk we're
  targeting here).

Tests
- 20 resolver tests (``test_gha_action_image.py``): docker URI
  stripping, plain image, JS / composite rejection, three
  Dockerfile-reference shapes, ``.yml`` → ``.yaml`` fallback,
  both-extensions-fail, malformed YAML, non-mapping top-level,
  empty image, unicode decode failure.
- 2 orchestrator wiring tests: gha_uses Docker action triggers
  resolver + extractor + detector with the right call sequence;
  gha_uses JS action skips the OCI fetch entirely (resolver
  returns None for current → bail before target).
- 183 bump tests pass.

Co-Authored-By: Natalie Somersall <natalie.somersall@gmail.com>
@grokjc
Copy link
Copy Markdown
Collaborator

grokjc commented May 24, 2026

Hi @some-natalie - now that #595 (the SCA behemoth) has landed, I want to close this out properly, because your PR turned into a lot more than one workflow's worth of value and I want to be specific about what survived and where it lives.

Your update_devcontainer.yml + update_dockerfile() was the proof-of-shape for a general "safe auto-bump" loop. We took the cron → branch → resolve-latest → rewrite → PR-open pattern and generalised it across eight version-pin surfaces instead of just the devcontainer:

  • Python / Debian apt / npm manifests (raptor-sca fix --harden)
  • Dockerfile ARG _VERSION= pins
  • Dockerfile FROM image refs
  • inline RUN pip install pkg==N
  • GHA uses: foo@ (tag-pinned and SHA-pinned-with-# was vX-comment)
  • k8s / compose / gitlab-ci image: refs
  • Helm Chart.yaml deps
  • git submodules

Every surface runs the same loop your Dockerfile code prototyped: walk → find pin → upstream-latest lookup → verdict → idempotent in-place rewrite.

The difference from vanilla dependabot/renovate is the verdict gate. Before a bump is applied it's checked against the full SCA signal set with no LLM in the CI path: OSV / KEV / EPSS, yanked-release, license policy, install-hook delta, typosquat / compromised-package feed, maintainer-change, version-diff size, binary-capability-delta (more on that below), and function-level reachability. Only Clean verdicts get written; Review/Block leave the finding for a human.

The workflow itself

.github/workflows/sca-self-bump.yml — directly descended from your update_devcontainer.yml:

  • Mondays 12:00 UTC, single self-updating PR (--force-with-lease so weekly runs don't stack)
  • --self-test re-runs SCA on the patched tree to confirm findings actually decrease before the patch is emitted
  • No auto-merge — branch protection + human review stays enforced. The Megalodon PPE attack (May 2026, ~5,500 repos) is cited inline as the reason we don't zero-touch this.

Where your work is in the tree

You're mentinoed via Co-Authored-By: on 17 commits on main. The load-bearing ones:

  • core/upstream_latest/github_releases.py: your _fetch() + release/tag fetchers + the stable-semver pre-release filter + v-prefix-strip (commit body literally reads "Adapted from Natalie Somersall's PR Add Actions workflow to update dependencies inside devcontainer #467")
  • packages/sca/rewriters/dockerfile_arg.py: direct adaptation of your update_dockerfile(): the ^(ARG =)(\S+) regex, the idempotent rewrite, the skip-if-unchanged + change-tuple shape
  • the SCA-side ARG-pin scanner: your workflow needed something to know which ARGs to bump; that's the scan-side complement
  • the sca-self-bump.yml workflow shape itself

And separately, your malcontent / capability-diff suggestion from the thread became a whole feature line, not just a footnote. Rather than bundle malcontent we reused our existing radare2-based binary-understanding substrate to diff the syscall/network/file-IO capability surface of current vs target; a bump that suddenly grows capabilities (network where there was none, new execve-family calls, etc.) escalates the verdict. That's the binary-capability-delta detector + the fingerprint CLI + the CycloneDX capability embedding + the --fail-on-capability-drift gate — all attributed to you, since the idea was yours.

Closing this PR

I'm closing #467 as superseded by #595 because the equivalents are already wired into the broader bumper and merging the original on top would conflict and undo the wider feature. But the design and the idea both shipped, at considerably larger scope than the original diff. Thank you for the idea, and the inspiration. As for your offer of help, I'm sure there are many bugs lurking here, it was a significant piece of work.

@grokjc grokjc closed this May 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants