diff --git a/.github/workflows/pages-smoke.yml b/.github/workflows/pages-smoke.yml index abc7e04..40aedf6 100644 --- a/.github/workflows/pages-smoke.yml +++ b/.github/workflows/pages-smoke.yml @@ -21,8 +21,8 @@ jobs: - name: Check out trusted pgextwin/website main for native and cross-repository calls uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - repository: pgextwin/website - ref: main + repository: ${{ job.workflow_repository }} + ref: ${{ job.workflow_sha }} persist-credentials: false - name: Check live GitHub Pages and independent Landscape Registry run: | diff --git a/en/cli.html b/en/cli.html index 14100f8..266b235 100644 --- a/en/cli.html +++ b/en/cli.html @@ -24,7 +24,7 @@

Get the Windows executable

Download pgextwin.exe (12.83 MB) - GitHub Release v0.3.1 + GitHub Release v0.3.2 SHA256SUMS.txt

Published EXE SHA256: d4e8f63d402066b21db9d537f7679b51137ec47d9834fa4fd75b5889ad34e6f4

diff --git a/en/index.html b/en/index.html index 4dbf0a7..4853220 100644 --- a/en/index.html +++ b/en/index.html @@ -32,7 +32,7 @@

PostgreSQL Extensions for Windows

-

Windows CLI · v0.3.1

+

Windows CLI · v0.3.2

Download Catalog-registered ZIPs with one command

14 extensions × PostgreSQL 14–18 = 70 original ZIPs. The CLI authenticates the Sigstore-signed Catalog feed, checks each ZIP SHA256, and preserves an explicit historical --fixed mode. Original ZIP signatures remain INTEGRITY_ONLY.

.\pgextwin.exe download-all --pg all
diff --git a/ja/cli.html b/ja/cli.html index 91bbfe7..a6002d2 100644 --- a/ja/cli.html +++ b/ja/cli.html @@ -24,7 +24,7 @@

Windows用EXEを入手

公開EXEのSHA256: d4e8f63d402066b21db9d537f7679b51137ec47d9834fa4fd75b5889ad34e6f4

diff --git a/ja/index.html b/ja/index.html index 66ac1ad..4663c98 100644 --- a/ja/index.html +++ b/ja/index.html @@ -32,7 +32,7 @@

PostgreSQL拡張機能のWindowsバイナリ

-

Windows CLI · v0.3.1

+

Windows CLI · v0.3.2

Catalog登録済みのZIPを1行でまとめて取得

14拡張×PostgreSQL 14~18、計70個の元ZIPに対応。CLIはSigstore署名付きCatalogフィードを認証し、各ZIPのSHA256を照合します。過去の固定版は--fixedで指定できます。個々のZIPの真正署名は検証せず、INTEGRITY_ONLYです。

.\pgextwin.exe download-all --pg all
diff --git a/scripts/published-cli-contract.mjs b/scripts/published-cli-contract.mjs new file mode 100644 index 0000000..7d93a29 --- /dev/null +++ b/scripts/published-cli-contract.mjs @@ -0,0 +1,24 @@ +import assert from 'node:assert/strict'; + +// Approved public CLI Release 417855312 / EXE asset 657731413, GET-reconciled +// on 2026-10-20. This checks served HTML against that identity; it does not +// replace the existing independent EXE Sigstore/Windows acceptance. +export const cliVersion = '0.3.2'; +export const cliExeSha = 'd4e8f63d402066b21db9d537f7679b51137ec47d9834fa4fd75b5889ad34e6f4'; + +export function verifyPublishedCli(page, home, locale) { + assert.ok(['en', 'ja'].includes(locale), 'Unknown CLI page language'); + assert.ok(page.includes('') && + page.includes('cli-v' + cliVersion) && page.includes(cliExeSha) && + page.includes('GitHub Release v' + cliVersion) && + page.includes('cli-flow-steps') && page.includes('SIGSTORE VERIFIED') && + page.includes('INTEGRITY_ONLY') && page.includes('download-all --pg all --fixed') && + page.includes('download-all --pg all --verbose') && page.includes('download-verbose.log') && + page.includes('83.83%'), 'Published CLI v' + cliVersion + ' incomplete (' + locale + ')'); + assert.ok(page.includes('
x.text()), get(root+"ja/cli.html").then(x=>x.text()) ]); - const expectedSha="baee38b3aafdd1bbb7f61857747358dbd40ab056d989aa0f753c93b2025a7580"; for (const [page,home,locale] of [ [cliEnglish,html,"en"],[cliJapanese,japanese,"ja"] ]) { - assert.ok(page.includes('') && - page.includes('cli-v0.3.1') && - page.includes(expectedSha) && - page.includes('cli-flow-steps') && - page.includes('SIGSTORE VERIFIED') && - page.includes('INTEGRITY_ONLY') && - page.includes('download-all --pg all --fixed') && - page.includes('83.83%'), - "Published CLI v0.3.1 incomplete ("+locale+")"); - assert.ok(page.includes('
{ + verifyPublishedCli(page, home, locale); + }); + test('Published ' + locale + ' CLI contract rejects stale tag/hash/label, missing verbose and mixed locales', () => { + const opposite = locale === 'en' ? 'ja' : 'en'; + const changes = [ + [page.replaceAll('cli-v' + cliVersion, 'cli-v0.3.1'), home], + [page.replaceAll(cliExeSha, '0'.repeat(64)), home], + [page.replaceAll('GitHub Release v' + cliVersion, 'GitHub Release v0.3.1'), home], + [page.replaceAll('download-all --pg all --verbose', 'download-all --pg all'), home], + [page.replaceAll('download-verbose.log', 'none.log'), home], + [page + '
', home], + [page, home.replaceAll('Windows CLI · v' + cliVersion, 'Windows CLI · v0.3.1')] + ]; + for (const [modified, modifiedHome] of changes) { + assert.throws(() => verifyPublishedCli(modified, modifiedHome, locale)); + } + }); +} diff --git a/tests/reusable-audit.test.js b/tests/reusable-audit.test.js index 1d5e83a..3f3f82d 100644 --- a/tests/reusable-audit.test.js +++ b/tests/reusable-audit.test.js @@ -7,8 +7,9 @@ const workflow = readFileSync(join(__dirname, "..", ".github", "workflows", "pag test("public Pages audit is available as a cross-repo reusable workflow", () => { assert.match(workflow, /on:\s*\n\s*workflow_call:/); - assert.match(workflow, /repository:\s*pgextwin\/website/); - assert.match(workflow, /ref:\s*main/); + assert.ok(workflow.includes('repository: ${{ job.workflow_repository }}')); + assert.ok(workflow.includes('ref: ${{ job.workflow_sha }}')); + assert.doesNotMatch(workflow, /ref:\s*main\b/); assert.match(workflow, /persist-credentials:\s*false/); });