feat: complete WorkBuddy parity and Windows release workflow
This commit is contained in:
1 parent
143516b3a8
commit
d5512df549
434 files changed
+54977
-1854
No files matched your search
@@ -0,0 +1,96 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { promises as fs } from 'node:fs'
|
||||
import { execFileSync } from 'node:child_process'
|
||||
import { join, resolve } from 'node:path'
|
||||
import { pathToFileURL } from 'node:url'
|
||||
import { configureSandbox } from '../src/main/sandbox/configuration'
|
||||
import { listSandboxToolchains, importSandboxToolchain } from '../src/main/sandbox/toolchains'
|
||||
import { executeSandboxCommand, sandboxStatus } from '../src/main/sandbox/service'
|
||||
|
||||
if (process.platform !== 'win32') throw new Error('Bundled Git verification requires real Windows isolation')
|
||||
const fixture = await fs.mkdtemp(resolve('.tmp/sandbox-bundled-git-'))
|
||||
const workspace = join(fixture, 'workspace \u4e2d\u6587'), stateRoot = join(fixture, 'data'), resources = resolve(process.env.YCODE_TEST_BUNDLED_RESOURCES ?? 'resources/sandbox/win32-x64')
|
||||
await fs.mkdir(workspace); await fs.writeFile(join(workspace, 'input.txt'), 'baseline\n')
|
||||
const lock = JSON.parse(await fs.readFile(resolve('resources/sandbox/git-runtime.lock.json'), 'utf8'))
|
||||
const checks: Array<{ label: string; pass: boolean }> = []
|
||||
function check(label: string, condition: unknown): void { checks.push({ label, pass: !!condition }); assert.ok(condition, label); console.log(`PASS ${label}`) }
|
||||
const context = { workspaceRoot: workspace, runtimes: ['git'], sessionId: 'bundled-git-session', runId: 'bundled-git-run', toolCallId: 'bundled-git-call', approve: async () => true }
|
||||
const configure = (resourceDirectory = resources, useBundledGit = true): void => configureSandbox({ stateRoot, resourceDirectory, useBundledGit })
|
||||
const gitView = async () => (await listSandboxToolchains()).find(item => item.kind === 'git')!
|
||||
const { verifyBundledGit } = await import(pathToFileURL(resolve('scripts/vendor-sandbox-git.mjs')).href)
|
||||
const originalPath = process.env.PATH
|
||||
try {
|
||||
configure()
|
||||
const view = await gitView()
|
||||
check('fresh userData exposes the pinned bundled Git without registration', view.state === 'registered' && view.source === 'bundled' && view.version === lock.version)
|
||||
check('availability queries do not create a user Git registration', !await fs.stat(join(stateRoot, 'toolchains/git.json')).catch(() => null))
|
||||
const component = JSON.parse(await fs.readFile(join(resources, 'manifest.json'), 'utf8'))
|
||||
const bundle = await verifyBundledGit(join(resources, 'git'))
|
||||
check('native component pins the complete bundled runtime manifest', component.bundledGit.manifestSha256 === bundle.manifestSha256 && component.bundledGit.archiveSha256 === lock.archive.sha256)
|
||||
const notices = await fs.readFile(join(resources, 'git/files/THIRD_PARTY_NOTICES.txt'), 'utf8')
|
||||
check('license, copyright and source provenance travel with the runtime', notices.includes(lock.releaseUrl) && notices.includes('GPL-2.0') && (await fs.readFile(join(resources, 'git/files/LICENSE.txt'), 'utf8')).includes('GNU GENERAL PUBLIC LICENSE'))
|
||||
process.env.PATH = ''
|
||||
let result = await executeSandboxCommand('git --version && git status --porcelain=v1', context)
|
||||
check('real AppContainer Git works with empty host PATH and no user registry', result.ok && result.data.stdout.includes(`git version ${lock.version}`) && result.data.toolchains?.[0].id === view.id && result.data.git?.persistence === 'unchanged')
|
||||
result = await executeSandboxCommand('echo bundled>bundled.txt && git add bundled.txt && git commit -q -m bundled-offline-commit', context)
|
||||
check('bundled Git stages and commits through the existing approval boundary', result.ok && result.data.git?.persistence === 'saved' && result.data.writeback === 'committed' && (await fs.readFile(join(workspace, 'bundled.txt'), 'utf8')).trim() === 'bundled')
|
||||
result = await executeSandboxCommand('git log -1 --oneline && git status --porcelain=v1', context)
|
||||
check('a later command sees the saved bundled-Git commit', result.ok && result.data.stdout.includes('bundled-offline-commit') && result.data.git?.persistence === 'unchanged')
|
||||
const copied = join(fixture, 'app resources \u5b89\u88c5/sandbox/win32-x64')
|
||||
await fs.cp(resources, copied, { recursive: true, errorOnExist: true, force: false })
|
||||
configure(copied)
|
||||
result = await executeSandboxCommand('git --version && git log -1 --oneline', context)
|
||||
check('copied application resources work at a space/Unicode installation path', result.ok && result.data.stdout.includes(`git version ${lock.version}`) && result.data.stdout.includes('bundled-offline-commit'))
|
||||
const override = await importSandboxToolchain('git', join(copied, 'git/files/git.exe'))
|
||||
check('a deliberate imported override takes precedence over the bundled runtime', (await gitView()).source === 'imported' && (await gitView()).id === override.id && override.id !== view.id)
|
||||
const overrideIdentity = JSON.parse(await fs.readFile(join(stateRoot, 'toolchains/git.json'), 'utf8'))
|
||||
const overrideImage = join(stateRoot, 'toolchains/objects', overrideIdentity.id, 'files/git.exe')
|
||||
await fs.appendFile(overrideImage, 'tampered')
|
||||
await assert.rejects(executeSandboxCommand('git --version', context), /摘要不匹配/)
|
||||
check('a damaged explicit override is rejected without silently switching sources', (await gitView()).source === 'imported')
|
||||
const alias = join(stateRoot, 'toolchains/git.json'), aliasBytes = await fs.readFile(alias)
|
||||
await fs.writeFile(alias, '{}')
|
||||
await assert.rejects(executeSandboxCommand('git --version', context), /引用无效/)
|
||||
check('an invalid user reference does not activate a bundled fallback', (await gitView()).state === 'invalid')
|
||||
await fs.writeFile(alias, aliasBytes); await fs.unlink(alias)
|
||||
check('removing the optional override restores the application default', (await gitView()).source === 'bundled' && (await gitView()).id === view.id)
|
||||
const image = join(copied, 'git/files/git.exe'), imageBytes = await fs.readFile(image)
|
||||
await fs.appendFile(image, 'tampered')
|
||||
await assert.rejects(executeSandboxCommand('git --version', context), /摘要不匹配/)
|
||||
await assert.rejects(verifyBundledGit(join(copied, 'git')), /digest mismatch/)
|
||||
check('tampered bundled executable fails runtime and packaging checks', true)
|
||||
await fs.writeFile(image, imageBytes)
|
||||
const manifestPath = join(copied, 'git/manifest.json'), manifestBytes = await fs.readFile(manifestPath)
|
||||
await fs.appendFile(manifestPath, ' ')
|
||||
await assert.rejects(executeSandboxCommand('git --version', context), /内置 Git 清单摘要不匹配/)
|
||||
await assert.rejects(verifyBundledGit(join(copied, 'git')), /manifest digest mismatch/)
|
||||
check('a bundled manifest replacement is rejected against the component pin', (await gitView()).state === 'invalid')
|
||||
await fs.writeFile(manifestPath, manifestBytes)
|
||||
await fs.rename(manifestPath, `${manifestPath}.missing`)
|
||||
await assert.rejects(executeSandboxCommand('git --version', context), /ENOENT/)
|
||||
check('missing bundled files never fall back to the system Git installation', (await gitView()).state === 'invalid')
|
||||
result = await executeSandboxCommand('echo SHELL_STILL_ISOLATED', { ...context, runtimes: [] })
|
||||
check('a Git component failure does not turn shell execution into a host fallback', result.ok && result.data.isolated && result.data.stdout.includes('SHELL_STILL_ISOLATED') && (await sandboxStatus()).capabilities?.some(item => item.id === 'git' && item.state === 'unavailable'))
|
||||
await fs.rename(`${manifestPath}.missing`, manifestPath)
|
||||
configure(copied, false)
|
||||
check('a host configuration can explicitly disable bundled Git without granting host PATH', (await gitView()).state === 'missing')
|
||||
configure(copied)
|
||||
check('restored resources expose the original pinned identity', (await gitView()).id === view.id && (await verifyBundledGit(join(copied, 'git'))).manifestSha256 === bundle.manifestSha256)
|
||||
process.env.PATH = originalPath
|
||||
const badArchive = join(fixture, 'bad.zip'); await fs.writeFile(badArchive, 'not-an-archive')
|
||||
assert.throws(() => execFileSync(process.execPath, [resolve('scripts/vendor-sandbox-git.mjs'), '--archive', badArchive, '--offline', '--output', join(fixture, 'bad-output/git')], { windowsHide: true, stdio: 'pipe' }), /Official MinGit archive digest mismatch/)
|
||||
check('the explicit vendor command rejects archives with a wrong digest before extraction', true)
|
||||
const unrelated = join(fixture, 'unrelated/git'); await fs.mkdir(unrelated, { recursive: true }); await fs.writeFile(join(unrelated, 'user-file.txt'), 'preserve-user-data')
|
||||
assert.throws(() => execFileSync(process.execPath, [resolve('scripts/vendor-sandbox-git.mjs'), '--offline', '--output', unrelated], { windowsHide: true, stdio: 'pipe' }), /Refusing to replace an existing directory/)
|
||||
check('vendoring refuses to move an unrelated existing output directory', await fs.readFile(join(unrelated, 'user-file.txt'), 'utf8') === 'preserve-user-data')
|
||||
if (process.env.YCODE_TEST_MINGIT_ARCHIVE) {
|
||||
const output = join(fixture, 'reproducible/git')
|
||||
execFileSync(process.execPath, [resolve('scripts/vendor-sandbox-git.mjs'), '--archive', resolve(process.env.YCODE_TEST_MINGIT_ARCHIVE), '--offline', '--output', output], { windowsHide: true, stdio: 'pipe', timeout: 60_000 })
|
||||
check('the pinned archive produces an identical manifest in an offline rebuild', (await verifyBundledGit(output)).manifestSha256 === bundle.manifestSha256)
|
||||
}
|
||||
console.log(`SANDBOX_BUNDLED_GIT_PASS ${checks.length}/${checks.length}`)
|
||||
} finally {
|
||||
if (originalPath === undefined) delete process.env.PATH; else process.env.PATH = originalPath
|
||||
await fs.writeFile(join(fixture, 'report.json'), JSON.stringify({ checks, fixture, resources, version: lock.version, scope: 'Real AppContainer execution using bundled Git with no user registration and empty host PATH; copied/actual packaged resources when supplied.' }, null, 2) + '\n')
|
||||
console.log(`SANDBOX_BUNDLED_GIT_REPORT ${join(fixture, 'report.json')}`)
|
||||
}
|
||||
Reference in new issue
Block a user