Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { walkFiles } from '../walk-files';
export type StrategyLocations = { [bundlePath: string]: Strategy[] };
export const LOCAL_STRATEGY_ID = 'local';

const ALLOWED_LOCAL_CMD = /^[a-zA-Z0-9._/\-]+((\s+(%[AOBLP]|\S+))+)?$/;

const getStrategyIds = (strategies: StrategyLocations): { [identifier: string]: Strategy } => {
const ids: { [id: string]: Strategy } = {};
for (const strategyList of Object.values(strategies)) {
Expand Down Expand Up @@ -47,6 +49,13 @@ export const deserializeStrategies = (existingBundle: string, strategyMatch: Str
});
}

if (!ALLOWED_LOCAL_CMD.test(deserializedStrategy.owner)) {
throw new BlueprintSynthesisError({
message: `Rejected unsafe local merge strategy command: ${deserializedStrategy.owner}`,
type: BlueprintSynthesisErrorTypes.ValidationError,
});
}

deserializedStrategy.strategy = constructLocalStrategy(deserializedStrategy.owner, ownershipPath);
relevantStrategies.push(deserializedStrategy);
} else if (deserializedStrategy.identifier in inMemStrategies) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { execSync } from 'child_process';
import { execFileSync } from 'child_process';
import { randomBytes } from 'crypto';
import { mkdirSync, readFileSync, rmSync, writeFileSync } from 'fs';
import * as path from 'path';
Expand Down Expand Up @@ -47,31 +47,32 @@ function runLocalCommand(
): Buffer | undefined {
createTempDir();

let cmd: string | undefined;
let cmdArgs: string[] | undefined;
try {
const commonTempFile = createTempFile(buffers.o);
const existingTempFile = createTempFile(buffers.a);
const proposedTempFile = createTempFile(buffers.b);

const cwd = path.dirname(ownershipPath);
cmd = formatLocalCommand(
cmdArgs = formatLocalCommandArgs(
owner,
path.relative(cwd, existingTempFile),
path.relative(cwd, commonTempFile),
path.relative(cwd, proposedTempFile),
resolvedPath,
);

execSync(cmd, {
const [executable, ...args] = cmdArgs;
execFileSync(executable, args, {
cwd,
});

// git merge driver conventions expect the resolved file to have been written to the existing file's path:
return getResolvedFile(existingTempFile);
} catch (error: unknown) {
let message = 'Failed to run local merge strategy';
if (cmd) {
message += `: ${cmd}`;
if (cmdArgs) {
message += `: ${cmdArgs.join(' ')}`;
}

throw new Error(`${message}: ${error}`);
Expand Down Expand Up @@ -118,12 +119,13 @@ function createTempFile(contents: Buffer): string {
return tempPath;
}

function formatLocalCommand(commandPattern: string, aPath: string, oPath: string, bPath: string, resolvedPath: string): string {
function formatLocalCommandArgs(commandPattern: string, aPath: string, oPath: string, bPath: string, resolvedPath: string): string[] {
// see: https://git-scm.com/docs/gitattributes#_defining_a_custom_merge_driver
return commandPattern
const substituted = commandPattern
.replace(/%O/g, oPath)
.replace(/%A/g, aPath)
.replace(/%B/g, bPath)
.replace(/%P/g, resolvedPath)
.replace(/%L/g, `${CONFLICT_MARKER_LENGTH}`);
return substituted.split(/\s+/).filter(s => s.length > 0);
}
8 changes: 3 additions & 5 deletions packages/blueprints/sam-serverless-app/src/blueprint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ export class Blueprint extends ParentBlueprint {

super.synth();

cp.execSync(`rm -rf ${toDeletePath}`);
fs.rmSync(toDeletePath, { recursive: true, force: true });

// update permissions
const permissionChangeContext: FileTemplateContext = {
Expand Down Expand Up @@ -392,12 +392,10 @@ export class Blueprint extends ParentBlueprint {
// `${sourceDir}`,
// ]);

const assetPath = path.join('static-assets', 'sam-templates', params.runtime, params.gitSrcPath, '{{cookiecutter.project_name}}', '*');
const assetDir = path.join('static-assets', 'sam-templates', params.runtime, params.gitSrcPath, '{{cookiecutter.project_name}}');

//TODO: this is a temporary fix to work around SVN failures. These assets need to be updated.
cp.execSync(`cp -R ./${assetPath} ${sourceDir}/`, {
cwd: process.cwd(),
});
fs.cpSync(path.resolve(process.cwd(), assetDir), sourceDir, { recursive: true });

cp.execFileSync('rm', ['-rf', `${sourceDir}/.svn`, `${sourceDir}/.gitignore`, `${sourceDir}/README.md`, `${sourceDir}/template.yaml`]);

Expand Down
8 changes: 4 additions & 4 deletions packages/utils/blueprint-cli/src/bundle/package-bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ export function packageBundle(
},
) {
try {
let zipCommand = [`zip ${path.basename(outputPathAbs)}`, `-r ${path.basename(folderPathAbs)}`, '-x **/.git/**'].join(' ');
logger.debug(zipCommand);
const zipArgs = [path.basename(outputPathAbs), '-r', path.basename(folderPathAbs), '-x', '**/.git/**'];
if (options.encrypt) {
logger.info('Packing folder. Enter zip password ...');
zipCommand = `${zipCommand} -e`;
zipArgs.push('-e');
}
cp.execSync(zipCommand, {
logger.debug(`zip ${zipArgs.join(' ')}`);
cp.execFileSync('zip', zipArgs, {
stdio: 'inherit',
cwd: path.dirname(folderPathAbs),
});
Expand Down
6 changes: 3 additions & 3 deletions packages/utils/blueprint-cli/src/bundle/write-elements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ export async function writeElements(
const sourceLocation = path.join(folderPathAbs, ExportableResource.SRC);
fs.mkdirSync(sourceLocation);
for (const repositoryName of repositories) {
const cloneCommand = ['git', 'clone', options.bundle.code[repositoryName].clone].join(' ');
logger.debug(`Running: ${cloneCommand}`);
cp.execSync(cloneCommand, {
const cloneArgs = ['clone', options.bundle.code[repositoryName].clone];
logger.debug(`Running: git ${cloneArgs.join(' ')}`);
cp.execFileSync('git', cloneArgs, {
stdio: 'inherit',
cwd: sourceLocation,
});
Expand Down
35 changes: 14 additions & 21 deletions packages/utils/blueprint-cli/src/resynth-drivers/resynth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,7 @@ export async function resynthesize(log: pino.BaseLogger, options: ResynthesizeOp
try {
// if something already exists at the output location, we remove it.
log.debug('cleaning up existing code at resynth resolved output location: %s', resolvedLocation);
const cleanCommand = `rm -rf ${resolvedLocation}`;
cp.execSync(cleanCommand, {
stdio: 'inherit',
cwd: options.blueprint,
});
fs.rmSync(path.resolve(options.blueprint, resolvedLocation), { recursive: true, force: true });

const timeStart = Date.now();
executeResynthesisCommand(log, options.blueprint, options.jobname, {
Expand Down Expand Up @@ -220,24 +216,21 @@ const executeResynthesisCommand = (
envVariables?: { [key: string]: string };
},
) => {
cp.execSync(`mkdir -p ${options.outputDirectory}`, {
stdio: 'inherit',
cwd,
});
fs.mkdirSync(options.outputDirectory, { recursive: true });

const command = [
`npx ${options.driver.runtime}`,
`${options.driver.path}`,
`'${JSON.stringify(options.options)}'`,
`${options.outputDirectory}`,
`${options.entropy}`,
`${options.ancestorBundleDirectory}`,
`${options.existingBundleDirectory}`,
`${options.proposedBundleDirectory}`,
].join(' ');
const resynthArgs = [
options.driver.runtime,
options.driver.path,
JSON.stringify(options.options),
options.outputDirectory,
options.entropy,
options.ancestorBundleDirectory,
options.existingBundleDirectory,
options.proposedBundleDirectory,
];

logger.debug(`[${jobname}] reynthesis Command: ${command}`);
cp.execSync(command, {
logger.debug(`[${jobname}] reynthesis Command: npx ${resynthArgs.join(' ')}`);
cp.execFileSync('npx', resynthArgs, {
stdio: 'inherit',
cwd,
env: {
Expand Down
33 changes: 16 additions & 17 deletions packages/utils/blueprint-cli/src/synth-drivers/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const fsLinkerPlugin = {
name: 'fs_linker',
setup(build: any) {
build.onStart(() => {
cp.execSync('rm -rf ./lib/externals');
fs.rmSync('./lib/externals', { recursive: true, force: true });
});

build.onLoad({ filter: /\.(t|j)s/ }, ({ path: filePath }) => {
Expand All @@ -73,9 +73,16 @@ const fsLinkerPlugin = {
const filesSegments = filePath.split('/');
const rootPkg = findParentPackageDir(filesSegments.slice(0, filesSegments.length - 1).join('/'));
const pkgName = JSON.parse(fs.readFileSync(`${rootPkg}/package.json`, { encoding: 'utf-8' })).name;
cp.execSync(
`mkdir -p ./lib/externals/${pkgName} && rsync -a ${rootPkg} ./lib/externals/${pkgName} --include="*/" --exclude="node_modules/**" --prune-empty-dirs`,
);
const externalsDir = `./lib/externals/${pkgName}`;
fs.mkdirSync(externalsDir, { recursive: true });
cp.execFileSync('rsync', [
'-a',
rootPkg,
externalsDir,
'--include=*/',
'--exclude=node_modules/**',
'--prune-empty-dirs',
]);
}
return {
contents,
Expand Down Expand Up @@ -116,11 +123,9 @@ export const createCache = async (
resynthCacheFile,
];
cleanup.forEach(file => {
if (fs.existsSync(path.join(params.buildDirectory, file))) {
cp.execSync(`rm -rf ${file}`, {
stdio: 'inherit',
cwd: params.buildDirectory,
});
const filePath = path.join(params.buildDirectory, file);
if (fs.existsSync(filePath)) {
fs.rmSync(filePath, { recursive: true, force: true });
}
});

Expand All @@ -147,16 +152,10 @@ export const createCache = async (
}));

// clean up the synth driver
cp.execSync(`rm ${synthDriver}`, {
stdio: 'inherit',
cwd: params.buildDirectory,
});
fs.rmSync(path.join(params.buildDirectory, synthDriver), { force: true });

// clean up the resynth driver
cp.execSync(`rm ${resynthDriver}`, {
stdio: 'inherit',
cwd: params.buildDirectory,
});
fs.rmSync(path.join(params.buildDirectory, resynthDriver), { force: true });

return {
synthDriver: path.join(params.buildDirectory, synthCacheFile),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import * as cp from 'child_process';
import * as fs from 'fs';
import * as path from 'path';
import * as deepmerge from 'deepmerge';
Expand Down Expand Up @@ -132,9 +131,7 @@ export const makeDriverFile = async (

export const cleanUpDriver = (log: pino.BaseLogger, file: DriverFile) => {
log.debug(`Cleaning up driver: ${file.path}`);
cp.execSync(`rm ${file.path}`, {
stdio: 'inherit',
});
fs.rmSync(file.path, { force: true });
};

/**
Expand Down
32 changes: 13 additions & 19 deletions packages/utils/blueprint-cli/src/synth-drivers/synth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,7 @@ export async function synthesize(log: pino.BaseLogger, options: SynthOptions) {
try {
// if something already exists at the synthesis location, we remove it.
log.debug('cleaning up existing code at synth location: %s', options.outputDirectory);
const cleanCommand = `rm -rf ${options.outputDirectory}`;
cp.execSync(cleanCommand, {
stdio: 'inherit',
cwd: options.blueprintPath,
});
fs.rmSync(path.resolve(options.blueprintPath, options.outputDirectory), { recursive: true, force: true });

const timeStart = Date.now();
executeSynthesisCommand(log, options.blueprintPath, options.jobname, {
Expand Down Expand Up @@ -127,20 +123,18 @@ function executeSynthesisCommand(
envVariables: { [key: string]: string };
},
) {
cp.execSync(`mkdir -p ${options.outputDirectory}`, {
stdio: 'inherit',
cwd,
});
const synthCommand = [
`npx ${options.driver.runtime}`,
`${options.driver.path}`,
`'${JSON.stringify(options.options)}'`,
`'${options.outputDirectory}'`,
`'${options.entropy}'`,
].join(' ');

logger.debug(`[${jobname}] Synthesis Command: ${synthCommand}`);
cp.execSync(synthCommand, {
fs.mkdirSync(options.outputDirectory, { recursive: true });

const synthArgs = [
options.driver.runtime,
options.driver.path,
JSON.stringify(options.options),
options.outputDirectory,
options.entropy,
];

logger.debug(`[${jobname}] Synthesis Command: npx ${synthArgs.join(' ')}`);
cp.execFileSync('npx', synthArgs, {
stdio: 'inherit',
cwd,
env: {
Expand Down
Loading