You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ru...@apache.org on 2026/06/26 00:15:38 UTC
(superset) branch master updated: ci: schedule a weekly Docker image rebuild against the latest release (#40426)
This is an automated email from the ASF dual-hosted git repository.
rusackas pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git
The following commit(s) were added to refs/heads/master by this push:
new 7410ff73c0a ci: schedule a weekly Docker image rebuild against the latest release (#40426)
7410ff73c0a is described below
commit 7410ff73c0aa169b433862a104fde397a1f150be
Author: Evan Rusackas <ev...@preset.io>
AuthorDate: Thu Jun 25 17:15:31 2026 -0700
ci: schedule a weekly Docker image rebuild against the latest release (#40426)
Co-authored-by: Claude Code <no...@anthropic.com>
---
.../workflows/scheduled-docker-image-refresh.yml | 177 +++++++++++++++++++++
.github/workflows/tag-release.yml | 6 +
2 files changed, 183 insertions(+)
diff --git a/.github/workflows/scheduled-docker-image-refresh.yml b/.github/workflows/scheduled-docker-image-refresh.yml
new file mode 100644
index 00000000000..3ac26561767
--- /dev/null
+++ b/.github/workflows/scheduled-docker-image-refresh.yml
@@ -0,0 +1,177 @@
+name: Scheduled Docker image refresh
+
+# Re-runs the Docker image build against the latest published release on a
+# weekly cadence. The code being built doesn't change — but the base image
+# layers (python:*-slim-trixie and its OS packages) DO get upstream
+# security patches between Superset releases, and those patches don't
+# reach our published images unless we rebuild.
+#
+# Without this workflow, `apache/superset:<latest>` lags behind upstream
+# Debian/Python base patches by whatever interval falls between Superset
+# releases (typically 3–6 weeks). With it, the lag drops to at most one
+# week regardless of release cadence.
+#
+# This is a security-hygiene cron, not a release. It overwrites the
+# existing tags for the most recent release (e.g. `apache/superset:5.0.0`
+# and `apache/superset:latest`) with bit-for-bit-equivalent contents
+# layered on a refreshed base. Image digests change; everything users
+# actually pin against (image content, code, deps) does not.
+
+on:
+ schedule:
+ # Mondays at 06:00 UTC — gives the weekend for upstream patches to
+ # settle and surfaces failures at the start of the work week so a
+ # human can react.
+ - cron: "0 6 * * 1"
+
+ # Manual trigger so operators can force a refresh on demand (e.g.
+ # immediately after a high-severity base-image CVE drops).
+ workflow_dispatch: {}
+
+permissions:
+ contents: read
+
+# Serialize with itself and with the release publisher (tag-release.yml) —
+# both push to the same Docker Hub tags, so a race could end with stale
+# layers winning. Both workflows must declare this group for the lock to work.
+concurrency:
+ group: docker-publish-latest-release
+ cancel-in-progress: false
+
+jobs:
+ config:
+ runs-on: ubuntu-24.04
+ outputs:
+ has-secrets: ${{ steps.check.outputs.has-secrets }}
+ latest-release: ${{ steps.latest.outputs.tag }}
+ force-latest: ${{ steps.latest.outputs.force-latest }}
+ steps:
+ - name: Check for Docker Hub secrets
+ id: check
+ shell: bash
+ run: |
+ if [ -n "${DOCKERHUB_USER}" ]; then
+ echo "has-secrets=1" >> "$GITHUB_OUTPUT"
+ fi
+ env:
+ DOCKERHUB_USER: ${{ (secrets.DOCKERHUB_USER != '' && secrets.DOCKERHUB_TOKEN != '') || '' }}
+
+ - name: Look up latest published release
+ id: latest
+ shell: bash
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ REPOSITORY: ${{ github.repository }}
+ run: |
+ # `releases/latest` returns the latest non-prerelease, non-draft
+ # release — which is exactly what `apache/superset:latest`
+ # should reflect.
+ TAG=$(gh api "repos/${REPOSITORY}/releases/latest" --jq .tag_name)
+ if [ -z "$TAG" ] || [ "$TAG" = "null" ]; then
+ echo "::error::Could not determine latest release tag"
+ exit 1
+ fi
+ echo "Latest release: $TAG"
+ echo "tag=$TAG" >> "$GITHUB_OUTPUT"
+
+ # Only move `:latest` when the release flagged "latest" is also the
+ # highest semver release. This guards against a mis-click leaving an
+ # older maintenance release (e.g. a 5.x patch shipped after 6.0 GA)
+ # marked latest, which would otherwise roll `:latest` back a major
+ # version on the next cron run. If it isn't the newest, we still
+ # refresh that release's own version tag but leave `:latest` alone.
+ HIGHEST=$(gh api --paginate "repos/${REPOSITORY}/releases" \
+ --jq '.[] | select(.draft|not) | select(.prerelease|not) | .tag_name' \
+ | sed 's/^v//' | sort -V | tail -n1)
+ if [ "${TAG#v}" = "$HIGHEST" ]; then
+ echo "force-latest=1" >> "$GITHUB_OUTPUT"
+ else
+ echo "::warning::Latest-flagged release $TAG is not the highest semver ($HIGHEST); refreshing its version tag but leaving :latest untouched"
+ fi
+
+ docker-rebuild:
+ needs: config
+ if: needs.config.outputs.has-secrets == '1'
+ name: docker-rebuild
+ runs-on: ubuntu-24.04
+ strategy:
+ # Mirror the same matrix the release publisher uses so every variant
+ # operators consume from Docker Hub gets the refreshed base.
+ matrix:
+ build_preset: ["dev", "lean", "py310", "websocket", "dockerize", "py311", "py312"]
+ fail-fast: false
+ steps:
+ - name: "Checkout release tag: ${{ needs.config.outputs.latest-release }}"
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with:
+ ref: ${{ needs.config.outputs.latest-release }}
+ fetch-depth: 0
+ persist-credentials: false
+
+ - name: Setup Docker Environment
+ uses: ./.github/actions/setup-docker
+ with:
+ dockerhub-user: ${{ secrets.DOCKERHUB_USER }}
+ dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }}
+ install-docker-compose: "false"
+ build: "true"
+
+ - name: Use Node.js 20
+ uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
+ with:
+ node-version: 20
+
+ - name: Setup supersetbot
+ uses: ./.github/actions/setup-supersetbot/
+
+ - name: Rebuild and push
+ env:
+ DOCKERHUB_USER: ${{ secrets.DOCKERHUB_USER }}
+ DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ BUILD_PRESET: ${{ matrix.build_preset }}
+ LATEST_RELEASE: ${{ needs.config.outputs.latest-release }}
+ FORCE_LATEST_FLAG: ${{ needs.config.outputs.force-latest == '1' && '--force-latest' || '' }}
+ run: |
+ # Reuses the same supersetbot invocation as the release
+ # publisher (`tag-release.yml`), so the resulting tags are
+ # identical to what a manual release dispatch would produce —
+ # just with a freshly-pulled base image layer underneath.
+ # `--force-latest` is only passed when the config job confirmed the
+ # fetched release is the newest one (see FORCE_LATEST_FLAG above).
+ supersetbot docker \
+ --push \
+ --preset "$BUILD_PRESET" \
+ --context release \
+ --context-ref "$LATEST_RELEASE" \
+ $FORCE_LATEST_FLAG \
+ --platform "linux/arm64" \
+ --platform "linux/amd64"
+
+ # The whole point of this cron is catching base-image CVEs, so a silent
+ # failure is the expensive case — a red X in the Actions tab nobody is
+ # watching on a Monday. File a tracked issue when any rebuild leg fails so
+ # a missed security refresh surfaces instead of sitting unnoticed.
+ notify-on-failure:
+ needs: [config, docker-rebuild]
+ if: failure() && needs.config.outputs.has-secrets == '1'
+ runs-on: ubuntu-24.04
+ permissions:
+ contents: read
+ issues: write
+ steps:
+ - name: Open a tracking issue
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ REPOSITORY: ${{ github.repository }}
+ LATEST_RELEASE: ${{ needs.config.outputs.latest-release }}
+ RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
+ run: |
+ gh issue create \
+ --repo "$REPOSITORY" \
+ --title "Scheduled Docker image refresh failed for ${LATEST_RELEASE}" \
+ --label "infra:container" \
+ --label "bug" \
+ --body "The weekly Docker base-image refresh failed for release \`${LATEST_RELEASE}\`. Published images may be missing upstream base-layer security patches until this is resolved.
+
+ Failed run: ${RUN_URL}"
diff --git a/.github/workflows/tag-release.yml b/.github/workflows/tag-release.yml
index 20c2213b01f..7488c555568 100644
--- a/.github/workflows/tag-release.yml
+++ b/.github/workflows/tag-release.yml
@@ -24,6 +24,12 @@ on:
permissions:
contents: read
+# Serialize with the scheduled Docker image refresh — both workflows push
+# to the same Docker Hub tags and must not race on apache/superset:latest.
+concurrency:
+ group: docker-publish-latest-release
+ cancel-in-progress: false
+
jobs:
config:
runs-on: ubuntu-24.04