From e7ed6865fb1293c1d9660867f70765492668dd9b Mon Sep 17 00:00:00 2001 From: Alexander Mills Date: Tue, 28 Jul 2026 08:24:33 -0500 Subject: [PATCH 1/6] test: define Node package self-tests --- package.json | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 4048f0a..a097b81 100644 --- a/package.json +++ b/package.json @@ -1 +1,15 @@ -{ "name": "@zed-pkg-test/node-lib", "version": "1.0.0", "main": "src/index.js", "license": "MIT" } +{ + "name": "@zed-pkg-test/node-lib", + "version": "1.0.0", + "description": "A tiny library sourced via zed for interoperability tests.", + "main": "src/index.js", + "files": [ + "src", + "README.md" + ], + "scripts": { + "test": "node --test", + "pack:check": "npm pack --dry-run --json" + }, + "license": "MIT" +} From c25ba73a5eaf43f7ddf418540c3a386756e5bdbd Mon Sep 17 00:00:00 2001 From: Alexander Mills Date: Tue, 28 Jul 2026 08:24:54 -0500 Subject: [PATCH 2/6] test: verify published Node API --- test/greet.test.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 test/greet.test.js diff --git a/test/greet.test.js b/test/greet.test.js new file mode 100644 index 0000000..1e7665b --- /dev/null +++ b/test/greet.test.js @@ -0,0 +1,12 @@ +"use strict"; + +const assert = require("node:assert/strict"); +const test = require("node:test"); +const { greet } = require("../src/index.js"); + +test("greet identifies the immutable Zed package namespace", () => { + assert.equal( + greet("consumer"), + "hello consumer from @zed-pkg-test/node-lib" + ); +}); From f11751b04adf4aa9fff2a72c4364ac30ad9ff395 Mon Sep 17 00:00:00 2001 From: Alexander Mills Date: Tue, 28 Jul 2026 08:25:38 -0500 Subject: [PATCH 3/6] ci: add deterministic Node package checks --- .github/workflows/ci.yml | 69 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..a01e3ca --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,69 @@ +name: package CI + +on: + pull_request: + push: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + verify: + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false + + - name: Validate workflow + uses: docker://rhysd/actionlint@sha256:b1934ee5f1c509618f2508e6eb47ee0d3520686341fec936f3b79331f9315667 + with: + args: .github/workflows/ci.yml + + - name: Verify Zed and npm metadata agree + shell: bash + run: | + set -euo pipefail + python3 - <<'PY' + import json + import tomllib + from pathlib import Path + + native = json.loads(Path("package.json").read_text()) + with Path(".zpkg.toml").open("rb") as handle: + zed = tomllib.load(handle)["package"] + + assert native["name"] == f"@{zed['org']}/{zed['name']}" + assert native["version"] == zed["version"] + assert native["license"] == zed["license"] + assert zed["repository"]["url"] == "https://github.com/zed-pkg-test/node-lib" + PY + + - name: Test API and packed contents in Node 22 + shell: bash + run: | + set -euo pipefail + docker run --rm \ + --volume "$GITHUB_WORKSPACE:/work:ro" \ + --workdir /work \ + node:22-bookworm-slim \ + sh -euc ' + npm test + npm pack --dry-run --json > /tmp/pack.json + node - <<"NODE" + const fs = require("node:fs"); + const report = JSON.parse(fs.readFileSync("/tmp/pack.json", "utf8")); + const files = report[0].files.map(({ path }) => path).sort(); + const expected = ["README.md", "package.json", "src/index.js"]; + if (JSON.stringify(files) !== JSON.stringify(expected)) { + throw new Error(`unexpected npm package contents: ${JSON.stringify(files)}`); + } + NODE + ' From b2e29f418446fc5aff86250bf449b0b2d03804ac Mon Sep 17 00:00:00 2001 From: Alexander Mills Date: Tue, 28 Jul 2026 08:35:47 -0500 Subject: [PATCH 4/6] test: assert package boundary without brittle exact list --- .github/workflows/ci.yml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a01e3ca..944fca2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -61,9 +61,18 @@ jobs: const fs = require("node:fs"); const report = JSON.parse(fs.readFileSync("/tmp/pack.json", "utf8")); const files = report[0].files.map(({ path }) => path).sort(); - const expected = ["README.md", "package.json", "src/index.js"]; - if (JSON.stringify(files) !== JSON.stringify(expected)) { - throw new Error(`unexpected npm package contents: ${JSON.stringify(files)}`); + for (const required of ["README.md", "package.json", "src/index.js"]) { + if (!files.includes(required)) { + throw new Error(`required package file missing: ${required}; got ${JSON.stringify(files)}`); + } + } + const forbidden = files.filter((path) => + /(^|\/)(?:\.github|\.git|\.zed|node_modules|test)(?:\/|$)/.test(path) || + /(^|\/)\.zpkg\.toml$/.test(path) || + /\.tgz$/.test(path) + ); + if (forbidden.length > 0) { + throw new Error(`local/test state leaked into package: ${JSON.stringify(forbidden)}`); } NODE ' From 152828bc163788f25bf7dead46ad47e15fcbd687 Mon Sep 17 00:00:00 2001 From: Alexander Mills Date: Tue, 28 Jul 2026 08:47:59 -0500 Subject: [PATCH 5/6] ci: run package checks directly on the hosted Node runtime --- .github/workflows/ci.yml | 49 ++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 944fca2..cc3c446 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,33 +46,28 @@ jobs: assert zed["repository"]["url"] == "https://github.com/zed-pkg-test/node-lib" PY - - name: Test API and packed contents in Node 22 + - name: Test API and packed contents shell: bash run: | set -euo pipefail - docker run --rm \ - --volume "$GITHUB_WORKSPACE:/work:ro" \ - --workdir /work \ - node:22-bookworm-slim \ - sh -euc ' - npm test - npm pack --dry-run --json > /tmp/pack.json - node - <<"NODE" - const fs = require("node:fs"); - const report = JSON.parse(fs.readFileSync("/tmp/pack.json", "utf8")); - const files = report[0].files.map(({ path }) => path).sort(); - for (const required of ["README.md", "package.json", "src/index.js"]) { - if (!files.includes(required)) { - throw new Error(`required package file missing: ${required}; got ${JSON.stringify(files)}`); - } - } - const forbidden = files.filter((path) => - /(^|\/)(?:\.github|\.git|\.zed|node_modules|test)(?:\/|$)/.test(path) || - /(^|\/)\.zpkg\.toml$/.test(path) || - /\.tgz$/.test(path) - ); - if (forbidden.length > 0) { - throw new Error(`local/test state leaked into package: ${JSON.stringify(forbidden)}`); - } - NODE - ' + node -e 'const major=Number(process.versions.node.split(".")[0]); if (major < 20) throw new Error(`Node 20+ required, got ${process.version}`)' + npm test + npm pack --dry-run --json > "$RUNNER_TEMP/pack.json" + PACK_REPORT="$RUNNER_TEMP/pack.json" node - <<'NODE' + const fs = require("node:fs"); + const report = JSON.parse(fs.readFileSync(process.env.PACK_REPORT, "utf8")); + const files = report[0].files.map(({ path }) => path).sort(); + for (const required of ["README.md", "package.json", "src/index.js"]) { + if (!files.includes(required)) { + throw new Error(`required package file missing: ${required}; got ${JSON.stringify(files)}`); + } + } + const forbidden = files.filter((path) => + /(^|\/)(?:\.github|\.git|\.zed|node_modules|test)(?:\/|$)/.test(path) || + /(^|\/)\.zpkg\.toml$/.test(path) || + /\.tgz$/.test(path) + ); + if (forbidden.length > 0) { + throw new Error(`local/test state leaked into package: ${JSON.stringify(forbidden)}`); + } + NODE From 712141a93d2478997e531165726b0ce5d48cf791 Mon Sep 17 00:00:00 2001 From: Alexander Mills Date: Tue, 28 Jul 2026 09:27:48 -0500 Subject: [PATCH 6/6] ci: avoid shell expansion ambiguity in Node version check --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cc3c446..2df6fcb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,7 +50,7 @@ jobs: shell: bash run: | set -euo pipefail - node -e 'const major=Number(process.versions.node.split(".")[0]); if (major < 20) throw new Error(`Node 20+ required, got ${process.version}`)' + node -e 'const major=Number(process.versions.node.split(".")[0]); if (major < 20) throw new Error("Node 20+ required, got " + process.version)' npm test npm pack --dry-run --json > "$RUNNER_TEMP/pack.json" PACK_REPORT="$RUNNER_TEMP/pack.json" node - <<'NODE'