Yes. Build the image in GitHub Actions with Docker Buildx, publish it to GitHub Container Registry (GHCR), and keep using rootless Podman locally only to pull and run it.
Recommended first target:
ghcr.io
ghcr.io/prabhashdiss/dotfiles-pi-runner
linux/amd64
.local/bin/pi.sh
setup/pi/Containerfile
Docker-built OCI images are compatible with Podman. A Docker daemon is not required on the workstation.
.local/bin/pi.sh currently:
localhost/pi-runner:0.84.4.
setup/pi/build.sh if that image is absent or --build is supplied.
setup/pi/build.sh is only called by pi.sh; there is no existing GitHub Actions workflow or registry configuration in this checkout.
The runtime contract can remain unchanged. Only image acquisition needs to change.
Add .github/workflows/pi-image.yml using:
actions/checkout
docker/login-action for ghcr.io
docker/setup-buildx-action
docker/metadata-action
docker/build-push-action
type=gha)
linux/amd64 only
packages: write and contents: read job permissions
Build context must be the repository root:
context: .
file: ./setup/pi/Containerfile
platforms: linux/amd64
push: true
Use a commit tag such as sha-<full-commit> as the immutable human-selected tag. Record the pushed digest and ultimately consume the image by @sha256:..., not latest.
A release-only workflow is the safest publication policy. A workflow_dispatch option is useful for rebuilding after dependency or base-image changes. Do not publish from pull_request or use pull_request_target with untrusted checkout content.
There is a current mismatch:
setup/pi/Containerfile copies .local/bin/helium-agent.sh.
.containerignore excludes .local/bin and does not unignore that file.
.dockerignore, not .containerignore.
Add a .dockerignore for the GitHub build and update .containerignore for Podman. Both should explicitly allow:
setup/**
.local/lib/**
.local/bin/helium-agent.sh
.pi/agent/extensions/package.json
.pi/agent/extensions/package-lock.json
Keep the allow-list narrow. Do not send the complete home directory, Pi state, credentials, or unrelated dotfiles as build context.
Also add this label to the image metadata or Containerfile:
LABEL org.opencontainers.image.source="https://github.com/PrabhashDiss/dotfiles"
This lets GHCR associate the package with the repository.
pi.sh from build-on-miss to pull-on-missReplace the local build branch with the remote image reference:
IMAGE=ghcr.io/prabhashdiss/dotfiles-pi-runner@sha256:<published-digest>
if ! podman image exists "$IMAGE"; then
podman pull "$IMAGE"
fi
The existing podman run flags and mounts can stay as they are.
Remove --build, or rename it to an explicit --refresh that performs podman pull. Keeping a local-build path would preserve the unwanted behavior and add a second image source to maintain.
Delete setup/pi/build.sh once no local fallback is desired. Update the comments and README so the wrapper’s pull-only behavior is explicit.
| Choice | Benefit | Cost |
|---|---|---|
Mutable :0.84.4 tag |
Smallest script change; easy updates | Reproducibility and rollback are weaker |
Commit tag :sha-... |
Easy to identify the source revision | The wrapper must be updated for each new image |
Digest @sha256:... |
Strongest reproducibility and rollback | The digest must be updated deliberately after publication |
Use a commit tag for publication and a digest in the final pi.sh. A mutable :0.84.4 alias may be published for convenience, but should not be the authoritative runtime reference.
The current PI_VERSION=0.84.4 identifies the Pi CLI, not the complete image. Changes to setup/**, the extension lockfiles, helium-agent.sh, or the base image can change the image without changing Pi’s version. Those changes must trigger a rebuild and produce a new image digest.
This is the simplest option: podman pull works without a login. It is reasonable if the image contains only public source and tools, and no credentials are copied into it.
Authenticate on the host, outside the container, before running pi.sh:
podman login ghcr.io
Do not make pi.sh perform an interactive login and do not pass registry credentials into the container. GitHub documents a classic PAT with read:packages for private command-line pulls. A package linked and published by the repository workflow can use the repository’s GITHUB_TOKEN during publication.
The image is a trusted-code boundary. The wrapper gives it access to:
--podman is supplied.
The current rootless, read-only-rootfs, dropped-capability setup is useful, but a compromised image can still read user-readable files and use explicitly mounted credentials. Keep --podman opt-in and verify the image digest before trusting it.
The hard-coded Helium amd64 package and other architecture-specific downloads mean that publishing linux/amd64 is the correct minimal scope. Do not advertise multi-architecture support until every dependency and the runtime wrapper have been tested on it.
Commit the container-context fixes and workflow; do not include local state or ignored credentials.
Run the GitHub build and verify the image digest, entrypoint, architecture, and GHCR package visibility.
Update pi.sh to the verified digest.
On the workstation, remove the old local image if desired:
podman rmi localhost/pi-runner:0.84.4
Run pi.sh once in the normal X11 session and once through the scheduled Pi job path.
Confirm FreshRSS/SearXNG network names, AWS access, Helium, Pi extensions, writable state, and optional nested-Podman behavior.
Keep setup/pi/build.sh deleted unless an emergency offline/local fallback is an explicit requirement.
The clean design is: GitHub Actions builds; GHCR stores; Podman pulls and runs. The smallest complete code change is to replace the build-on-miss branch in .local/bin/pi.sh, add a GHCR workflow, and fix the Docker/Podman build-context allow-list. Digest pinning avoids silently running a changed image and avoids maintaining a local image-building toolchain.