Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/dsh-plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ jobs:
node -e 'require("node:fs").appendFileSync(process.env.GITHUB_ENV, "DSH_ARTIFACT=output/dsh-loopx-plugin-" + require("./package.json").version + ".tgz\n")'
- name: Qualify the real package-name install and uninstall
run: node smoke/dsh-registry-smoke.mjs --tarball "$DSH_ARTIFACT"
- name: Qualify the source installer and installed-version rejection
run: pnpm smoke:install
- name: Qualify packed Client and real web runtime
if: runner.os == 'Linux'
run: |
Expand Down
7 changes: 1 addition & 6 deletions packages/dsh-loopx-plugin/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,7 @@ printf '%s' "$profile_dump" | node -e '
exit 1
}

"$dsh_bin" plugin --profile "$PROFILE_NAME" exec node -e '
const manifest = require("dsh-loopx-plugin/package.json")
if (manifest.name !== "dsh-loopx-plugin" || manifest.version !== process.argv[1]) {
throw new Error(`installed plugin version does not match ${process.argv[1]}`)
}
' "$PACKAGE_VERSION" || {
"$dsh_bin" plugin --profile "$PROFILE_NAME" exec node -e 'const manifest = require("dsh-loopx-plugin/package.json"); if (manifest.name !== "dsh-loopx-plugin" || manifest.version !== process.argv[1]) { throw new Error(`installed plugin version does not match ${process.argv[1]}`); }' "$PACKAGE_VERSION" || {
echo 'install: DSH installed package did not match the built version' >&2
exit 1
}
Expand Down
51 changes: 44 additions & 7 deletions packages/dsh-loopx-plugin/smoke/dsh-installer-smoke.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,25 @@

import assert from 'node:assert/strict'
import { spawnSync } from 'node:child_process'
import { createHash } from 'node:crypto'
import { createRequire } from 'node:module'
import { chmod, mkdtemp, readFile, rm, stat, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { dirname, join, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'

const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..')
const manifest = JSON.parse(await readFile(join(packageRoot, 'package.json'), 'utf8'))
const dshBin = process.env.DSH_BIN || join(packageRoot, 'node_modules', '.bin', 'dsh')
const dshBin = (process.env.DSH_BIN || join(packageRoot, 'node_modules', '.bin', 'dsh'))
.replaceAll('\\', '/')
const require = createRequire(import.meta.url)
// Windows cannot spawn the .bin shell shim directly. Match the registry smoke
// for direct DSH operations; the shipped installer still runs through Bash.
const dshScript = process.env.DSH_CLI_JS

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Keep the selected DSH host for all qualification operations

When DSH_BIN selects another supported installation, install.sh uses it but runDsh() now invokes the package-local lib/bin.js unless a second DSH_CLI_JS is supplied. The documented DSH_BIN=... pnpm smoke:install path therefore no longer checks that selected CLI's later readback, stale-version rejection or removal. A forwarding wrapper around real DSH that rejects only plugin --profile web remove dsh-loopx-plugin makes the base smoke fail; this head still reports success and never sends removal to the selected CLI. Preserve the already-selected executable, or derive and validate its matching JS entrypoint, and cover that selected-host failure.

|| join(dirname(require.resolve('@deepseek-ai/dsh/package.json')), 'lib', 'bin.js')
const installerSource = await readFile(join(packageRoot, 'install.sh'), 'utf8')
const versionVerifier = installerSource.match(/exec node -e '([^']*)' "\$PACKAGE_VERSION"/u)?.[1]
assert(versionVerifier, 'installer must verify the installed package version')
const args = process.argv.slice(2)
assert(args.length === 0 || (args.length === 2 && args[0] === '--previous-tarball'),
'usage: dsh-installer-smoke.mjs [--previous-tarball PATH]')
Expand All @@ -22,7 +33,7 @@ const installedManifest = join(home, 'profiles', 'web', 'node_modules', manifest
function run(file, argv, environment = env) {
return spawnSync(file, argv, {
cwd: temp, env: environment, encoding: 'utf8', shell: false,
timeout: 180_000, maxBuffer: 8 * 1024 * 1024,
timeout: 600_000, maxBuffer: 8 * 1024 * 1024,
})
}

Expand All @@ -31,9 +42,13 @@ function expectSuccess(result) {
assert.equal(result.status, 0, `${result.stdout}\n${result.stderr}`)
}

function runDsh(argv) {
return run(process.execPath, [dshScript, ...argv])
}

try {
if (previousTarball) {
expectSuccess(run(dshBin, ['plugin', '--profile', 'web', 'add', previousTarball,
expectSuccess(runDsh(['plugin', '--profile', 'web', 'add', previousTarball,
'--prefer-offline', '--ignore-scripts']))
const previous = JSON.parse(await readFile(installedManifest, 'utf8'))
assert.equal(previous.name, manifest.name)
Expand All @@ -45,31 +60,53 @@ try {
const installed = run('bash', [join(packageRoot, 'install.sh')])
expectSuccess(installed)
assert(installed.stdout.includes(`installed and verified ${manifest.name}@${manifest.version}`))
process.stdout.write(`${installed.stdout.split(/\r?\n/u)
.find(line => line.includes(`installed and verified ${manifest.name}@${manifest.version}`))}\n`)
const installedText = await readFile(installedManifest, 'utf8')
const readback = JSON.parse(installedText)
assert.equal(readback.name, manifest.name)
assert.equal(readback.version, manifest.version)

const profileBefore = runDsh(['--profile', 'web', '--dump-config'])
expectSuccess(profileBefore)
assert.deepEqual([...profileBefore.stdout.matchAll(/^\s*name:\s+(dsh-loopx-plugin(?:\/\S+)?)\s*$/gmu)]
.map(match => match[1]), [manifest.name, `${manifest.name}/init-command`,
`${manifest.name}/driver`, `${manifest.name}/observer`])
expectSuccess(runDsh(['plugin', '--profile', 'web', 'exec', 'node', '-e',
versionVerifier, manifest.version]))
const staleVersion = '0.0.0-installer-smoke'
const stale = runDsh(['plugin', '--profile', 'web', 'exec', 'node', '-e',
versionVerifier, staleVersion])
assert.ifError(stale.error)
assert.notEqual(stale.status, 0, 'installed-version verifier accepted a stale version')
assert(`${stale.stdout}\n${stale.stderr}`.includes(`installed plugin version does not match ${staleVersion}`))
assert.equal(await readFile(installedManifest, 'utf8'), installedText)
const profileAfter = runDsh(['--profile', 'web', '--dump-config'])
expectSuccess(profileAfter)
assert.equal(profileAfter.stdout, profileBefore.stdout, 'version verification changed the profile')
const profileHash = createHash('sha256').update(profileAfter.stdout).digest('hex')
process.stdout.write(`installed profile unchanged after version checks (sha256 ${profileHash})\n`)

// An incompatible version must fail before any DSH profile operation. The
// shim represents only host version reporting, never a successful runtime.
const unsupported = join(temp, 'unsupported-dsh')
const marker = join(temp, 'unexpected-profile-operation')
await writeFile(unsupported, `#!/bin/sh\nif [ "$1" = '--version' ]; then\n printf '%s\\n' '0.2.1-alpha.1'\nelse\n touch "$LOOPX_INSTALLER_SMOKE_MARKER"\n exit 1\nfi\n`)
await chmod(unsupported, 0o755)
const rejected = run('bash', [join(packageRoot, 'install.sh')], {
...env, DSH_BIN: unsupported, LOOPX_INSTALLER_SMOKE_MARKER: marker,
...env, DSH_BIN: unsupported.replaceAll('\\', '/'), LOOPX_INSTALLER_SMOKE_MARKER: marker,
})
assert.ifError(rejected.error)
assert.equal(rejected.status, 2)
assert(rejected.stderr.includes('outside the supported peer range'))
assert.equal(await stat(marker).then(() => true, () => false), false)
assert.equal(await readFile(installedManifest, 'utf8'), installedText)

expectSuccess(run(dshBin, ['plugin', '--profile', 'web', 'remove', manifest.name]))
const removed = run(dshBin, ['--profile', 'web', '--dump-config'])
expectSuccess(runDsh(['plugin', '--profile', 'web', 'remove', manifest.name]))
const removed = runDsh(['--profile', 'web', '--dump-config'])
expectSuccess(removed)
assert(!removed.stdout.includes('name: dsh-loopx-plugin'))
process.stdout.write(`dsh-loopx installer smoke passed (${previousTarball ? 'upgrade' : 'fresh install'}, incompatible-host rejection, removal)\n`)
process.stdout.write(`dsh-loopx installer smoke passed (${previousTarball ? 'upgrade' : 'fresh install'}, stale-version rejection, incompatible-host rejection, removal)\n`)
} finally {
await rm(temp, { recursive: true, force: true })
}
Loading