Diffinery

codician/diffinerypublic

Open-source, agent-first GitHub and GitHub Actions alternative that runs on your own Cloudflare account: git hosting, pull requests, code review and drop-in GitHub Actions YAML on Workers, Durable Objects, R2 and Containers.

Actions keep running when GitHub is down: Diffinery keeps a copy of every action jobs use #333

Mergedtest-botagenton behalf of cnbrkdmrcimerged into main from claude/action-mirror
test-botagenton behalf of cnbrkdmrciopened Author

Requested by Can · project thread

What

A Reddit question asked whether workflows keep working when GitHub is down, since actions are downloaded from GitHub at run time. Until now they didn't: every uses: owner/repo@ref that isn't a built-in was downloaded from codeload.github.com (or github.com with git) in each job, so a GitHub outage failed those steps.

Now Diffinery keeps its own copy of every public action jobs use:

  • Runner (containers/runner/src/steps/actions.ts): downloads from GitHub first, unchanged. After a successful download it tells Diffinery in the background (POST /runner/jobs/:id/action-mirror), never waiting on it. When the tarball download and the git fallback both fail, it downloads Diffinery's copy (GET /runner/jobs/:id/action-mirror) and logs a warning plus an annotation naming when the copy was fetched from GitHub. A tarball attempt now gives up after 60 s without an answer and the git fallback after 5 minutes, so a hanging GitHub can't hold a job for long. Nothing changes when DIFFINERY_ACTIONS_DOWNLOAD_URL is set.
  • Server (src/lib/action-mirror.ts, src/http/runner.ts): on a report from a running job, fetches the archive from codeload.github.com itself and streams it to R2 under action-mirror/ when the copy is missing or stale (tags and branches after a day, commit SHAs after a week). 256 MB cap. Both routes need the job's token and a running job.
  • Safety: runners never upload a copy, so a job can't plant an action that other repositories would run. Only public actions are stored (the fetch has no credentials). A failed refresh keeps the old copy.
  • Storage: new prefix action-mirror/ with a 30-day lifecycle rule (scripts/bootstrap.sh, applied on deploy); copies in use are refreshed before they reach it.

Docs

  • Compatibility: new "When GitHub is down" section, including what still depends on GitHub (run-time downloads such as release assets, setup-python builds other than 3.12, ghcr.io images).
  • Runners: the self-hosted download order.

Tests

  • Runner: a job where one action comes from GitHub (reported), one is served from Diffinery's copy while GitHub answers 503 (warning logged, action runs), and one has no copy (fails as before).
  • Server unit tests: name validation, keys, staleness, refresh only when stale, an old copy kept when GitHub fails, 404 and size limit.

🤖 Generated with Claude Code

https://claude.ai/code/session_01FL6rJXsUCeA4ZVKUGfZUkj

Intentwhat this change is meant to do

Keep workflows running through a GitHub outage: jobs fall back to Diffinery's own copy of each action they use, fetched from GitHub by Diffinery itself

test-bot merged commit 640174e into main
Pull request successfully merged and closed
test-bot merged 640174e into main
Sign in to join the conversation.