diff --git a/src/features/os-config/index.ts b/src/features/os-config/index.ts index 4885a972b0..cc8273aade 100644 --- a/src/features/os-config/index.ts +++ b/src/features/os-config/index.ts @@ -1,27 +1,51 @@ -import type { Application, RequestHandler } from 'express'; +import type { Application } from 'express'; import { DEVICE_CONFIG_OPENVPN_CA, DEVICE_CONFIG_OPENVPN_CONFIG, DEVICE_CONFIG_SSH_AUTHORIZED_KEYS, + LOGS_HOST, } from '../../lib/config'; import { b64decode } from '../../lib/utils'; -const getOsConfiguration: RequestHandler = (_req, res) => { - res.json({ - services: { - openvpn: { - config: DEVICE_CONFIG_OPENVPN_CONFIG, - ca: b64decode(DEVICE_CONFIG_OPENVPN_CA), - }, - ssh: { - authorized_keys: DEVICE_CONFIG_SSH_AUTHORIZED_KEYS, - }, - }, - schema_version: '1.0.0', - }); +// OS service configurations +const services = { + openvpn: { + config: DEVICE_CONFIG_OPENVPN_CONFIG, + ca: b64decode(DEVICE_CONFIG_OPENVPN_CA), + }, + ssh: { + authorized_keys: DEVICE_CONFIG_SSH_AUTHORIZED_KEYS, + }, +}; + +// Config.json migrations: changes should be evaluated for security risks before applying. +// +// - A field with a value of `null` tells os-config that the value will be deleted from config.json. +// - A field with a value of non-null tells os-config that the value will be updated to the new value if it's different. +// - Delete takes precedence over update. +// - A field not found in the whitelist of the os-config schema will be ignored. +const config = { + overrides: { + logsEndpoint: LOGS_HOST != null ? `https://${LOGS_HOST}` : null, + }, }; export const setup = (app: Application) => { - app.get('/os/v1/config/', getOsConfiguration); + app.get('/os/v1/config/', (_req, res) => { + res.json({ + services, + schema_version: '1.0.0', + }); + }); + // This endpoint no longer sees the need to include a schema_version in the response, as os-configs + // that query it all follow the v2 os-config schema. The contract between os-config and this endpoint + // is that os-config should be compatible with all minor changes to `config` as defined above. `config` + // refers to config.json migrations required by the API. + app.get('/os/v2/config', (_req, res) => { + res.json({ + services, + config, + }); + }); }; diff --git a/test/22_os-config.ts b/test/22_os-config.ts new file mode 100644 index 0000000000..e2e6d17ed5 --- /dev/null +++ b/test/22_os-config.ts @@ -0,0 +1,34 @@ +import { expect } from 'chai'; + +import { supertest } from './test-lib/supertest'; +import { LOGS_HOST } from '../src/lib/config'; + +describe('OS configuration endpoints', () => { + describe('/os/v1/config', () => { + it('should return a valid JSON response', async () => { + const { body } = await supertest().get('/os/v1/config').expect(200); + + expect(body) + .to.have.property('services') + .that.has.all.keys('openvpn', 'ssh'); + expect(body).to.have.property('schema_version').that.equals('1.0.0'); + }); + }); + + describe('/os/v2/config', () => { + it('should return a valid JSON response', async () => { + const { body } = await supertest().get('/os/v2/config').expect(200); + + expect(body) + .to.have.property('services') + .that.has.all.keys('openvpn', 'ssh'); + expect(body) + .to.have.property('config') + .that.deep.equals({ + overrides: { + logsEndpoint: LOGS_HOST ? `https://${LOGS_HOST}` : null, + }, + }); + }); + }); +});