Skip to content

Conversation

@chaptersix
Copy link
Contributor

Summary

  • Fix critical Docker build bugs preventing multi-platform builds
  • Simplify Dockerfile to use Alpine base with digest pinning
  • Restrict trigger-docs workflow to official repo only
  • Use version tags instead of commit SHAs for actions

Changes

Docker Build Fixes

  • Fix invalid TARGETARCH usage in Dockerfile that broke multi-platform builds
  • Fix TAG_LATEST referencing undefined output in non-publish workflows
  • Restore intermediate dist stage for reliable path normalization
  • Use Alpine 3.22 (digest-pinned) as base image
  • Add explicit chmod=755 to binary COPY instruction

Workflow Improvements

  • Add repository check to trigger-docs workflow (only runs in temporalio/cli)
  • Use [email protected] instead of commit SHA reference
  • Clean up Dockerfile structure and remove unnecessary syntax directive

File Organization

  • Move docker-bake.hcl to root directory
  • Move Dockerfile to root directory
  • Update all workflow references accordingly

Migrate Docker publishing from Docker Hub to GHCR
- Replace Docker Hub authentication with GHCR using GITHUB_TOKEN
- Update image namespace to ghcr.io/chaptersix/temporal-cli
- Remove repository owner checks to enable publishing from fork
- Remove Docker Hub secrets from workflow configuration
Migrate Docker publishing from Docker Hub to GHCR (actual changes)
The metadata step was only setting image_repo to the repository owner
(e.g., 'chaptersix') instead of the full registry path ('ghcr.io/chaptersix').
This caused Docker to try pushing to Docker Hub instead of GHCR.
Fix IMAGE_REPO to include ghcr.io registry prefix for forks
This change makes Docker image publishing fully configurable while maintaining
backward compatibility with both temporalio (Docker Hub) and forks (GHCR).

Changes:
- Add workflow inputs: registry, registry_namespace, and image_name
- Smart defaults: temporalio uses Docker Hub, forks use GHCR
- Conditional authentication for multiple registries
- Standardize image name to "temporal" everywhere
- Proper handling of Docker Hub's no-prefix format

Workflow inputs (all optional with smart defaults):
- registry: Container registry (docker.io, ghcr.io, etc.)
- registry_namespace: Organization/user (defaults to repository_owner)
- image_name: Image name (defaults to "temporal")

Default behavior:
- temporalio/cli → docker.io/temporalio/temporal
- forks → ghcr.io/{owner}/temporal

This design is PR-able to upstream while working for forks out of the box.
Improve repository and registry parameterization
This change makes Docker image publishing fully configurable while maintaining
backward compatibility with both temporalio (Docker Hub) and forks (GHCR).

Changes:
- Add workflow inputs: registry, registry_namespace, and image_name
- Smart defaults: temporalio uses Docker Hub, forks use GHCR
- Conditional authentication for multiple registries
- Standardize image name to "temporal" everywhere
- Proper handling of Docker Hub's no-prefix format

Workflow inputs (all optional with smart defaults):
- registry: Container registry (docker.io, ghcr.io, etc.)
- registry_namespace: Organization/user (defaults to repository_owner)
- image_name: Image name (defaults to "temporal")

Default behavior:
- temporalio/cli → docker.io/temporalio/temporal
- forks → ghcr.io/{owner}/temporal

This design is PR-able to upstream while working for forks out of the box.
Keep the conditional expression approach (no local variables) to avoid HCL syntax errors.
Improve repository and registry parameterization
Creates a new workflow (update-latest-tag.yml) that runs when a release
is edited or published and automatically updates the 'latest' Docker tag
to point to the release version if the release is marked as latest.

Changes:
- Add .github/workflows/update-latest-tag.yml
  - Triggers on release edited/released events
  - Checks if release is latest (not prerelease, not draft)
  - Pulls the versioned image and retags it as 'latest'
  - Supports both Docker Hub and GHCR
  - Uses environment variables to prevent command injection

- Update .github/workflows/build-and-publish.yml
  - Remove 'Check if release is latest' step
  - Set TAG_LATEST to false (always)
  - Latest tag is now managed by the separate workflow

Benefits:
- Decouples latest tag management from release creation
- Allows updating latest tag when release status changes
- Cleaner separation of concerns

Tagging strategy matches temporalio/temporal on Docker Hub:
- Full version tags (e.g., 1.5.1)
- Latest tag
- SHA tags (additional, useful for debugging)
- Remove 'Upload build artifacts' step from build-and-publish.yml
  (no longer needed)
- Add 'packages: write' permission to goreleaser.yml
  (required for pushing Docker images to GHCR)
Add separate workflow for managing latest Docker tag
Add GITHUB_REPOSITORY variable and use it in OCI labels so GitHub
correctly associates the package with the right repository.

This fixes the issue where chaptersix/temporal-cli images were being
associated with temporalio/cli repository.
Make Docker image labels dynamic based on repository
Major improvements:
- Add full parameterization (registry, namespace, image name)
- Auto-detect registry: temporalio → docker.io, others → ghcr.io
- Separate workflow for managing 'latest' tag on release events
- Dynamic Docker labels using GITHUB_REPOSITORY variable
- Add packages:write permission for GHCR
- Remove artifact uploading (no longer needed)

Benefits:
- Works out-of-box for both upstream and forks
- Flexible registry support (Docker Hub, GHCR, any registry)
- Clean separation of release vs latest-tag concerns
- Proper package association in GitHub

Configuration requirements:
- DOCKER_USERNAME and DOCKER_PASSWORD secrets needed for Docker Hub
- GITHUB_TOKEN automatically provides GHCR access
- Move Dockerfile to repo root and simplify to single-stage Alpine build
- Remove complex multi-stage build and ARG ALPINE_IMAGE parameterization
- Change USER 1000:1000 to USER temporal:temporal for readability
- Delete Makefile entirely (not needed in this repo)
- Update GitHub Actions to use major version tags instead of fixed hashes
- Convert bash registry logic to JavaScript in update-latest-tag.yml
- Keep fork support logic for temporalio vs ghcr.io auto-detection
- Update docker-bake.hcl to reference new Dockerfile location
- Test Docker build functionality - all working correctly
- Replace bash script with GitHub Script for registry configuration
- Keep all existing functionality including fork support logic
- Improve maintainability and consistency with update-latest-tag.yml
- Use environment variables to pass inputs to JavaScript script
- Replace Alpine base with gcr.io/distroless/static-debian12:nonroot
- Use multi-stage build to copy CA certificates from temporary Alpine stage
- Remove user creation since distroless images handle non-root execution
- Improve security and reduce image size with distroless approach
- Maintain same functionality while following security best practices
- Move docker-bake.hcl from .github/docker/ to repo root
- Update workflow references to use new file location
- Remove old cli.Dockerfile from .github/docker/ directory
- Consolidate Docker build files in root directory for better organization
- Maintain all existing functionality with cleaner file structure
- Replace gcr.io/distroless/static-debian12:nonroot with FROM scratch
- Create completely minimal image with only essential components
- Manually copy CA certificates, passwd, and group files from Alpine stage
- Maintain non-root user execution with USER 1000:1000
- Achieve smallest possible attack surface and image size
- Follow container security best practices with truly minimal base
- Use ARG TARGETARCH (built-in Docker Buildx arg) instead of custom BUILDARCH
- Copy binaries from GoReleaser output structure: dist/nix_linux_amd64_v1/temporal
- Add multi-stage dist build to properly handle GoReleaser output paths
- Remove unnecessary TARGETPLATFORM from workflows and docker-bake.hcl
- Ensure Docker build works correctly with actual GoReleaser binary locations
- Remove empty .github/docker directory since all files moved to root
- dist/ already exists in .gitignore (no changes needed)
- Consolidate all Docker build files in root directory
- Final clean structure: Dockerfile, docker-bake.hcl in repo root
- Add step to detect if release is marked as latest (not prerelease/draft)
- Use GitHub API to check release status via github-script
- Set TAG_LATEST based on actual release latest status
- Push both version tag and latest tag when appropriate
- Maintains existing version tagging behavior for non-latest releases
- Works for both temporalio (docker.io) and fork (ghcr.io) registries
- Correct TAG_LATEST logic to use boolean comparison == 'true'
- When release is latest: push both 'latest' AND 'vX.Y.Z' tags
- When release is not latest: push only 'vX.Y.Z' tag (no latest)
- Ensures users can always pull :latest for stable releases
- Maintains version-specific tags for all releases
The intermediate stage approach copies both architecture binaries into
normalized paths within Docker's build context, then uses TARGETARCH
to select the correct one. This is more reliable than filesystem
wildcards which depend on the host build environment.
Remove the intermediate dist stage and copy binaries directly using
TARGETARCH-based wildcards. The Alpine base (digest-pinned to 3.22)
provides CA certificates and a non-root user environment in a simple,
maintainable format.
- Remove syntax directive comment
- Remove leading ./ from COPY path for consistency
- ARG TARGETARCH declared after FROM (required for build stage scope)
- Verified working with goreleaser output structure
The intermediate stage approach is more reliable than wildcards as it:
- Operates entirely within Docker's build context
- Explicitly copies both architecture binaries to normalized paths
- Allows clean selection via TARGETARCH without filesystem assumptions
- Avoids reliance on shell glob expansion behavior
Prevent the workflow from running in forks by adding a repository check.
This ensures documentation updates only trigger from the official repo.
@chaptersix chaptersix requested review from a team as code owners November 22, 2025 00:57
@chaptersix
Copy link
Contributor Author

Wrong target repo, opening against chaptersix instead

@chaptersix chaptersix closed this Nov 22, 2025
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