From 2f45b95930f7800873fb8f5d59512acb70b519e9 Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Fri, 22 Sep 2023 01:08:35 +0530 Subject: [PATCH] feat(#199): bru lang updates to store environment secrets --- packages/bruno-lang/v2/src/envToJson.js | 53 ++++- packages/bruno-lang/v2/src/jsonToEnv.js | 34 ++- .../bruno-lang/v2/tests/envToJson.spec.js | 204 +++++++++++++++++- .../bruno-lang/v2/tests/jsonToEnv.spec.js | 83 +++++++ 4 files changed, 357 insertions(+), 17 deletions(-) diff --git a/packages/bruno-lang/v2/src/envToJson.js b/packages/bruno-lang/v2/src/envToJson.js index 63bd7f2bf..eef4de375 100644 --- a/packages/bruno-lang/v2/src/envToJson.js +++ b/packages/bruno-lang/v2/src/envToJson.js @@ -2,7 +2,7 @@ const ohm = require('ohm-js'); const _ = require('lodash'); const grammar = ohm.grammar(`Bru { - BruEnvFile = (vars)* + BruEnvFile = (vars | secretvars)* nl = "\\r"? "\\n" st = " " | "\\t" @@ -19,6 +19,13 @@ const grammar = ohm.grammar(`Bru { key = keychar* value = valuechar* + // Array Blocks + array = st* "[" stnl* valuelist stnl* "]" + valuelist = stnl* arrayvalue stnl* ("," stnl* arrayvalue)* + arrayvalue = arrayvaluechar* + arrayvaluechar = ~(nl | st | "[" | "]" | ",") any + + secretvars = "vars:secret" array vars = "vars" dictionary }`); @@ -44,6 +51,29 @@ const mapPairListToKeyValPairs = (pairList = []) => { }); }; +const mapArrayListToKeyValPairs = (arrayList = []) => { + arrayList = arrayList.filter((v) => v && v.length); + + if (!arrayList.length) { + return []; + } + + return _.map(arrayList, (value) => { + let name = value; + let enabled = true; + if (name && name.length && name.charAt(0) === '~') { + name = name.slice(1); + enabled = false; + } + + return { + name, + value: null, + enabled + }; + }); +}; + const concatArrays = (objValue, srcValue) => { if (_.isArray(objValue) && _.isArray(srcValue)) { return objValue.concat(srcValue); @@ -66,6 +96,15 @@ const sem = grammar.createSemantics().addAttribute('ast', { {} ); }, + array(_1, _2, _3, valuelist, _4, _5) { + return valuelist.ast; + }, + arrayvalue(chars) { + return chars.sourceString ? chars.sourceString.trim() : ''; + }, + valuelist(_1, value, _2, _3, _4, rest) { + return [value.ast, ...rest.ast]; + }, dictionary(_1, _2, pairlist, _3) { return pairlist.ast; }, @@ -97,6 +136,18 @@ const sem = grammar.createSemantics().addAttribute('ast', { }, vars(_1, dictionary) { const vars = mapPairListToKeyValPairs(dictionary.ast); + _.each(vars, (v) => { + v.secret = false; + }); + return { + variables: vars + }; + }, + secretvars: (_1, array) => { + const vars = mapArrayListToKeyValPairs(array.ast); + _.each(vars, (v) => { + v.secret = true; + }); return { variables: vars }; diff --git a/packages/bruno-lang/v2/src/jsonToEnv.js b/packages/bruno-lang/v2/src/jsonToEnv.js index 46106f336..42d0a4281 100644 --- a/packages/bruno-lang/v2/src/jsonToEnv.js +++ b/packages/bruno-lang/v2/src/jsonToEnv.js @@ -2,22 +2,42 @@ const _ = require('lodash'); const envToJson = (json) => { const variables = _.get(json, 'variables', []); - const vars = variables.map((variable) => { - const { name, value, enabled } = variable; - const prefix = enabled ? '' : '~'; - return ` ${prefix}${name}: ${value}`; - }); + const vars = variables + .filter((variable) => !variable.secret) + .map((variable) => { + const { name, value, enabled } = variable; + const prefix = enabled ? '' : '~'; + return ` ${prefix}${name}: ${value}`; + }); - if (!vars || !vars.length) { + const secretVars = variables + .filter((variable) => variable.secret) + .map((variable) => { + const { name, enabled } = variable; + const prefix = enabled ? '' : '~'; + return ` ${prefix}${name}`; + }); + + if (!variables || !variables.length) { return `vars { } `; } - const output = `vars { + let output = ''; + if (vars.length) { + output += `vars { ${vars.join('\n')} } `; + } + + if (secretVars.length) { + output += `vars:secret [ +${secretVars.join(',\n')} +] +`; + } return output; }; diff --git a/packages/bruno-lang/v2/tests/envToJson.spec.js b/packages/bruno-lang/v2/tests/envToJson.spec.js index a082e2cf4..fbb74f2b9 100644 --- a/packages/bruno-lang/v2/tests/envToJson.spec.js +++ b/packages/bruno-lang/v2/tests/envToJson.spec.js @@ -26,7 +26,8 @@ vars { { name: 'url', value: 'http://localhost:3000', - enabled: true + enabled: true, + secret: false } ] }; @@ -48,17 +49,20 @@ vars { { name: 'url', value: 'http://localhost:3000', - enabled: true + enabled: true, + secret: false }, { name: 'port', value: '3000', - enabled: true + enabled: true, + secret: false }, { name: 'token', value: 'secret', - enabled: false + enabled: false, + secret: false } ] }; @@ -82,12 +86,14 @@ vars { { name: 'url', value: 'http://localhost:3000', - enabled: true + enabled: true, + secret: false }, { name: 'port', value: '3000', - enabled: true + enabled: true, + secret: false } ] }; @@ -110,17 +116,197 @@ vars { { name: 'url', value: '', - enabled: true + enabled: true, + secret: false }, { name: 'phone', value: '', - enabled: true + enabled: true, + secret: false }, { name: 'api-key', value: '', - enabled: true + enabled: true, + secret: false + } + ] + }; + + expect(output).toEqual(expected); + }); + + it('should parse empty secret vars', () => { + const input = ` +vars { + url: http://localhost:3000 +} + +vars:secret [ + +] +`; + + const output = parser(input); + const expected = { + variables: [ + { + name: 'url', + value: 'http://localhost:3000', + enabled: true, + secret: false + } + ] + }; + + expect(output).toEqual(expected); + }); + + it('should parse secret vars', () => { + const input = ` +vars { + url: http://localhost:3000 +} + +vars:secret [ + token +] +`; + + const output = parser(input); + const expected = { + variables: [ + { + name: 'url', + value: 'http://localhost:3000', + enabled: true, + secret: false + }, + { + name: 'token', + value: null, + enabled: true, + secret: true + } + ] + }; + + expect(output).toEqual(expected); + }); + + it('should parse multiline secret vars', () => { + const input = ` +vars { + url: http://localhost:3000 +} + +vars:secret [ + access_token, + access_secret, + + ~access_password +] +`; + + const output = parser(input); + const expected = { + variables: [ + { + name: 'url', + value: 'http://localhost:3000', + enabled: true, + secret: false + }, + { + name: 'access_token', + value: null, + enabled: true, + secret: true + }, + { + name: 'access_secret', + value: null, + enabled: true, + secret: true + }, + { + name: 'access_password', + value: null, + enabled: false, + secret: true + } + ] + }; + + expect(output).toEqual(expected); + }); + + it('should parse inline secret vars', () => { + const input = ` +vars { + url: http://localhost:3000 +} + +vars:secret [access_key] +`; + + const output = parser(input); + const expected = { + variables: [ + { + name: 'url', + value: 'http://localhost:3000', + enabled: true, + secret: false + }, + { + name: 'access_key', + value: null, + enabled: true, + secret: true + } + ] + }; + + expect(output).toEqual(expected); + }); + + it('should parse inline multiple secret vars', () => { + const input = ` +vars { + url: http://localhost:3000 +} + +vars:secret [access_key,access_secret, access_password ] +`; + + const output = parser(input); + const expected = { + variables: [ + { + name: 'url', + value: 'http://localhost:3000', + enabled: true, + secret: false + }, + { + name: 'access_key', + value: null, + enabled: true, + secret: true + }, + { + name: 'access_secret', + value: null, + enabled: true, + secret: true + }, + { + name: 'access_password', + value: null, + enabled: true, + secret: true } ] }; diff --git a/packages/bruno-lang/v2/tests/jsonToEnv.spec.js b/packages/bruno-lang/v2/tests/jsonToEnv.spec.js index 7aee11428..62b7aa269 100644 --- a/packages/bruno-lang/v2/tests/jsonToEnv.spec.js +++ b/packages/bruno-lang/v2/tests/jsonToEnv.spec.js @@ -57,4 +57,87 @@ describe('env parser', () => { const output = parser(input); expect(output).toEqual(expected); }); + + it('should parse secret vars', () => { + const input = { + variables: [ + { + name: 'url', + value: 'http://localhost:3000', + enabled: true + }, + { + name: 'token', + value: 'abracadabra', + enabled: true, + secret: true + } + ] + }; + + const output = parser(input); + const expected = `vars { + url: http://localhost:3000 +} +vars:secret [ + token +] +`; + expect(output).toEqual(expected); + }); + + it('should parse multiple secret vars', () => { + const input = { + variables: [ + { + name: 'url', + value: 'http://localhost:3000', + enabled: true + }, + { + name: 'access_token', + value: 'abracadabra', + enabled: true, + secret: true + }, + { + name: 'access_secret', + value: 'abracadabra', + enabled: false, + secret: true + } + ] + }; + + const output = parser(input); + const expected = `vars { + url: http://localhost:3000 +} +vars:secret [ + access_token, + ~access_secret +] +`; + expect(output).toEqual(expected); + }); + + it('should parse even if the only secret vars are present', () => { + const input = { + variables: [ + { + name: 'token', + value: 'abracadabra', + enabled: true, + secret: true + } + ] + }; + + const output = parser(input); + const expected = `vars:secret [ + token +] +`; + expect(output).toEqual(expected); + }); });