mirror of
https://github.com/zitadel/zitadel.git
synced 2026-07-25 18:28:00 +00:00
# Which Problems Are Solved For switching v4.x releases to a corresponding maintenance branch, we had to trick semantic release and create a `5.0.0-base` tag on main. This now breaks the docs build, which tries to fetch all tags and build a corresponding version. # How the Problems Are Solved - Ignore pre-released tags/releases for the moment. # Additional Changes None # Additional Context - requires backport to v4.x
162 lines
6.0 KiB
JavaScript
162 lines
6.0 KiB
JavaScript
import { test, describe, beforeEach, afterEach, mock } from 'node:test';
|
|
import assert from 'node:assert';
|
|
import fs from 'fs';
|
|
import path from 'path';
|
|
import { getCurrentRef, resetCache, downloadFileContent, isValidRef, safeLog } from './fetch-remote-content.mjs';
|
|
|
|
const TEST_TMP_DIR = path.join(process.cwd(), '.test-tmp');
|
|
const MOCK_REPO_ROOT = path.join(TEST_TMP_DIR, 'mock-repo');
|
|
|
|
describe('fetch-remote-content', () => {
|
|
|
|
// --- Setup & Teardown ---
|
|
const originalEnv = process.env;
|
|
|
|
beforeEach(() => {
|
|
process.env = { ...originalEnv };
|
|
resetCache();
|
|
|
|
// Set up a mock repo structure
|
|
if (fs.existsSync(TEST_TMP_DIR)) {
|
|
fs.rmSync(TEST_TMP_DIR, { recursive: true, force: true });
|
|
}
|
|
fs.mkdirSync(MOCK_REPO_ROOT, { recursive: true });
|
|
|
|
// Create some dummy content
|
|
fs.writeFileSync(path.join(MOCK_REPO_ROOT, 'README.md'), '# Mock Repo');
|
|
fs.mkdirSync(path.join(MOCK_REPO_ROOT, 'secrets'), { recursive: true });
|
|
fs.writeFileSync(path.join(MOCK_REPO_ROOT, 'secrets/passwd'), 'super_secret');
|
|
});
|
|
|
|
afterEach(() => {
|
|
process.env = originalEnv;
|
|
mock.restoreAll();
|
|
resetCache();
|
|
if (fs.existsSync(TEST_TMP_DIR)) {
|
|
fs.rmSync(TEST_TMP_DIR, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
// --- Helper Tests ---
|
|
describe('isValidRef', () => {
|
|
test('accepts valid alphanumeric refs', () => {
|
|
assert.strictEqual(isValidRef('main'), true);
|
|
assert.strictEqual(isValidRef('v1.0.0'), true);
|
|
assert.strictEqual(isValidRef('feature/new-docs'), true);
|
|
assert.strictEqual(isValidRef('fix_bug-123'), true);
|
|
assert.strictEqual(isValidRef('dependabot/npm_and_yarn/@types/react'), true);
|
|
assert.strictEqual(isValidRef('build+test'), true);
|
|
});
|
|
|
|
test('rejects malicious refs', () => {
|
|
assert.strictEqual(isValidRef('; rm -rf'), false);
|
|
assert.strictEqual(isValidRef('main && echo pwned'), false);
|
|
assert.strictEqual(isValidRef('../parent'), false); // contains .. which isn't allowed in regex
|
|
});
|
|
});
|
|
|
|
describe('safeLog', () => {
|
|
test('strips newlines', () => {
|
|
assert.strictEqual(safeLog('valid'), 'valid');
|
|
assert.strictEqual(safeLog('malicious\nlog'), 'maliciouslog');
|
|
assert.strictEqual(safeLog('malicious\r\nlog'), 'maliciouslog');
|
|
});
|
|
});
|
|
|
|
// --- getCurrentRef Tests ---
|
|
describe('getCurrentRef', () => {
|
|
test('returns VERCEL_GIT_COMMIT_REF if set and valid', () => {
|
|
process.env.VERCEL_GIT_COMMIT_REF = 'vercel-branch';
|
|
delete process.env.GITHUB_REF_NAME;
|
|
assert.strictEqual(getCurrentRef(), 'vercel-branch');
|
|
});
|
|
|
|
test('ignores invalid VERCEL_GIT_COMMIT_REF', () => {
|
|
// Should fall through to GITHUB or git command
|
|
process.env.VERCEL_GIT_COMMIT_REF = 'invalid;cmd';
|
|
process.env.GITHUB_REF_NAME = 'valid-github';
|
|
assert.strictEqual(getCurrentRef(), 'valid-github');
|
|
});
|
|
|
|
test('returns GITHUB_REF_NAME if set and valid', () => {
|
|
delete process.env.VERCEL_GIT_COMMIT_REF;
|
|
process.env.GITHUB_REF_NAME = 'github-branch';
|
|
assert.strictEqual(getCurrentRef(), 'github-branch');
|
|
});
|
|
});
|
|
|
|
// --- downloadFileContent Tests ---
|
|
describe('downloadFileContent', () => {
|
|
|
|
test('refuses traversal attempts (..)', async () => {
|
|
// We expect this to return null and log a warning
|
|
const content = await downloadFileContent('main', '../secrets/passwd');
|
|
assert.strictEqual(content, null);
|
|
});
|
|
|
|
test('refuses absolute paths', async () => {
|
|
const content = await downloadFileContent('main', '/etc/passwd');
|
|
assert.strictEqual(content, null);
|
|
});
|
|
|
|
test('refuses encoded traversal attempts', async () => {
|
|
// %2e%2e is ..
|
|
const content = await downloadFileContent('main', '%2e%2e/secrets/passwd');
|
|
assert.strictEqual(content, null);
|
|
});
|
|
|
|
test('reads valid local file (README.md)', async () => {
|
|
// Mock getCurrentRef to return 'main' and pass 'main' to simulate local
|
|
process.env.VERCEL_GIT_COMMIT_REF = 'main';
|
|
|
|
const content = await downloadFileContent('main', 'README.md');
|
|
// It should find the real README.md of the project since the script resolves from __dirname
|
|
assert.ok(content);
|
|
assert.ok(content.length > 0);
|
|
});
|
|
|
|
test('refuses invalid ref strings', async () => {
|
|
// Validation check for command injection protection
|
|
const content = await downloadFileContent('invalid; rm -rf', 'README.md');
|
|
assert.strictEqual(content, null);
|
|
});
|
|
});
|
|
|
|
// --- filterVersions Tests ---
|
|
describe('filterVersions', () => {
|
|
test('filters versions older than CUTOFF (4.10.0)', async () => {
|
|
const { filterVersions } = await import('./fetch-remote-content.mjs');
|
|
const tags = [
|
|
{ name: 'v4.9.0' },
|
|
{ name: 'v4.10.0' }, // Equal to cutoff — excluded (gt is strict)
|
|
{ name: 'v4.11.0' },
|
|
{ name: 'invalid' }
|
|
];
|
|
|
|
const result = filterVersions(tags);
|
|
assert.ok(result.includes('v4.11.0'));
|
|
assert.ok(!result.includes('v4.10.0'));
|
|
assert.ok(!result.includes('v4.9.0'));
|
|
});
|
|
|
|
test('excludes prerelease tags', async () => {
|
|
const { filterVersions } = await import('./fetch-remote-content.mjs');
|
|
const tags = [
|
|
{ name: 'v5.0.0' },
|
|
{ name: 'v5.0.0-alpha' },
|
|
{ name: 'v5.0.0-beta.1' },
|
|
{ name: 'v4.11.0-rc.1' },
|
|
{ name: 'v4.11.0' },
|
|
];
|
|
|
|
const result = filterVersions(tags);
|
|
assert.ok(result.includes('v5.0.0'), 'stable release should be included');
|
|
assert.ok(result.includes('v4.11.0'), 'stable release should be included');
|
|
assert.ok(!result.includes('v5.0.0-alpha'), 'alpha prerelease should be excluded');
|
|
assert.ok(!result.includes('v5.0.0-beta.1'), 'beta prerelease should be excluded');
|
|
assert.ok(!result.includes('v4.11.0-rc.1'), 'rc prerelease should be excluded');
|
|
});
|
|
});
|
|
|
|
});
|