Skip to content

Draft: automate weekly cross-repo dependency alert sync#195

Draft
ihalatci wants to merge 10 commits into
masterfrom
automation/security-sync-orchestrator
Draft

Draft: automate weekly cross-repo dependency alert sync#195
ihalatci wants to merge 10 commits into
masterfrom
automation/security-sync-orchestrator

Conversation

@ihalatci
Copy link
Copy Markdown
Contributor

@ihalatci ihalatci commented Mar 3, 2026

Summary

Implements weekly cross-repo dependency alert orchestration (Sunday 02:00 UTC) driven by packagingApp credentials. Manual approval/merge of the resulting PRs is preserved.

What this adds

Orchestrator workflow — .github/workflows/dependency-security-sync.yml

  • Runs weekly on schedule and on manual workflow_dispatch
  • Mints a packagingApp token via actions/create-github-app-token@v1 (GH_APP_ID / GH_APP_KEY org secrets)
  • Fetches open Dependabot alerts from citusdata/citus
  • Invokes the sync script (see below) to mutate citus Pipfiles and regenerate lockfiles
  • Opens/updates the citus sync PR as a Draft on branch automation/dependency-security-sync (--base main)
  • Regenerates the four the-process requirements.txt files using pipenv requirements against the updated lockfile, with headers pointing at citusdata/citus#<CITUS_PR> (matching existing convention)
  • Opens/updates the the-process sync PR on the same branch (--base master)
  • Closes only those Dependabot PRs whose title bumps a package the run actually addressed (search: author:app/dependabot in:title Bump <pkg>); leaves unrelated Dependabot PRs alone
  • Surfaces a per-alert outcome table in the run summary

Sync script — .github/scripts/security_sync.py

CLI: --alerts <json> --citus-root <path> --summary-out <path>

Behavior:

  • Deduplicates alerts by package, keeps the highest first_patched_version per package
  • For each target, edits both Pipfiles (citus src/test/regress and .devcontainer/src/test/regress):
    • Direct dep already in the file → rewrites the constraint to ">=<patched>"
    • Transitive dep → appends <package> = ">=<patched>" under [packages] or [dev-packages] based on alert scope (runtime vs development), so pipenv lock will pull a fixing version
  • Runs pipenv lock in both regress trees
  • Reads each post-state lockfile and classifies every target as applied / already-satisfied / not-fixed / absent, with an overall verdict of addressed / already-satisfied / failed
  • Writes sync-summary.json ({ "addressed": [...], "details": [...] }) consumed by the workflow
  • Exits non-zero when nothing was addressed, so the workflow fails loudly and does not open PRs nor close any Dependabot PRs

Post-merge callback — .github/workflows/dependency-security-post-merge.yml

  • On merge of the the-process sync PR to master, computes the new image postfix from the merged SHA (-v<sha7>)
  • Updates image_suffix in citus/.github/workflows/build_and_test.yml on the citus sync branch so the corresponding citus PR picks up rebuilt images

Design guarantees

  1. No fix → no PR. If alerts cannot be resolved (e.g., upstream dep caps the patched range, no actionable first_patched_version, or pipenv lock fails), the workflow fails and opens nothing. Dependabot PRs are not closed.
  2. Narrow PR closure. Dependabot PRs are closed only when the consolidated PR actually addresses that specific package.
  3. No package-specific hardcoding. Alert payload drives all updates.
  4. Header convention preserved. Regenerated requirements.txt headers reference citusdata/citus#<PR_NUMBER>.

Operational prerequisites

  • Org secrets available to both repos:
    • GH_APP_ID
    • GH_APP_KEY
  • packagingApp GitHub App installed on citusdata/citus and citusdata/the-process with at minimum:
    • Contents: read & write
    • Pull requests: read & write
    • Issues: read & write (for PR comments)
    • Dependabot alerts: read (on citus)
    • Workflows: write (post-merge step edits a workflow file in citus)
  • Automation branch in both repos: automation/dependency-security-sync

Known upstream blockers

At time of writing, the live pyOpenSSL Dependabot alerts on citus cannot be resolved by this automation because mitmproxy 12.2.2 (citus's git-pinned version) declares pyOpenSSL<=25.3.0,>=24.3 while the alert wants >=26.0.0. The workflow correctly fails and opens no PR until mitmproxy is bumped past that cap. This is a real upstream constraint, not an automation defect.

Smoke testing performed (local mirror in /tmp/smoke-test)

Scenario Expected Actual
Empty alerts exit 1, no PR
Already-satisfied alert (werkzeug 3.1.1) exit 1, classified already-satisfied
Unfixable transitive (pyopenssl 26 blocked by mitmproxy cap) exit 1, no PR
Non-existent target version exit 1, no PR

Live happy-path (addressed != []) will be exercised on the first scheduled run after merge once a real upstream patch is available.

Follow-ups (not in this PR)

  • Optionally suppress Dependabot's own PR opening on citusdata/citus after this lands (alerts-only mode) so the consolidated PR is the single channel.
  • Promote this PR from Draft → Ready for review once the App permissions above are confirmed.

- update_pipfile() appends to [packages]/[dev-packages] when alert is for a
  transitive dep, so pipenv lock can pull the patched version.
- Use >= constraint instead of == to avoid over-pinning.
- Verify per-alert outcome by reading both Pipfile.lock files post-lock,
  classify as addressed / already-satisfied / failed.
- Write summary JSON consumed by the workflow; print one line per alert.
- Exit non-zero (no PRs opened) when no alerts are actually addressed.
- Workflow: pass --summary-out, surface details in run summary, expose
  addressed-package list as step output, only close Dependabot PRs whose
  title matches a package we addressed (instead of closing all of them).
Defer requirements regeneration from the Python script to a workflow step
that runs after the citus PR is created, so the header can reference
`citusdata/citus#<PR_NUMBER>` (matching the existing convention) rather
than a transient SHA.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant