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 _ = require('lodash');
const grammar = ohm.grammar(`Bru { const grammar = ohm.grammar(`Bru {
BruEnvFile = (vars)* BruEnvFile = (vars | secretvars)*
nl = "\\r"? "\\n" nl = "\\r"? "\\n"
st = " " | "\\t" st = " " | "\\t"
@ -19,6 +19,13 @@ const grammar = ohm.grammar(`Bru {
key = keychar* key = keychar*
value = valuechar* 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 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) => { const concatArrays = (objValue, srcValue) => {
if (_.isArray(objValue) && _.isArray(srcValue)) { if (_.isArray(objValue) && _.isArray(srcValue)) {
return objValue.concat(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) { dictionary(_1, _2, pairlist, _3) {
return pairlist.ast; return pairlist.ast;
}, },
@ -97,6 +136,18 @@ const sem = grammar.createSemantics().addAttribute('ast', {
}, },
vars(_1, dictionary) { vars(_1, dictionary) {
const vars = mapPairListToKeyValPairs(dictionary.ast); 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 { return {
variables: vars variables: vars
}; };

View File

@ -2,22 +2,42 @@ const _ = require('lodash');
const envToJson = (json) => { const envToJson = (json) => {
const variables = _.get(json, 'variables', []); const variables = _.get(json, 'variables', []);
const vars = variables.map((variable) => { const vars = variables
.filter((variable) => !variable.secret)
.map((variable) => {
const { name, value, enabled } = variable; const { name, value, enabled } = variable;
const prefix = enabled ? '' : '~'; const prefix = enabled ? '' : '~';
return ` ${prefix}${name}: ${value}`; 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 { return `vars {
} }
`; `;
} }
const output = `vars { let output = '';
if (vars.length) {
output += `vars {
${vars.join('\n')} ${vars.join('\n')}
} }
`; `;
}
if (secretVars.length) {
output += `vars:secret [
${secretVars.join(',\n')}
]
`;
}
return output; return output;
}; };

View File

@ -26,7 +26,8 @@ vars {
{ {
name: 'url', name: 'url',
value: 'http://localhost:3000', value: 'http://localhost:3000',
enabled: true enabled: true,
secret: false
} }
] ]
}; };
@ -48,17 +49,20 @@ vars {
{ {
name: 'url', name: 'url',
value: 'http://localhost:3000', value: 'http://localhost:3000',
enabled: true enabled: true,
secret: false
}, },
{ {
name: 'port', name: 'port',
value: '3000', value: '3000',
enabled: true enabled: true,
secret: false
}, },
{ {
name: 'token', name: 'token',
value: 'secret', value: 'secret',
enabled: false enabled: false,
secret: false
} }
] ]
}; };
@ -82,12 +86,14 @@ vars {
{ {
name: 'url', name: 'url',
value: 'http://localhost:3000', value: 'http://localhost:3000',
enabled: true enabled: true,
secret: false
}, },
{ {
name: 'port', name: 'port',
value: '3000', value: '3000',
enabled: true enabled: true,
secret: false
} }
] ]
}; };
@ -110,17 +116,197 @@ vars {
{ {
name: 'url', name: 'url',
value: '', value: '',
enabled: true enabled: true,
secret: false
}, },
{ {
name: 'phone', name: 'phone',
value: '', value: '',
enabled: true enabled: true,
secret: false
}, },
{ {
name: 'api-key', name: 'api-key',
value: '', 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); const output = parser(input);
expect(output).toEqual(expected); 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);
});
}); });