From bd69791ccee7eb9d0aa10bf69f54a56f60fb7953 Mon Sep 17 00:00:00 2001 From: ShutenOishi Date: Sun, 11 Oct 2026 21:05:30 +0900 Subject: [PATCH 1/6] security: retire legacy release-branch automatic formal publisher --- .github/workflows/windows.yml | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 1aa0bd4..c6692a9 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -5,7 +5,6 @@ on: push: branches: - main - - "release/**" workflow_dispatch: concurrency: @@ -15,9 +14,10 @@ concurrency: permissions: contents: read +# No release/* publisher. A new manual-only verified promotion gate must be +# separately implemented and accepted before formal Release publication. jobs: windows: - if: ${{ !startsWith(github.ref, 'refs/heads/release/') }} permissions: contents: read uses: pgextwin/build/.github/workflows/build-extension.yml@21c99b933da98f397f739971e738ecb685fe55d2 @@ -26,28 +26,6 @@ jobs: test_contract_path: config/test-contract.json # OIDC and attestation write scopes exist only on the release build path. - release_build: - if: ${{ startsWith(github.ref, 'refs/heads/release/') }} - permissions: - contents: read - id-token: write - attestations: write - artifact-metadata: write - uses: pgextwin/build/.github/workflows/build-extension-attested.yml@8246f4d3415a48b1ad4af13f421277057886b58f - with: - extension_config_path: config/extension.json - test_contract_path: config/test-contract.json - - release: - if: ${{ startsWith(github.ref, 'refs/heads/release/') }} - needs: release_build - permissions: - contents: write - uses: pgextwin/build/.github/workflows/release-extension.yml@8246f4d3415a48b1ad4af13f421277057886b58f - with: - extension_name: ${{ needs.release_build.outputs.extension_name }} - upstream_repository: ${{ needs.release_build.outputs.upstream_repository }} - candidate_report: name: Verify candidate matrix and evidence if: ${{ always() && github.event_name == 'workflow_dispatch' && startsWith(github.ref, 'refs/heads/auto-candidate/') }} From ae08458734217f611fe3ce90e4eed17d36cdefaa Mon Sep 17 00:00:00 2001 From: ShutenOishi Date: Sun, 11 Oct 2026 21:48:24 +0900 Subject: [PATCH 2/6] policy: require explicit human PUBLISH under central promotion allowlist --- config/release-promotion.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 config/release-promotion.json diff --git a/config/release-promotion.json b/config/release-promotion.json new file mode 100644 index 0000000..ed8f1cb --- /dev/null +++ b/config/release-promotion.json @@ -0,0 +1,5 @@ +{ + "schemaVersion": 1, + "enabled": true, + "releasePolicy": "manual-dispatch" +} From 8b0a1022a9601536c2e545c3d8f06d5441a1bfdb Mon Sep 17 00:00:00 2001 From: ShutenOishi Date: Sun, 11 Oct 2026 21:50:16 +0900 Subject: [PATCH 3/6] ci(release): introduce central-allowlisted human-only attested Release Promotion --- .github/workflows/promote.yml | 142 ++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 .github/workflows/promote.yml diff --git a/.github/workflows/promote.yml b/.github/workflows/promote.yml new file mode 100644 index 0000000..d6e4957 --- /dev/null +++ b/.github/workflows/promote.yml @@ -0,0 +1,142 @@ +name: Promote verified upstream candidate to attested Release (manual only) + +on: + workflow_dispatch: + inputs: + candidate_pr: + description: Merged automation-owned immutable manifest-only candidate PR number + required: true + type: string + candidate_run_id: + description: Successful exact-head Windows candidate dispatch run ID + required: true + type: string + decision_run_id: + description: Completed upstream watch run holding candidate-decision artifact + required: true + type: string + release_tag: + description: New and NEVER-used Windows Release tag + required: true + type: string + confirm_release: + description: Type PUBLISH to explicitly authorize this formal Release + required: true + type: string + +concurrency: + group: pg_cron-human-release-promotion + cancel-in-progress: false + +permissions: + contents: read + +jobs: + authorize: + name: Verify central and local manual operator policy, SHA-pinned candidate and exact PG matrix + if: github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + permissions: + contents: read + actions: read + pull-requests: read + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + persist-credentials: false + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: pgextwin/build + ref: 455f0ccc667697f600700a6e64bcfd6c57b6a977 + path: .pgextwin-build + persist-credentials: false + - name: Require explicit operator PUBLISH and independently VERIFIED candidate + env: + GH_TOKEN: ${{ github.token }} + CANDIDATE_PR: ${{ inputs.candidate_pr }} + CANDIDATE_RUN: ${{ inputs.candidate_run_id }} + DECISION_RUN: ${{ inputs.decision_run_id }} + RELEASE_TAG: ${{ inputs.release_tag }} + CONFIRM_RELEASE: ${{ inputs.confirm_release }} + run: | + python .pgextwin-build/scripts/fleet-promotion-gate.py \ + --candidate-pr "$CANDIDATE_PR" \ + --candidate-run-id "$CANDIDATE_RUN" \ + --decision-run-id "$DECISION_RUN" \ + --release-tag "$RELEASE_TAG" \ + --confirm-release "$CONFIRM_RELEASE" \ + --extension config/extension.json \ + --local-policy config/release-promotion.json \ + --lifecycle .pgextwin-build/metadata/postgresql.json \ + --output "$RUNNER_TEMP/promotion-receipt.json" + - name: Preserve immutable authorization receipt + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: promotion-receipt + path: ${{ runner.temp }}/promotion-receipt.json + if-no-files-found: error + + release_build: + name: Rebuild signed Windows x64 binary and SBOM from verified current main + needs: authorize + permissions: + contents: read + id-token: write + attestations: write + artifact-metadata: write + uses: pgextwin/build/.github/workflows/build-extension-attested.yml@5756b3c5136a8bf4db710016cfe97555f0a71c6d + with: + extension_config_path: config/extension.json + test_contract_path: config/test-contract.json + + publish: + name: Check signatures, exact SHA256 and create-only Release ID + needs: [authorize, release_build] + runs-on: ubuntu-latest + permissions: + contents: write + actions: read + attestations: read + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: pgextwin/build + ref: 455f0ccc667697f600700a6e64bcfd6c57b6a977 + path: .pgextwin-build + persist-credentials: false + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: promotion-receipt + path: ${{ runner.temp }}/authorization + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + pattern: pg_cron-pg*-windows-x64 + path: dist + merge-multiple: true + - name: Verify signed binaries and publish only the fresh exact Release ID + env: + GH_TOKEN: ${{ github.token }} + RELEASE_TAG: ${{ inputs.release_tag }} + run: | + python .pgextwin-build/scripts/fleet-publish-release.py \ + --manifest config/extension.json \ + --lifecycle .pgextwin-build/metadata/postgresql.json \ + --receipt "$RUNNER_TEMP/authorization/promotion-receipt.json" \ + --tag "$RELEASE_TAG" \ + --dist dist \ + --recovery "$RUNNER_TEMP/promotion-recovery.json" + - name: Preserve partial-Draft recovery record, never auto-retry an occupied tag + if: always() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: promotion-recovery + path: ${{ runner.temp }}/promotion-recovery.json + if-no-files-found: warn + - name: Record manual post-Release Catalog handoff requirement + if: success() + run: | + echo "Formal Release published and verified. Catalog ingestion requires an independently verified public-Release update; do not report Catalog complete from this step." >> "$GITHUB_STEP_SUMMARY" From 7a609d87a46131ade96cf6f74f7967b9a194789a Mon Sep 17 00:00:00 2001 From: ShutenOishi Date: Sun, 11 Oct 2026 22:01:50 +0900 Subject: [PATCH 4/6] ci(windows): use vetted shared build with bounded Chocolatey retry and robust candidate audit --- .github/workflows/windows.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index c6692a9..fe8b5f2 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -20,7 +20,7 @@ jobs: windows: permissions: contents: read - uses: pgextwin/build/.github/workflows/build-extension.yml@21c99b933da98f397f739971e738ecb685fe55d2 + uses: pgextwin/build/.github/workflows/build-extension.yml@455f0ccc667697f600700a6e64bcfd6c57b6a977 with: extension_config_path: config/extension.json test_contract_path: config/test-contract.json @@ -34,6 +34,6 @@ jobs: contents: read actions: read issues: write - uses: pgextwin/build/.github/workflows/verify-candidate.yml@16b886b9d06d6f389b369b87ce0c155767697ca0 + uses: pgextwin/build/.github/workflows/verify-candidate.yml@ecf84241c1c4cd99fab3f964cb309f9c6e2a01f8 with: matrix_result: ${{ needs.windows.result }} From d18b35b892530d2f72c7bae76678029c22db59ef Mon Sep 17 00:00:00 2001 From: ShutenOishi Date: Sun, 11 Oct 2026 22:29:52 +0900 Subject: [PATCH 5/6] security: lock current verified upstream tags to exact peeled 40-digit commit SHAs --- config/extension.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/extension.json b/config/extension.json index 366a426..a99425b 100644 --- a/config/extension.json +++ b/config/extension.json @@ -4,7 +4,8 @@ "upstream": { "repository": "citusdata/pg_cron", "ref": "v1.6.8", - "version": "1.6.8" + "version": "1.6.8", + "commit": "5cedfa472ccc83567aa23ec645925ed8489a7797" }, "postgresql": { "minMajor": 14, From 9bfa0376016bb6640458959f628a8607505d29d9 Mon Sep 17 00:00:00 2001 From: ShutenOishi Date: Sun, 11 Oct 2026 22:53:02 +0900 Subject: [PATCH 6/6] security: pin every current upstream tag to verified immutable commit SHA