-
Notifications
You must be signed in to change notification settings - Fork 259
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Randomize SSH auth socket, kill agent to support non-ephemeral, self …
…hosted runners (@thommyhh, #27) Thanks to @thommyhh for this contribution! Unless the `SSH_AUTH_SOCK` is configured explicitly, this change will make the SSH agent use a random file name for the socket. That way, multiple, concurrent SSH agents can be used on non-ephemeral, self-hosted runners. A new post-action step will automatically clean up the running agent at the end of a job. Be aware of the possible security implications: Two jobs running on the same runner might be able to access each other's socket and thus access repositories and/or hosts.
- Loading branch information
Showing
9 changed files
with
424 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
const core = require('@actions/core') | ||
const { execSync } = require('child_process') | ||
|
||
try { | ||
// Kill the started SSH agent | ||
console.log('Stopping SSH agent') | ||
execSync('kill ${SSH_AGENT_PID}', { stdio: 'inherit' }) | ||
} catch (error) { | ||
core.setFailed(error.message) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,332 @@ | ||
module.exports = | ||
/******/ (function(modules, runtime) { // webpackBootstrap | ||
/******/ "use strict"; | ||
/******/ // The module cache | ||
/******/ var installedModules = {}; | ||
/******/ | ||
/******/ // The require function | ||
/******/ function __webpack_require__(moduleId) { | ||
/******/ | ||
/******/ // Check if module is in cache | ||
/******/ if(installedModules[moduleId]) { | ||
/******/ return installedModules[moduleId].exports; | ||
/******/ } | ||
/******/ // Create a new module (and put it into the cache) | ||
/******/ var module = installedModules[moduleId] = { | ||
/******/ i: moduleId, | ||
/******/ l: false, | ||
/******/ exports: {} | ||
/******/ }; | ||
/******/ | ||
/******/ // Execute the module function | ||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); | ||
/******/ | ||
/******/ // Flag the module as loaded | ||
/******/ module.l = true; | ||
/******/ | ||
/******/ // Return the exports of the module | ||
/******/ return module.exports; | ||
/******/ } | ||
/******/ | ||
/******/ | ||
/******/ __webpack_require__.ab = __dirname + "/"; | ||
/******/ | ||
/******/ // the startup function | ||
/******/ function startup() { | ||
/******/ // Load entry module and return exports | ||
/******/ return __webpack_require__(175); | ||
/******/ }; | ||
/******/ | ||
/******/ // run startup | ||
/******/ return startup(); | ||
/******/ }) | ||
/************************************************************************/ | ||
/******/ ({ | ||
|
||
/***/ 87: | ||
/***/ (function(module) { | ||
|
||
module.exports = require("os"); | ||
|
||
/***/ }), | ||
|
||
/***/ 129: | ||
/***/ (function(module) { | ||
|
||
module.exports = require("child_process"); | ||
|
||
/***/ }), | ||
|
||
/***/ 175: | ||
/***/ (function(__unusedmodule, __unusedexports, __webpack_require__) { | ||
|
||
const core = __webpack_require__(470) | ||
const { execSync } = __webpack_require__(129) | ||
|
||
try { | ||
// Kill the started SSH agent | ||
console.log('Stopping SSH agent') | ||
execSync('kill ${SSH_AGENT_PID}', { stdio: 'inherit' }) | ||
} catch (error) { | ||
core.setFailed(error.message) | ||
} | ||
|
||
|
||
/***/ }), | ||
|
||
/***/ 431: | ||
/***/ (function(__unusedmodule, exports, __webpack_require__) { | ||
|
||
"use strict"; | ||
|
||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const os = __webpack_require__(87); | ||
/** | ||
* Commands | ||
* | ||
* Command Format: | ||
* ##[name key=value;key=value]message | ||
* | ||
* Examples: | ||
* ##[warning]This is the user warning message | ||
* ##[set-secret name=mypassword]definitelyNotAPassword! | ||
*/ | ||
function issueCommand(command, properties, message) { | ||
const cmd = new Command(command, properties, message); | ||
process.stdout.write(cmd.toString() + os.EOL); | ||
} | ||
exports.issueCommand = issueCommand; | ||
function issue(name, message = '') { | ||
issueCommand(name, {}, message); | ||
} | ||
exports.issue = issue; | ||
const CMD_PREFIX = '##['; | ||
class Command { | ||
constructor(command, properties, message) { | ||
if (!command) { | ||
command = 'missing.command'; | ||
} | ||
this.command = command; | ||
this.properties = properties; | ||
this.message = message; | ||
} | ||
toString() { | ||
let cmdStr = CMD_PREFIX + this.command; | ||
if (this.properties && Object.keys(this.properties).length > 0) { | ||
cmdStr += ' '; | ||
for (const key in this.properties) { | ||
if (this.properties.hasOwnProperty(key)) { | ||
const val = this.properties[key]; | ||
if (val) { | ||
// safely append the val - avoid blowing up when attempting to | ||
// call .replace() if message is not a string for some reason | ||
cmdStr += `${key}=${escape(`${val || ''}`)};`; | ||
} | ||
} | ||
} | ||
} | ||
cmdStr += ']'; | ||
// safely append the message - avoid blowing up when attempting to | ||
// call .replace() if message is not a string for some reason | ||
const message = `${this.message || ''}`; | ||
cmdStr += escapeData(message); | ||
return cmdStr; | ||
} | ||
} | ||
function escapeData(s) { | ||
return s.replace(/\r/g, '%0D').replace(/\n/g, '%0A'); | ||
} | ||
function escape(s) { | ||
return s | ||
.replace(/\r/g, '%0D') | ||
.replace(/\n/g, '%0A') | ||
.replace(/]/g, '%5D') | ||
.replace(/;/g, '%3B'); | ||
} | ||
//# sourceMappingURL=command.js.map | ||
|
||
/***/ }), | ||
|
||
/***/ 470: | ||
/***/ (function(__unusedmodule, exports, __webpack_require__) { | ||
|
||
"use strict"; | ||
|
||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const command_1 = __webpack_require__(431); | ||
const path = __webpack_require__(622); | ||
/** | ||
* The code to exit an action | ||
*/ | ||
var ExitCode; | ||
(function (ExitCode) { | ||
/** | ||
* A code indicating that the action was successful | ||
*/ | ||
ExitCode[ExitCode["Success"] = 0] = "Success"; | ||
/** | ||
* A code indicating that the action was a failure | ||
*/ | ||
ExitCode[ExitCode["Failure"] = 1] = "Failure"; | ||
})(ExitCode = exports.ExitCode || (exports.ExitCode = {})); | ||
//----------------------------------------------------------------------- | ||
// Variables | ||
//----------------------------------------------------------------------- | ||
/** | ||
* sets env variable for this action and future actions in the job | ||
* @param name the name of the variable to set | ||
* @param val the value of the variable | ||
*/ | ||
function exportVariable(name, val) { | ||
process.env[name] = val; | ||
command_1.issueCommand('set-env', { name }, val); | ||
} | ||
exports.exportVariable = exportVariable; | ||
/** | ||
* exports the variable and registers a secret which will get masked from logs | ||
* @param name the name of the variable to set | ||
* @param val value of the secret | ||
*/ | ||
function exportSecret(name, val) { | ||
exportVariable(name, val); | ||
// the runner will error with not implemented | ||
// leaving the function but raising the error earlier | ||
command_1.issueCommand('set-secret', {}, val); | ||
throw new Error('Not implemented.'); | ||
} | ||
exports.exportSecret = exportSecret; | ||
/** | ||
* Prepends inputPath to the PATH (for this action and future actions) | ||
* @param inputPath | ||
*/ | ||
function addPath(inputPath) { | ||
command_1.issueCommand('add-path', {}, inputPath); | ||
process.env['PATH'] = `${inputPath}${path.delimiter}${process.env['PATH']}`; | ||
} | ||
exports.addPath = addPath; | ||
/** | ||
* Gets the value of an input. The value is also trimmed. | ||
* | ||
* @param name name of the input to get | ||
* @param options optional. See InputOptions. | ||
* @returns string | ||
*/ | ||
function getInput(name, options) { | ||
const val = process.env[`INPUT_${name.replace(' ', '_').toUpperCase()}`] || ''; | ||
if (options && options.required && !val) { | ||
throw new Error(`Input required and not supplied: ${name}`); | ||
} | ||
return val.trim(); | ||
} | ||
exports.getInput = getInput; | ||
/** | ||
* Sets the value of an output. | ||
* | ||
* @param name name of the output to set | ||
* @param value value to store | ||
*/ | ||
function setOutput(name, value) { | ||
command_1.issueCommand('set-output', { name }, value); | ||
} | ||
exports.setOutput = setOutput; | ||
//----------------------------------------------------------------------- | ||
// Results | ||
//----------------------------------------------------------------------- | ||
/** | ||
* Sets the action status to failed. | ||
* When the action exits it will be with an exit code of 1 | ||
* @param message add error issue message | ||
*/ | ||
function setFailed(message) { | ||
process.exitCode = ExitCode.Failure; | ||
error(message); | ||
} | ||
exports.setFailed = setFailed; | ||
//----------------------------------------------------------------------- | ||
// Logging Commands | ||
//----------------------------------------------------------------------- | ||
/** | ||
* Writes debug message to user log | ||
* @param message debug message | ||
*/ | ||
function debug(message) { | ||
command_1.issueCommand('debug', {}, message); | ||
} | ||
exports.debug = debug; | ||
/** | ||
* Adds an error issue | ||
* @param message error issue message | ||
*/ | ||
function error(message) { | ||
command_1.issue('error', message); | ||
} | ||
exports.error = error; | ||
/** | ||
* Adds an warning issue | ||
* @param message warning issue message | ||
*/ | ||
function warning(message) { | ||
command_1.issue('warning', message); | ||
} | ||
exports.warning = warning; | ||
/** | ||
* Begin an output group. | ||
* | ||
* Output until the next `groupEnd` will be foldable in this group | ||
* | ||
* @param name The name of the output group | ||
*/ | ||
function startGroup(name) { | ||
command_1.issue('group', name); | ||
} | ||
exports.startGroup = startGroup; | ||
/** | ||
* End an output group. | ||
*/ | ||
function endGroup() { | ||
command_1.issue('endgroup'); | ||
} | ||
exports.endGroup = endGroup; | ||
/** | ||
* Wrap an asynchronous function call in a group. | ||
* | ||
* Returns the same type as the function itself. | ||
* | ||
* @param name The name of the group | ||
* @param fn The function to wrap in the group | ||
*/ | ||
function group(name, fn) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
startGroup(name); | ||
let result; | ||
try { | ||
result = yield fn(); | ||
} | ||
finally { | ||
endGroup(); | ||
} | ||
return result; | ||
}); | ||
} | ||
exports.group = group; | ||
//# sourceMappingURL=core.js.map | ||
|
||
/***/ }), | ||
|
||
/***/ 622: | ||
/***/ (function(module) { | ||
|
||
module.exports = require("path"); | ||
|
||
/***/ }) | ||
|
||
/******/ }); |
Oops, something went wrong.