fix(release): supply the Landlock entry tarball to the packed install

dsh-sandbox-local declares @deepseek-ai/node-addon-landlock-run in
dependencies, not optionalDependencies, so omitting optional dependencies left
npm resolving it from a registry that does not carry it. The dsh pack job now
packs that entry for verification; its own platform packages stay out, being
optional and needing a musl toolchain per architecture.

The verification reads each directory by its contents rather than a pack order
file, because a directory packed only to satisfy a cross-sequence dependency has
no release order to describe.
This commit is contained in:
imccyu
2026-08-11 01:48:56 +08:00
parent 21db3220d6
commit ae75aca776
5 changed files with 28 additions and 13 deletions
@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write .agents/notes/implemented/process/2026-08-10-npm-release-sequences.md
2026-08-10-npm-release-sequences.md: 7efe5c9a1c3aa30d4c0a52aa5983b61a01f514cd
2026-08-10-npm-release-sequences.zh.md: cca853bae3f0b19dbf50aca0f2cf32aa573293ef
2026-08-10-npm-release-sequences.md: d51054b90aa0acd82d252cdb6e97dc1f3c0e51b5
2026-08-10-npm-release-sequences.zh.md: 8c2b7b048af407a79f62c5842f0bd04790a61c9a
@@ -101,7 +101,7 @@ The `pack` job walks the whole release set once, packing each member into one di
A dsh verification installs the vendored family's pack output too. The harness packages declare the vendored framework as a peer, those packages live in another sequence, and the credential-free job cannot fetch them from a private registry — so `release.yml` packs the vendored family for verification while publishing only its own set.
The verification omits optional dependencies. The Landlock platform packages behind them belong to the native sequence, whose pack needs a musl toolchain and one build per architecture, so a job on one runner cannot produce them; a consumer that cannot install them must still start, which is what optional means here.
The verification also packs the Landlock entry, which `dsh-sandbox-local` declares as a plain dependency, and omits optional dependencies. The platform packages behind those optional entries need a musl toolchain and one build per architecture, so a job on one runner cannot produce them; a consumer that cannot install them must still start, which is what optional means here. The verification therefore reads a directory by its contents rather than a pack order, because a directory can hold tarballs packed only to satisfy a cross-sequence dependency.
### Repository changes this carried
@@ -101,7 +101,7 @@ dsh 族套用仓库的发布 payload 策略(拒绝源码与声明映射)。v
dsh 的验证会一并安装 vendored 族的 pack 产物。harness 的包把 vendored 框架声明成 peer,而那些包属于另一条序列,无凭据的 job 无法从私有 registry 取到——所以 `release.yml` 为验证而打包 vendored 族,发布的仍只有自己那一份。
验证会略去可选依赖。它们背后的 Landlock 平台包属于 native 序列,那条序列的 pack 需要 musl 工具链且每个架构各构建一次,单台 runner 产不出来;而装不到它们的消费方也必须能起——这正是「可选」在这里的含义。
验证还会打一份 Landlock entry 的 tarball——`dsh-sandbox-local` 把它声明为普通 `dependencies`——同时略去可选依赖。那些可选项背后的平台包需要 musl 工具链且每个架构各构建一次,单台 runner 产不出来;而装不到它们的消费方也必须能起这正是「可选」在这里的含义。因此验证按目录内容读取 tarball,而不是读发布顺序:一个目录可能只装着为满足跨序列依赖而打出来的包,任何发布顺序都不描述它。
### 本次带出的仓库改动
+9 -1
View File
@@ -86,8 +86,16 @@ jobs:
- name: Pack the vendored framework for verification
run: pnpm run release:pack --family vendor --out dist/npm-vendor
# dsh-sandbox-local declares the Landlock entry as a runtime dependency, so
# the verification needs its tarball. Its platform packages stay out: they
# are optional, and building them needs a musl toolchain per architecture.
- name: Pack the Landlock entry for verification
run: |
pnpm --dir native/landlock-run run build:ts
pnpm --dir native/landlock-run/packages/entry pack --pack-destination "$PWD/dist/npm-landlock"
- name: Verify packed install
run: pnpm run release:verify-packed-install --family dsh --from dist/npm --from dist/npm-vendor
run: pnpm run release:verify-packed-install --family dsh --from dist/npm --from dist/npm-vendor --from dist/npm-landlock
- uses: actions/upload-artifact@v4
with:
+15 -8
View File
@@ -15,14 +15,14 @@
* checkout cannot stand in for a missing file here.
*/
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'
import { mkdtempSync, readdirSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join, resolve } from 'node:path'
import { pathToFileURL } from 'node:url'
import { parseArgs } from 'node:util'
import { releaseFamily } from './families.ts'
import { capture, isEntry } from './process.ts'
import { packedIdentity, readPublishOrder } from './tarball.ts'
import { packedIdentity } from './tarball.ts'
/**
* Environment for the installed artifact: no host Node hooks, no host DeepSeek
@@ -44,13 +44,19 @@ function consumerEnvironment(consumerRoot: string): NodeJS.ProcessEnv {
/**
* Every packed tarball in the given directories, as `file:` dependency entries.
* @param directories - absolute pack output directories.
*
* The directories are read by their contents rather than a pack order file: a
* directory here can hold tarballs packed only to satisfy a cross-sequence
* dependency, which no release order describes.
* @param directories - absolute directories holding packed tarballs.
* @returns Package name to tarball file URL, and the version each carries.
*/
function packedDependencies(directories: readonly string[]): Map<string, { url: string; version: string }> {
const dependencies = new Map<string, { url: string; version: string }>()
for (const directory of directories) {
for (const filename of readPublishOrder(directory)) {
const tarballs = readdirSync(directory).filter(name => name.endsWith('.tgz')).sort()
if (tarballs.length === 0) throw new Error(`${directory} holds no packed tarball`)
for (const filename of tarballs) {
const tarball = join(directory, filename)
const { name, version } = packedIdentity(tarball)
dependencies.set(name, { url: pathToFileURL(tarball).href, version })
@@ -92,10 +98,11 @@ function main(): void {
const environment = consumerEnvironment(consumerRoot)
console.log(`release verify-packed-install: installing ${String(packed.size)} tarball(s) into ${consumerRoot}`)
// Optional dependencies are omitted: the platform packages behind them
// belong to the native release sequence, this job holds no credentials for
// the private scope, and a consumer that cannot install them must still
// start — which is what optional means here.
// Optional dependencies are omitted: the Landlock platform packages behind
// them need a musl toolchain and one build per architecture, and a consumer
// that cannot install them must still start — which is what optional means
// here. Their entry package is a plain dependency of dsh-sandbox-local, so
// its tarball is supplied through --from.
capture('npm', ['install', '--no-audit', '--no-fund', '--package-lock=false', '--omit=optional'],
{ cwd: consumerRoot, env: environment })