55 lines
4.1 KiB
JavaScript
55 lines
4.1 KiB
JavaScript
import test from 'node:test'
|
|||
|
|
import assert from 'node:assert/strict'
|
||
|
|
import { buildGrayEvidenceRemoteScript, createGrayEvidenceReaders, validateGrayEvidenceConfig } from './gray-regression-evidence.mjs'
|
||
|
|
|
||
|
|
const env = { JENKINS_URL: 'https://jenkins.example.invalid/', JENKINS_USER: 'reader', JENKINS_API_TOKEN: 'private-test-token' }
|
||
|
|
const probeSql = "SET NAMES utf8mb4 COLLATE utf8mb4_bin;\nSET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;\nSTART TRANSACTION WITH CONSISTENT SNAPSHOT, READ ONLY;\nSELECT JSON_OBJECT('grayProbe',1);\nCOMMIT;"
|
||
|
|
test('gray reader refuses missing credentials, embedded URL credentials and SQL mutations', () => {
|
||
|
|
assert.throws(() => validateGrayEvidenceConfig({}), /Missing/)
|
||
|
|
assert.throws(() => validateGrayEvidenceConfig({ ...env, JENKINS_URL: 'https://secret@host.invalid' }), /Invalid/)
|
||
|
|
assert.throws(() => buildGrayEvidenceRemoteScript('auth', probeSql), /target/)
|
||
|
|
assert.throws(() => buildGrayEvidenceRemoteScript('order', probeSql.replace('SELECT JSON_OBJECT', 'DELETE JSON_OBJECT')), /Read-only/)
|
||
|
|
})
|
||
|
|
test('gray SSH reader pins registered production host, known hosts, runtime and database credentials', () => {
|
||
|
|
const script = buildGrayEvidenceRemoteScript('order', probeSql)
|
||
|
|
for (const credential of ['ssh', 'host', 'known-hosts', 'env']) assert.ok(script.includes(`firstleg-production-${credential}`))
|
||
|
|
assert.ok(script.includes('StrictHostKeyChecking=yes'))
|
||
|
|
assert.ok(script.includes('finally {dir.listFiles().each{it.delete()};dir.delete()}'))
|
||
|
|
assert.ok(!script.includes('java-test-agent') && !script.includes('RemotingDiagnostics'))
|
||
|
|
const encodedPython = [...script.matchAll(/\['([A-Za-z0-9+/=]+)'(?:,'[A-Za-z0-9+/=]+')*\]\.join\(''\)/g)]
|
||
|
|
.map(match => [...match[0].matchAll(/'([A-Za-z0-9+/=]+)'/g)].map(part => part[1]).join(''))
|
||
|
|
const python = encodedPython.map(value => Buffer.from(value, 'base64').toString()).find(value => value.includes('subprocess'))
|
||
|
|
assert.ok(python?.includes("labels.get('com.docker.compose.project')!='firstleg-production'"))
|
||
|
|
assert.ok(python.includes("e.get(key)!=expected[key]"))
|
||
|
|
assert.ok(python.includes("u.path!='/'+ 'baiyue_order'"))
|
||
|
|
assert.ok(python.includes('READ ONLY') === false, 'SQL is encoded independently')
|
||
|
|
const lastleg = buildGrayEvidenceRemoteScript('lastleg', probeSql)
|
||
|
|
const payload = [...lastleg.matchAll(/\['([A-Za-z0-9+/=]+)'(?:,'[A-Za-z0-9+/=]+')*\]\.join\(''\)/g)]
|
||
|
|
.map(match => [...match[0].matchAll(/'([A-Za-z0-9+/=]+)'/g)].map(part => part[1]).join(''))
|
||
|
|
.map(value => Buffer.from(value, 'base64').toString()).find(value => value.includes('subprocess'))
|
||
|
|
assert.ok(payload.includes("labels.get('com.docker.compose.service')!='lastleg-service'"))
|
||
|
|
})
|
||
|
|
test('preflight performs only two scoped gray probes and never exposes remote raw errors', async () => {
|
||
|
|
const requests = []
|
||
|
|
const readers = createGrayEvidenceReaders(env, async (url, options) => {
|
||
|
|
requests.push({ url: String(url), script: options.body.get('script') })
|
||
|
|
return { ok: true, text: async () => 'GRAY_EVIDENCE_JSON={"ok":true,"rows":[{"grayProbe":1}]}\n' }
|
||
|
|
})
|
||
|
|
await readers.preflight()
|
||
|
|
assert.equal(requests.length, 2)
|
||
|
|
assert.ok(requests.every(request => request.url === 'https://jenkins.example.invalid/scriptText'))
|
||
|
|
const failed = createGrayEvidenceReaders(env, async () => ({ ok: true, text: async () => 'MYSQL_PWD=hidden\nTraceback secret-value' }))
|
||
|
|
await assert.rejects(failed.preflight(), error => error.message === 'Gray evidence JSON missing or ambiguous')
|
||
|
|
})
|
||
|
|
test('preflight rejects failed probes and ambiguous results', async () => {
|
||
|
|
for (const raw of ['GRAY_EVIDENCE_JSON={"ok":true,"rows":[{"grayProbe":0}]}',
|
||
|
|
'GRAY_EVIDENCE_JSON={"ok":false,"error":"MYSQL_1146"}',
|
||
|
|
'GRAY_EVIDENCE_JSON={}\nGRAY_EVIDENCE_JSON={}']) {
|
||
|
|
const readers = createGrayEvidenceReaders(env, async () => ({ ok: true, text: async () => raw }))
|
||
|
|
await assert.rejects(readers.preflight())
|
||
|
|
}
|
||
|
|
const sourceFailure = createGrayEvidenceReaders(env, async () => ({ ok: true,
|
||
|
|
text: async () => 'GRAY_EVIDENCE_JSON={"ok":false,"error":"GRAY_DATABASE_SOURCE_FAILED"}' }))
|
||
|
|
await assert.rejects(sourceFailure.preflight(), { message: 'GRAY_DATABASE_SOURCE_FAILED' })
|
||
|
|
})
|