Skip to content

Commit

Permalink
fix(transliterate): installing snippet dependencies can fail due to s…
Browse files Browse the repository at this point in the history
…cripts (backport #1820) (#1821)

# Backport

This will backport the following commits from `main` to
`maintenance/v5.3`:
- [fix(transliterate): installing snippet dependencies can fail due to
scripts (#1820)](#1820)

<!--- Backport version: 9.5.1 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

Co-authored-by: Momo Kornher <[email protected]>
  • Loading branch information
aws-cdk-automation and mrgrain authored Aug 28, 2024
1 parent 429c689 commit baeb208
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 6 deletions.
29 changes: 25 additions & 4 deletions src/snippet-dependencies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,10 +244,31 @@ export async function prepareDependencyDirectory(deps: Record<string, Compilatio
},
);

// Run NPM install on this package.json. We need to include --force for packages
// that have a symbolic version in the symlinked dev tree (like "0.0.0"), but have
// actual version range dependencies from externally installed packages (like "^2.0.0").
cp.execSync(`npm install --force --loglevel error`, { cwd: tmpDir, encoding: 'utf-8' });
// Run NPM install on this package.json.
cp.execSync(
[
'npm install',
// We need to include --force for packages
// that have a symbolic version in the symlinked dev tree (like "0.0.0"), but have
// actual version range dependencies from externally installed packages (like "^2.0.0").
'--force',
// this is critical from a security perspective to prevent
// code execution as part of the install command using npm hooks. (e.g postInstall)
'--ignore-scripts',
// save time by not running audit
'--no-audit',
// ensures npm does not insert anything in $PATH
'--no-bin-links',
// don't write or update a package-lock.json file
'--no-package-lock',
// only print errors
`--loglevel error`,
].join(' '),
{
cwd: tmpDir,
encoding: 'utf-8',
},
);

return tmpDir;
}
Expand Down
61 changes: 59 additions & 2 deletions test/rosetta-translator.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import { mkdirSync, writeFileSync } from 'node:fs';
import { mkdtemp, rm } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import * as path from 'node:path';
import { withTemporaryDirectory } from './testutil';
import { RosettaTranslator, typeScriptSnippetFromVisibleSource, SnippetLocation, TargetLanguage } from '../lib';
import {
RosettaTranslator,
typeScriptSnippetFromVisibleSource,
SnippetLocation,
TargetLanguage,
TypeScriptSnippet,
} from '../lib';

const location: SnippetLocation = { api: { api: 'file', fileName: 'test.ts' } };

Expand Down Expand Up @@ -33,7 +41,7 @@ test('translator can read from cache', async () => {
await cacheBuilder.translateAll([snippet]);
await cacheBuilder.tablet.save(join(cacheDir, 'temp.tabl.json'));

// WHEN: new translater
// WHEN: new translator
const translator = new RosettaTranslator({ includeCompilerDiagnostics: true });
await translator.loadCache(join(cacheDir, 'temp.tabl.json'));

Expand All @@ -47,3 +55,52 @@ test('translator can read from cache', async () => {
}
});
});

test('translator can install snippet dependencies with script', async () => {
await withTemporaryDirectory(async (dir) => {
// GIVEN: prepare dependency
const snippetDepName = '@cdklabs/foobar';
const snippetDepDir = 'foobar';
mkdirSync(join(dir, snippetDepDir));
writeFileSync(
path.join(dir, snippetDepDir, 'package.json'),
JSON.stringify(
{
name: snippetDepName,
version: '0.0.1',
private: true,
scripts: {
// fail the script
postinstall: 'exit 1',
},
},
undefined,
2,
),
{
encoding: 'utf-8',
},
);

const translator = new RosettaTranslator({
includeCompilerDiagnostics: true,
});

const snippet: TypeScriptSnippet = {
...typeScriptSnippetFromVisibleSource('console.log("hello world");', location, true),
compilationDependencies: {
[snippetDepName]: {
type: 'concrete',
resolvedDirectory: path.resolve(dir, snippetDepDir),
},
},
};

const { translatedSnippets } = await translator.translateAll([snippet]);

expect(translatedSnippets).toHaveLength(1);
expect(translatedSnippets[0].get(TargetLanguage.PYTHON)?.source).toEqual('print("hello world")');

expect(translator.tablet.snippetKeys).toHaveLength(1);
});
});

0 comments on commit baeb208

Please sign in to comment.