53 lines
3.2 KiB
JavaScript
53 lines
3.2 KiB
JavaScript
import test from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
import fs from 'node:fs'
|
|
import path from 'node:path'
|
|
import os from 'node:os'
|
|
import { execFileSync } from 'node:child_process'
|
|
import { frontendRoot, validTag, shellQuote, deploymentTarget, validateEntries, inspectPackage, bashExecutable } from './release.mjs'
|
|
import { installScript } from './deploy-test.mjs'
|
|
|
|
test('release and SSH inputs reject paths, options and shell injection', () => {
|
|
for (const value of ['', '../release', '-latest', 'a;touch x', 'a\nother']) assert.throws(() => validTag(value))
|
|
assert.equal(validTag('a846bd90-rc.1'), 'a846bd90-rc.1')
|
|
for (const args of [{ host: '-oProxyCommand=id' }, { user: 'root;id' }, { directory: '/' }, { directory: '/www/../etc' }, { port: '65536' }]) assert.throws(() => deploymentTarget(args))
|
|
assert.equal(shellQuote("a'b$(id)"), "'a'\\''b$(id)'")
|
|
assert.equal(deploymentTarget().base, '/www/wwwroot/sw2.fuhua91.com')
|
|
})
|
|
|
|
test('runtime archives exclude backend source and filesystem links', () => {
|
|
const required = ['./Dockerfile', './nginx.conf', './deploy.sh', './release.json', './dist/index.html', './dist/version.txt']
|
|
validateEntries(required, required.map(() => '-'))
|
|
for (const extra of ['../outside', '/etc/passwd', './dist/../../outside', './backend/app', './internal/data.go', './dist\\..\\outside']) assert.throws(() => validateEntries([...required, extra], required.map(() => '-')))
|
|
for (const type of ['l', 'h', 'p', 'b']) assert.throws(() => validateEntries(required, ['-', type]))
|
|
})
|
|
|
|
test('package inspection verifies embedded version and reads the actual archive checksum', () => {
|
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'sw-frontend-release-test-'))
|
|
try {
|
|
const stage = path.join(root, 'stage'); fs.mkdirSync(path.join(stage, 'dist'), { recursive: true })
|
|
for (const file of ['Dockerfile', 'nginx.conf', 'deploy.sh', 'dist/index.html']) fs.writeFileSync(path.join(stage, file), 'test\n')
|
|
fs.writeFileSync(path.join(stage, 'release.json'), JSON.stringify({ formatVersion: 1, version: 'test-1', revision: 'a'.repeat(40), tree: 'b'.repeat(40) }))
|
|
fs.writeFileSync(path.join(stage, 'dist/version.txt'), 'test-1\n')
|
|
const archive = path.join(root, 'release.tar.gz')
|
|
execFileSync('tar', ['-czf', archive, '-C', stage, '.'])
|
|
const result = inspectPackage(archive)
|
|
assert.equal(result.info.version, 'test-1')
|
|
assert.match(result.checksum, /^[a-f0-9]{64}$/)
|
|
fs.writeFileSync(path.join(stage, 'dist/version.txt'), 'wrong-version\n')
|
|
execFileSync('tar', ['-czf', archive, '-C', stage, '.'])
|
|
assert.throws(() => inspectPackage(archive), /版本标记不一致/)
|
|
} finally {
|
|
assert.equal(path.dirname(root), path.resolve(os.tmpdir()))
|
|
fs.rmSync(root, { recursive: true })
|
|
}
|
|
})
|
|
|
|
test('server shell syntax and deployment rollback preserve the backend', () => {
|
|
const bash = bashExecutable()
|
|
execFileSync(bash, ['-n', 'deploy/deploy.sh'], { cwd: frontendRoot })
|
|
execFileSync(bash, ['-n'], { input: installScript, cwd: frontendRoot })
|
|
const output = execFileSync(bash, ['deploy/deploy.test.sh'], { cwd: frontendRoot, encoding: 'utf8' })
|
|
assert.match(output, /all deployment scenarios passed/)
|
|
})
|