Skip to content

Fix RoboShield CI and migrate builds to Docker Bake - #1507

Merged
kelvinkipruto merged 6 commits into
mainfrom
ft/roboshield-docker-bake
Aug 19, 2026
Merged

Fix RoboShield CI and migrate builds to Docker Bake#1507
kelvinkipruto merged 6 commits into
mainfrom
ft/roboshield-docker-bake

Conversation

@kelvinkipruto

Copy link
Copy Markdown
Contributor

Description

Fix RoboShield's CI/CD, which has been failing on every push to main since at least April, and migrate it to the repository's per-app Dockerfile and Docker Bake build architecture.

Fixes the RoboShield | Deploy | DEV workflow, which has failed on every run since at least April 2026.

Why

RoboShield | Deploy | DEV has failed on every push to main for months: next build's lint step throws Cannot find module '@babel/preset-react'. eslint-config-commons-ui's babel-eslint-parser resolves that preset via Node module resolution starting from the consuming app's own directory, not from the shared config package. Every other app on this config (pesayetu, charterafrica, civicsignalblog, climatemappedafrica, codeforafrica, twoopstracker) declares the preset directly as a workaround; roboshield never did.

RoboShield | Deploy | PROD looked green throughout, but only because it gates the actual build behind a version-bump check that has stayed false — it has been skipping the build entirely, not validating it.

While fixing this, RoboShield was still built from the legacy shared root Dockerfile via two independent docker/build-push-action workflows, each hand-rolling its own build-args and Dokku push — unlike pesayetu/techlabblog/trustlab, which already share the published builder/runner base images, Bake caching, and reusable workflows. Since the build needed fixing anyway, this migrates it onto the same architecture.

What changed

RoboShield CI fix

  • Add the missing @babel/preset-react devDependency to apps/roboshield/package.json.

RoboShield Docker Bake migration

  • Add a pruned, multi-stage Dockerfile at docker/apps/roboshield/Dockerfile.
  • Add the roboshield target to docker-bake.hcl and the shared apps group. Reads MONGO_URL/NEXT_PUBLIC_SENTRY_DSN as BuildKit secrets (RoboShield's own env var names), rather than inheriting _payload-app-runner's DATABASE_URL, which trustlab uses instead.
  • Reuse the published ui-builder-base/ui-runner-base images in CI.
  • Package the standalone server, public/static assets, and Dokku health-check metadata.
  • Switch local make roboshield and Compose usage to the Bake-built image.
  • Mark RoboShield migrated in docker/README.md.
  • Remove the now-dead roboshield-* stages from the legacy root Dockerfile.

CI/CD

  • Add a reusable RoboShield Bake workflow (_build-roboshield.yml) and a new orchestration workflow (roboshield.yml): version-check, then build+deploy to dev on every push and to prod on a version bump.
  • RoboShield bakes NEXT_PUBLIC_APP_URL into the client bundle, and dev/prod are genuinely different Dokku apps with different canonical URLs — so, unlike techlabblog/trustlab, which build once and promote, dev and prod each get their own build here, matching the two-workflow setup this replaces.
  • Extend the shared _bake-and-push.yml workflow with RoboShield's MONGO_URL/NEXT_PUBLIC_SENTRY_DSN secret plumbing.
  • Remove the legacy roboshield-deploy-dev.yml/roboshield-deploy-prod.yml workflows entirely (no shared root Dockerfile dependency left to preserve).

Deployment and rollout

No new GitHub secrets or variables are required — all existing ROBOSHIELD_* secrets (ROBOSHIELD_MONGO_URL, ROBOSHIELD_PAYLOAD_SECRET, ROBOSHIELD_SENTRY_DSN, ROBOSHIELD_SENTRY_PROJECT) and shared secrets (SENTRY_AUTH_TOKEN, SENTRY_ORG, SSH_PRIVATE_KEY, DOCKER_HUB_*) carry over unchanged, along with the existing vars.UI_BASE_TAG.

Validation

  • docker buildx bake roboshield — full turbo-prune → install → next build (compile, lint, static export) completes and exports an image.
  • docker run smoke test — the built image boots, Next.js starts, and it connects to its configured database with no errors.
  • Reproduced the exact make roboshield / bake-up.sh flow (env-sourced build args, no explicit --set overrides) end to end, after wiring NEXT_PUBLIC_APP_URL/SENTRY_ENVIRONMENT into the target's args map.
  • Workflow YAML parses successfully.

Commits

  1. fix roboshield missing @babel/preset-react dependency
  2. migrate roboshield builds to Docker Bake

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Screenshots

N/A

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation

eslint-config-commons-ui's babel-eslint-parser resolves
"@babel/preset-react" via Node module resolution starting from the
consuming app's own directory, not from the shared config package.
Every other app on this config declares the preset directly as a
workaround; roboshield never did, so the Next.js lint-on-build step
has been failing "Cannot find module '@babel/preset-react'" on every
RoboShield | Deploy | DEV run since at least April.
RoboShield was still built from the legacy shared root Dockerfile via
two independent docker/build-push-action workflows, each hand-rolling
its own build-args and Dokku push. Move it onto the same per-app
Dockerfile + Docker Bake architecture as pesayetu/techlabblog/trustlab.

### What changed

- Add a pruned, multi-stage Dockerfile at docker/apps/roboshield/Dockerfile.
- Add the roboshield target to docker-bake.hcl and the shared apps group.
  Reads MONGO_URL/NEXT_PUBLIC_SENTRY_DSN as BuildKit secrets (roboshield's
  own env var names), rather than inheriting _payload-app-runner's
  DATABASE_URL, which trustlab uses instead.
- Reuse the published ui-builder-base/ui-runner-base images in CI.
- Package the standalone server, public/static assets, and Dokku
  health-check metadata.
- Switch local `make roboshield` and Compose usage to the Bake-built image.
- Mark roboshield migrated in docker/README.md.
- Remove the now-dead roboshield-* stages from the legacy root Dockerfile.

### CI/CD

- Add a reusable RoboShield Bake workflow (_build-roboshield.yml) and a
  new orchestration workflow (roboshield.yml): version-check, then
  build+deploy to dev on every push and to prod on a version bump.
- RoboShield bakes NEXT_PUBLIC_APP_URL into the client bundle and dev/prod
  are genuinely different Dokku apps with different canonical URLs, so —
  unlike techlabblog/trustlab, which build once and promote — dev and prod
  each get their own build, matching the two-workflow setup this replaces.
- Extend the shared _bake-and-push.yml workflow with roboshield's
  MONGO_URL/NEXT_PUBLIC_SENTRY_DSN secret plumbing.
- Remove the legacy roboshield-deploy-dev.yml/roboshield-deploy-prod.yml
  workflows entirely (no shared root Dockerfile dependency to preserve).
- No new GitHub secrets or variables required; all existing ROBOSHIELD_*
  secrets carry over unchanged.

### Validation

- `docker buildx bake roboshield` — full turbo-prune -> install -> next
  build (compile, lint, static export) completes and exports an image.
- `docker run` smoke test — the built image boots, Next.js starts, and it
  connects to its configured database with no errors.
- Reproduced the exact `make roboshield` / bake-up.sh flow (env-sourced
  build args, no explicit --set overrides) end to end after wiring
  NEXT_PUBLIC_APP_URL/SENTRY_ENVIRONMENT into the target's args map.
- Workflow YAML parses successfully.
@kelvinkipruto
kelvinkipruto requested review from kilemensi and koechkevin and removed request for kilemensi August 17, 2026 08:43
Comment thread .github/workflows/_bake-and-push.yml Outdated
Comment thread .github/workflows/_bake-and-push.yml Outdated
Comment thread .github/workflows/roboshield-deploy-dev.yml
Comment thread Dockerfile
@kilemensi

Copy link
Copy Markdown
Member

Before I forget @kelvinkipruto, there is also pr-build workflow that ensures Docker images actually build on PR before merging. It should use dummy ENVs whenever possible to avoid sharing main secrets with PR.

- Standardize on DATABASE_URL instead of MONGO_URL for RoboShield's
  Payload DB connection, matching trustlab. RoboShield's target now
  inherits _payload-app-runner directly instead of declaring its own
  mongo_url secret. Fall back to MONGO_URL in the app itself so Dokku
  environments not yet reconfigured with the new var name keep working.
- Restore the legacy roboshield-deploy-dev.yml/roboshield-deploy-prod.yml
  workflows and the root Dockerfile's roboshield-* stages verbatim.
  They're disabled in the GitHub UI and being kept as a rollback path
  until the new pipeline is validated across all environments, same as
  pesayetu-deploy-prod.yml alongside the shared root Dockerfile.
- Add roboshield to the pr-build.yml image-validation workflow and
  scripts/pr-build-targets.mjs's target detection, so roboshield's Docker
  image is exercised on trusted PRs before merging, using dummy build
  secrets (RoboShield doesn't query its database during static
  generation, unlike trustlab, so a well-formed but unreachable
  DATABASE_URL is sufficient).
@kelvinkipruto

kelvinkipruto commented Aug 18, 2026

Copy link
Copy Markdown
Contributor Author

@claude Review

Mirror trustlab's pattern: read SENTRY_DSN fresh via process.env on the
server, inject it into a window global from _document.tsx at SSR time,
and read it from there on the client (src/utils/site.ts). Changing the
DSN is now a Dokku config:set + restart, not a rebuild.

instrumentation-client.ts falls back to the existing build-time
NEXT_PUBLIC_SENTRY_DSN secret, since Payload's admin panel is served
from a generated App Router layout (src/app/(payload)/layout.tsx) that
must not be edited and has no equivalent runtime-injection point.

Deployment note: SENTRY_DSN (not NEXT_PUBLIC_SENTRY_DSN) needs to be set
as a runtime config var on both the dev and prod Dokku apps for the
public site to pick up the DSN without a rebuild.
Per review feedback (github.com//pull/1507#discussion_r3803422254),
drop the build-time NEXT_PUBLIC_SENTRY_DSN fallback rather than keeping it
as a secondary source. instrumentation-client.ts now relies solely on
site.sentryDsn: undefined on Payload's admin panel (App Router, no
runtime-injection point), populated everywhere else via the window global
injected by _document.tsx. This matches trustlab's own tradeoff exactly.

Removes the now-unnecessary build-time secret plumbing entirely:
Dockerfile's next_public_sentry_dsn mount, docker-bake.hcl's roboshield
secret list (fully inherited now, no app-specific secrets left),
_bake-and-push.yml, _build-roboshield.yml, roboshield.yml, and
pr-build.yml. Also trims comments that were left duplicated or
restating the code after the surrounding logic changed.
@kelvinkipruto

Copy link
Copy Markdown
Contributor Author

@claude Review

@claude

This comment was marked as resolved.

@kilemensi

This comment was marked as resolved.

@kilemensi kilemensi added the chore A task that needs to be done (neither enhancement or bug) label Aug 19, 2026
@github-project-automation github-project-automation Bot moved this to 🚧 In Progress in COMMONS Aug 19, 2026
kilemensi updated the DEV/PROD Dokku config and scripts in the vault to
set DATABASE_URL, so the MONGO_URL fallback in payload.config.ts and
the migration file is no longer needed.

Also renames the legacy (disabled) roboshield-deploy-dev.yml/
roboshield-deploy-prod.yml workflows' secret id/build-arg from
mongo_url/MONGO_URL to database_url/DATABASE_URL, and the matching
--mount in the root Dockerfile's roboshield-builder stage, so that
frozen rollback path still resolves a database URL if ever re-enabled.
The underlying ROBOSHIELD_MONGO_URL GitHub secret is unchanged, only
the build arg/secret id it's mapped to.

@kilemensi kilemensi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀


Checking the code, I think in all of the Payload apps that uses Page router, Sentry is only configured for pages and not admin/Payload itself. We should do a fix on a separate PR.

@kelvinkipruto
kelvinkipruto added this pull request to the merge queue Aug 19, 2026
Merged via the queue into main with commit 4406c00 Aug 19, 2026
13 checks passed
@kelvinkipruto
kelvinkipruto deleted the ft/roboshield-docker-bake branch August 19, 2026 11:17
@github-project-automation github-project-automation Bot moved this from 🚧 In Progress to ✅ Done in COMMONS Aug 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chore A task that needs to be done (neither enhancement or bug)

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

3 participants