diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f8204865b80..6abe70d0e0b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,6 +20,7 @@ permissions: pull-requests: write # needed by lint (PR comment) + supply-chain (PR comment) actions: read # needed by osv-scanner (SARIF upload) security-events: write # needed by osv-scanner (SARIF upload) + packages: write # needed by docker build concurrency: group: ci-${{ github.ref }} @@ -94,6 +95,11 @@ jobs: if: needs.detect.outputs.docker_meta == 'true' uses: ./.github/workflows/docker-lint.yml + docker: + needs: detect + if: needs.detect.outputs.python == 'true' || needs.detect.outputs.frontend == 'true' || needs.detect.outputs.docker_meta == 'true' + uses: ./.github/workflows/docker-publish.yml + supply-chain: needs: detect if: needs.detect.outputs.event_name == 'pull_request' && (needs.detect.outputs.scan == 'true' || needs.detect.outputs.deps == 'true' || needs.detect.outputs.mcp_catalog == 'true') @@ -128,6 +134,8 @@ jobs: - docker-lint - supply-chain - osv-scanner + # we don't require docker to pass rn because it's so slow lol + # - docker if: always() runs-on: ubuntu-latest steps: diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index bf0d1b632c8..83d6eac261c 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -1,24 +1,9 @@ -name: Docker Build and Publish +name: Docker Build, Test, and Publish on: - push: - branches: [main] - paths: - - '**/*.py' - - 'pyproject.toml' - - 'uv.lock' - - 'Dockerfile' - - 'docker/**' - - '.github/workflows/docker-publish.yml' - - '.github/actions/hermes-smoke-test/**' - - # No paths filter — the job must always run so the required check - # reports a status (path-gated workflows leave checks "pending" forever - # when no matching files change, which blocks merge). - pull_request: - release: types: [published] + workflow_call: permissions: contents: read @@ -53,24 +38,19 @@ jobs: digest: ${{ steps.push.outputs.digest }} steps: - name: Checkout code - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - # The image build + smoke test + integration tests run ONLY on - # push-to-main and release — never on PRs. They are the heaviest jobs - # in CI (~15-45 min) and a broken build surfaces on the main push (and - # is gated pre-merge by docker-lint + uv-lockfile-check). Every step - # below is skipped on PRs, so the job still reports green and the - # required check never hangs. + # The image build + smoke test + integration tests run on every event + # (PRs, push-to-main, release). Publish steps below are gated to + # push-to-main / release only. - name: Set up Docker Buildx - if: github.event_name != 'pull_request' - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 # Build once, load into the local daemon for smoke testing. Cached # to gha with a per-arch scope; the push step below reuses every # layer from this build. - name: Build image (amd64, smoke test) - if: github.event_name != 'pull_request' - uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 with: context: . file: Dockerfile @@ -83,7 +63,6 @@ jobs: cache-to: type=gha,mode=max,scope=docker-amd64 - name: Smoke test image - if: github.event_name != 'pull_request' uses: ./.github/actions/hermes-smoke-test with: image: ${{ env.IMAGE_NAME }}:test @@ -110,15 +89,12 @@ jobs: # cheapest path to coverage on every PR that touches docker code. # --------------------------------------------------------------------- - name: Install uv (for docker tests) - if: github.event_name != 'pull_request' - uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5 + uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5 - name: Set up Python 3.11 (for docker tests) - if: github.event_name != 'pull_request' run: uv python install 3.11 - name: Install Python dependencies (for docker tests) - if: github.event_name != 'pull_request' run: | # ``dev`` extra pulls in pytest, pytest-asyncio — # everything tests/docker/ needs. We deliberately avoid ``all`` @@ -127,7 +103,6 @@ jobs: uv sync --locked --python 3.11 --extra dev - name: Run docker integration tests - if: github.event_name != 'pull_request' env: # Skip rebuild; use the image already loaded by the build step. HERMES_TEST_IMAGE: ${{ env.IMAGE_NAME }}:test @@ -142,7 +117,7 @@ jobs: - name: Log in to Docker Hub if: github.event_name == 'push' && github.ref == 'refs/heads/main' || github.event_name == 'release' - uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 + uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} @@ -153,7 +128,7 @@ jobs: - name: Push amd64 by digest id: push if: github.event_name == 'push' && github.ref == 'refs/heads/main' || github.event_name == 'release' - uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 with: context: . file: Dockerfile @@ -177,7 +152,7 @@ jobs: - name: Upload digest artifact if: github.event_name == 'push' && github.ref == 'refs/heads/main' || github.event_name == 'release' - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: digest-amd64 path: /tmp/digests/* @@ -198,12 +173,10 @@ jobs: digest: ${{ steps.push.outputs.digest }} steps: - name: Checkout code - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - # arm64 build runs only on push-to-main and release (see build-amd64). - name: Set up Docker Buildx - if: github.event_name != 'pull_request' - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 # Log in to ghcr.io so the registry-backed build cache below can be # read (cache-from) on every event and written (cache-to) on @@ -213,8 +186,7 @@ jobs: # crashed the build before the smoke test (the reason the gha cache # was removed from arm64 PRs in the first place). - name: Log in to ghcr.io (build cache) - if: github.event_name != 'pull_request' - uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 + uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 with: registry: ghcr.io username: ${{ github.actor }} @@ -229,8 +201,7 @@ jobs: # GITHUB_TOKEN, not a short-lived SAS token, so the cold-build-outlives- # token failure mode cannot recur. - name: Build image (arm64, smoke test, cached publish) - if: github.event_name != 'pull_request' - uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 with: context: . file: Dockerfile @@ -243,14 +214,13 @@ jobs: cache-to: type=registry,ref=ghcr.io/nousresearch/hermes-agent:buildcache-arm64,mode=max - name: Smoke test image - if: github.event_name != 'pull_request' uses: ./.github/actions/hermes-smoke-test with: image: ${{ env.IMAGE_NAME }}:test - name: Log in to Docker Hub if: github.event_name == 'push' && github.ref == 'refs/heads/main' || github.event_name == 'release' - uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 + uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} @@ -258,7 +228,7 @@ jobs: - name: Push arm64 by digest id: push if: github.event_name == 'push' && github.ref == 'refs/heads/main' || github.event_name == 'release' - uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 with: context: . file: Dockerfile @@ -280,7 +250,7 @@ jobs: - name: Upload digest artifact if: github.event_name == 'push' && github.ref == 'refs/heads/main' || github.event_name == 'release' - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: digest-arm64 path: /tmp/digests/* @@ -302,17 +272,17 @@ jobs: timeout-minutes: 10 steps: - name: Download digests - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: path: /tmp/digests pattern: digest-* merge-multiple: true - name: Set up Docker Buildx - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 - name: Log in to Docker Hub - uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 + uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }}