mirror of
https://github.com/usebruno/bruno.git
synced 2025-02-18 02:30:58 +01:00
feat(#199): bru lang updates to store environment secrets
This commit is contained in:
parent
4531cfc994
commit
2f45b95930
@ -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
|
||||||
};
|
};
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
@ -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);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user