AikidoSec-safe-chain/packages/safe-chain/src/shell-integration/setup-ci.js
2026-04-14 11:30:29 -07:00

152 lines
4.2 KiB
JavaScript

import chalk from "chalk";
import { ui } from "../environment/userInteraction.js";
import { getPackageManagerList, knownAikidoTools } from "./helpers.js";
import {
getShimsDir,
getBinDir,
getPathWrapperTemplatePath,
} from "../config/safeChainDir.js";
import fs from "fs";
import os from "os";
import path from "path";
/**
* Loops over the detected shells and calls the setup function for each.
*/
export async function setupCi() {
ui.writeInformation(
chalk.bold("Setting up shell aliases.") +
` This will wrap safe-chain around ${getPackageManagerList()}.`
);
ui.emptyLine();
const shimsDir = getShimsDir();
const binDir = getBinDir();
// Create the shims directory if it doesn't exist
if (!fs.existsSync(shimsDir)) {
fs.mkdirSync(shimsDir, { recursive: true });
}
createShims(shimsDir);
ui.writeInformation(`Created shims in ${shimsDir}`);
modifyPathForCi(shimsDir, binDir);
ui.writeInformation(`Added shims directory to PATH for CI environments.`);
}
/**
* @param {string} shimsDir
*
* @returns {void}
*/
function createUnixShims(shimsDir) {
// Read the template file
const templatePath = getPathWrapperTemplatePath(import.meta.url, "unix-wrapper.template.sh");
if (!fs.existsSync(templatePath)) {
ui.writeError(`Template file not found: ${templatePath}`);
return;
}
const template = fs.readFileSync(templatePath, "utf-8");
// Create a shim for each tool
let created = 0;
for (const toolInfo of getToolsToSetup()) {
const shimContent = template
.replaceAll("{{PACKAGE_MANAGER}}", toolInfo.tool)
.replaceAll("{{AIKIDO_COMMAND}}", toolInfo.aikidoCommand);
const shimPath = path.join(shimsDir, toolInfo.tool);
fs.writeFileSync(shimPath, shimContent, "utf-8");
// Make the shim executable on Unix systems
fs.chmodSync(shimPath, 0o755);
created++;
}
ui.writeInformation(`Created ${created} Unix shim(s) in ${shimsDir}`);
}
/**
* @param {string} shimsDir
*
* @returns {void}
*/
function createWindowsShims(shimsDir) {
// Read the template file
const templatePath = getPathWrapperTemplatePath(import.meta.url, "windows-wrapper.template.cmd");
if (!fs.existsSync(templatePath)) {
ui.writeError(`Windows template file not found: ${templatePath}`);
return;
}
const template = fs.readFileSync(templatePath, "utf-8");
// Create a shim for each tool
let created = 0;
for (const toolInfo of getToolsToSetup()) {
const shimContent = template
.replaceAll("{{PACKAGE_MANAGER}}", toolInfo.tool)
.replaceAll("{{AIKIDO_COMMAND}}", toolInfo.aikidoCommand);
const shimPath = `${shimsDir}/${toolInfo.tool}.cmd`;
fs.writeFileSync(shimPath, shimContent, "utf-8");
created++;
}
ui.writeInformation(`Created ${created} Windows shim(s) in ${shimsDir}`);
}
/**
* @param {string} shimsDir
*
* @returns {void}
*/
function createShims(shimsDir) {
if (os.platform() === "win32") {
createWindowsShims(shimsDir);
} else {
createUnixShims(shimsDir);
}
}
/**
* @param {string} shimsDir
* @param {string} binDir
*
* @returns {void}
*/
function modifyPathForCi(shimsDir, binDir) {
if (process.env.GITHUB_PATH) {
// In GitHub Actions, append the shims directory to GITHUB_PATH
fs.appendFileSync(
process.env.GITHUB_PATH,
shimsDir + os.EOL + binDir + os.EOL,
"utf-8"
);
ui.writeInformation(
`Added shims directory to GITHUB_PATH for GitHub Actions.`
);
}
if (process.env.TF_BUILD) {
// In Azure Pipelines, prepending the path is done via a logging command:
// ##vso[task.prependpath]/path/to/add
// Logging this to stdout will cause the Azure Pipelines agent to pick it up
ui.writeInformation("##vso[task.prependpath]" + shimsDir);
ui.writeInformation("##vso[task.prependpath]" + binDir);
}
if (process.env.BASH_ENV) {
// In CircleCI, persisting PATH across steps is done by appending shell exports
// to the file referenced by BASH_ENV. CircleCI sources this file for 'run' each step.
const exportLine = `export PATH="${shimsDir}:${binDir}:$PATH"` + os.EOL;
fs.appendFileSync(process.env.BASH_ENV, exportLine, "utf-8");
ui.writeInformation(`Added shims directory to BASH_ENV for CircleCI.`);
}
}
function getToolsToSetup() {
return knownAikidoTools;
}