diff --git a/.github/workflows/docker-build-publish.yaml b/.github/workflows/docker-build-publish.yaml index b3bb9a0..155942c 100644 --- a/.github/workflows/docker-build-publish.yaml +++ b/.github/workflows/docker-build-publish.yaml @@ -24,14 +24,62 @@ on: branches: [ master ] env: - DOCKER_BUILDX_PLATFORM: linux/amd64 + # https://hub.docker.com/r/athenz/authorization-proxy/tags + DOCKER_REGISTRY_URL: docker.io DOCKER_REGISTRY_ORG: athenz + DOCKER_REGISTRY_IMAGE: authorization-proxy # DOCKER_REGISTRY_USER: values for docker login is stored in repository variables # DOCKER_REGISTRY_TOKEN_NAME: values for docker login is stored in repository variables + TAGS_CONFIG: | + # If branch is master, main or default branch, push the latest tag image: + type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }} + type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'master') }} + type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }} + + # If the event is a tag release following the semver regex, push the latest tag image: + # Semver official regex: https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string + type=match,value=latest,group=0,pattern=^v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$ + + # If it is PR version, push the pr- tag image: + type=ref,event=pr + + type=semver,pattern=v{{version}} + + # Any cron builds (scheduled workflows) push the nightly tag image: + type=schedule,pattern=nightly + jobs: - build: + set_matrix: runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.set.outputs.matrix }} + suffixes: ${{ steps.set.outputs.suffixes }} + steps: + - id: set + run: | + # We define BUILD_MATRIX so that we have multiple platform supported, + # maybe Windows as well in the future: + + MATRIX_JSON='{ + "include": [ + { "platform": "linux/amd64", "runner": "ubuntu-latest", "suffix": "-amd64" }, + { "platform": "linux/arm64", "runner": "ubuntu-24.04-arm", "suffix": "-arm64" } + ] + }' + + # Store JSON data: + echo "matrix=$(echo "$MATRIX_JSON" | jq -c .)" >> $GITHUB_OUTPUT + + # Store Suffix list: + echo "suffixes=$(echo "$MATRIX_JSON" | jq -r '.include[].suffix' | xargs)" >> $GITHUB_OUTPUT + + build: + needs: set_matrix + runs-on: ${{ matrix.runner }} + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.set_matrix.outputs.matrix) }} permissions: actions: none checks: none @@ -39,7 +87,7 @@ jobs: deployments: none issues: none discussions: none - packages: none + packages: write # for ghcr read permission pull-requests: none repository-projects: none security-events: none @@ -54,16 +102,6 @@ jobs: # uses: https://github.com/FranzDiebold/github-env-vars-action/tags uses: FranzDiebold/github-env-vars-action@v2 - # A GitHub Action to prepare default environment variables. - - - name: Set Default Environment Variables - id: default_env - run: | - # Use docker.io for Docker Hub if empty - [[ "${{ env.DOCKER_REGISTRY_URL}}" = "" ]] && echo "DOCKER_REGISTRY_URL=docker.io" >> $GITHUB_ENV - [[ "${{ env.DOCKER_REGISTRY_ORG }}" = "" ]] && echo "DOCKER_REGISTRY_ORG=${{ env.CI_REPOSITORY_OWNER }}" >> $GITHUB_ENV - [[ "${{ env.DOCKER_REGISTRY_IMAGE }}" = "" ]] && echo "DOCKER_REGISTRY_IMAGE=${{ env.CI_REPOSITORY_NAME }}" >> $GITHUB_ENV - # This action checks-out your repository under $GITHUB_WORKSPACE, so your workflow can access it. # https://github.com/actions/checkout - @@ -84,8 +122,9 @@ jobs: # uses: https://github.com/actions/setup-go/tags uses: actions/setup-go@v4 with: + # Fix the following warning: Both go-version and go-version-file inputs are specified, only go-version will be used go-version: "stable" - go-version-file: './go.mod' + # go-version-file: './go.mod' cache: true # A GitHub Action for golang tests @@ -101,6 +140,7 @@ jobs: # https://github.com/apache/skywalking-eyes # issue: go version hard-coded: https://github.com/apache/skywalking-eyes/blob/5dfa68f93380a5e57259faaf95088b7f133b5778/header/action.yml#L47-L51 - name: Check License Header + if: matrix.platform == 'linux/amd64' # Only required once for any platform, and will do the most general amd64 uses: apache/skywalking-eyes/header@main with: log: "info" # optional: set the log level. The default value is `info`. @@ -113,6 +153,7 @@ jobs: - name: Sysdig Benchmark Dockerfile id: sysdig + if: matrix.platform == 'linux/amd64' # Only required once for any platform, and will do the most general amd64 # You may pin to the exact commit or the version. # uses: https://github.com/sysdiglabs/benchmark-dockerfile/tags uses: sysdiglabs/benchmark-dockerfile@v1.0.0 @@ -130,6 +171,7 @@ jobs: - name: Post Sysdig Benchmark Dockerfile id: postsysdig + if: matrix.platform == 'linux/amd64' # Only required once for any platform, and will do the most general amd64 run: | echo ${{ toJSON(steps.sysdig.outputs.violation_report) }} | \ jq -r . @@ -138,50 +180,6 @@ jobs: wc -l | \ xargs -I% test 0 -eq % - # Extract metadata (tags, labels) for Docker - # https://github.com/docker/metadata-action - - - name: Extract Docker metadata - id: meta - # You may pin to the exact commit or the version. - # uses: https://github.com/docker/metadata-action/tags - uses: docker/metadata-action@v5 - with: - images: ${{ env.DOCKER_REGISTRY_URL }}/${{ env.DOCKER_REGISTRY_ORG }}/${{ env.DOCKER_REGISTRY_IMAGE }} - # for latest tag - # latest=auto for tagging latest only for "master" branch - flavor: | - latest=true - # eg. refs/heads/master - # eg. refs/pull/318/merge - # shorthand for {{major}}.{{minor}}.{{patch}} (can include pre-release) - tags: | - type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }} - type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'master') }} - type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }} - type=ref,event=pr - type=semver,pattern=v{{version}} - type=schedule,pattern=nightly - - # GitHub Action to login against a Docker registry. - # Login against a Docker registry except on PR - # https://github.com/docker/login-action - - - name: Docker Login to registry ${{ env.DOCKER_REGISTRY_URL }} - id: login - # You may pin to the exact commit or the version. - # uses: https://github.com/docker/login-action/tags - uses: docker/login-action@v3 - with: - # Server address of Docker registry. If not set then will default to Docker Hub - registry: ${{ env.DOCKER_REGISTRY_URL }} # optional - # Username used to log against the Docker registry - username: ${{ vars.DOCKER_REGISTRY_USER }} # optional - # Password or personal access token used to log against the Docker registry - password: ${{ secrets[vars.DOCKER_REGISTRY_TOKEN_NAME] }} # optional - # Log out from the Docker registry at the end of a job - logout: true # optional, default is true - # GitHub Action to install QEMU static binaries. # https://github.com/docker/setup-qemu-action - @@ -200,30 +198,133 @@ jobs: # uses: https://github.com/docker/setup-buildx-action/tags uses: docker/setup-buildx-action@v3 - # Build and push Docker image with Buildx (don't push on PR) - # https://github.com/docker/build-push-action - - - name: Build and push Docker image - id: build_and_push - # You may pin to the exact commit or the version. - # uses: https://github.com/docker/build-push-action/tags + - name: Login to Temporary Registry (GitHub Container Registry) + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Lowercase image id name to follow the docker name rule + run: | + IMAGE_ID=ghcr.io/${{ github.repository }} + echo "GHCR_IMAGE_ID=$(echo $IMAGE_ID | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV + + - name: Build and Push to GHCR (Staging) uses: docker/build-push-action@v4 with: context: . - push: ${{ github.event_name != 'pull_request' }} - load: ${{ github.event_name == 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} - # push: true - # load: false - # tags: ${{ env.DOCKER_REGISTRY_URL }}/${{ env.DOCKER_REGISTRY_ORG }}/${{ env.DOCKER_REGISTRY_IMAGE }}:nightly - labels: ${{ steps.meta.outputs.labels }} - platforms: ${{ env.DOCKER_BUILDX_PLATFORM }} - build-args: | - APP_VERSION=${{ steps.meta.outputs.version }} + push: true + # tag i.e) ghcr.io/athenz/authorization-proxy:sha-ck29d1-amd64 + tags: ${{ env.GHCR_IMAGE_ID }}:${{ github.sha }}${{ matrix.suffix }} + platforms: ${{ matrix.platform }} + cache-from: type=gha + cache-to: type=gha,mode=max # Test Docker image - name: Test Docker image id: test_docker run: | - docker run --rm ${{ fromJSON(steps.meta.outputs.json).tags[0] }} --version + docker run --rm ${{ env.GHCR_IMAGE_ID }}:${{ github.sha }}${{ matrix.suffix }} --version + merge: + if: github.event_name != 'pull_request' # We do not need to push pr images to official registry (Docker.io) + needs: + - set_matrix + - build # Make sure each build of every platform defined in matrix is completed + runs-on: ubuntu-latest + permissions: + packages: write # Give read permission WITHOUT making the registry_visibility=Public + steps: + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Login to Docker registry + uses: docker/login-action@v3 + with: + # Server address of Docker registry. If not set then will default to Docker Hub + registry: ${{ env.DOCKER_REGISTRY_URL }} # optional + # Username used to log against the Docker registry + username: ${{ vars.DOCKER_REGISTRY_USER }} # optional + # Password or personal access token used to log against the Docker registry + password: ${{ secrets[vars.DOCKER_REGISTRY_TOKEN_NAME] }} # optional + # Log out from the Docker registry at the end of a job + logout: true # optional, default is true + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.DOCKER_REGISTRY_URL }}/${{ env.DOCKER_REGISTRY_ORG }}/${{ env.DOCKER_REGISTRY_IMAGE }} + flavor: | + latest=false + # No suffix defined as this will be the merged one! + tags: ${{ env.TAGS_CONFIG }} + - name: Set GHCR Image Name (Lowercase) + run: | + IMAGE_ID=ghcr.io/${{ github.repository }} + echo "GHCR_IMAGE_ID=$(echo $IMAGE_ID | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV + - name: Create Manifest and Push to Docker Hub + env: + PLATFORM_SUFFIXES: ${{ needs.set_matrix.outputs.suffixes }} + SHA_TAG: ${{ github.sha }} + run: | + echo "${{ steps.meta.outputs.tags }}" | while read -r docker_registry_tag; do + echo "Merging sources into final tag: $docker_registry_tag" + + sources="" + for suffix in $PLATFORM_SUFFIXES; do + # i.e) ghcr.io/athenz/authorization-proxy:sha-xxx-amd64 + sources="$sources ${{ env.GHCR_IMAGE_ID }}:${SHA_TAG}${suffix}" + done + + docker buildx imagetools create -t "$docker_registry_tag" $sources + done + cleanup: + name: Cleanup Temporary Images from GitHub Container Registry + needs: [set_matrix, build, merge] + if: always() + runs-on: ubuntu-latest + permissions: + packages: write # Permission to delete images from GitHub Container Registry + steps: + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Delete Temporary Images using GitHub API + env: + OWNER: ${{ github.repository_owner }} + PACKAGE_NAME: authorization-proxy + SHA_TAG: ${{ github.sha }} + PLATFORM_SUFFIXES: ${{ needs.set_matrix.outputs.suffixes }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + echo "๐Ÿงน Cleanup using GitHub API..." + + for suffix in $PLATFORM_SUFFIXES; do + TAG_NAME="${SHA_TAG}${suffix}" + echo "๐Ÿ” Finding version ID for tag: $TAG_NAME" + + VERSION_ID=$(gh api "/orgs/$OWNER/packages/container/$PACKAGE_NAME/versions" \ + -H "Accept: application/vnd.github+json" \ + --jq ".[] | select(.metadata.container.tags[]? == \"$TAG_NAME\") | .id") + + if [ -z "$VERSION_ID" ]; then + echo "โš ๏ธ Tag $TAG_NAME not found (already deleted?)" + continue + fi + + echo "๐Ÿ—‘๏ธ Deleting Version ID: $VERSION_ID (Tag: $TAG_NAME)" + + # Delete based on ID: + gh api -X DELETE "/orgs/$OWNER/packages/container/$PACKAGE_NAME/versions/$VERSION_ID" \ + -H "Accept: application/vnd.github+json" || true + done + + echo "โœจ Cleanup finished!" diff --git a/Dockerfile b/Dockerfile index 9d39a2c..7c17944 100644 --- a/Dockerfile +++ b/Dockerfile @@ -50,7 +50,9 @@ COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ COPY --from=builder /etc/passwd /etc/passwd # Copy our dynamic-linked executable and library COPY --from=builder /usr/bin/${APP_NAME} /go/bin/${APP_NAME} -COPY --from=builder /lib/ld-musl-x86_64.so* /lib/ + +# Copy dynamic-linked libraries for musl, like /lib/ld-musl-x86_64.so* or /lib/ld-musl-arm64.so* etc: +COPY --from=builder /lib/ld-musl-*.so* /lib/ # Copy user COPY --from=builder /etc/passwd /etc/passwd