diff --git a/.mdeprc.js b/.mdeprc.js index 9bc54e4..04e7b21 100644 --- a/.mdeprc.js +++ b/.mdeprc.js @@ -1,5 +1,4 @@ /* eslint-disable no-template-curly-in-string */ -const execa = require('execa'); module.exports = { nycCoverage: false, @@ -27,8 +26,10 @@ module.exports = { }, }, }, + euser: 'root', + tuser: 'node', arbitrary_exec: [ 'apk add git curl', - 'npm i --global pnpm@6' + 'wget -qO- https://get.pnpm.io/v6.16.js | node - add --global pnpm', ], }; diff --git a/bin/cmds/test.js b/bin/cmds/test.js index b2d4b4d..e6d86cc 100644 --- a/bin/cmds/test.js +++ b/bin/cmds/test.js @@ -167,6 +167,16 @@ exports.builder = (yargs) => ( type: 'boolean', default: false, }) + .option('exec-user', { + alias: 'euser', + describe: 'user to run setup commands with', + type: 'string', + }) + .option('test-user', { + alias: 'tuser', + describe: 'user to run test commands with', + type: 'string', + }) .option('in-one', { alias: 'in_one', describe: 'runs all tests in 1 test runner', diff --git a/bin/cmds/test_cmds/run.js b/bin/cmds/test_cmds/run.js index 9956d9a..982b2d9 100644 --- a/bin/cmds/test_cmds/run.js +++ b/bin/cmds/test_cmds/run.js @@ -119,8 +119,8 @@ exports.handler = async (argv) => { bodyTimeout: 0, }); - dockerExec = async (cmd, args, { stream = true, timeout = 0, assertCode = true } = {}) => { - const body = JSON.stringify({ file: cmd, args, timeout }); + dockerExec = async (cmd, args, { stream = true, timeout = 0, assertCode = true, user } = {}) => { + const body = JSON.stringify({ file: cmd, args, timeout, user }); debug(body); const res = await client.request({ method: 'POST', @@ -168,9 +168,11 @@ exports.handler = async (argv) => { return result; }; } else { - dockerExec = async (cmd, args = [], { stream = true } = {}) => { + dockerExec = async (cmd, args = [], { stream = true, user } = {}) => { const command = `${cmd} ${args.join(' ')}`.trim(); - const ex = execAsync('docker', ['exec', container, '/bin/sh', '-c', command], { buffer: !stream }); + const argOpts = user ? ['--user', user] : []; + debug(command); + const ex = execAsync('docker', ['exec', ...argOpts, container, '/bin/sh', '-c', command], { buffer: !stream }); if (stream) { ex.stdout.pipe(process.stdout); @@ -186,13 +188,13 @@ exports.handler = async (argv) => { echo('rebuilding modules'); for (const mod of argv.rebuild) { // eslint-disable-next-line no-await-in-loop - await dockerExec('npm', ['rebuild', mod]); + await dockerExec('npm', ['rebuild', mod], { user: argv.euser }); } } if (argv.gyp) { - await dockerExec('node-gyp', ['configure']); - await dockerExec('node-gyp', ['build']); + await dockerExec('node-gyp', ['configure'], { user: argv.euser }); + await dockerExec('node-gyp', ['build'], { user: argv.euser }); } if (argv.sleep) { @@ -240,14 +242,14 @@ exports.handler = async (argv) => { } await Promise.map(argv.pre, (cmd) => execa.command(cmd)); - await Promise.map(argv.arbitrary_exec, (cmd) => dockerExec(cmd, undefined)); + await Promise.map(argv.arbitrary_exec, (cmd) => dockerExec(cmd, undefined, { user: argv.euser })); const testCmds = argv.sort - ? Promise.each(testCommands, ([cmd, ...args]) => dockerExec(cmd, args)) - : Promise.map(testCommands, ([cmd, ...args]) => dockerExec(cmd, args), { concurrency: argv.parallel || 1 }); + ? Promise.each(testCommands, ([cmd, ...args]) => dockerExec(cmd, args, { user: argv.tuser })) + : Promise.map(testCommands, ([cmd, ...args]) => dockerExec(cmd, args), { user: argv.tuser, concurrency: argv.parallel || 1 }); await testCmds; - await Promise.map(argv.post_exec, (cmd) => dockerExec(cmd)); + await Promise.map(argv.post_exec, (cmd) => dockerExec(cmd, undefined, { user: argv.euser })); // upload codecoverage report if (argv.coverage) { diff --git a/bin/runner.js b/bin/runner.js old mode 100644 new mode 100755 index 124b37f..dc16eb5 --- a/bin/runner.js +++ b/bin/runner.js @@ -13,6 +13,7 @@ const Command = Type.Object({ file: Type.String(), args: Type.Optional(Type.Array(Type.String({ minLength: 1 }))), timeout: Type.Optional(Type.Number({ default: 0 })), + user: Type.Optional(Type.String()), }); const fastify = Fastify({ @@ -21,11 +22,23 @@ const fastify = Fastify({ fastify.register(require('fastify-compress')); +const uidCache = Object.create(null); +const hasOwnProperty = Object.prototype.hasOwnProperty.bind(uidCache); + fastify.post('/exec', { schema: { body: Command } }, async (request, reply) => { - const { file, args, timeout } = request.body; + const { file, args, timeout, user } = request.body; + const opts = { all: true, buffer: false, timeout }; + + if (user) { + if (!hasOwnProperty(user)) { + uidCache[user] = (await execa('id', ['-u', user])).stdout; + } + opts.user = uidCache[user]; + } + const subprocess = args - ? execa(file, args, { all: true, buffer: false, timeout }) - : execa.command(file, { all: true, buffer: false, timeout }); + ? execa(file, args, opts) + : execa.command(file, opts); reply.type('text/plain');