Files
UNITRONIX abc00b8804 feat(guest): enforce scoped guest access lifecycle
Bind guest WebSocket sessions to a single target peer, enforce grant lifecycle and atomic usage, add the guest issuer scope, and document the password-less security boundary.\n\nRefs #440\n\nThanks: INSOLVE (Honorary); Marco Jakobs (@jacotec); MyNameisStitch (@MyNameisStitch); Redspin (@playerumpknow)
2026-10-03 10:22:20 +02:00

117 lines
4.4 KiB
JavaScript

'use strict';
const assert = require('node:assert/strict');
const test = require('node:test');
const {
OUT_OF_SCOPE,
atLeastVersion,
calculateOverall,
containsUnexpectedSkip,
discoverSecurityManifests,
extractPyprojectDependencies,
formatCommand,
parseArgs,
parseVersion,
processInvocation,
redactSensitive,
resultStatus,
run,
} = require('./local-gate');
test('argument parsing keeps the gate local and supports dry runs', () => {
const options = parseArgs(['--dry-run', '--report-dir', '.local-test-results/test']);
assert.equal(options.dryRun, true);
assert.match(options.reportDir, /local-test-results[\\/]+test$/u);
});
test('command formatting redacts database credentials', () => {
const command = formatCommand('node', [
'scripts/local-docker-smoke.js',
'--database-url',
'postgres://user:password@example.test:5432/db?sslmode=disable',
]);
assert.match(command, /postgres:\/\/user:\[REDACTED\]@example\.test/u);
assert.doesNotMatch(command, /password/u);
});
test('captured diagnostics redact passwords and bearer tokens', () => {
const safe = redactSensitive(
'password=plain-secret token:plain-token Authorization: Bearer bearer-secret',
);
assert.doesNotMatch(safe, /plain-secret|plain-token|bearer-secret/u);
assert.match(safe, /\[REDACTED\]/u);
});
test('Windows command shims are invoked through cmd.exe', () => {
const invocation = processInvocation('npm.cmd', ['--version']);
if (process.platform === 'win32') {
assert.equal(invocation.command, 'cmd.exe');
assert.deepEqual(invocation.args.slice(0, 3), ['/d', '/s', '/c']);
assert.match(invocation.args[3], /npm\.cmd --version/u);
} else {
assert.equal(invocation.command, 'npm.cmd');
}
});
test('skips are blocking unless explicitly allowed', () => {
assert.equal(containsUnexpectedSkip('--- SKIP: Docker is not available'), true);
assert.equal(containsUnexpectedSkip('Tests: 12 passed, 0 skipped'), false);
assert.equal(resultStatus({ code: 0, stdout: 'SKIP: unavailable', stderr: '' }), 'BLOCKED');
assert.equal(
resultStatus({ code: 0, stdout: 'SKIP: unavailable', stderr: '' }, { allowSkip: true }),
'PASS',
);
assert.equal(
resultStatus({ code: 0, stdout: '1 skipped', stderr: '' }, { expectedSkip: true }),
'OUT_OF_SCOPE',
);
assert.equal(resultStatus({ code: null, error: { code: 'ENOENT' } }), 'BLOCKED');
});
test('version checks compare semantic versions conservatively', () => {
assert.deepEqual(parseVersion('go version go1.26.6 windows/amd64'), {
major: 1,
minor: 26,
patch: 6,
});
assert.equal(atLeastVersion(parseVersion('v22.1.0'), { major: 22, minor: 0, patch: 0 }), true);
assert.equal(atLeastVersion(parseVersion('v21.9.0'), { major: 22, minor: 0, patch: 0 }), false);
});
test('security manifest discovery includes all dependency ecosystems', () => {
const manifests = discoverSecurityManifests();
assert.ok(manifests.pythonRequirements.some((file) => file.endsWith('bridges\\modbus\\requirements.txt')
|| file.endsWith('bridges/modbus/requirements.txt')));
assert.ok(manifests.pythonProjects.some((file) => file.endsWith('sdks\\python\\pyproject.toml')
|| file.endsWith('sdks/python/pyproject.toml')));
assert.deepEqual(manifests.rustProjects, []);
});
test('Python project dependencies can be converted for pip-audit', () => {
const dependencies = extractPyprojectDependencies('sdks/python/pyproject.toml');
assert.deepEqual(dependencies, ['websockets>=12.0']);
});
test('overall status blocks on required failures but ignores explicit boundaries', () => {
const report = {
results: [
{ status: 'PASS', required: true },
{ status: 'OUT_OF_SCOPE', required: false },
],
};
assert.equal(calculateOverall(report), 'PASS');
report.results.push({ status: 'BLOCKED', required: true });
assert.equal(calculateOverall(report), 'BLOCKED');
report.results.push({ status: 'FAIL', required: true });
assert.equal(calculateOverall(report), 'FAIL');
assert.equal(OUT_OF_SCOPE.length >= 1, true);
});
test('dry run does not execute the external test suites', async () => {
const report = await run({ dryRun: true });
assert.equal(report.dryRun, true);
assert.equal(report.overall, 'PASS');
assert.equal(report.results.length, 0);
});