You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
github-backup: drainer needs an owner allowlist — public App admits foreign installs #3326
The backup GitHub App developing-today-backup (ID 5562183) was made public on 2026-10-31 — GitHub does not allow a private App to be installed by organizations, and org installs were a hard requirement. A side effect: anyone can now install the App on their own repositories.
Their webhook deliveries verify against the App secret (it is genuinely our App), reach the Worker queue, and bin/drain_queue.py currently acts on any queued event whose repo appears in plan.json — and files fetch attempts / state for anything else it is handed. A foreign install could make the laptop drainer clone/fetch strangers' repositories into ~/backups/github, burning disk, bandwidth, and the App installation rate limit, and polluting the backup tree.
Fix
Drop foreign events at the drainer door, before any fetch work:
Determine each queued event's owner (repository.owner.login; fall back to the installation account login where the payload carries it; the queued repo full_name carries the owner for Worker-flattened events).
Allowed set = owners in infra/github-backup/config.json (the same set reconcile plans from). Case-insensitive compare.
Extend tests/test_drain_queue.py: allowed owner proceeds exactly as today; foreign owner dropped + acked + logged (even if the repo is in plan.json); missing-owner payload dropped; repository-owner precedence over installation account; #3219 failure semantics unchanged for allowed owners.
Deploy / proof
Merge → pull on the laptop primary → just github-backup-units → one drain run Result=success → hand-inject one foreign event through the Worker and show the DRAIN-DROP line with no clone attempted.
Refs #3215 (system issue). Approved by Drew 2026-10-31 23:08 CDT.
Change: bin/drain_queue.py checks each queued event's owner against config.json owners before any fetch work (repository.owner.login → full_name owner segment → installation.account.login; case-insensitive; fails closed). Foreign/owner-less events are dropped: acked as handled-by-policy, one DRAIN-DROP log line each, counted as dropped_foreign in the run summary, never counted toward the #3219 DRAIN-CHRONIC streak.
Tests: 54/54 in tests/test_drain_queue.py (22 new). Repro first: the new foreign-owner case run against the pre-fix drainer reached fetch (the hole); closed after. Sibling suites 18/18 + 9/9.
Deploy: laptop primary pulled to the merge, just github-backup-units refreshed, drain timer healthy.
Live proof (2026-10-31 23:12 CDT): hand-injected a signed webhook for stranger-danger/evil-repo through the Worker (202 queued). Drain run Result=success; summary dropped_foreign: 1, acked: 1 (the other 28 queued events were allowed-owner repos inside their coalesce windows, untouched). fetch.log:
Activity
Merge pull request #3328 from developing-today/fix/3326-drainer-owner…
dezren39 commentedon Nov 1, 2026
Done — implemented, merged, deployed, and proven live.
PR: #3328 (merge
72e347609).Change:
bin/drain_queue.pychecks each queued event's owner againstconfig.jsonowners before any fetch work (repository.owner.login → full_name owner segment → installation.account.login; case-insensitive; fails closed). Foreign/owner-less events are dropped: acked as handled-by-policy, oneDRAIN-DROPlog line each, counted asdropped_foreignin the run summary, never counted toward the #3219 DRAIN-CHRONIC streak.Tests: 54/54 in
tests/test_drain_queue.py(22 new). Repro first: the new foreign-owner case run against the pre-fix drainer reached fetch (the hole); closed after. Sibling suites 18/18 + 9/9.Deploy: laptop primary pulled to the merge,
just github-backup-unitsrefreshed, drain timer healthy.Live proof (2026-10-31 23:12 CDT): hand-injected a signed webhook for
stranger-danger/evil-repothrough the Worker (202 queued). Drain run Result=success; summarydropped_foreign: 1, acked: 1(the other 28 queued events were allowed-owner repos inside their coalesce windows, untouched). fetch.log:No
~/backups/github/stranger-dangerexists — no clone was attempted.