Account for runtime RCON passwords in config drift
This commit is contained in:
@@ -26,6 +26,8 @@ async function setup(capable = true) {
|
||||
VALUES(?,'t5','zombie_theater','zombie','theater','ui')`).run(server);
|
||||
database.prepare(`INSERT INTO native_instances(id,server,host_id,library_id,image,port,created_at)
|
||||
VALUES(?,?,?,'library','image',28960,?)`).run(randomUUID(), server, host.id, new Date().toISOString());
|
||||
database.prepare(`INSERT INTO ec_host_operations(id,host_id,instance_id,generation,kind,payload,state,created_at,updated_at)
|
||||
SELECT 'launch',host_id,id,generation,'instance.create','{}','completed',created_at,created_at FROM native_instances WHERE server=?`).run(server);
|
||||
|
||||
const { createScript } = await import('../../src/lib/server/fleet/scripts.js');
|
||||
const { recordScript } = await import('../../src/lib/server/fleet/inventory.js');
|
||||
@@ -94,6 +96,45 @@ function expectOneManifest(request: Awaited<ReturnType<typeof setup>>['request']
|
||||
}
|
||||
|
||||
describe('native drift manifests', () => {
|
||||
it.each([true, false])('reconciles verified startup password changes without writing server files (manifest: %s)', async capable => {
|
||||
const api = await setup(capable);
|
||||
const { applyRuntimePassword } = await import('../../src/lib/server/fleet/runtime-config.js');
|
||||
const { getServerScript, recordScript } = await import('../../src/lib/server/fleet/inventory.js');
|
||||
const promoted = Buffer.from('set rcon_password "password"\nset sv_maprotation "map zombie_theater"\n');
|
||||
const { uploadNewVersion } = await import('../../src/lib/server/fleet/scripts.js');
|
||||
// Replace the promoted baseline bytes, retaining a legacy inventory hash.
|
||||
const next = uploadNewVersion(api.baseline.script.id, promoted);
|
||||
api.database.prepare('UPDATE scripts SET current_version_id=? WHERE id=?').run(next.id, api.baseline.script.id);
|
||||
const password = 'a'.repeat(64);
|
||||
api.database.prepare('UPDATE ec_host_operations SET payload=? WHERE id=?').run(JSON.stringify({ rconPassword: password }), 'launch');
|
||||
recordScript(server, 'dedicated_sp.cfg', null, hash(promoted), promoted.length, 'native-create');
|
||||
const effective = Buffer.from(applyRuntimePassword(promoted.toString(), password));
|
||||
expect(effective.length - promoted.length).toBe(56);
|
||||
api.contents.set('configs/dedicated_sp.cfg', effective);
|
||||
|
||||
expect(await api.scanServerDrift(server)).toEqual([]);
|
||||
expect(getServerScript(server, 'dedicated_sp.cfg')).toMatchObject({ sha256: hash(effective), size: effective.length,
|
||||
source: 'runtime-config-reconciliation' });
|
||||
if (capable) expectOneManifest(api.request);
|
||||
expect((await api.prepareDriftCampaign(server)).plan.files).toEqual([]);
|
||||
|
||||
// A wrong password of the same length is still real drift.
|
||||
api.contents.set('configs/dedicated_sp.cfg', Buffer.from(applyRuntimePassword(promoted.toString(), 'b'.repeat(64))));
|
||||
expect(await api.scanServerDrift(server)).toEqual([expect.objectContaining({ relPath: 'dedicated_sp.cfg', driftKind: 'replace' })]);
|
||||
if (!capable) {
|
||||
const repair = await api.prepareDriftCampaign(server);
|
||||
expect(repair.files[0].after).toEqual(effective);
|
||||
}
|
||||
api.contents.set('configs/dedicated_sp.cfg', Buffer.concat([effective, Buffer.from('set sv_voice "0"\n')]));
|
||||
expect(await api.scanServerDrift(server)).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('reports unavailable credentials as a scan failure rather than scheduling a destructive repair', async () => {
|
||||
const api = await setup();
|
||||
api.database.prepare("UPDATE ec_host_operations SET history_expired_at='expired',payload='{}' WHERE id='launch'").run();
|
||||
await expect(api.scanServerDrift(server)).rejects.toThrow('launch credentials are unavailable');
|
||||
});
|
||||
|
||||
it('checks managed files, composed config, generated config, and untracked trees in one request', async () => {
|
||||
const api = await setup();
|
||||
expect(await api.scanServerDrift(server)).toEqual([]);
|
||||
|
||||
Reference in New Issue
Block a user