ci(pesacheck_meedan_bridge): Add continuous deployment workflow - #1209
Merged
Merged
Conversation
Mirror the TwoopsTracker CD workflow for the bridge: on a push to main that changes pesacheck_meedan_bridge/py/VERSION, lint, build the Docker image with Pants, push it to DockerHub and deploy to Dokku.
koechkevin
force-pushed
the
chore/pesacheck-bridge-cd
branch
from
September 24, 2026 09:27
11519b7 to
964781a
Compare
Temporarily runs the workflow on pushes to chore/pesacheck-bridge-cd and bumps VERSION to 0.1.19 so the paths filter matches. The branch entry is removed before merging.
The repo has no ./pants launcher script, so the tailor and package steps failed with exit 127. twoops-tracker-cd.yaml has the same two calls and would fail the same way. Also temporarily triggers on changes to the workflow file so it can be tested without bumping VERSION each time.
Without deploy_docker_image, Dokku tries to build the pushed monorepo with the Heroku Python buildpack and fails: there is no top-level requirements.txt. Deploy the image pushed to DockerHub instead.
Requests went out as python-requests/x.y.z, which Cloudflare challenges in front of pesacheck.org: the daily run got the "Just a moment..." page instead of the Content API. Name the bridge instead. A custom User-Agent may not be enough on its own where the challenge is driven by IP reputation; the Content API path still wants a Cloudflare allowlist for the Dokku host.
Ships the identifying User-Agent for the Ghost Content API.
With deploy_docker_image set, dokku/github-action runs `git:from-image` and never pushes a branch, so branch/git_push_flags were dead inputs that made the step look like a git-push deploy. Name the deploy commit author instead, and rename the step to match what it does.
The workflow now only runs on main, on a VERSION change. 0.1.20 is already built and deployed, so bump so the merge deploys cleanly instead of failing on git:from-image's "No changes detected".
Flagged by CodeQL on #1209: the workflow didn't restrict the token. The job only needs to check out the repo.
kilemensi
approved these changes
Sep 24, 2026
…aCheck Review feedback on #1209. py/VERSION isn't packaged into the pex, so the User-Agent carries its own version rather than reading that file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The bridge had no deploy workflow:
.github/workflows/only covered TwoopsTracker, sopesacheck_meedan_bridgewas built and deployed by hand.What changed
.github/workflows/pesacheck-meedan-bridge-cd.yamlModelled on
twoops-tracker-cd.yaml, pointed at the bridge:maintouchingpesacheck_meedan_bridge/py/VERSION, so a deploy needs a deliberate version bump.VERSIONfrompy/VERSION→ init/bootstrap Pants →tailor --check→pants lint --lint-skip-formatters pesacheck_meedan_bridge/::→pants package pesacheck_meedan_bridge/docker/::→ pushcodeforafrica/pesacheck_meedan_bridge:$VERSIONto DockerHub → deploy to Dokku.ssh://dokku@dokku-1.dev.codeforafrica.org/pesacheck-meedan-bridge, deployed withdeploy_docker_image, i.e.dokku git:from-imageagainst the tag we just pushed.DOCKER_HUB_USERNAME,DOCKER_HUB_ACCESS_TOKEN,SSH_PRIVATE_KEY.main.py: identify the bridge to GhostRequests went out as
python-requests/x.y.z, which Cloudflare challenges in front ofpesacheck.org: the first production run got the "Just a moment..." interstitial instead of the Content API, and the error surfaced in Sentry. The bridge now sends:That alone was not enough from the Dokku host, where the challenge is driven by IP reputation. What fixed it is a Cloudflare WAF skip rule on the
pesacheck.orgzone for/ghost/api/content/*from the host's IP (3.248.206.242), skipping Super Bot Fight Mode, managed rules, rate limiting and remaining custom rules. Worth knowing that the rule is pinned to an ordinary EC2 public IP: if the instance is ever stopped and started, the IP changes and this failure returns. An Elastic IP, or matching on a secret header instead, would make it sturdier.Version
VERSION→0.1.21.0.1.20is already built and deployed (from testing this workflow), so merging at0.1.20would fire the workflow and fail ongit:from-image's "No changes detected".0.1.21gives a clean first deploy frommain.Testing
Run from this branch, with a temporary branch trigger that has been removed again. Five runs:
./pants→ fixed by callingpants.deploy_docker_image.0.1.19,git:from-image, "Application deployed".0.1.20, shipping the User-Agent change.VERSIONtrigger means each real deploy carries a new tag.Also verified on the host:
cron:listshows the@daily ./pexentry fromapp.jsoninside the image, andcron:runexecutes it. Two Dokku gotchas found while testing:ps:rebuildon this app. There's nothing to rebuild for an image deploy, and it resurrects whatever Dockerfile the app's git HEAD points at. It rolled prod back to0.1.16and, because that image predatesapp.json, deregistered the cron.dokku runrefuses withInvalid image stage detected: expected 'release', got '', since images built outside Dokku carry nocom.dokku.image-stagelabel.cron:runworks, anddokku enter <app> webis the fallback for ad-hoc commands.yamllintpasses with the repo's.yamllintconfig.