name: Publish Components Image permissions: # required for bump step to push branch and create PR contents: write pull-requests: write id-token: write attestations: write artifact-metadata: write packages: write on: workflow_dispatch: inputs: component: description: 'Component to build' required: true type: choice options: - execd - code-interpreter - ingress - egress - controller - task-executor - image-committer default: 'execd' image_tag: description: 'Docker image tag' required: true default: 'latest' push: tags: - 'docker/execd/**' - 'docker/code-interpreter/**' - 'docker/ingress/**' - 'docker/egress/**' - 'k8s/controller/**' - 'k8s/task-executor/**' - 'k8s/image-committer/**' jobs: release-preflight: uses: ./.github/workflows/release-preflight.yml publish: needs: release-preflight runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v6 - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Install Cosign if: github.ref_type == 'tag' uses: sigstore/cosign-installer@v4.1.1 - name: Login to DockerHub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_PASSWORD }} - name: Login to ACR uses: docker/login-action@v3 with: registry: sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com username: ${{ secrets.ACR_USERNAME }} password: ${{ secrets.ACR_PASSWORD }} - name: Login to GHCR uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Parse tag and set variables id: parse_tag run: | if [[ "${{ github.ref }}" == refs/tags/docker/* ]]; then TAG_PATH="${{ github.ref }}" TAG_PATH="${TAG_PATH#refs/tags/}" COMPONENT=$(echo "$TAG_PATH" | cut -d'/' -f2) IMAGE_TAG=$(echo "$TAG_PATH" | cut -d'/' -f3) echo "component=$COMPONENT" >> $GITHUB_OUTPUT echo "image_tag=$IMAGE_TAG" >> $GITHUB_OUTPUT elif [[ "${{ github.ref }}" == refs/tags/k8s/* ]]; then TAG_PATH="${{ github.ref }}" TAG_PATH="${TAG_PATH#refs/tags/}" COMPONENT=$(echo "$TAG_PATH" | cut -d'/' -f2) IMAGE_TAG=$(echo "$TAG_PATH" | cut -d'/' -f3) echo "component=$COMPONENT" >> $GITHUB_OUTPUT echo "image_tag=$IMAGE_TAG" >> $GITHUB_OUTPUT else echo "component=${{ inputs.component }}" >> $GITHUB_OUTPUT echo "image_tag=${{ inputs.image_tag }}" >> $GITHUB_OUTPUT fi - name: Free disk space run: | sudo rm -rf /usr/share/dotnet /opt/ghc /opt/hostedtoolcache sudo apt-get clean sudo rm -rf /var/lib/apt/lists/* df -h - name: Build and push to registries id: build env: BUILD_METADATA_FILE: ${{ runner.temp }}/opensandbox-component-image-metadata.json run: | COMPONENT="${{ steps.parse_tag.outputs.component }}" IMAGE_TAG="${{ steps.parse_tag.outputs.image_tag }}" if [ "$COMPONENT" == "execd" ]; then cd components/execd elif [ "$COMPONENT" == "ingress" ]; then cd components/ingress elif [ "$COMPONENT" == "egress" ]; then cd components/egress elif [ "$COMPONENT" == "controller" ]; then cd kubernetes elif [ "$COMPONENT" == "task-executor" ]; then cd kubernetes elif [ "$COMPONENT" == "image-committer" ]; then cd kubernetes else cd sandboxes/$COMPONENT fi export TAG=$IMAGE_TAG export COMPONENT=$COMPONENT export GHCR_REPO="ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/opensandbox" chmod +x build.sh ./build.sh DIGEST="$(jq -r '."containerimage.digest" // empty' "$BUILD_METADATA_FILE")" if [[ -z "$DIGEST" ]]; then echo "Unable to resolve image digest from $BUILD_METADATA_FILE" >&2 cat "$BUILD_METADATA_FILE" >&2 exit 1 fi echo "digest=$DIGEST" >> "$GITHUB_OUTPUT" echo "dockerhub_image=docker.io/opensandbox/$COMPONENT" >> "$GITHUB_OUTPUT" echo "acr_image=sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/$COMPONENT" >> "$GITHUB_OUTPUT" echo "ghcr_image=$GHCR_REPO/$COMPONENT" >> "$GITHUB_OUTPUT" - name: Sign release images if: github.ref_type == 'tag' && steps.parse_tag.outputs.image_tag != 'latest' && steps.parse_tag.outputs.image_tag != '' env: DIGEST: ${{ steps.build.outputs.digest }} DOCKERHUB_IMAGE: ${{ steps.build.outputs.dockerhub_image }} ACR_IMAGE: ${{ steps.build.outputs.acr_image }} GHCR_IMAGE: ${{ steps.build.outputs.ghcr_image }} run: | set -euo pipefail cosign sign --yes "${DOCKERHUB_IMAGE}@${DIGEST}" "${ACR_IMAGE}@${DIGEST}" "${GHCR_IMAGE}@${DIGEST}" - name: Attest Docker Hub image if: github.ref_type == 'tag' && steps.parse_tag.outputs.image_tag != 'latest' && steps.parse_tag.outputs.image_tag != '' uses: actions/attest@v4 with: subject-name: ${{ steps.build.outputs.dockerhub_image }} subject-digest: ${{ steps.build.outputs.digest }} push-to-registry: true create-storage-record: false - name: Attest ACR image if: github.ref_type == 'tag' && steps.parse_tag.outputs.image_tag != 'latest' && steps.parse_tag.outputs.image_tag != '' uses: actions/attest@v4 with: subject-name: ${{ steps.build.outputs.acr_image }} subject-digest: ${{ steps.build.outputs.digest }} push-to-registry: true create-storage-record: false - name: Attest GHCR image if: github.ref_type == 'tag' && steps.parse_tag.outputs.image_tag != 'latest' && steps.parse_tag.outputs.image_tag != '' uses: actions/attest@v4 with: subject-name: ${{ steps.build.outputs.ghcr_image }} subject-digest: ${{ steps.build.outputs.digest }} push-to-registry: true create-storage-record: false - name: Bump component version in repo if: steps.parse_tag.outputs.image_tag != 'latest' && steps.parse_tag.outputs.image_tag != '' env: GH_TOKEN: ${{ github.token }} run: | COMPONENT="${{ steps.parse_tag.outputs.component }}" IMAGE_TAG="${{ steps.parse_tag.outputs.image_tag }}" # Ensure version has 'v' prefix for bump script if [[ "$IMAGE_TAG" =~ ^v ]]; then VERSION="$IMAGE_TAG" else VERSION="v${IMAGE_TAG}" fi ./scripts/bump-component-version.sh "$COMPONENT" "$VERSION" BRANCH="bump/${COMPONENT}-${VERSION}" git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" git checkout -b "$BRANCH" git add -A git diff --staged --quiet && echo "No changes to commit" && exit 0 git commit -m "chore: bump $COMPONENT to $VERSION" git push origin "$BRANCH" gh pr create \ --title "chore: bump $COMPONENT to $VERSION" \ --body "Auto-generated by Publish Components workflow after building \`$COMPONENT:$VERSION\`." \ --base "$(gh api repos/${{ github.repository }} --jq .default_branch)"