Skip to content

introduce a nightly and on push to main github action for the image#1

Open
cooktheryan wants to merge 6 commits into
LobsterTrap:mainfrom
cooktheryan:nightly
Open

introduce a nightly and on push to main github action for the image#1
cooktheryan wants to merge 6 commits into
LobsterTrap:mainfrom
cooktheryan:nightly

Conversation

@cooktheryan

@cooktheryan cooktheryan commented Apr 23, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • Chores
    • Added automated multi-architecture (linux/amd64 & linux/arm64) build-and-publish workflow for container images, triggered on main and by a daily schedule.
    • Added post-build smoke tests that validate image filesystem layout, required executables/configuration, and service HTTP readiness before publishing.
    • Assembles and publishes a multi-arch manifest, tagging artifacts as nightly for scheduled runs and latest for regular runs.

Signed-off-by: Ryan Cook <rcook@redhat.com>
@coderabbitai

coderabbitai Bot commented Apr 23, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@cooktheryan has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 9 minutes and 14 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cbb251a4-9196-41d0-8e66-2cd069ca81e2

📥 Commits

Reviewing files that changed from the base of the PR and between 08ea41c and 4bf86b2.

📒 Files selected for processing (1)
  • .github/workflows/build-push.yml
📝 Walkthrough

Walkthrough

Adds a GitHub Actions workflow that builds and pushes per-architecture container images (linux/amd64, linux/arm64) to quay.io, runs an amd64 smoke-test that bootstraps and validates OpenClaw and its gateway, and assembles/pushes a multi-arch manifest (nightly for schedule, latest otherwise).

Changes

CI/CD: multi-arch image build, smoke-test, manifest

Layer / File(s) Summary
Workflow Metadata & Triggers
.github/workflows/build-push.yml
New workflow Build and push bootc image with triggers (push to main, daily cron, workflow_dispatch), concurrency group, and registry/image env vars.
Build (matrix)
.github/workflows/build-push.yml
build job with matrix for linux/amd64 and linux/arm64 builds; builds bootc/Containerfile and pushes per-arch tags ${{ github.sha }}-${{ matrix.arch }} to quay.io using registry credentials.
Smoke Test (amd64)
.github/workflows/build-push.yml
smoke-test job (depends on build) pulls the ${{ github.sha }}-amd64 image, performs in-container checks (required binaries, quadlet files, sudoers/subuid/subgid, openclaw user/system), runs /usr/libexec/tank-os/bootstrap-openclaw to generate config, parses the image quadlet to construct a podman run invocation, starts the gateway container, waits for HTTP readiness on 127.0.0.1:18789/ (status 200–399), verifies container liveness, and always removes the smoke container.
Manifest Assembly & Push
.github/workflows/build-push.yml
manifest job selects MANIFEST_TAG (nightly for scheduled events, otherwise latest), logs into quay, creates a multi-arch manifest referencing ${{ github.sha }}-arm64 and ${{ github.sha }}-amd64, and pushes it to quay.io.

Sequence Diagram

sequenceDiagram
  participant GH as GitHub Actions
  participant RunnerA as Runner (amd64)
  participant RunnerB as Runner (arm64)
  participant Quay as quay.io
  participant Smoke as Smoke-test Job
  participant Image as Built Image (amd64)
  participant Gateway as OpenClaw Gateway Container

  GH->>RunnerA: start build (amd64)
  GH->>RunnerB: start build (arm64)
  RunnerA->>Quay: push `${{ github.sha }}-amd64`
  RunnerB->>Quay: push `${{ github.sha }}-arm64`
  GH->>Smoke: trigger smoke-test (after build)
  Smoke->>Quay: pull `${{ github.sha }}-amd64`
  Smoke->>Image: run checks & `/usr/libexec/tank-os/bootstrap-openclaw` -> generate config
  Smoke->>Gateway: start gateway container with mounted config
  Gateway-->>Smoke: respond on 127.0.0.1:18789 (HTTP)
  Smoke->>Smoke: verify HTTP 200–399 and container running
  GH->>Quay: create & push multi-arch manifest (`nightly` or `latest`)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Poem

🐰 I hopped into CI at break of dawn,
Built two arches, pushed them on,
I bootstrapped Gate and watched the port,
Checked each file and made report,
Now multi-arch images bound to run 🌱

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: introducing a GitHub Actions workflow that builds and pushes a bootc image on pushes to main and on a nightly schedule.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 9 minutes and 14 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (2)
.github/workflows/build-push.yml (2)

22-23: Add timeout-minutes to each job.

The arm64 build under QEMU and the Wait for OpenClaw to be ready loop (60s) plus container startup can all hang on bad days; without a job-level timeout, a stuck step inherits the default 6-hour limit and burns runner minutes (and blocks the concurrency slot). A modest timeout-minutes: 60 on build and timeout-minutes: 20 on smoke-test / manifest would be a cheap safety net.

Also applies to: 52-54, 217-219

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/build-push.yml around lines 22 - 23, Add a job-level
timeout to prevent stuck steps from consuming runner time: set timeout-minutes:
60 on the build job (the job named "build") and set timeout-minutes: 20 on the
smoke-test and manifest jobs (the jobs named "smoke-test" and "manifest"); apply
the same changes to the other occurrences noted (the other
build/smoke-test/manifest blocks referenced near the second and third
occurrences) so each job has the appropriate timeout.

24-26: Use native arm64 runners instead of QEMU emulation.

Building linux/arm64 via QEMU emulation on amd64 hardware is substantially slower and occasionally flakier than native execution. GitHub offers free ubuntu-24.04-arm / ubuntu-22.04-arm runners for public repositories; using runs-on: ${{ matrix.runner }} with separate matrix entries for architecture and runner would eliminate QEMU and improve build performance and reliability.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/build-push.yml around lines 24 - 26, The current
strategy.matrix.platform uses platform: [linux/arm64, linux/amd64] which forces
QEMU emulation for arm64; replace that with a matrix that separates architecture
and runner (e.g., matrix.arch and matrix.runner) and update the job to use
runs-on: ${{ matrix.runner }} so arm64 jobs use native GitHub arm runners (for
example ubuntu-24.04-arm or ubuntu-22.04-arm) while amd64 uses the appropriate
ubuntu runner, ensuring native arm64 execution instead of QEMU emulation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/build-push.yml:
- Around line 151-164: The workflow action "Start OpenClaw container" currently
launches ghcr.io/openclaw/openclaw:latest directly which bypasses the built
bootc image and its quadlet; update this step so it either (a) reads/parses the
quadlet used by the built image and uses those exact Image=, PublishPort=,
Volume= and env var values when invoking podman run (replace hardcoded values in
the "Start OpenClaw container" step with variables sourced from the quadlet), or
(b) instead runs the built bootc image itself (with --privileged and systemd
enabled) so the quadlet inside the image brings up the gateway; if you cannot
implement (a) or (b) immediately, at minimum replace
ghcr.io/openclaw/openclaw:latest with the exact digest referenced by the quadlet
to prevent silent tag drift.
- Around line 13-15: The concurrency config uses group: `${{ github.workflow
}}-${{ github.ref }}` and cancel-in-progress: true which causes scheduled runs
to be cancelled by pushes to main; update the concurrency grouping or
cancellation logic so scheduled/nightly runs aren't killed — for example,
include `${{ github.event_name }}` or `${{ github.sha }}` in the concurrency
group (e.g., append `${{ github.event_name }}`) or conditionally disable
cancel-in-progress for schedule events (check `github.event_name == 'schedule'`)
so the concurrency/group and cancel-in-progress settings in the workflow's
concurrency block avoid cancelling long-running nightly builds.
- Around line 33-50: The build step tags the image as `${{ github.sha }}` but
the push step expects `${{ github.sha }}-amd64` or `-arm64`; update the build
step (the "Build image" step that uses redhat-actions/buildah-build, id: build)
to produce the per-arch tag to match the push step by changing its `tags:` value
to include the platform suffix (e.g. `${{ github.sha }}-${{ matrix.platform ==
'linux/arm64' && 'arm64' || 'amd64' }}`) so the image pushed by the "Push
per-arch image to quay.io" step (uses: redhat-actions/push-to-registry) exists
in local storage.
- Around line 250-256: The cleanup loop using "skopeo delete" suppresses
failures with "|| true" and doesn't supply the Podman auth file, so
authentication errors can be masked; update the loop that runs skopeo delete
(the for arch in arm64 amd64; do ... skopeo delete
"docker://${REGISTRY}/${IMAGE_NAME}:${COMMIT_SHA}-${arch}" ...) to pass the
Podman auth file via --authfile "${REGISTRY_AUTH_FILE}" and remove the "|| true"
so deletion failures (e.g., 401) surface in the workflow logs; ensure
REGISTRY_AUTH_FILE remains exported by the login step so the value is available
to the cleanup step.

---

Nitpick comments:
In @.github/workflows/build-push.yml:
- Around line 22-23: Add a job-level timeout to prevent stuck steps from
consuming runner time: set timeout-minutes: 60 on the build job (the job named
"build") and set timeout-minutes: 20 on the smoke-test and manifest jobs (the
jobs named "smoke-test" and "manifest"); apply the same changes to the other
occurrences noted (the other build/smoke-test/manifest blocks referenced near
the second and third occurrences) so each job has the appropriate timeout.
- Around line 24-26: The current strategy.matrix.platform uses platform:
[linux/arm64, linux/amd64] which forces QEMU emulation for arm64; replace that
with a matrix that separates architecture and runner (e.g., matrix.arch and
matrix.runner) and update the job to use runs-on: ${{ matrix.runner }} so arm64
jobs use native GitHub arm runners (for example ubuntu-24.04-arm or
ubuntu-22.04-arm) while amd64 uses the appropriate ubuntu runner, ensuring
native arm64 execution instead of QEMU emulation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 235b9ca2-b553-40ca-b0aa-5d410a32e119

📥 Commits

Reviewing files that changed from the base of the PR and between e1274bf and 33a5f16.

📒 Files selected for processing (1)
  • .github/workflows/build-push.yml

Comment thread .github/workflows/build-push.yml
Comment thread .github/workflows/build-push.yml
Comment thread .github/workflows/build-push.yml Outdated
Comment thread .github/workflows/build-push.yml Outdated
cooktheryan and others added 3 commits April 23, 2026 16:12
Signed-off-by: Ryan Cook <rcook@redhat.com>
Signed-off-by: Ryan Cook <rcook@redhat.com>
- Replace QEMU emulation with native GitHub arm64 runners
  (ubuntu-24.04-arm) so each arch builds natively in parallel
- Fix tag mismatch: build step now produces the per-arch suffixed
  tag that the push step expects
- Remove per-arch tag cleanup step from manifest job

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
.github/workflows/build-push.yml (1)

156-169: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Smoke test still bypasses the image’s actual runtime wiring.

This step hardcodes Image=, ports, env, and the command instead of exercising bootc/rootfs/etc/containers/systemd/users/1000/openclaw.container. A regression in the quadlet can still pass CI because the workflow never runs the built bootc image the way users consume it.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/build-push.yml around lines 156 - 169, The workflow step
currently invokes podman run with hardcoded Image, ports, env and command which
bypasses the container unit file; instead run the built bootc image through
podman run so systemd/quadlet reads
bootc/rootfs/etc/containers/systemd/users/1000/openclaw.container (do not
hardcode PORT/ENV/COMMAND). Concretely, replace the manual podman run invocation
with a podman run that uses the workflow’s built bootc image/artifact, mounts
the built bootc rootfs (so /etc/containers/systemd/users/1000/openclaw.container
is available), and enables systemd/quadlet (so the unit file wires ports, env
and command); remove the explicit -p, -e and command overrides so the
container’s unit file defines runtime wiring. Ensure the step references the
built image variable from the build step and still mounts
${RUNNER_TEMP}/openclaw-home for test state.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/build-push.yml:
- Around line 227-236: The Determine tag step (id: tag) currently treats
workflow_dispatch like other non-schedule runs and emits tag=latest, which can
overwrite latest from non-main refs; update this step to: if EVENT_NAME ==
"schedule" set tag=nightly, else if EVENT_NAME == "workflow_dispatch" set a
distinct tag (e.g., tag=manual-${GITHUB_REF#refs/heads/} or tag=manual) or
output a flag to skip pushing the manifest, and only emit tag=latest when
GITHUB_REF (or github.ref) equals refs/heads/main; keep the step id: tag and env
EVENT_NAME usage but add the GITHUB_REF check to gate latest to main and handle
manual runs separately.

---

Duplicate comments:
In @.github/workflows/build-push.yml:
- Around line 156-169: The workflow step currently invokes podman run with
hardcoded Image, ports, env and command which bypasses the container unit file;
instead run the built bootc image through podman run so systemd/quadlet reads
bootc/rootfs/etc/containers/systemd/users/1000/openclaw.container (do not
hardcode PORT/ENV/COMMAND). Concretely, replace the manual podman run invocation
with a podman run that uses the workflow’s built bootc image/artifact, mounts
the built bootc rootfs (so /etc/containers/systemd/users/1000/openclaw.container
is available), and enables systemd/quadlet (so the unit file wires ports, env
and command); remove the explicit -p, -e and command overrides so the
container’s unit file defines runtime wiring. Ensure the step references the
built image variable from the build step and still mounts
${RUNNER_TEMP}/openclaw-home for test state.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cc5b498f-4083-47db-a165-5ea95115b022

📥 Commits

Reviewing files that changed from the base of the PR and between 33a5f16 and 01403ef.

📒 Files selected for processing (1)
  • .github/workflows/build-push.yml

Comment on lines +227 to +236
- name: Determine tag
id: tag
run: |
if [[ "${EVENT_NAME}" == "schedule" ]]; then
echo "tag=nightly" >> "$GITHUB_OUTPUT"
else
echo "tag=latest" >> "$GITHUB_OUTPUT"
fi
env:
EVENT_NAME: ${{ github.event_name }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't publish latest for manual runs from non-main refs.

workflow_dispatch falls into the latest branch here, so dispatching this workflow from refs/heads/nightly or any future topic branch will overwrite the public latest tag with an unmerged commit. Please gate latest behind refs/heads/main, and give manual runs a separate tag or skip the manifest push for them.

Suggested change
       - name: Determine tag
         id: tag
         run: |
           if [[ "${EVENT_NAME}" == "schedule" ]]; then
             echo "tag=nightly" >> "$GITHUB_OUTPUT"
-          else
+          elif [[ "${GITHUB_REF}" == "refs/heads/main" ]]; then
             echo "tag=latest" >> "$GITHUB_OUTPUT"
+          else
+            echo "tag=manual-${COMMIT_SHA}" >> "$GITHUB_OUTPUT"
           fi
         env:
           EVENT_NAME: ${{ github.event_name }}
+          GITHUB_REF: ${{ github.ref }}
+          COMMIT_SHA: ${{ github.sha }}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/build-push.yml around lines 227 - 236, The Determine tag
step (id: tag) currently treats workflow_dispatch like other non-schedule runs
and emits tag=latest, which can overwrite latest from non-main refs; update this
step to: if EVENT_NAME == "schedule" set tag=nightly, else if EVENT_NAME ==
"workflow_dispatch" set a distinct tag (e.g.,
tag=manual-${GITHUB_REF#refs/heads/} or tag=manual) or output a flag to skip
pushing the manifest, and only emit tag=latest when GITHUB_REF (or github.ref)
equals refs/heads/main; keep the step id: tag and env EVENT_NAME usage but add
the GITHUB_REF check to gate latest to main and handle manual runs separately.

- Remove workflow_dispatch trigger to prevent accidental overwrites
  of the latest tag from non-main branches
- Smoke test now extracts Image, Environment, PublishPort, Volume,
  RunInit, and Exec from the quadlet baked into the built image
  rather than hardcoding them, so quadlet drift is caught in CI

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/build-push.yml:
- Around line 155-186: The workflow extracts the quadlet into QUADLET but
ignores the quadlet's UserNS and User directives, so the generated podman run
(constructed via ARGS and used with podman run $ARGS "$OC_IMAGE" $EXEC_CMD)
doesn't preserve production user/namespace semantics; modify the parsing of
QUADLET (the same block that builds ARGS, reads
Environment/PublishPort/Volume/Exec) to translate UserNS=keep-id into adding
--userns=keep-id to ARGS and parse User=%U:%G (or concrete UID:GID values) to
add --user UID:GID (or --user="%U:%G" after expanding) so podman run uses the
same user/namespace as the quadlet, or alternatively invoke the quadlet directly
instead of reconstructing the podman run command to guarantee identical
behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6df35c8e-c62f-40e8-9d29-604baf3e5649

📥 Commits

Reviewing files that changed from the base of the PR and between 01403ef and 08ea41c.

📒 Files selected for processing (1)
  • .github/workflows/build-push.yml

Comment thread .github/workflows/build-push.yml
Translates UserNS=keep-id to --userns=keep-id and expands
User=%U:%G to the runner's UID:GID so the smoke test matches
production user/namespace semantics.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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