feat(organizations): support many independent organizations per proce… #1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Docker | |
| on: | |
| push: | |
| branches: [main] | |
| tags: ["v*"] | |
| # Serialize builds of the same ref so two runs never race to push the same | |
| # image tag / manifest list into GHCR. Different refs (main vs a release tag) | |
| # push different tags, so they may still run concurrently. | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: false | |
| env: | |
| REGISTRY: ghcr.io | |
| IMAGE_NAME: ${{ github.repository }} | |
| jobs: | |
| build: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - platform: linux/amd64 | |
| runner: ubuntu-24.04 | |
| - platform: linux/arm64 | |
| runner: ubuntu-24.04-arm | |
| runs-on: ${{ matrix.runner }} | |
| timeout-minutes: 75 | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 | |
| - name: Log in to GitHub Container Registry | |
| uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Extract metadata | |
| id: meta | |
| uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
| - name: Build and push by digest | |
| id: build | |
| uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 | |
| with: | |
| context: . | |
| platforms: ${{ matrix.platform }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha,scope=${{ matrix.platform }} | |
| cache-to: type=gha,scope=${{ matrix.platform }},mode=max | |
| outputs: type=image,name=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true | |
| # Real artifact test: the published image must contain `nft` (EC2 | |
| # security-group enforcement) and the `docker` CLI (container-backed | |
| # services spawn siblings via it), or those features silently degrade even | |
| # with the right caps (the #1539 Bug-4 / bug-hunt 2026-06-18 finding 0.1 | |
| # class — "documented feature, missing binary"). Load the just-built | |
| # native-arch image locally (reusing the gha cache) and assert the | |
| # binaries are present. | |
| - name: Smoke-test image (nft + docker CLI present) | |
| run: | | |
| docker buildx build --load \ | |
| --cache-from type=gha,scope=${{ matrix.platform }} \ | |
| -t fakecloud-smoke:test . | |
| docker run --rm --entrypoint nft fakecloud-smoke:test --version | |
| docker run --rm --entrypoint docker fakecloud-smoke:test --version | |
| - name: Export digest | |
| run: | | |
| mkdir -p /tmp/digests | |
| digest="${{ steps.build.outputs.digest }}" | |
| touch "/tmp/digests/${digest#sha256:}" | |
| - name: Upload digest | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: digest-${{ matrix.runner }} | |
| path: /tmp/digests/* | |
| if-no-files-found: error | |
| retention-days: 1 | |
| merge: | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 75 | |
| needs: build | |
| permissions: | |
| contents: read | |
| packages: write | |
| id-token: write | |
| steps: | |
| - name: Download digests | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| path: /tmp/digests | |
| pattern: digest-* | |
| merge-multiple: true | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 | |
| - name: Log in to GitHub Container Registry | |
| uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Extract metadata | |
| id: meta | |
| uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
| tags: | | |
| type=ref,event=branch | |
| type=semver,pattern={{version}} | |
| type=semver,pattern={{major}}.{{minor}} | |
| type=raw,value=latest,enable={{is_default_branch}} | |
| type=sha | |
| - name: Create manifest list and push | |
| id: manifest | |
| working-directory: /tmp/digests | |
| run: | | |
| set -euo pipefail | |
| docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ | |
| $(printf '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *) | |
| DIGEST=$(docker buildx imagetools inspect \ | |
| "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}" \ | |
| --format '{{ .Manifest.Digest }}') | |
| echo "digest=$DIGEST" >> "$GITHUB_OUTPUT" | |
| - name: Inspect image | |
| run: | | |
| docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }} | |
| - name: Install cosign | |
| uses: sigstore/cosign-installer@d7d6bc7722e3daa8354c50bcb52f4837da5e9b6a # v3.8.1 | |
| with: | |
| cosign-release: v2.4.1 | |
| - name: Sign image with cosign (keyless, GitHub OIDC) | |
| env: | |
| COSIGN_EXPERIMENTAL: "1" | |
| run: | | |
| cosign sign --yes "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.manifest.outputs.digest }}" | |
| scan: | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 75 | |
| needs: merge | |
| permissions: | |
| contents: read | |
| packages: read | |
| steps: | |
| # The Trivy step reads .trivyignore from the workspace, so the repo must be | |
| # checked out here — the scan job otherwise starts from an empty workspace | |
| # (it only pulls the published image), and trivy-action fails hard with | |
| # "cannot find ignorefile '.trivyignore'". | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | |
| - name: Log in to GitHub Container Registry | |
| uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Extract metadata | |
| id: meta | |
| uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
| tags: | | |
| type=semver,pattern={{version}} | |
| type=raw,value=latest,enable={{is_default_branch}} | |
| - name: Trivy vulnerability scan | |
| uses: aquasecurity/trivy-action@a9c7b0f06e461e9d4b4d1711f154ee024b8d7ab8 # v0.36.0 | |
| with: | |
| image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }} | |
| format: table | |
| exit-code: '1' | |
| ignore-unfixed: true | |
| trivyignores: .trivyignore | |
| vuln-type: os,library | |
| severity: CRITICAL,HIGH |