ci: add Windows quality and packaging gates
Teach ESLint the classic renderer and mixed CommonJS harness runtimes while retaining actionable rules. Add deterministic credential, lockfile, release-manifest, and lint contracts plus equivalent GitHub and Gitea Windows pipelines. Gate clean installs, focused offline smoke coverage, builds, packaged launches, and silent installer verification without enabling authenticated network tests.
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
const test = require('node:test');
|
||||
|
||||
const securityCheck = require('./security-check');
|
||||
|
||||
test('detects credential material and private machine paths', () => {
|
||||
const githubToken = ['gh', 'p_', 'a'.repeat(40)].join('');
|
||||
const privateKey = ['-----BEGIN ', 'PRIVATE KEY-----'].join('');
|
||||
const source = `${githubToken}\n${privateKey}\nC:\\Users\\real-user\\AppData`;
|
||||
const findings = securityCheck.scanText('fixture.txt', source);
|
||||
|
||||
assert.deepEqual(findings.map((finding) => finding.rule).sort(), [
|
||||
'github-token',
|
||||
'private-key',
|
||||
'windows-user-path'
|
||||
]);
|
||||
});
|
||||
|
||||
test('accepts public source with secret field names but no credential value', () => {
|
||||
const findings = securityCheck.scanText('fixture.ts', "const client_secret = config.client_secret;\nconst token = '';\n");
|
||||
assert.deepEqual(findings, []);
|
||||
});
|
||||
|
||||
test('rejects public manifest traversal and symbolic links', () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'tvm-security-'));
|
||||
const outside = path.join(path.dirname(root), `${path.basename(root)}-outside.txt`);
|
||||
try {
|
||||
fs.writeFileSync(path.join(root, 'safe.txt'), 'safe', 'utf8');
|
||||
fs.writeFileSync(outside, 'outside', 'utf8');
|
||||
const entries = ['safe.txt', '../outside.txt'];
|
||||
const findings = securityCheck.inspectPublicFiles(root, entries);
|
||||
assert.ok(findings.some((finding) => finding.rule === 'manifest-path'));
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
fs.symlinkSync(outside, path.join(root, 'linked.txt'), 'file');
|
||||
const linkedFindings = securityCheck.inspectPublicFiles(root, ['linked.txt']);
|
||||
assert.ok(linkedFindings.some((finding) => finding.rule === 'manifest-symlink'));
|
||||
}
|
||||
} finally {
|
||||
fs.rmSync(root, { recursive: true, force: true });
|
||||
fs.rmSync(outside, { force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test('requires registry dependency integrity in the lockfile', () => {
|
||||
const lockfile = {
|
||||
lockfileVersion: 3,
|
||||
packages: {
|
||||
'': { dependencies: { example: '^1.0.0' } },
|
||||
'node_modules/example': {
|
||||
version: '1.0.0',
|
||||
resolved: 'https://registry.npmjs.org/example/-/example-1.0.0.tgz'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const findings = securityCheck.inspectLockfile(lockfile);
|
||||
assert.ok(findings.some((finding) => finding.rule === 'dependency-integrity'));
|
||||
});
|
||||
Reference in New Issue
Block a user