48 lines
2.8 KiB
JavaScript
48 lines
2.8 KiB
JavaScript
'use strict';
|
|
|
|
const assert = require('node:assert/strict');
|
|
const crypto = require('node:crypto');
|
|
const test = require('node:test');
|
|
const { createCompanionWorkerService } = require('../../src/services/companion-worker-service');
|
|
|
|
function fixture() {
|
|
const values = new Map(); const secretValues = new Map();
|
|
const settings = { get: (key, fallback) => values.has(key) ? values.get(key) : fallback, set: (key, value) => values.set(key, value) };
|
|
const secrets = { has: key => secretValues.has(key), get: key => secretValues.get(key) || '', set: (key, value) => value ? secretValues.set(key, value) : secretValues.delete(key) };
|
|
return { settings, secrets, secretValues };
|
|
}
|
|
|
|
test('companion workers require HTTPS and never accept shell or arbitrary path jobs', () => {
|
|
const f = fixture(); const service = createCompanionWorkerService(f);
|
|
assert.throws(() => service.save({ id: 'win-one', endpoint: 'http://worker.local:9443' }), /HTTPS/);
|
|
service.save({ id: 'win-one', endpoint: 'https://worker.local:9443' });
|
|
const pairing = service.pair('win-one');
|
|
assert.equal(pairing.shownOnce, true);
|
|
assert.equal(pairing.pairingKey.length, 64);
|
|
const key = Buffer.from(pairing.pairingKey, 'hex');
|
|
assert.throws(() => service.signedJob(key, 'win-one', { type: 'shell', artifactId: 'game:1', outputSlot: 'exports' }), /workertype/);
|
|
assert.throws(() => service.signedJob(key, 'win-one', { type: 'exfat', artifactId: '../../etc', outputSlot: 'exports' }), /uitsluitend/);
|
|
const job = service.signedJob(key, 'win-one', { type: 'exfat', artifactId: 'game:1', outputSlot: 'exports' });
|
|
assert.equal(job.job.type, 'exfat');
|
|
assert.equal(Object.prototype.hasOwnProperty.call(job.job, 'path'), false);
|
|
assert.equal(Object.prototype.hasOwnProperty.call(job.job, 'command'), false);
|
|
});
|
|
|
|
test('capability response must be nonce-bound, HMAC-authenticated and allowlisted', async () => {
|
|
const f = fixture(); let key;
|
|
const fetchImpl = async (_url, options) => {
|
|
const nonce = options.headers['X-Chimera-Nonce'];
|
|
const payload = Buffer.from(JSON.stringify({ version: '1.0.0', capabilities: ['exfat', 'shell'], slots: ['exports', '../../bad'], limits: { maxInputBytes: 123 } })).toString('base64');
|
|
const transcript = `capabilities|win-one|${nonce}|${payload}`;
|
|
return { ok: true, json: async () => ({ schema: 1, workerId: 'win-one', nonce, payload, hmac: crypto.createHmac('sha256', key).update(transcript).digest('hex') }) };
|
|
};
|
|
const service = createCompanionWorkerService({ ...f, fetchImpl });
|
|
service.save({ id: 'win-one', endpoint: 'https://worker.local:9443' });
|
|
key = Buffer.from(service.pair('win-one').pairingKey, 'hex');
|
|
const result = await service.capabilities('win-one');
|
|
assert.deepEqual(result.capabilities, ['exfat']);
|
|
assert.deepEqual(result.slots, ['exports']);
|
|
assert.equal(result.shell, false);
|
|
assert.equal(result.arbitraryPaths, false);
|
|
});
|