mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-21 00:38:14 +08:00
132 lines
4.1 KiB
JavaScript
132 lines
4.1 KiB
JavaScript
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs');
|
|
const os = require('node:os');
|
|
const path = require('node:path');
|
|
const { test } = require('node:test');
|
|
const {
|
|
POSTGRES_CA_MAX_CERTIFICATES,
|
|
POSTGRES_CA_MAX_FILE_BYTES,
|
|
PostgresCertificateAuthorityFileError,
|
|
inspectPostgresCertificateAuthorityFile,
|
|
loadPostgresCertificateAuthorityFile,
|
|
} = require('@qinglong/cluster-postgres/runtime');
|
|
|
|
const FIXTURES = path.resolve(
|
|
__dirname,
|
|
'../../ql3-cluster-control/test/fixtures/mtls',
|
|
);
|
|
const CA = fs.readFileSync(path.join(FIXTURES, 'ca-cert.pem'), 'utf8');
|
|
|
|
function temporaryDirectory(t) {
|
|
const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'ql3-pg-ca-'));
|
|
t.after(() => fs.rmSync(directory, { recursive: true, force: true }));
|
|
return directory;
|
|
}
|
|
|
|
function expectCode(callback, code) {
|
|
assert.throws(
|
|
callback,
|
|
(error) =>
|
|
error instanceof PostgresCertificateAuthorityFileError &&
|
|
error.code === code,
|
|
);
|
|
}
|
|
|
|
test('loads a bounded CA bundle through a projected-Secret symlink', (t) => {
|
|
const directory = temporaryDirectory(t);
|
|
const dataDirectory = path.join(directory, '..data');
|
|
fs.mkdirSync(dataDirectory);
|
|
fs.writeFileSync(path.join(dataDirectory, 'ca.crt'), CA, { mode: 0o444 });
|
|
fs.symlinkSync(path.join('..data', 'ca.crt'), path.join(directory, 'ca.crt'));
|
|
|
|
const bundle = loadPostgresCertificateAuthorityFile(
|
|
path.join(directory, 'ca.crt'),
|
|
);
|
|
assert.match(bundle, /^-----BEGIN CERTIFICATE-----/);
|
|
assert.match(bundle, /-----END CERTIFICATE-----\n$/);
|
|
|
|
const inspection = inspectPostgresCertificateAuthorityFile(
|
|
path.join(directory, 'ca.crt'),
|
|
);
|
|
assert.equal(inspection.bundle, bundle);
|
|
assert.equal(inspection.fingerprints256.length, 1);
|
|
assert.match(
|
|
inspection.fingerprints256[0],
|
|
/^(?:[0-9A-F]{2}:){31}[0-9A-F]{2}$/,
|
|
);
|
|
assert.equal(Object.isFrozen(inspection), true);
|
|
assert.equal(Object.isFrozen(inspection.fingerprints256), true);
|
|
});
|
|
|
|
test('rejects ambiguous paths, file types, permissions and sizes', (t) => {
|
|
const directory = temporaryDirectory(t);
|
|
expectCode(
|
|
() => loadPostgresCertificateAuthorityFile('relative-ca.pem'),
|
|
'QL3_POSTGRES_CA_INVALID_PATH',
|
|
);
|
|
expectCode(
|
|
() =>
|
|
loadPostgresCertificateAuthorityFile(path.join(directory, 'missing.pem')),
|
|
'QL3_POSTGRES_CA_UNAVAILABLE',
|
|
);
|
|
expectCode(
|
|
() => loadPostgresCertificateAuthorityFile(directory),
|
|
'QL3_POSTGRES_CA_NOT_REGULAR',
|
|
);
|
|
|
|
const writable = path.join(directory, 'writable.pem');
|
|
fs.writeFileSync(writable, CA, { mode: 0o666 });
|
|
fs.chmodSync(writable, 0o666);
|
|
expectCode(
|
|
() => loadPostgresCertificateAuthorityFile(writable),
|
|
'QL3_POSTGRES_CA_INSECURE_PERMISSIONS',
|
|
);
|
|
|
|
const oversized = path.join(directory, 'oversized.pem');
|
|
fs.writeFileSync(oversized, Buffer.alloc(POSTGRES_CA_MAX_FILE_BYTES + 1), {
|
|
mode: 0o444,
|
|
});
|
|
expectCode(
|
|
() => loadPostgresCertificateAuthorityFile(oversized),
|
|
'QL3_POSTGRES_CA_INVALID_SIZE',
|
|
);
|
|
});
|
|
|
|
test('rejects malformed, non-CA, duplicate and oversized bundles', (t) => {
|
|
const directory = temporaryDirectory(t);
|
|
const malformed = path.join(directory, 'malformed.pem');
|
|
fs.writeFileSync(malformed, `${CA}\nunreviewed`, { mode: 0o444 });
|
|
expectCode(
|
|
() => loadPostgresCertificateAuthorityFile(malformed),
|
|
'QL3_POSTGRES_CA_INVALID_PEM',
|
|
);
|
|
|
|
const nonCa = path.join(directory, 'non-ca.pem');
|
|
fs.copyFileSync(path.join(FIXTURES, 'server-cert.pem'), nonCa);
|
|
fs.chmodSync(nonCa, 0o444);
|
|
expectCode(
|
|
() => loadPostgresCertificateAuthorityFile(nonCa),
|
|
'QL3_POSTGRES_CA_NOT_CA',
|
|
);
|
|
|
|
const duplicate = path.join(directory, 'duplicate.pem');
|
|
fs.writeFileSync(duplicate, `${CA}\n${CA}`, { mode: 0o444 });
|
|
expectCode(
|
|
() => loadPostgresCertificateAuthorityFile(duplicate),
|
|
'QL3_POSTGRES_CA_DUPLICATE_CERTIFICATE',
|
|
);
|
|
|
|
const tooMany = path.join(directory, 'too-many.pem');
|
|
fs.writeFileSync(
|
|
tooMany,
|
|
Array.from({ length: POSTGRES_CA_MAX_CERTIFICATES + 1 }, () => CA).join(
|
|
'\n',
|
|
),
|
|
{ mode: 0o444 },
|
|
);
|
|
expectCode(
|
|
() => loadPostgresCertificateAuthorityFile(tooMany),
|
|
'QL3_POSTGRES_CA_TOO_MANY_CERTIFICATES',
|
|
);
|
|
});
|