5
0
Fork 0
mirror of https://github.com/hashicorp/vault-action.git synced 2025-11-14 18:13:45 +00:00

Mask each line of multi-line secrets

This commit is contained in:
Tom Proctor 2021-04-30 16:23:05 +01:00
parent 8417c61f8a
commit ae8016eaab
No known key found for this signature in database
GPG key ID: 9AA1838744D16345
3 changed files with 131 additions and 81 deletions

165
dist/index.js vendored
View file

@ -216,9 +216,70 @@ function wrappy (fn, cb) {
/***/ }), /***/ }),
/***/ 16: /***/ 16:
/***/ (function(module) { /***/ (function(module, __unusedexports, __webpack_require__) {
"use strict";
const {constants: BufferConstants} = __webpack_require__(293);
const pump = __webpack_require__(453);
const bufferStream = __webpack_require__(375);
class MaxBufferError extends Error {
constructor() {
super('maxBuffer exceeded');
this.name = 'MaxBufferError';
}
}
async function getStream(inputStream, options) {
if (!inputStream) {
return Promise.reject(new Error('Expected a stream'));
}
options = {
maxBuffer: Infinity,
...options
};
const {maxBuffer} = options;
let stream;
await new Promise((resolve, reject) => {
const rejectPromise = error => {
// Don't retrieve an oversized buffer.
if (error && stream.getBufferedLength() <= BufferConstants.MAX_LENGTH) {
error.bufferedData = stream.getBufferedValue();
}
reject(error);
};
stream = pump(inputStream, bufferStream(options), error => {
if (error) {
rejectPromise(error);
return;
}
resolve();
});
stream.on('data', () => {
if (stream.getBufferedLength() > maxBuffer) {
rejectPromise(new MaxBufferError());
}
});
});
return stream.getBufferedValue();
}
module.exports = getStream;
// TODO: Remove this for the next major release
module.exports.default = getStream;
module.exports.buffer = (stream, options) => getStream(stream, {...options, encoding: 'buffer'});
module.exports.array = (stream, options) => getStream(stream, {...options, array: true});
module.exports.MaxBufferError = MaxBufferError;
module.exports = require("tls");
/***/ }), /***/ }),
@ -10210,7 +10271,7 @@ module.exports = options => {
const EventEmitter = __webpack_require__(614); const EventEmitter = __webpack_require__(614);
const urlLib = __webpack_require__(835); const urlLib = __webpack_require__(835);
const normalizeUrl = __webpack_require__(53); const normalizeUrl = __webpack_require__(53);
const getStream = __webpack_require__(997); const getStream = __webpack_require__(16);
const CachePolicy = __webpack_require__(154); const CachePolicy = __webpack_require__(154);
const Response = __webpack_require__(93); const Response = __webpack_require__(93);
const lowercaseKeys = __webpack_require__(474); const lowercaseKeys = __webpack_require__(474);
@ -11227,7 +11288,7 @@ module.exports = url => {
"use strict"; "use strict";
const tls = __webpack_require__(16); const tls = __webpack_require__(818);
module.exports = (options = {}) => new Promise((resolve, reject) => { module.exports = (options = {}) => new Promise((resolve, reject) => {
const socket = tls.connect(options, () => { const socket = tls.connect(options, () => {
@ -12893,12 +12954,14 @@ exports.default = async (body, headers) => {
/***/ }), /***/ }),
/***/ 790: /***/ 790:
/***/ (function(module, exports, __webpack_require__) { /***/ (function(module, exports) {
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
const tls_1 = __webpack_require__(16); function isTLSSocket(socket) {
return socket.encrypted;
}
const deferToConnect = (socket, fn) => { const deferToConnect = (socket, fn) => {
let listeners; let listeners;
if (typeof fn === 'function') { if (typeof fn === 'function') {
@ -12915,7 +12978,7 @@ const deferToConnect = (socket, fn) => {
if (hasConnectListener) { if (hasConnectListener) {
listeners.connect(); listeners.connect();
} }
if (socket instanceof tls_1.TLSSocket && hasSecureConnectListener) { if (isTLSSocket(socket) && hasSecureConnectListener) {
if (socket.authorized) { if (socket.authorized) {
listeners.secureConnect(); listeners.secureConnect();
} }
@ -13072,6 +13135,13 @@ exports.default = (request, delays, options) => {
}; };
/***/ }),
/***/ 818:
/***/ (function(module) {
module.exports = require("tls");
/***/ }), /***/ }),
/***/ 835: /***/ 835:
@ -13170,7 +13240,7 @@ module.exports = require("dns");
"use strict"; "use strict";
const EventEmitter = __webpack_require__(614); const EventEmitter = __webpack_require__(614);
const tls = __webpack_require__(16); const tls = __webpack_require__(818);
const http2 = __webpack_require__(565); const http2 = __webpack_require__(565);
const QuickLRU = __webpack_require__(904); const QuickLRU = __webpack_require__(904);
@ -14155,7 +14225,11 @@ async function exportSecrets() {
if (cachedResponse) { if (cachedResponse) {
core.debug(' using cached response'); core.debug(' using cached response');
} }
command.issue('add-mask', value); for (const line of value.split('\n')) {
if (line.length > 0) {
command.issue('add-mask', line);
}
}
if (exportEnv) { if (exportEnv) {
core.exportVariable(request.envVarName, `${value}`); core.exportVariable(request.envVarName, `${value}`);
} }
@ -14317,7 +14391,7 @@ const is_response_ok_1 = __webpack_require__(422);
const deprecation_warning_1 = __webpack_require__(189); const deprecation_warning_1 = __webpack_require__(189);
const normalize_arguments_1 = __webpack_require__(992); const normalize_arguments_1 = __webpack_require__(992);
const calculate_retry_delay_1 = __webpack_require__(594); const calculate_retry_delay_1 = __webpack_require__(594);
const globalDnsCache = new cacheable_lookup_1.default(); let globalDnsCache;
const kRequest = Symbol('request'); const kRequest = Symbol('request');
const kResponse = Symbol('response'); const kResponse = Symbol('response');
const kResponseSize = Symbol('responseSize'); const kResponseSize = Symbol('responseSize');
@ -14874,6 +14948,9 @@ class Request extends stream_1.Duplex {
options.cacheOptions = { ...options.cacheOptions }; options.cacheOptions = { ...options.cacheOptions };
// `options.dnsCache` // `options.dnsCache`
if (options.dnsCache === true) { if (options.dnsCache === true) {
if (!globalDnsCache) {
globalDnsCache = new cacheable_lookup_1.default();
}
options.dnsCache = globalDnsCache; options.dnsCache = globalDnsCache;
} }
else if (!is_1.default.undefined(options.dnsCache) && !options.dnsCache.lookup) { else if (!is_1.default.undefined(options.dnsCache) && !options.dnsCache.lookup) {
@ -16019,74 +16096,6 @@ const normalizeArguments = (options, defaults) => {
exports.default = normalizeArguments; exports.default = normalizeArguments;
/***/ }),
/***/ 997:
/***/ (function(module, __unusedexports, __webpack_require__) {
"use strict";
const {constants: BufferConstants} = __webpack_require__(293);
const pump = __webpack_require__(453);
const bufferStream = __webpack_require__(375);
class MaxBufferError extends Error {
constructor() {
super('maxBuffer exceeded');
this.name = 'MaxBufferError';
}
}
async function getStream(inputStream, options) {
if (!inputStream) {
return Promise.reject(new Error('Expected a stream'));
}
options = {
maxBuffer: Infinity,
...options
};
const {maxBuffer} = options;
let stream;
await new Promise((resolve, reject) => {
const rejectPromise = error => {
// Don't retrieve an oversized buffer.
if (error && stream.getBufferedLength() <= BufferConstants.MAX_LENGTH) {
error.bufferedData = stream.getBufferedValue();
}
reject(error);
};
stream = pump(inputStream, bufferStream(options), error => {
if (error) {
rejectPromise(error);
return;
}
resolve();
});
stream.on('data', () => {
if (stream.getBufferedLength() > maxBuffer) {
rejectPromise(new MaxBufferError());
}
});
});
return stream.getBufferedValue();
}
module.exports = getStream;
// TODO: Remove this for the next major release
module.exports.default = getStream;
module.exports.buffer = (stream, options) => getStream(stream, {...options, encoding: 'buffer'});
module.exports.array = (stream, options) => getStream(stream, {...options, array: true});
module.exports.MaxBufferError = MaxBufferError;
/***/ }) /***/ })
/******/ }); /******/ });

View file

@ -78,7 +78,11 @@ async function exportSecrets() {
if (cachedResponse) { if (cachedResponse) {
core.debug(' using cached response'); core.debug(' using cached response');
} }
command.issue('add-mask', value); for (const line of value.split('\n')) {
if (line.length > 0) {
command.issue('add-mask', line);
}
}
if (exportEnv) { if (exportEnv) {
core.exportVariable(request.envVarName, `${value}`); core.exportVariable(request.envVarName, `${value}`);
} }

View file

@ -2,6 +2,7 @@ jest.mock('got');
jest.mock('@actions/core'); jest.mock('@actions/core');
jest.mock('@actions/core/lib/command'); jest.mock('@actions/core/lib/command');
const command = require('@actions/core/lib/command');
const core = require('@actions/core'); const core = require('@actions/core');
const got = require('got'); const got = require('got');
const { const {
@ -294,4 +295,40 @@ describe('exportSecrets', () => {
expect(core.exportVariable).toBeCalledWith('KEY', '1'); expect(core.exportVariable).toBeCalledWith('KEY', '1');
expect(core.setOutput).toBeCalledWith('key', '1'); expect(core.setOutput).toBeCalledWith('key', '1');
}); });
it('single-line secret gets masked', async () => {
mockInput('test key');
mockVaultData({
key: 'secret'
});
mockExportToken("false")
await exportSecrets();
expect(command.issue).toBeCalledTimes(1);
expect(command.issue).toBeCalledWith('add-mask', 'secret');
expect(core.setOutput).toBeCalledWith('key', 'secret');
})
it('multi-line secret gets masked for each line', async () => {
const multiLineString = `a multi-line string
with blank lines
`
mockInput('test key');
mockVaultData({
key: multiLineString
});
mockExportToken("false")
await exportSecrets();
expect(command.issue).toBeCalledTimes(2); // 1 for each non-empty line.
expect(command.issue).toBeCalledWith('add-mask', 'a multi-line string');
expect(command.issue).toBeCalledWith('add-mask', 'with blank lines');
expect(core.setOutput).toBeCalledWith('key', multiLineString);
})
}); });