|
| 1 | +# Continuous build of the Thai-government overlay image |
| 2 | +# (agent-sandbox-thailand): the default image plus the Thailand-only skills in |
| 3 | +# skills-thailand/ (Dockerfile.thailand overlays them onto an ARG-templated |
| 4 | +# base). Like build.yml this has NO tag trigger — semver releases of the Thai |
| 5 | +# image are handled by release.yml. |
| 6 | +# |
| 7 | +# Three entry points, one job: |
| 8 | +# - workflow_run : after "Build and Push" rebuilt the base on this commit, |
| 9 | +# overlay that exact base (sha-<short>) and mirror its tags. |
| 10 | +# - push : Thai skills changed but the base did not — overlay the |
| 11 | +# current published base (`latest`). A guard skips this when |
| 12 | +# base-image paths also changed (the workflow_run path will |
| 13 | +# rebuild off the fresh base instead, avoiding a duplicate |
| 14 | +# build that would otherwise overlay a stale `latest`). |
| 15 | +# - workflow_dispatch : overlay an explicitly chosen base tag, tagging the |
| 16 | +# result with the dispatch branch's moving tag. Run it from a |
| 17 | +# branch, NEVER a tag — semver Thai images come from |
| 18 | +# release.yml (a tag-ref dispatch is rejected in resolve). |
1 | 19 | name: Build and Push (Thailand) |
2 | 20 |
|
3 | | -# Builds the Thai-government sandbox image: the default agent-sandbox plus the |
4 | | -# Thailand-only skills (Dockerfile.thailand overlays `skills-thailand/`). It runs |
5 | | -# AFTER the default "Build and Push" workflow succeeds so the base image it |
6 | | -# overlays already exists, and pins the base to that same commit's `sha-` tag. |
7 | | -# This keeps the Thai skill out of the default image while shipping it in a |
8 | | -# separate, optional image. |
9 | | - |
10 | 21 | on: |
11 | 22 | workflow_run: |
12 | 23 | workflows: ["Build and Push"] |
13 | 24 | types: [completed] |
| 25 | + # No `branches:` filter — gate on conclusion (and, implicitly, on the base |
| 26 | + # having actually built) inside the job. workflow_run.head_branch is |
| 27 | + # unreliable, so we don't filter on it. |
| 28 | + push: |
14 | 29 | branches: [main] |
| 30 | + paths: |
| 31 | + - 'skills-thailand/**' |
| 32 | + - 'Dockerfile.thailand' |
| 33 | + - '.github/workflows/build-thailand.yml' |
15 | 34 | workflow_dispatch: |
16 | 35 | inputs: |
17 | 36 | base_tag: |
18 | | - description: "Default agent-sandbox tag to overlay (e.g. latest, 0.3.0, sha-abc1234)" |
| 37 | + description: "agent-sandbox base tag to overlay (e.g. latest, sha-abc1234). Run from a branch; semver images come from release.yml." |
19 | 38 | default: latest |
20 | 39 |
|
| 40 | +concurrency: |
| 41 | + group: ${{ github.workflow }}-${{ github.event.workflow_run.head_sha || github.ref }} |
| 42 | + cancel-in-progress: true |
| 43 | + |
21 | 44 | env: |
22 | 45 | REGISTRY: ghcr.io |
23 | | - # Separate image name: <owner>/agent-sandbox-thailand. |
24 | | - IMAGE_NAME: ${{ github.repository }}-thailand |
25 | | - BASE_IMAGE_NAME: eternisai/agent-sandbox |
26 | 46 |
|
27 | 47 | jobs: |
28 | 48 | build: |
29 | | - # workflow_run: only proceed if the base build succeeded. workflow_dispatch |
30 | | - # always proceeds. |
31 | | - if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }} |
| 49 | + # workflow_run: only proceed if the base build succeeded. push/dispatch: |
| 50 | + # always enter; the resolve step decides whether to actually build. |
| 51 | + if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }} |
32 | 52 | runs-on: ubuntu-latest |
33 | 53 | permissions: |
34 | 54 | contents: read |
35 | 55 | packages: write |
36 | 56 |
|
37 | 57 | steps: |
38 | | - - uses: actions/checkout@v4 |
| 58 | + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 |
39 | 59 | with: |
40 | | - # Build from the same commit the base image was built from. |
| 60 | + # Build from the same commit the base image was built from on the |
| 61 | + # workflow_run path; otherwise the pushed / dispatched ref. |
41 | 62 | ref: ${{ github.event.workflow_run.head_sha || github.ref }} |
42 | 63 |
|
43 | | - - uses: docker/setup-buildx-action@v3 |
44 | | - |
45 | | - - uses: docker/login-action@v3 |
| 64 | + # push only: did base-image paths also change in this push? If so, defer |
| 65 | + # to the chained workflow_run (which overlays the freshly built base). |
| 66 | + - name: Detect base-relevant changes |
| 67 | + if: ${{ github.event_name == 'push' }} |
| 68 | + id: basepaths |
| 69 | + uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1 |
46 | 70 | with: |
47 | | - registry: ${{ env.REGISTRY }} |
48 | | - username: ${{ github.actor }} |
49 | | - password: ${{ secrets.GITHUB_TOKEN }} |
| 71 | + filters: | |
| 72 | + base: |
| 73 | + - 'Dockerfile' |
| 74 | + - 'skills/**' |
| 75 | + - 'plugins/**' |
| 76 | + - 'agent/**' |
| 77 | + - 'entrypoint.sh' |
50 | 78 |
|
51 | | - - name: Resolve base image tag |
52 | | - id: base |
| 79 | + - name: Resolve build parameters |
| 80 | + id: resolve |
| 81 | + env: |
| 82 | + EVENT: ${{ github.event_name }} |
| 83 | + WR_HEAD_SHA: ${{ github.event.workflow_run.head_sha }} |
| 84 | + WR_HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }} |
| 85 | + BASE_PATHS_CHANGED: ${{ steps.basepaths.outputs.base }} |
| 86 | + INPUT_BASE_TAG: ${{ inputs.base_tag }} |
53 | 87 | run: | |
54 | | - if [ "${{ github.event_name }}" = "workflow_run" ]; then |
55 | | - short="$(git rev-parse --short=7 '${{ github.event.workflow_run.head_sha }}')" |
56 | | - echo "ref=sha-${short}" >> "$GITHUB_OUTPUT" |
57 | | - else |
58 | | - echo "ref=${{ inputs.base_tag }}" >> "$GITHUB_OUTPUT" |
59 | | - fi |
| 88 | + set -euo pipefail |
| 89 | + image="${REGISTRY}/$(echo "${GITHUB_REPOSITORY}" | tr '[:upper:]' '[:lower:]')" |
| 90 | + thai="${image}-thailand" |
| 91 | + proceed=true |
| 92 | + slugify() { echo "$1" | tr '[:upper:]' '[:lower:]' | sed -E 's#[^a-z0-9._-]+#-#g; s#^[._-]+##; s#[._-]+$##' | cut -c1-128; } |
| 93 | + case "${EVENT}" in |
| 94 | + workflow_run) |
| 95 | + short="$(echo "${WR_HEAD_SHA}" | cut -c1-7)" |
| 96 | + base_ref="${image}:sha-${short}" |
| 97 | + if [ "${WR_HEAD_BRANCH}" = "main" ]; then moving="latest"; else moving="$(slugify "${WR_HEAD_BRANCH}")"; fi |
| 98 | + ;; |
| 99 | + push) |
| 100 | + # Only build if base paths did NOT change (else defer to workflow_run). |
| 101 | + if [ "${BASE_PATHS_CHANGED}" = "true" ]; then proceed=false; fi |
| 102 | + short="${GITHUB_SHA::7}" |
| 103 | + base_ref="${image}:latest" |
| 104 | + moving="latest" |
| 105 | + ;; |
| 106 | + workflow_dispatch) |
| 107 | + # Dispatch is for branch overlays only. On a tag ref the output |
| 108 | + # would be a v-prefixed slug (e.g. v0.3.0) overlaying the wrong |
| 109 | + # base and bypassing release.yml's promote — reject it. |
| 110 | + if [ "${GITHUB_REF_TYPE}" = "tag" ]; then |
| 111 | + echo "::error::Do not dispatch this workflow for a tag (${GITHUB_REF_NAME}). Semver Thai images are produced by release.yml when you push a vX.Y.Z git tag (it promotes agent-sandbox-thailand:sha-<short> -> <ver>). Re-run this dispatch from a branch." |
| 112 | + exit 1 |
| 113 | + fi |
| 114 | + short="${GITHUB_SHA::7}" |
| 115 | + base_ref="${image}:${INPUT_BASE_TAG}" |
| 116 | + if [ "${GITHUB_REF_NAME}" = "main" ]; then moving="latest"; else moving="$(slugify "${GITHUB_REF_NAME}")"; fi |
| 117 | + ;; |
| 118 | + esac |
| 119 | + { |
| 120 | + echo "proceed=${proceed}" |
| 121 | + echo "thai=${thai}" |
| 122 | + echo "base_ref=${base_ref}" |
| 123 | + echo "short=${short}" |
| 124 | + echo "moving=${moving}" |
| 125 | + } >> "$GITHUB_OUTPUT" |
| 126 | +
|
| 127 | + - uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 |
| 128 | + if: ${{ steps.resolve.outputs.proceed == 'true' }} |
60 | 129 |
|
61 | | - - uses: docker/metadata-action@v5 |
62 | | - id: meta |
| 130 | + - uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 |
| 131 | + if: ${{ steps.resolve.outputs.proceed == 'true' }} |
63 | 132 | with: |
64 | | - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} |
65 | | - tags: | |
66 | | - type=raw,value=latest,enable={{is_default_branch}} |
67 | | - type=sha |
| 133 | + registry: ${{ env.REGISTRY }} |
| 134 | + username: ${{ github.actor }} |
| 135 | + password: ${{ secrets.GITHUB_TOKEN }} |
68 | 136 |
|
69 | | - - uses: docker/build-push-action@v5 |
| 137 | + - name: Build and push (overlay) |
| 138 | + if: ${{ steps.resolve.outputs.proceed == 'true' }} |
| 139 | + uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 |
70 | 140 | with: |
71 | 141 | context: . |
72 | 142 | file: Dockerfile.thailand |
73 | | - push: true |
74 | | - tags: ${{ steps.meta.outputs.tags }} |
75 | | - labels: ${{ steps.meta.outputs.labels }} |
76 | 143 | platforms: linux/amd64 |
| 144 | + push: true |
77 | 145 | build-args: | |
78 | | - BASE_IMAGE=${{ env.REGISTRY }}/${{ env.BASE_IMAGE_NAME }}:${{ steps.base.outputs.ref }} |
| 146 | + BASE_IMAGE=${{ steps.resolve.outputs.base_ref }} |
| 147 | + tags: | |
| 148 | + ${{ steps.resolve.outputs.thai }}:sha-${{ steps.resolve.outputs.short }} |
| 149 | + ${{ steps.resolve.outputs.thai }}:${{ steps.resolve.outputs.moving }} |
| 150 | + provenance: false |
| 151 | + sbom: false |
79 | 152 | cache-from: type=gha |
80 | 153 | cache-to: type=gha,mode=max |
0 commit comments