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
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/);
});