test(cli): compose the real Windows shell roster through the shipped bundle layers

The resolver suite previously exercised only fixture patch lists, leaving
the real shipped windows.cordis.patch.yml and the bundle→windows→user
composition ordering untested on Linux CI. The new cases load a temp
profile whose bundle layers resolve from the real dsh-base/dsh-web-app
packages (app installation anchor), apply the platform layer through the
boot's own composeEntries algorithm with the platform injected, and
assert the win32 danger-full-access roster (eight disables, three
inserts, no warnings on the web profile). A second case pins POSIX
unchanged and the base-only-profile ui-permission no-match warning as
warned-but-harmless, matching the patch header's documented contract.
This commit is contained in:
Huanqi Cao
2026-08-07 20:50:36 +08:00
parent 1ee773317c
commit 431783426e
4 changed files with 64 additions and 4 deletions

View File

@@ -2,7 +2,9 @@ import { afterEach, describe, expect, it } from 'vitest'
import { mkdtempSync, writeFileSync, rmSync, mkdirSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { fileURLToPath } from 'node:url'
import type { ProfileLayer } from '@deepseek-ai/dsh-app-boot'
import { composeEntries, initProfile, loadProfile, PROFILES_DIR } from '@deepseek-ai/dsh-app-boot'
import {
BASE_BUNDLE,
resolveWindowsShellLayer,
@@ -62,3 +64,61 @@ describe('resolveWindowsShellLayer', () => {
.toThrow(/@deepseek-ai\/dsh-base ships no windows\.cordis\.patch\.yml/)
})
})
describe('the shipped Windows composition (real bundle layers)', () => {
let home: string
afterEach(() => { if (home !== undefined) rmSync(home, { recursive: true, force: true }) })
// The app installation anchor, mirroring profile-boot.ts: the bundle layers
// resolve from the REAL dsh-base/dsh-web-app packages through it, so this
// suite composes the shipped patch files, not test fixtures.
const anchor = fileURLToPath(new URL('../package.json', import.meta.url))
it('composes the win32 danger-full-access roster through the real patch layers', () => {
home = mkdtempSync(join(tmpdir(), 'dsh-windows-home-'))
initProfile(join(home, PROFILES_DIR, 'web'), ['@deepseek-ai/dsh-base', '@deepseek-ai/dsh-web-app'])
const profile = loadProfile('dsh', 'web', anchor, home)
const warnings: string[] = []
const win32 = resolveWindowsShellLayer('win32', profile.layers, 'dsh')
expect(win32).toBeDefined()
const rows = composeEntries(
[...profile.layers.map(layer => layer.patches), win32!.patches],
message => warnings.push(message),
)
const byId = new Map(rows.map(row => [row.id, row]))
for (const id of ['bash-sandbox', 'tool-bash', 'permission', 'ui-permission',
'sandbox', 'sandbox-policy', 'fs-sandbox', 'approval']) {
expect(byId.get(id)?.disabled, `row ${id}`).toBe(true)
}
for (const id of ['pwsh-local', 'tool-pwsh', 'fs-local']) {
expect(byId.has(id), `inserted row ${id}`).toBe(true)
}
// The web-app layer provides ui-permission, so the full web profile
// composes without any no-match warning.
expect(warnings).toEqual([])
})
it('leaves POSIX untouched and base-only profiles warned but harmless', () => {
home = mkdtempSync(join(tmpdir(), 'dsh-windows-home-'))
initProfile(join(home, PROFILES_DIR, 'web'), ['@deepseek-ai/dsh-base', '@deepseek-ai/dsh-web-app'])
const profile = loadProfile('dsh', 'web', anchor, home)
// POSIX: no platform layer, the bash stack stays enabled.
const posixRows = composeEntries(profile.layers.map(layer => layer.patches))
const posixById = new Map(posixRows.map(row => [row.id, row]))
expect(posixById.get('bash-sandbox')?.disabled).not.toBe(true)
expect(posixById.has('pwsh-local')).toBe(false)
// A base-only custom profile (the DEFAULT_PROFILE_BUNDLES template):
// ui-permission has no row to patch, so the shipped layer warns once per
// composition — never fails — exactly as its header comment documents.
initProfile(join(home, PROFILES_DIR, 'base-only'), ['@deepseek-ai/dsh-base'])
const baseOnly = loadProfile('dsh', 'base-only', anchor, home)
const baseWarnings: string[] = []
const win32 = resolveWindowsShellLayer('win32', baseOnly.layers, 'dsh')
expect(win32).toBeDefined()
composeEntries(
[...baseOnly.layers.map(layer => layer.patches), win32!.patches],
message => baseWarnings.push(message),
)
expect(baseWarnings.some(message => message.includes('ui-permission'))).toBe(true)
})
})