From 2b9e5df4cbf15049a7099e1ed95c7adea449d0f3 Mon Sep 17 00:00:00 2001 From: afirth Date: Tue, 23 Jul 2024 14:00:19 +0200 Subject: [PATCH 1/2] Support subdirectory for install action --- install/action.yml | 4 ++-- install/main.js | 5 +++++ src/install/index.ts | 6 ++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/install/action.yml b/install/action.yml index cde0b21f..b2f9c6f4 100644 --- a/install/action.yml +++ b/install/action.yml @@ -6,11 +6,11 @@ runs: main: main.js inputs: tool_versions: - description: + description: |- If present, this value will be written to the .tool-versions file. required: false before_install: - description: + description: |- Bash script to run after plugins are installed but before `asdf install`. eg, to install npm keyring required: false diff --git a/install/main.js b/install/main.js index 5e1063d7..09b3adae 100644 --- a/install/main.js +++ b/install/main.js @@ -3261,6 +3261,7 @@ var require_exec = __commonJS({ var core4 = __toESM(require_core()); // src/install/index.ts +var import_node_process = require("node:process"); var core3 = __toESM(require_core()); var exec5 = __toESM(require_exec()); @@ -3363,6 +3364,10 @@ async function pluginsAdd() { // src/install/index.ts async function toolsInstall() { + const dir = core3.getInput("directory", { required: false }); + if (dir) { + (0, import_node_process.chdir)(dir); + } await pluginsAdd(); const before = core3.getInput("before_install", { required: false }); if (before) { diff --git a/src/install/index.ts b/src/install/index.ts index 25ffe834..7f613bcb 100644 --- a/src/install/index.ts +++ b/src/install/index.ts @@ -1,8 +1,14 @@ +import {chdir} from 'node:process'; import * as core from '@actions/core'; import * as exec from '@actions/exec'; import {pluginsAdd} from '~/plugins-add/index.ts'; async function toolsInstall(): Promise { + const dir = core.getInput('directory', {required: false}); + if (dir) { + chdir(dir); + } + await pluginsAdd(); const before = core.getInput('before_install', {required: false}); From 57d8bccffd9c019a1fc869f94b9921fcbdeb4f10 Mon Sep 17 00:00:00 2001 From: afirth Date: Tue, 23 Jul 2024 14:18:02 +0200 Subject: [PATCH 2/2] ensure dir is a subdir of curdir --- install/action.yml | 4 ++ install/main.js | 144 ++++++++++++++++++++++--------------------- src/install/index.ts | 14 ++++- 3 files changed, 91 insertions(+), 71 deletions(-) diff --git a/install/action.yml b/install/action.yml index b2f9c6f4..da6fc319 100644 --- a/install/action.yml +++ b/install/action.yml @@ -14,6 +14,10 @@ inputs: Bash script to run after plugins are installed but before `asdf install`. eg, to install npm keyring required: false + directory: + description: |- + If present, the action will execute from this subdirectory + required: false asdf_branch: description: asdf branch to clone required: false diff --git a/install/main.js b/install/main.js index 09b3adae..ee2e5068 100644 --- a/install/main.js +++ b/install/main.js @@ -891,11 +891,11 @@ var require_lib = __commonJS({ }; var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) { function adopt(value) { - return value instanceof P ? value : new P(function(resolve) { - resolve(value); + return value instanceof P ? value : new P(function(resolve2) { + resolve2(value); }); } - return new (P || (P = Promise))(function(resolve, reject) { + return new (P || (P = Promise))(function(resolve2, reject) { function fulfilled(value) { try { step(generator.next(value)); @@ -911,7 +911,7 @@ var require_lib = __commonJS({ } } function step(result) { - result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); + result.done ? resolve2(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); @@ -996,26 +996,26 @@ var require_lib = __commonJS({ } readBody() { return __awaiter(this, void 0, void 0, function* () { - return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () { + return new Promise((resolve2) => __awaiter(this, void 0, void 0, function* () { let output = Buffer.alloc(0); this.message.on("data", (chunk) => { output = Buffer.concat([output, chunk]); }); this.message.on("end", () => { - resolve(output.toString()); + resolve2(output.toString()); }); })); }); } readBodyBuffer() { return __awaiter(this, void 0, void 0, function* () { - return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () { + return new Promise((resolve2) => __awaiter(this, void 0, void 0, function* () { const chunks = []; this.message.on("data", (chunk) => { chunks.push(chunk); }); this.message.on("end", () => { - resolve(Buffer.concat(chunks)); + resolve2(Buffer.concat(chunks)); }); })); }); @@ -1224,14 +1224,14 @@ var require_lib = __commonJS({ */ requestRaw(info3, data) { return __awaiter(this, void 0, void 0, function* () { - return new Promise((resolve, reject) => { + return new Promise((resolve2, reject) => { function callbackForResult(err, res) { if (err) { reject(err); } else if (!res) { reject(new Error("Unknown error")); } else { - resolve(res); + resolve2(res); } } this.requestRawWithCallback(info3, data, callbackForResult); @@ -1387,12 +1387,12 @@ var require_lib = __commonJS({ return __awaiter(this, void 0, void 0, function* () { retryNumber = Math.min(ExponentialBackoffCeiling, retryNumber); const ms = ExponentialBackoffTimeSlice * Math.pow(2, retryNumber); - return new Promise((resolve) => setTimeout(() => resolve(), ms)); + return new Promise((resolve2) => setTimeout(() => resolve2(), ms)); }); } _processResponse(res, options) { return __awaiter(this, void 0, void 0, function* () { - return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { + return new Promise((resolve2, reject) => __awaiter(this, void 0, void 0, function* () { const statusCode = res.message.statusCode || 0; const response = { statusCode, @@ -1400,7 +1400,7 @@ var require_lib = __commonJS({ headers: {} }; if (statusCode === HttpCodes.NotFound) { - resolve(response); + resolve2(response); } function dateTimeDeserializer(key, value) { if (typeof value === "string") { @@ -1439,7 +1439,7 @@ var require_lib = __commonJS({ err.result = response.result; reject(err); } else { - resolve(response); + resolve2(response); } })); }); @@ -1456,11 +1456,11 @@ var require_auth = __commonJS({ "use strict"; var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) { function adopt(value) { - return value instanceof P ? value : new P(function(resolve) { - resolve(value); + return value instanceof P ? value : new P(function(resolve2) { + resolve2(value); }); } - return new (P || (P = Promise))(function(resolve, reject) { + return new (P || (P = Promise))(function(resolve2, reject) { function fulfilled(value) { try { step(generator.next(value)); @@ -1476,7 +1476,7 @@ var require_auth = __commonJS({ } } function step(result) { - result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); + result.done ? resolve2(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); @@ -1560,11 +1560,11 @@ var require_oidc_utils = __commonJS({ "use strict"; var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) { function adopt(value) { - return value instanceof P ? value : new P(function(resolve) { - resolve(value); + return value instanceof P ? value : new P(function(resolve2) { + resolve2(value); }); } - return new (P || (P = Promise))(function(resolve, reject) { + return new (P || (P = Promise))(function(resolve2, reject) { function fulfilled(value) { try { step(generator.next(value)); @@ -1580,7 +1580,7 @@ var require_oidc_utils = __commonJS({ } } function step(result) { - result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); + result.done ? resolve2(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); @@ -1658,11 +1658,11 @@ var require_summary = __commonJS({ "use strict"; var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) { function adopt(value) { - return value instanceof P ? value : new P(function(resolve) { - resolve(value); + return value instanceof P ? value : new P(function(resolve2) { + resolve2(value); }); } - return new (P || (P = Promise))(function(resolve, reject) { + return new (P || (P = Promise))(function(resolve2, reject) { function fulfilled(value) { try { step(generator.next(value)); @@ -1678,7 +1678,7 @@ var require_summary = __commonJS({ } } function step(result) { - result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); + result.done ? resolve2(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); @@ -1980,7 +1980,7 @@ var require_path_utils = __commonJS({ }; Object.defineProperty(exports, "__esModule", { value: true }); exports.toPlatformPath = exports.toWin32Path = exports.toPosixPath = void 0; - var path2 = __importStar(require("path")); + var path3 = __importStar(require("path")); function toPosixPath(pth) { return pth.replace(/[\\]/g, "/"); } @@ -1990,7 +1990,7 @@ var require_path_utils = __commonJS({ } exports.toWin32Path = toWin32Path; function toPlatformPath(pth) { - return pth.replace(/[/\\]/g, path2.sep); + return pth.replace(/[/\\]/g, path3.sep); } exports.toPlatformPath = toPlatformPath; } @@ -2030,11 +2030,11 @@ var require_core = __commonJS({ }; var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) { function adopt(value) { - return value instanceof P ? value : new P(function(resolve) { - resolve(value); + return value instanceof P ? value : new P(function(resolve2) { + resolve2(value); }); } - return new (P || (P = Promise))(function(resolve, reject) { + return new (P || (P = Promise))(function(resolve2, reject) { function fulfilled(value) { try { step(generator.next(value)); @@ -2050,7 +2050,7 @@ var require_core = __commonJS({ } } function step(result) { - result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); + result.done ? resolve2(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); @@ -2061,7 +2061,7 @@ var require_core = __commonJS({ var file_command_1 = require_file_command(); var utils_1 = require_utils(); var os2 = __importStar(require("os")); - var path2 = __importStar(require("path")); + var path3 = __importStar(require("path")); var oidc_utils_1 = require_oidc_utils(); var ExitCode; (function(ExitCode2) { @@ -2089,7 +2089,7 @@ var require_core = __commonJS({ } else { command_1.issueCommand("add-path", {}, inputPath); } - process.env["PATH"] = `${inputPath}${path2.delimiter}${process.env["PATH"]}`; + process.env["PATH"] = `${inputPath}${path3.delimiter}${process.env["PATH"]}`; } exports.addPath = addPath2; function getInput4(name, options) { @@ -2259,11 +2259,11 @@ var require_io_util = __commonJS({ }; var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) { function adopt(value) { - return value instanceof P ? value : new P(function(resolve) { - resolve(value); + return value instanceof P ? value : new P(function(resolve2) { + resolve2(value); }); } - return new (P || (P = Promise))(function(resolve, reject) { + return new (P || (P = Promise))(function(resolve2, reject) { function fulfilled(value) { try { step(generator.next(value)); @@ -2279,7 +2279,7 @@ var require_io_util = __commonJS({ } } function step(result) { - result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); + result.done ? resolve2(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); @@ -2288,7 +2288,7 @@ var require_io_util = __commonJS({ Object.defineProperty(exports, "__esModule", { value: true }); exports.getCmdPath = exports.tryGetExecutablePath = exports.isRooted = exports.isDirectory = exports.exists = exports.READONLY = exports.UV_FS_O_EXLOCK = exports.IS_WINDOWS = exports.unlink = exports.symlink = exports.stat = exports.rmdir = exports.rm = exports.rename = exports.readlink = exports.readdir = exports.open = exports.mkdir = exports.lstat = exports.copyFile = exports.chmod = void 0; var fs3 = __importStar(require("fs")); - var path2 = __importStar(require("path")); + var path3 = __importStar(require("path")); _a = fs3.promises, exports.chmod = _a.chmod, exports.copyFile = _a.copyFile, exports.lstat = _a.lstat, exports.mkdir = _a.mkdir, exports.open = _a.open, exports.readdir = _a.readdir, exports.readlink = _a.readlink, exports.rename = _a.rename, exports.rm = _a.rm, exports.rmdir = _a.rmdir, exports.stat = _a.stat, exports.symlink = _a.symlink, exports.unlink = _a.unlink; exports.IS_WINDOWS = process.platform === "win32"; exports.UV_FS_O_EXLOCK = 268435456; @@ -2337,7 +2337,7 @@ var require_io_util = __commonJS({ } if (stats && stats.isFile()) { if (exports.IS_WINDOWS) { - const upperExt = path2.extname(filePath).toUpperCase(); + const upperExt = path3.extname(filePath).toUpperCase(); if (extensions.some((validExt) => validExt.toUpperCase() === upperExt)) { return filePath; } @@ -2361,11 +2361,11 @@ var require_io_util = __commonJS({ if (stats && stats.isFile()) { if (exports.IS_WINDOWS) { try { - const directory = path2.dirname(filePath); - const upperName = path2.basename(filePath).toUpperCase(); + const directory = path3.dirname(filePath); + const upperName = path3.basename(filePath).toUpperCase(); for (const actualName of yield exports.readdir(directory)) { if (upperName === actualName.toUpperCase()) { - filePath = path2.join(directory, actualName); + filePath = path3.join(directory, actualName); break; } } @@ -2437,11 +2437,11 @@ var require_io = __commonJS({ }; var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) { function adopt(value) { - return value instanceof P ? value : new P(function(resolve) { - resolve(value); + return value instanceof P ? value : new P(function(resolve2) { + resolve2(value); }); } - return new (P || (P = Promise))(function(resolve, reject) { + return new (P || (P = Promise))(function(resolve2, reject) { function fulfilled(value) { try { step(generator.next(value)); @@ -2457,7 +2457,7 @@ var require_io = __commonJS({ } } function step(result) { - result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); + result.done ? resolve2(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); @@ -2465,7 +2465,7 @@ var require_io = __commonJS({ Object.defineProperty(exports, "__esModule", { value: true }); exports.findInPath = exports.which = exports.mkdirP = exports.rmRF = exports.mv = exports.cp = void 0; var assert_1 = require("assert"); - var path2 = __importStar(require("path")); + var path3 = __importStar(require("path")); var ioUtil = __importStar(require_io_util()); function cp(source, dest, options = {}) { return __awaiter(this, void 0, void 0, function* () { @@ -2474,7 +2474,7 @@ var require_io = __commonJS({ if (destStat && destStat.isFile() && !force) { return; } - const newDest = destStat && destStat.isDirectory() && copySourceDirectory ? path2.join(dest, path2.basename(source)) : dest; + const newDest = destStat && destStat.isDirectory() && copySourceDirectory ? path3.join(dest, path3.basename(source)) : dest; if (!(yield ioUtil.exists(source))) { throw new Error(`no such file or directory: ${source}`); } @@ -2486,7 +2486,7 @@ var require_io = __commonJS({ yield cpDirRecursive(source, newDest, 0, force); } } else { - if (path2.relative(source, newDest) === "") { + if (path3.relative(source, newDest) === "") { throw new Error(`'${newDest}' and '${source}' are the same file`); } yield copyFile(source, newDest, force); @@ -2499,7 +2499,7 @@ var require_io = __commonJS({ if (yield ioUtil.exists(dest)) { let destExists = true; if (yield ioUtil.isDirectory(dest)) { - dest = path2.join(dest, path2.basename(source)); + dest = path3.join(dest, path3.basename(source)); destExists = yield ioUtil.exists(dest); } if (destExists) { @@ -2510,7 +2510,7 @@ var require_io = __commonJS({ } } } - yield mkdirP(path2.dirname(dest)); + yield mkdirP(path3.dirname(dest)); yield ioUtil.rename(source, dest); }); } @@ -2573,7 +2573,7 @@ var require_io = __commonJS({ } const extensions = []; if (ioUtil.IS_WINDOWS && process.env["PATHEXT"]) { - for (const extension of process.env["PATHEXT"].split(path2.delimiter)) { + for (const extension of process.env["PATHEXT"].split(path3.delimiter)) { if (extension) { extensions.push(extension); } @@ -2586,12 +2586,12 @@ var require_io = __commonJS({ } return []; } - if (tool.includes(path2.sep)) { + if (tool.includes(path3.sep)) { return []; } const directories = []; if (process.env.PATH) { - for (const p of process.env.PATH.split(path2.delimiter)) { + for (const p of process.env.PATH.split(path3.delimiter)) { if (p) { directories.push(p); } @@ -2599,7 +2599,7 @@ var require_io = __commonJS({ } const matches = []; for (const directory of directories) { - const filePath = yield ioUtil.tryGetExecutablePath(path2.join(directory, tool), extensions); + const filePath = yield ioUtil.tryGetExecutablePath(path3.join(directory, tool), extensions); if (filePath) { matches.push(filePath); } @@ -2690,11 +2690,11 @@ var require_toolrunner = __commonJS({ }; var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) { function adopt(value) { - return value instanceof P ? value : new P(function(resolve) { - resolve(value); + return value instanceof P ? value : new P(function(resolve2) { + resolve2(value); }); } - return new (P || (P = Promise))(function(resolve, reject) { + return new (P || (P = Promise))(function(resolve2, reject) { function fulfilled(value) { try { step(generator.next(value)); @@ -2710,7 +2710,7 @@ var require_toolrunner = __commonJS({ } } function step(result) { - result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); + result.done ? resolve2(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); @@ -2720,7 +2720,7 @@ var require_toolrunner = __commonJS({ var os2 = __importStar(require("os")); var events = __importStar(require("events")); var child = __importStar(require("child_process")); - var path2 = __importStar(require("path")); + var path3 = __importStar(require("path")); var io2 = __importStar(require_io()); var ioUtil = __importStar(require_io_util()); var timers_1 = require("timers"); @@ -2935,10 +2935,10 @@ var require_toolrunner = __commonJS({ exec() { return __awaiter(this, void 0, void 0, function* () { if (!ioUtil.isRooted(this.toolPath) && (this.toolPath.includes("/") || IS_WINDOWS && this.toolPath.includes("\\"))) { - this.toolPath = path2.resolve(process.cwd(), this.options.cwd || process.cwd(), this.toolPath); + this.toolPath = path3.resolve(process.cwd(), this.options.cwd || process.cwd(), this.toolPath); } this.toolPath = yield io2.which(this.toolPath, true); - return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { + return new Promise((resolve2, reject) => __awaiter(this, void 0, void 0, function* () { this._debug(`exec tool: ${this.toolPath}`); this._debug("arguments:"); for (const arg of this.args) { @@ -3021,7 +3021,7 @@ var require_toolrunner = __commonJS({ if (error) { reject(error); } else { - resolve(exitCode); + resolve2(exitCode); } }); if (this.options.input) { @@ -3179,11 +3179,11 @@ var require_exec = __commonJS({ }; var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) { function adopt(value) { - return value instanceof P ? value : new P(function(resolve) { - resolve(value); + return value instanceof P ? value : new P(function(resolve2) { + resolve2(value); }); } - return new (P || (P = Promise))(function(resolve, reject) { + return new (P || (P = Promise))(function(resolve2, reject) { function fulfilled(value) { try { step(generator.next(value)); @@ -3199,7 +3199,7 @@ var require_exec = __commonJS({ } } function step(result) { - result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); + result.done ? resolve2(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); @@ -3262,6 +3262,7 @@ var core4 = __toESM(require_core()); // src/install/index.ts var import_node_process = require("node:process"); +var path2 = __toESM(require("node:path")); var core3 = __toESM(require_core()); var exec5 = __toESM(require_exec()); @@ -3366,7 +3367,12 @@ async function pluginsAdd() { async function toolsInstall() { const dir = core3.getInput("directory", { required: false }); if (dir) { - (0, import_node_process.chdir)(dir); + const currentDir = (0, import_node_process.cwd)(); + const targetDir = path2.resolve(currentDir, dir); + if (!targetDir.startsWith(currentDir + path2.sep)) { + throw new Error(`The specified directory (${dir}) is not a subdirectory of the current working directory.`); + } + (0, import_node_process.chdir)(targetDir); } await pluginsAdd(); const before = core3.getInput("before_install", { required: false }); diff --git a/src/install/index.ts b/src/install/index.ts index 7f613bcb..f6aff528 100644 --- a/src/install/index.ts +++ b/src/install/index.ts @@ -1,4 +1,5 @@ -import {chdir} from 'node:process'; +import {chdir, cwd} from 'node:process'; +import * as path from 'node:path'; import * as core from '@actions/core'; import * as exec from '@actions/exec'; import {pluginsAdd} from '~/plugins-add/index.ts'; @@ -6,7 +7,16 @@ import {pluginsAdd} from '~/plugins-add/index.ts'; async function toolsInstall(): Promise { const dir = core.getInput('directory', {required: false}); if (dir) { - chdir(dir); + // Resolve the current working directory and the provided directory to their absolute paths + // Check if the target directory is a subdirectory of the current directory for security reasons + const currentDir = cwd(); + const targetDir = path.resolve(currentDir, dir); + + if (!targetDir.startsWith(currentDir + path.sep)) { + throw new Error(`The specified directory (${dir}) is not a subdirectory of the current working directory.`); + } + + chdir(targetDir); } await pluginsAdd();