67 lines
3.3 KiB
JavaScript
67 lines
3.3 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import validation from '../src/shared/validation.cjs';
|
|
import redaction from '../src/main/log-redaction.cjs';
|
|
|
|
const {
|
|
normalizeBaseUrl,
|
|
assertRepositoryRelativePath,
|
|
assertRepositoryRelativePaths,
|
|
assertFullCommitSha,
|
|
assertWorkflowFile,
|
|
assertWorkflowFileName,
|
|
assertBranchName,
|
|
assertEnvironmentName,
|
|
assertHttpUrl,
|
|
assertCloneRemote
|
|
} = validation;
|
|
const { redactSecrets } = redaction;
|
|
|
|
test('rejects credentials embedded in service URLs', () => {
|
|
assert.throws(() => normalizeBaseUrl(`https://${['jens', 'secret'].join(':')}@gitea.example.test`), /credentials/i);
|
|
assert.throws(() => assertHttpUrl(`https://${['user', 'secret'].join(':')}@app.example.test/health`), /credentials/i);
|
|
});
|
|
|
|
test('accepts repository-relative paths but blocks escapes and absolute paths', () => {
|
|
assert.equal(assertRepositoryRelativePath('./src/main.ts'), 'src/main.ts');
|
|
assert.deepEqual(assertRepositoryRelativePaths(['src/main.ts', 'src/main.ts', 'docs/readme.md']), ['src/main.ts', 'docs/readme.md']);
|
|
assert.throws(() => assertRepositoryRelativePath('../secrets.txt'), /escape/i);
|
|
assert.throws(() => assertRepositoryRelativePath('/etc/passwd'), /absolute/i);
|
|
assert.throws(() => assertRepositoryRelativePath('C:\\Windows\\win.ini'), /absolute/i);
|
|
});
|
|
|
|
test('validates full commit SHAs and workflow filenames', () => {
|
|
const sha = 'A'.repeat(40);
|
|
assert.equal(assertFullCommitSha(sha), 'a'.repeat(40));
|
|
assert.equal(assertWorkflowFile('.gitea/workflows/deploy.yml'), '.gitea/workflows/deploy.yml');
|
|
assert.throws(() => assertFullCommitSha('abc1234'), /full commit SHA/i);
|
|
assert.throws(() => assertWorkflowFile('../deploy.yml'), /escape/i);
|
|
assert.throws(() => assertWorkflowFile('deploy.sh'), /YAML/i);
|
|
assert.equal(assertWorkflowFileName('deploy.yml'), 'deploy.yml');
|
|
assert.throws(() => assertWorkflowFileName('.gitea/workflows/deploy.yml'), /filename/i);
|
|
});
|
|
|
|
test('allows supported Git remotes and rejects unsafe protocols/passwords', () => {
|
|
assert.equal(assertCloneRemote('git@gitea.example.test:jens/app.git'), 'git@gitea.example.test:jens/app.git');
|
|
assert.equal(assertCloneRemote('ssh://git@gitea.example.test/jens/app.git'), 'ssh://git@gitea.example.test/jens/app.git');
|
|
assert.throws(() => assertCloneRemote('file:///tmp/repo.git'), /unsupported/i);
|
|
assert.throws(() => assertCloneRemote(`https://${['jens', 'secret'].join(':')}@gitea.example.test/jens/app.git`), /password/i);
|
|
});
|
|
|
|
test('redacts known tokens, authorization headers, query tokens and URL passwords', () => {
|
|
const token = 'super-secret-token';
|
|
const source = `Authorization: token ${token}\nhttps://gitea.test/api?access_token=${token}\nhttps://${['jens', 'password'].join(':')}@gitea.test\n${token}`;
|
|
const result = redactSecrets(source, [token]);
|
|
assert.doesNotMatch(result, /super-secret-token|password/);
|
|
assert.match(result, /\[REDACTED\]/);
|
|
});
|
|
|
|
|
|
test('validates deployment branch and environment identifiers', () => {
|
|
assert.equal(assertBranchName('release/staging'), 'release/staging');
|
|
assert.equal(assertEnvironmentName('Production-EU'), 'production-eu');
|
|
assert.throws(() => assertBranchName('-dangerous'), /invalid/i);
|
|
assert.throws(() => assertBranchName('main..backup'), /invalid/i);
|
|
assert.throws(() => assertEnvironmentName('production eu'), /environment/i);
|
|
});
|