feat(#199): bru lang updates to store environment secrets

This commit is contained in:
Anoop M D 2023-09-22 01:08:35 +05:30
parent 4531cfc994
commit 2f45b95930
4 changed files with 357 additions and 17 deletions

View File

@ -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
};

View File

@ -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;
};

View File

@ -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
}
]
};

View File

@ -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);
});
});