diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..dde583f --- /dev/null +++ b/.npmignore @@ -0,0 +1,4 @@ +.github/ +swagger.yaml +EXTENSIONS.md +.travis.yml \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..4460917 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - "node" + - "lts/*" \ No newline at end of file diff --git a/README.md b/README.md index e8e7586..e6f53ab 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # platform-chaos + +[![Build Status](https://travis-ci.org/azure/platform-chaos.svg?branch=master)](https://travis-ci.org/azure/platform-chaos) + A node sdk for building services capable of injecting chaos into PaaS offerings. ⚙️ 🌩 ![hero image](.github/hero.png) diff --git a/index.js b/index.js new file mode 100644 index 0000000..f3778d9 --- /dev/null +++ b/index.js @@ -0,0 +1,4 @@ +module.exports = { + parsers: require('./parsers'), + validators: require('./validators') +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..5ebee8d --- /dev/null +++ b/package-lock.json @@ -0,0 +1,195 @@ +{ + "name": "azure-chaos-fn", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "dev": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "browser-stdout": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", + "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", + "dev": true + }, + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "diff": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz", + "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "growl": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz", + "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==", + "dev": true + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "1.1.8" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.0.0.tgz", + "integrity": "sha512-ukB2dF+u4aeJjc6IGtPNnJXfeby5d4ZqySlIBT0OEyva/DrMjVm5HkQxKnHDLKEfEQBsEnwTg9HHhtPHJdTd8w==", + "dev": true, + "requires": { + "browser-stdout": "1.3.0", + "commander": "2.11.0", + "debug": "3.1.0", + "diff": "3.3.1", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.3", + "he": "1.1.1", + "mkdirp": "0.5.1", + "supports-color": "4.4.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..0d6f83a --- /dev/null +++ b/package.json @@ -0,0 +1,18 @@ +{ + "name": "azure-chaos-fn", + "version": "1.0.0", + "description": "The base module for all azure-chaos extensions", + "main": "index.js", + "scripts": { + "test": "mocha" + }, + "keywords": [ + "azure", + "chaos" + ], + "author": "Ben Greenier", + "license": "MIT", + "devDependencies": { + "mocha": "^5.0.0" + } +} diff --git a/parsers.js b/parsers.js new file mode 100644 index 0000000..2775314 --- /dev/null +++ b/parsers.js @@ -0,0 +1,30 @@ +const validate = require('./validators') + +module.exports = { + accessTokenToCredentials: (req) => { + // ensure we have a valid accessToken before proceeding + validate.accessToken(req) + + // this implements the contract defined by msRestAzure + // see https://github.com/Azure/azure-sdk-for-node/blob/0a52678ea7b3a24a478975f7169fc30e9fc9759e/runtime/ms-rest-azure/lib/credentials/deviceTokenCredentials.js + return { + signRequest: (webResource, callback) => { + webResource.headers['Authorization'] = req.body.accessToken + callback(null) + } + } + }, + resourcesToObjects: (req) => { + // ensure we have a valid resources array before proceeding + validate.resources(req) + + // parse the resources into objects + return req.body.resources.map(r => r.split('/')).map(r => { + return { + subscriptionId: r[0], + resourceGroupName: r[1], + resourceName: r[2] + } + }) + } +} \ No newline at end of file diff --git a/test/basic.js b/test/basic.js new file mode 100644 index 0000000..afbcb8d --- /dev/null +++ b/test/basic.js @@ -0,0 +1,94 @@ +const assert = require('assert') +const index = require('../') + +describe('azure-chaos-fn', () => { + it('parses resources', () => { + assert.throws(() => { + index.validators.resources({ + body: { + resources: [1] + } + }) + }) + + assert.throws(() => { + index.validators.resources({ + body: { + resources: [''] + } + }) + }) + + assert.throws(() => { + index.validators.resources({ + body: { + resources: ['one/two/three/four'] + } + }) + }) + + const instance = index.parsers.resourcesToObjects({ + body: { + resources: ['sub/rg/resource'] + } + })[0] + + assert.equal(instance.subscriptionId, "sub") + assert.equal(instance.resourceGroupName, "rg") + assert.equal(instance.resourceName, "resource") + }) + + it('parses accessTokens', () => { + // invalid at + assert.throws(() => { + index.validators.accessToken({ + body: { + accessToken: 1 + } + }) + }) + + // empty resourceIds + assert.throws(() => { + index.validators.accessToken({ + body: { + accessToken: "valid type" + } + }) + }) + + // invalid resourceIds type + assert.throws(() => { + index.validators.accessToken({ + body: { + accessToken: "valid type" + } + }) + }) + + // invalid resourceIds format + assert.throws(() => { + index.validators.accessToken({ + body: { + accessToken: "valid type" + } + }) + }) + + // valid + const expectedAccessToken = "Bearer 12345234r2" + const instance =index.parsers.accessTokenToCredentials({ + body: { + accessToken: expectedAccessToken + } + }) + + const res = { + headers: {} + } + + instance.signRequest(res, () => {}) + + assert.equal(res.headers['Authorization'], expectedAccessToken) + }) +}) \ No newline at end of file diff --git a/validators.js b/validators.js new file mode 100644 index 0000000..3c2facc --- /dev/null +++ b/validators.js @@ -0,0 +1,17 @@ +const assert = require('assert') + +module.exports = { + accessToken: (req) => { + assert.ok(req.body.accessToken) + assert.ok(typeof req.body.accessToken === 'string') + assert.ok(req.body.accessToken.startsWith('Bearer ')) + }, + resources: (req) => { + assert.ok(req.body.resources) + req.body.resources.forEach((res) => { + assert.ok(typeof res === 'string') + assert.ok(1 < res.split('/').length) + assert.ok(res.split('/').length < 4) + }) + } +} \ No newline at end of file