Container Releases
Publish coordinated Oblive images to Amazon ECR Public and deployment bundles to Cloudflare R2.
Oblive publishes three first-party images and one coordinated portable deployment bundle from the manual Publish release GitHub Actions workflow:
| Image | Runtime roles |
|---|---|
backend | Backend API and one-shot migrations |
frontend | Frontend server |
agents | Chat, worker, and Codex auth synchronizer |
PostgreSQL, Redis, and Garage retain the exact upstream tags in compose.yaml:
pgvector/pgvector:0.8.1-pg17, redis:8.2.1-alpine, and dxflrs/garage:v2.3.0.
Configure GitHub
Create these repository secrets:
AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYCLOUDFLARE_ACCOUNT_IDCLOUDFLARE_R2_ACCESS_KEY_IDCLOUDFLARE_R2_SECRET_ACCESS_KEY
Create these repository variables:
| Variable | Value |
|---|---|
ECR_PUBLIC_REGISTRY_ALIAS | w3z5w3s0 |
ECR_PUBLIC_REPOSITORY | skyfall/oblive |
CLOUDFLARE_R2_BUCKET | oblive |
OBLIVE_DOWNLOAD_BASE_URL | https://downloads.oblive.dev |
The credentials must belong to a dedicated least-privilege IAM principal. Amazon ECR Public
authentication runs through us-east-1, while image upload permission is scoped to the existing
repository:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "GetAuthorizationToken",
"Effect": "Allow",
"Action": ["ecr-public:GetAuthorizationToken", "sts:GetServiceBearerToken"],
"Resource": "*"
},
{
"Sid": "PublishObliveImages",
"Effect": "Allow",
"Action": [
"ecr-public:BatchCheckLayerAvailability",
"ecr-public:CompleteLayerUpload",
"ecr-public:InitiateLayerUpload",
"ecr-public:PutImage",
"ecr-public:UploadLayerPart"
],
"Resource": "arn:aws:ecr-public::<aws-account-id>:repository/skyfall/oblive"
}
]
}Replace <aws-account-id> with the AWS account that owns the public repository. The workflow does
not create or configure the repository. The same AWS credentials authenticate image publication and
the release smoke test; no second credential pair is required.
Create the Cloudflare credentials under R2 → Overview → Manage R2 API Tokens. Use an account
token with Object Read & Write access limited to the oblive bucket, then store its generated
Access Key ID and Secret Access Key in the matching GitHub secrets. The existing Cloudflare account
ID can be reused; the Pages API token and AWS ECR credentials are separate and must not be reused
for R2 S3 uploads. Connect downloads.oblive.dev as the bucket’s public custom domain.
Publish a Release
-
Open Actions → Publish release → Run workflow.
-
Select the
mainbranch. -
Select the release mode:
Mode Use when fullBackend, frontend, agents, or their image dependencies changed. bundle-onlyOnly the CLI, Compose files, schema, or packaged config changed. -
Choose a
patch,minor, ormajorbump. The first release must usefullwithpatch, producingv0.0.1. -
Optionally add maintainer notes. They appear before GitHub’s generated release notes.
-
Run the workflow.
The workflow refuses non-main releases, commits without a successful main CI run, and releases
with no commits after the latest stable vX.Y.Z tag. CI owns formatting, linting, type checks, unit
and integration tests, bundle and installer tests, and the complete source-stack smoke. The release
workflow keeps only the checks that depend on newly published semantic artifacts.
The release boundary is deliberately ordered:
- In
fullmode, build AMD64 and ARM64 digests for all three services. Inbundle-onlymode, resolve and validate the immediately previous stable release’s digests without rebuilding. - Publish and verify immutable semantic image tags.
- Build and checksum the deployment bundle.
- Authenticate to Public ECR, start the complete semantic deployment with a non-operational API key, and verify backend health plus the frontend HTML, CSS, and JavaScript assets.
- Promote all three
latesttags to the tested digests. - Publish and publicly verify the versioned bundle in Cloudflare R2, then advance the
latestpointer. - Create the matching GitHub tag and Release metadata.
If bundle generation, smoke testing, R2 publication, or public checksum verification fails, the download pointer and GitHub Release are not advanced. The smoke job always removes its containers and volumes.
Use bundle-only only when the existing service images remain valid for the packaged changes. It
creates a normal coordinated semantic release: the new service tags point to the reused immutable
digests, the complete stack is smoke tested, and only then are the moving tags and download pointer
advanced. Reused images retain their original OCI build metadata and provenance. The bundle owns
the dependency-bundled stack generator used for configuration and environment generation, so it
does not require reused backend images to contain current repository scripts.
Changes limited to the landing page or public install.sh do not require this workflow. Publish
those through Publish landing instead. Documentation and landing deployments run only after CI
succeeds for the same main commit; unchanged sites are skipped. Manual site deployments are also
limited to CI-passing commits on main.
Image Tags
Every release creates a new version-specific semantic tag and updates the moving latest tag for
each image. A bundle-only release may point its new tag to the previous release’s immutable image
digest, but the workflow never overwrites an earlier semantic tag:
public.ecr.aws/w3z5w3s0/skyfall/oblive:backend-v0.0.1
public.ecr.aws/w3z5w3s0/skyfall/oblive:backend-latest
public.ecr.aws/w3z5w3s0/skyfall/oblive:frontend-v0.0.1
public.ecr.aws/w3z5w3s0/skyfall/oblive:frontend-latest
public.ecr.aws/w3z5w3s0/skyfall/oblive:agents-v0.0.1
public.ecr.aws/w3z5w3s0/skyfall/oblive:agents-latestThe installer never places moving image tags in a deployment. The latest installation channel
resolves the R2 releases/latest pointer, then writes the matching <service>-vX.Y.Z references
for all three first-party services. oblive update is the only normal boundary that advances that
selection.
Deployment Bundle
Every semantic release publishes stable asset names under an immutable version path:
https://downloads.oblive.dev/releases/vX.Y.Z/oblive-deployment.tar.gz
https://downloads.oblive.dev/releases/vX.Y.Z/oblive-deployment.tar.gz.sha256
https://downloads.oblive.dev/releases/latestThe final path contains only the exact current stable version, such as v1.2.3, and is updated
after the versioned archive passes checksum verification through the public hostname. GitHub
Releases retain the semantic tag and generated release notes; R2 is the public bundle owner.
The archive contains the semantic VERSION, image repository, build-free base and local-auth
Compose files, Garage and PostgreSQL initialization files, local-stack JSON Schema, a portable stack
runtime bundled with its dependencies, and the standalone oblive CLI. The CLI mounts that runtime
into the backend container, which supplies the pinned Bun executable without owning the generator
source. The generator runs as the invoking host user so its mode-0600 configuration and
environment files remain private without becoming root-owned on Linux.
The Installed CLI Architecture page defines the bundle layout, root resolution, Compose invocation, update transaction, and destructive-command boundaries.
Install the repository dependencies, then build the archive locally for inspection with:
bun install --frozen-lockfile
.github/scripts/release/build-deployment-bundle.sh \
v1.2.3 public.ecr.aws/w3z5w3s0/skyfall/oblive /tmp/oblive-release
.github/scripts/tests/deployment-bundle.test.sh
.github/scripts/tests/deployment-bundle-container.test.sh
.github/scripts/tests/portable-install.test.shThe public /install.sh endpoint resolves latest when necessary and downloads the stable assets
from the exact R2 semantic-version path. Keep the asset names, bundle layout, semantic tag contract,
download pointer, and CLI update logic compatible in one change.