From a26b7f02418599683a658beca3adbdac93f054e4 Mon Sep 17 00:00:00 2001 From: carole-lavillonniere Date: Tue, 30 Jun 2026 15:53:17 +0200 Subject: [PATCH 1/6] Add weekly auto-release workflow for the LocalStack RIE Cut a new patch release once a week when there are new commits on localstack, so Go-dep/stdlib CVE fixes self-publish without a manual tag. - weekly-release.yml: Friday cron + workflow_dispatch; discovers the latest published release, patch-bumps, skips if no new commits, then calls build.yml. - build.yml: add workflow_call with an optional version input so the same test -> build -> release path publishes the computed version (no PAT needed). --- .github/workflows/build.yml | 15 +++++- .github/workflows/weekly-release.yml | 70 ++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/weekly-release.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2f76ee6..ba60244 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,6 +6,14 @@ on: tags: v*.* pull_request: branches: [ localstack ] + # Callable by weekly-release.yml; publishes a release when `version` is set. + workflow_call: + inputs: + version: + description: "Release version to tag and publish (e.g. v0.2.1). When set, a release is published." + type: string + required: false + default: "" jobs: @@ -25,6 +33,8 @@ jobs: build: runs-on: ubuntu-latest needs: test + permissions: + contents: write steps: - uses: actions/checkout@v7 @@ -44,8 +54,9 @@ jobs: path: bin/* - name: Release binaries uses: softprops/action-gh-release@v3 - if: startsWith(github.ref, 'refs/tags/') + if: startsWith(github.ref, 'refs/tags/') || inputs.version != '' with: + tag_name: ${{ inputs.version || github.ref_name }} files: bin/* generate_release_notes: true - prerelease: ${{ endsWith(github.ref, '-pre') }} + prerelease: ${{ endsWith(github.ref, '-pre') || endsWith(inputs.version, '-pre') }} diff --git a/.github/workflows/weekly-release.yml b/.github/workflows/weekly-release.yml new file mode 100644 index 0000000..50e1988 --- /dev/null +++ b/.github/workflows/weekly-release.yml @@ -0,0 +1,70 @@ +# Weekly auto-release: patch-bumps and publishes if there are new commits on localstack. +name: Weekly Release + +on: + schedule: + # Fridays 06:00 UTC: ahead of lambda-images' Mon 13:00 UTC rebuild so Renovate can bump downstream pins first. + - cron: '0 6 * * 5' + workflow_dispatch: + inputs: + dryRun: + description: "Compute the next version but do not release." + type: boolean + default: false + +permissions: + contents: read + +jobs: + version: + runs-on: ubuntu-latest + outputs: + should_release: ${{ steps.ver.outputs.should_release }} + next: ${{ steps.ver.outputs.next }} + steps: + - uses: actions/checkout@v7 + with: + ref: localstack + fetch-depth: 0 + + - name: Determine next version + id: ver + env: + GH_TOKEN: ${{ github.token }} + run: | + git fetch --tags --force + # Latest published release (same source as downstream Renovate); sort -V for highest version, not newest. + latest=$(gh release list --exclude-pre-releases --exclude-drafts \ + --json tagName -q '.[].tagName' \ + | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -n1) + if [ -z "$latest" ]; then + echo "::error::No published vX.Y.Z release found to bump from." && exit 1 + fi + count=$(git rev-list "${latest}..HEAD" --count) + ver=${latest#v} + IFS=. read -r major minor patch <<< "$ver" + next="v${major}.${minor}.$((patch + 1))" + should_release=true + if [ "$count" = "0" ]; then + should_release=false + echo "No new commits since $latest; nothing to release." + fi + if [ "${{ inputs.dryRun }}" = "true" ]; then + should_release=false + echo "dryRun requested; not releasing." + fi + { + echo "next=$next" + echo "should_release=$should_release" + } >> "$GITHUB_OUTPUT" + echo "Latest release: $latest | new commits since: $count | next: $next | release: $should_release" + + release: + needs: version + if: needs.version.outputs.should_release == 'true' + permissions: + contents: write + # Reuse build.yml's test -> build -> release path with the computed version. + uses: ./.github/workflows/build.yml + with: + version: ${{ needs.version.outputs.next }} From 2e08a7dc29451026f6568dbd886030ff4dac9825 Mon Sep 17 00:00:00 2001 From: carole-lavillonniere Date: Mon, 10 Aug 2026 14:46:09 +0200 Subject: [PATCH 2/6] Push the release tag after tests and build --- .github/workflows/build.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ba60244..4b9de95 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -52,6 +52,12 @@ jobs: with: name: aws-lambda-rie path: bin/* + - name: Push tag + if: inputs.version != '' + run: | + git tag "${{ inputs.version }}" "$GITHUB_SHA" + git push origin "${{ inputs.version }}" + - name: Release binaries uses: softprops/action-gh-release@v3 if: startsWith(github.ref, 'refs/tags/') || inputs.version != '' From ecfc0cfedd3a143ed6d3a8774ec6b38a133b6efb Mon Sep 17 00:00:00 2001 From: carole-lavillonniere Date: Wed, 12 Aug 2026 11:59:47 +0200 Subject: [PATCH 3/6] Publish weekly releases as pre-releases pending validation --- .github/workflows/build.yml | 7 ++++++- .github/workflows/weekly-release.yml | 10 +++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4b9de95..6ecc75c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,6 +14,11 @@ on: type: string required: false default: "" + prerelease: + description: "Publish as a pre-release. Promoted to a full release once localstack-pro validates it." + type: boolean + required: false + default: false jobs: @@ -65,4 +70,4 @@ jobs: tag_name: ${{ inputs.version || github.ref_name }} files: bin/* generate_release_notes: true - prerelease: ${{ endsWith(github.ref, '-pre') || endsWith(inputs.version, '-pre') }} + prerelease: ${{ inputs.prerelease || endsWith(github.ref, '-pre') || endsWith(inputs.version, '-pre') }} diff --git a/.github/workflows/weekly-release.yml b/.github/workflows/weekly-release.yml index 50e1988..f96567f 100644 --- a/.github/workflows/weekly-release.yml +++ b/.github/workflows/weekly-release.yml @@ -33,8 +33,10 @@ jobs: GH_TOKEN: ${{ github.token }} run: | git fetch --tags --force - # Latest published release (same source as downstream Renovate); sort -V for highest version, not newest. - latest=$(gh release list --exclude-pre-releases --exclude-drafts \ + # Highest released version, including pre-releases still awaiting promotion, so a pending + # promotion cannot make us recompute a version whose tag already exists. The grep keeps + # RC tags (v0.0.0-rc.*) out; sort -V picks the highest version, not the newest. + latest=$(gh release list --exclude-drafts \ --json tagName -q '.[].tagName' \ | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -n1) if [ -z "$latest" ]; then @@ -64,7 +66,9 @@ jobs: if: needs.version.outputs.should_release == 'true' permissions: contents: write - # Reuse build.yml's test -> build -> release path with the computed version. + # Reuse build.yml's test -> build -> release path with the computed version. Published as a + # pre-release; localstack-pro promotes it to a full release once its CI validates the version. uses: ./.github/workflows/build.yml with: version: ${{ needs.version.outputs.next }} + prerelease: true From 104b0ce50a4e9d5d6a0591133cab9c12b23b2d8a Mon Sep 17 00:00:00 2001 From: carole-lavillonniere Date: Wed, 12 Aug 2026 12:06:43 +0200 Subject: [PATCH 4/6] Correct stale scheduling rationale in weekly-release comment --- .github/workflows/weekly-release.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/weekly-release.yml b/.github/workflows/weekly-release.yml index f96567f..7078a73 100644 --- a/.github/workflows/weekly-release.yml +++ b/.github/workflows/weekly-release.yml @@ -3,7 +3,8 @@ name: Weekly Release on: schedule: - # Fridays 06:00 UTC: ahead of lambda-images' Mon 13:00 UTC rebuild so Renovate can bump downstream pins first. + # Fridays 06:00 UTC. The release is a pre-release until localstack-pro validates and promotes it, + # which is what gates the downstream lambda-images bump. - cron: '0 6 * * 5' workflow_dispatch: inputs: From 0f5e8786ec2c8423cfdf09f7fa688b72491543b5 Mon Sep 17 00:00:00 2001 From: carole-lavillonniere Date: Wed, 12 Aug 2026 15:41:19 +0200 Subject: [PATCH 5/6] Alert the team on Slack when the weekly release fails --- .github/workflows/weekly-release.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/.github/workflows/weekly-release.yml b/.github/workflows/weekly-release.yml index 7078a73..6102e49 100644 --- a/.github/workflows/weekly-release.yml +++ b/.github/workflows/weekly-release.yml @@ -73,3 +73,25 @@ jobs: with: version: ${{ needs.version.outputs.next }} prerelease: true + + notify: + name: Report a broken weekly release + if: always() && (needs.version.result == 'failure' || needs.release.result == 'failure') + runs-on: ubuntu-latest + needs: + - version + - release + steps: + - name: "Send Message" + uses: slackapi/slack-github-action@dcb1066f776dd043e64d0e8ba94ca15cc7e1875d # v4.0.0 + env: + MESSAGE: "_*Weekly RIE release failed*_ :turtle-headache::broken_heart:\n\nNo new pre-release was published, so CVE remediation is stalled until this is fixed. Investigate the failed workflow run <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|here> :mag_right:" + with: + webhook: ${{ secrets.COSY_WEBHOOK_URL }} + webhook-type: incoming-webhook + payload: | + blocks: + - type: "section" + text: + type: "mrkdwn" + text: "${{ env.MESSAGE }}" From 74e6fb54037cc6953f339aa41fa0cbf445c3dd65 Mon Sep 17 00:00:00 2001 From: carole-lavillonniere Date: Wed, 12 Aug 2026 16:26:08 +0200 Subject: [PATCH 6/6] Document the weekly auto-release and promotion flow --- README-LOCALSTACK.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/README-LOCALSTACK.md b/README-LOCALSTACK.md index 03e893d..6efa417 100644 --- a/README-LOCALSTACK.md +++ b/README-LOCALSTACK.md @@ -69,6 +69,25 @@ previous release (e.g. [`v0.1.47`](https://github.com/localstack/lambda-runtime- > LocalStack releases — it is a manual `workflow_dispatch` that checks out `main` (the upstream > mirror) rather than `localstack`, so it would not include the LocalStack customizations. +### Weekly auto-release + +[`weekly-release.yml`](./.github/workflows/weekly-release.yml) runs every Friday at 06:00 UTC. If +`localstack` has new commits since the highest existing release, it patch-bumps the version and calls +`build.yml` to run the tests, build the binaries, push the tag, and publish the release. Together with +Renovate automerge, this is what carries dependency and CVE fixes downstream without manual work. + +The release is published as a **pre-release**, and only reaches consumers once it has been validated: + +1. `weekly-release.yml` publishes `vX.Y.Z`, marked as a pre-release. +2. localstack-pro opens a PR bumping `LAMBDA_RUNTIME_DEFAULT_VERSION` to that version; its CI is the + quality gate. +3. On merge, localstack-pro flips the same release to a full release through the GitHub API — no new + tag and no rebuild, so the binaries that were validated are the binaries that ship. +4. lambda-images ignores pre-releases, so Renovate only opens a bump PR there after the promotion. + +Run it manually via the **Weekly Release** workflow (`workflow_dispatch`); `dryRun` reports the next +version without releasing. A failed run posts to Slack. + ### RC (release candidate) pre-release RC pre-releases let an **unmerged** PR be tested against localstack-pro CI without cutting a real