-
Notifications
You must be signed in to change notification settings - Fork 141
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Issue234 Import all keys from specific path #238
Changes from all commits
cc9c383
f09a7fe
6c9a25f
a729d0a
755188e
8bf66ca
5ecd962
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,25 @@ const core = require('@actions/core'); | |
const command = require('@actions/core/lib/command'); | ||
const got = require('got').default; | ||
const jsonata = require('jsonata'); | ||
module.exports = {}; | ||
const wildcard = '*'; | ||
module.exports.wildcard = wildcard; | ||
|
||
/** | ||
* Replaces any dot chars to __ and removes non-ascii charts | ||
* @param {string} dataKey | ||
* @param {boolean=} isEnvVar | ||
*/ | ||
function normalizeOutputKey(dataKey, isEnvVar = false) { | ||
let outputKey = dataKey | ||
.replace('.', '__').replace(new RegExp('-', 'g'), '').replace(/[^\p{L}\p{N}_-]/gu, ''); | ||
if (isEnvVar) { | ||
outputKey = outputKey.toUpperCase(); | ||
} | ||
return outputKey; | ||
} | ||
module.exports.normalizeOutputKey = normalizeOutputKey; | ||
|
||
const { auth: { retrieveToken }, secrets: { getSecrets } } = require('./index'); | ||
|
||
const AUTH_METHODS = ['approle', 'token', 'github', 'jwt', 'kubernetes']; | ||
|
@@ -113,6 +132,7 @@ async function exportSecrets() { | |
core.debug(`✔ ${request.path} => outputs.${request.outputVarName}${exportEnv ? ` | env.${request.envVarName}` : ''}`); | ||
} | ||
}; | ||
module.exports.exportSecrets = exportSecrets; | ||
|
||
/** @typedef {Object} SecretRequest | ||
* @property {string} path | ||
|
@@ -167,7 +187,7 @@ function parseSecretsInput(secretsInput) { | |
const selectorAst = jsonata(selectorQuoted).ast(); | ||
const selector = selectorQuoted.replace(new RegExp('"', 'g'), ''); | ||
|
||
if ((selectorAst.type !== "path" || selectorAst.steps[0].stages) && selectorAst.type !== "string" && !outputVarName) { | ||
if (selector !== wildcard && (selectorAst.type !== "path" || selectorAst.steps[0].stages) && selectorAst.type !== "string" && !outputVarName) { | ||
throw Error(`You must provide a name for the output key when using json selectors. Input: "${secret}"`); | ||
} | ||
|
||
|
@@ -186,20 +206,7 @@ function parseSecretsInput(secretsInput) { | |
} | ||
return output; | ||
} | ||
|
||
/** | ||
* Replaces any dot chars to __ and removes non-ascii charts | ||
* @param {string} dataKey | ||
* @param {boolean=} isEnvVar | ||
*/ | ||
function normalizeOutputKey(dataKey, isEnvVar = false) { | ||
let outputKey = dataKey | ||
.replace('.', '__').replace(new RegExp('-', 'g'), '').replace(/[^\p{L}\p{N}_-]/gu, ''); | ||
if (isEnvVar) { | ||
outputKey = outputKey.toUpperCase(); | ||
} | ||
return outputKey; | ||
} | ||
module.exports.parseSecretsInput = parseSecretsInput; | ||
|
||
/** | ||
* @param {string} inputKey | ||
|
@@ -225,10 +232,14 @@ function parseHeadersInput(inputKey, inputOptions) { | |
return map; | ||
}, new Map()); | ||
} | ||
|
||
module.exports.parseHeadersInput = parseHeadersInput; | ||
// restructured module.exports to avoid circular dependency when secrets imports this. | ||
/* | ||
module.exports = { | ||
exportSecrets, | ||
parseSecretsInput, | ||
normalizeOutputKey, | ||
parseHeadersInput | ||
parseHeadersInput, | ||
wildcard | ||
}; | ||
*/ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we go ahead and move the normalization method in its own file well be able to keep this unique export block which I think is more "standard" than exporting methods one at a time throughout the file. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,5 @@ | ||
const jsonata = require("jsonata"); | ||
|
||
|
||
const { normalizeOutputKey, wildcard} = require('./action'); | ||
/** | ||
* @typedef {Object} SecretRequest | ||
* @property {string} path | ||
|
@@ -24,6 +23,7 @@ const jsonata = require("jsonata"); | |
async function getSecrets(secretRequests, client) { | ||
const responseCache = new Map(); | ||
const results = []; | ||
|
||
for (const secretRequest of secretRequests) { | ||
let { path, selector } = secretRequest; | ||
|
||
|
@@ -46,25 +46,77 @@ async function getSecrets(secretRequests, client) { | |
throw error | ||
} | ||
} | ||
if (!selector.match(/.*[\.].*/)) { | ||
selector = '"' + selector + '"' | ||
|
||
if (selector == wildcard) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe strict equality with === should be used unless there is a specific reason not to. |
||
body = JSON.parse(body); | ||
let keys = body.data; | ||
if (body.data["data"] != undefined) { | ||
keys = keys.data; | ||
} | ||
|
||
for (let key in keys) { | ||
let newRequest = Object.assign({},secretRequest); | ||
newRequest.selector = key; | ||
if (secretRequest.selector === secretRequest.outputVarName) { | ||
newRequest.outputVarName = key; | ||
newRequest.envVarName = key; | ||
} | ||
else { | ||
newRequest.outputVarName = secretRequest.outputVarName+key; | ||
newRequest.envVarName = secretRequest.envVarName+key; | ||
} | ||
newRequest.outputVarName = normalizeOutputKey(newRequest.outputVarName); | ||
newRequest.envVarName = normalizeOutputKey(newRequest.envVarName,true); | ||
|
||
selector = key; | ||
|
||
//This code (with exception of parsing body again and using newRequest instead of secretRequest) should match the else code for a single key | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it be better to isolate the shared code in a method instead of hoping maintainers see this comment and think to copy-paste changes between the wildcard and single-key paths? |
||
if (!selector.match(/.*[\.].*/)) { | ||
selector = '"' + selector + '"' | ||
} | ||
selector = "data." + selector | ||
//body = JSON.parse(body) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Leftover comment, should it be deleted or it's important? |
||
if (body.data["data"] != undefined) { | ||
selector = "data." + selector | ||
} | ||
const value = selectData(body, selector); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. selectData was changed to be async due to the recent bump to Jsonata 2.x, you'll need to await the response otherwise the code does not work and tries to manipulate a promise.
|
||
results.push({ | ||
request: newRequest, | ||
value, | ||
cachedResponse | ||
}); | ||
|
||
//DEBUG | ||
//console.log("After", newRequest, value); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We try not to leave leftover debug code or console.logs even if commented out. |
||
|
||
// used cachedResponse for first entry in wildcard list and set to true for the rest | ||
cachedResponse = true; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think setting this to true does anything here? It gets reset to false at the beginning of every loops before we check for a cache hit. |
||
} | ||
|
||
} | ||
selector = "data." + selector | ||
body = JSON.parse(body) | ||
if (body.data["data"] != undefined) { | ||
else { | ||
if (!selector.match(/.*[\.].*/)) { | ||
selector = '"' + selector + '"' | ||
} | ||
selector = "data." + selector | ||
} | ||
body = JSON.parse(body) | ||
if (body.data["data"] != undefined) { | ||
selector = "data." + selector | ||
} | ||
|
||
const value = await selectData(body, selector); | ||
results.push({ | ||
request: secretRequest, | ||
value, | ||
cachedResponse | ||
}); | ||
|
||
const value = await selectData(body, selector); | ||
results.push({ | ||
request: secretRequest, | ||
value, | ||
cachedResponse | ||
}); | ||
} | ||
} | ||
return results; | ||
} | ||
|
||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This extra empty line can be removed? |
||
/** | ||
* Uses a Jsonata selector retrieve a bit of data from the result | ||
* @param {object} data | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it causes circular dependency problems, it'd be better to move the
normalizeOutputKey
method into it's own normalization.js or utils.js file so it can be imported and used by both secrets.js & actions.js.It's usually better to rethink how a project is compartmentalised rather than hack the exports.