diff --git a/config.schema.json b/config.schema.json index 9a187ae4..9784f397 100644 --- a/config.schema.json +++ b/config.schema.json @@ -4,44 +4,40 @@ "title": "Git Proxy configuration file", "description": "Configuration for customizing git-proxy", "type": "object", - "oneOf": [ - { + "properties": { + "authorisedList": { + "description": "List of repositories that are authorised to be pushed to through the proxy.", + "type": "array", + "items": { + "$ref": "#/definitions/authorisedRepo" + } + }, + "sink": { + "description": "List of database sources. The first source in the configuration with enabled=true will be used.", + "type": "array", + "items": { + "$ref": "#/definitions/database" + } + }, + "authentication": { + "description": "List of authentication sources. The first source in the configuration with enabled=true will be used.", + "type": "array", + "items": { + "$ref": "#/definitions/authentication" + } + }, + "tempPassword": { + "description": "Toggle the generation of temporary password for git-proxy admin user", + "type": "object", "properties": { - "authorisedList": { - "description": "List of repositories that are authorised to be pushed to through the proxy.", - "type": "array", - "items": { - "$ref": "#/definitions/authorisedRepo" - } - }, - "sink": { - "description": "List of database sources. The first source in the configuration with enabled=true will be used.", - "type": "array", - "items": { - "$ref": "#/definitions/database" - } - }, - "authentication": { - "description": "List of authentication sources. The first source in the configuration with enabled=true will be used.", - "type": "array", - "items": { - "$ref": "#/definitions/authentication" - } - }, - "tempPassword": { - "description": "Toggle the generation of temporary password for git-proxy admin user", - "type": "object", - "properties": { - "sendEmail": { "type": "boolean" }, - "emailConfig": { - "description": "Generic object to configure nodemailer. For full type information, please see https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/nodemailer", - "type": "object" - } - } + "sendEmail": { "type": "boolean" }, + "emailConfig": { + "description": "Generic object to configure nodemailer. For full type information, please see https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/nodemailer", + "type": "object" } } } - ], + }, "definitions": { "authorisedRepo": { "type": "object", diff --git a/index.js b/index.js index 144f9b06..c86c0425 100755 --- a/index.js +++ b/index.js @@ -18,32 +18,26 @@ const argv = require('yargs/yargs')(process.argv.slice(2)) }) .strict().argv; -require('./src/config/file').configFile = argv.c ? argv.c : undefined; +const config = require('./src/config/file'); +config.configFile = argv.c ? argv.c : undefined; if (argv.v) { const fs = require('fs'); - const path = require('path'); - const validate = require('jsonschema').validate; - const configFile = require('./src/config/file').configFile; - if (!fs.existsSync(configFile)) { + if (!fs.existsSync(config.configFile)) { console.error( - `Config file ${configFile} doesn't exist, nothing to validate! Did you forget -c/--config?`, + `Config file ${config.configFile} doesn't exist, nothing to validate! Did you forget -c/--config?`, ); process.exit(1); } - const config = JSON.parse(fs.readFileSync(configFile)); - const schema = JSON.parse( - fs.readFileSync(path.join(__dirname, 'config.schema.json')), - ); - - validate(config, schema, { required: true, throwError: true }); - - console.log(`${configFile} is valid`); + config.validate(); + console.log(`${config.configFile} is valid`); process.exit(0); } +config.validate(); + const proxy = require('./src/proxy'); const service = require('./src/service'); diff --git a/src/config/file.js b/src/config/file.js index fd1f284d..8779e604 100644 --- a/src/config/file.js +++ b/src/config/file.js @@ -2,6 +2,25 @@ const path = require('path'); // eslint-disable-next-line prefer-const let configFile = undefined; +/** + * Validate config file. + * @param {string} configFilePath - The path to the config file. + * @return {boolean} - Returns true if validation is successful. + * @throws Will throw an error if the validation fails. + */ +function validate(configFilePath = configFile) { + const fs = require('fs'); + const path = require('path'); + const validate = require('jsonschema').validate; + + const config = JSON.parse(fs.readFileSync(configFilePath)); + const schema = JSON.parse( + fs.readFileSync(path.join(__dirname, '..', '..', 'config.schema.json')), + ); + validate(config, schema, { required: true, throwError: true }); + return true; +} + module.exports = { get configFile() { return configFile @@ -11,4 +30,5 @@ module.exports = { set configFile(file) { configFile = file; }, + validate, }; diff --git a/test/fixtures/proxy.config.invalid-1.json b/test/fixtures/proxy.config.invalid-1.json new file mode 100644 index 00000000..541044ab --- /dev/null +++ b/test/fixtures/proxy.config.invalid-1.json @@ -0,0 +1,9 @@ +{ + "invalidProperty": [ + { + "project": "finos", + "name": "git-proxy", + "url": "https://www.github.com/finos/git-proxy.git" + } + ] +} \ No newline at end of file diff --git a/test/fixtures/proxy.config.invalid-2.json b/test/fixtures/proxy.config.invalid-2.json new file mode 100644 index 00000000..fa3e48bb --- /dev/null +++ b/test/fixtures/proxy.config.invalid-2.json @@ -0,0 +1,9 @@ +{ + "authorisedList": [ + { + "project": "finos", + "name": "git-proxy", + "link": "https://www.github.com/finos/git-proxy" + } + ] +} \ No newline at end of file diff --git a/test/fixtures/proxy.config.valid-1.json b/test/fixtures/proxy.config.valid-1.json new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/test/fixtures/proxy.config.valid-1.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/test/fixtures/proxy.config.valid-2.json b/test/fixtures/proxy.config.valid-2.json new file mode 100644 index 00000000..c18dc1ea --- /dev/null +++ b/test/fixtures/proxy.config.valid-2.json @@ -0,0 +1,14 @@ +{ + "authorisedList": [ + { + "project": "finos", + "name": "git-proxy", + "url": "https://github.com/finos/git-proxy.git" + }, + { + "project": "finos", + "name": "git-proxy-test", + "url": "git@github.com:finos/git-proxy-test.git" + } + ] +} \ No newline at end of file diff --git a/test/testConfig.js b/test/testConfig.js index d0afb061..072f8a66 100644 --- a/test/testConfig.js +++ b/test/testConfig.js @@ -3,6 +3,7 @@ const chai = require('chai'); const fs = require('fs'); const path = require('path'); const defaultSettings = require('../proxy.config.json'); +const fixtures = 'fixtures'; chai.should(); const expect = chai.expect; @@ -10,6 +11,7 @@ const expect = chai.expect; describe('default configuration', function () { it('should use default values if no user-settings.json file exists', function () { const config = require('../src/config'); + config.logConfiguration(); expect(config.getAuthentication()).to.be.eql( defaultSettings.authentication[0], @@ -113,3 +115,35 @@ describe('user configuration', function () { delete require.cache[require.resolve('../src/config')]; }); }); + +describe('validate config files', function () { + const config = require('../src/config/file'); + + it('all valid config files should pass validation', function () { + const validConfigFiles = [ + 'proxy.config.valid-1.json', + 'proxy.config.valid-2.json', + ]; + for (const testConfigFile of validConfigFiles) { + expect(config.validate(path.join(__dirname, fixtures, testConfigFile))).to + .be.true; + } + }); + + it('all invalid config files should fail validation', function () { + const invalidConfigFiles = [ + 'proxy.config.invalid-1.json', + 'proxy.config.invalid-2.json', + ]; + for (const testConfigFile of invalidConfigFiles) { + const test = function () { + config.validate(path.join(__dirname, fixtures, testConfigFile)); + }; + expect(test).to.throw(); + } + }); + + after(function () { + delete require.cache[require.resolve('../src/config')]; + }); +});