Skip to content

Commit 89bd0bf

Browse files
authored
fix: CodeQL CDS extractor support for private @sap/cds-indexer package installs via .npmrc (#347)
1 parent 04e620b commit 89bd0bf

File tree

6 files changed

+377
-7
lines changed

6 files changed

+377
-7
lines changed

extractors/cds/tools/dist/cds-extractor.bundle.js

Lines changed: 34 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

extractors/cds/tools/dist/cds-extractor.bundle.js.map

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

extractors/cds/tools/src/packageManager/cacheInstaller.ts

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { execFileSync } from 'child_process';
22
import { createHash } from 'crypto';
3-
import { existsSync, mkdirSync, writeFileSync } from 'fs';
4-
import { join, resolve } from 'path';
3+
import { copyFileSync, existsSync, mkdirSync, writeFileSync } from 'fs';
4+
import { dirname, join, resolve } from 'path';
55

66
import type { CdsDependencyCombination } from './types';
77
import { CdsDependencyGraph, CdsProject } from '../cds/parser/types';
@@ -48,6 +48,61 @@ function addDependencyVersionWarning(
4848
}
4949
}
5050

51+
/**
52+
* Find the nearest `.npmrc` file by searching the given directory and its
53+
* ancestors up to (and including) the filesystem root. npm itself walks the
54+
* directory tree when looking for project-level `.npmrc` files, so we mirror
55+
* that behaviour here.
56+
*
57+
* @param startDir The directory from which to start the upward search.
58+
* @returns The absolute path to the nearest `.npmrc`, or `undefined` if none is found.
59+
*/
60+
export function findNearestNpmrc(startDir: string): string | undefined {
61+
let current = resolve(startDir);
62+
63+
// Walk up the directory tree until we find an .npmrc or reach the root
64+
65+
while (true) {
66+
const candidate = join(current, '.npmrc');
67+
if (existsSync(candidate)) {
68+
return candidate;
69+
}
70+
const parent = dirname(current);
71+
if (parent === current) {
72+
// Reached filesystem root without finding .npmrc
73+
return undefined;
74+
}
75+
current = parent;
76+
}
77+
}
78+
79+
/**
80+
* Copy the project's `.npmrc` file (if any) into the cache directory so that
81+
* `npm install` inside the cache respects custom registry configuration such
82+
* as scoped registries (`@sap:registry=...`), authentication tokens, and
83+
* `strict-ssl` settings.
84+
*
85+
* @param cacheDir The cache directory where dependencies will be installed.
86+
* @param projectDir Absolute path to the project directory whose `.npmrc` should be used.
87+
*/
88+
export function copyNpmrcToCache(cacheDir: string, projectDir: string): void {
89+
const npmrcPath = findNearestNpmrc(projectDir);
90+
if (!npmrcPath) {
91+
return;
92+
}
93+
94+
const dest = join(cacheDir, '.npmrc');
95+
try {
96+
copyFileSync(npmrcPath, dest);
97+
cdsExtractorLog('info', `Copied .npmrc from '${npmrcPath}' to cache directory '${cacheDir}'`);
98+
} catch (err) {
99+
cdsExtractorLog(
100+
'warn',
101+
`Failed to copy .npmrc to cache directory: ${err instanceof Error ? err.message : String(err)}`,
102+
);
103+
}
104+
}
105+
51106
/**
52107
* Install dependencies for CDS projects using a robust cache strategy with fallback logic
53108
* @param dependencyGraph The dependency graph of the project
@@ -206,6 +261,14 @@ export function cacheInstallDependencies(
206261
}
207262
}
208263

264+
// Ensure the cache directory has an .npmrc that reflects the projects' registry configuration
265+
const npmrcProjectDir = Array.from(dependencyGraph.projects.values())
266+
.map(project => project.projectDir)
267+
.find(projectDir => projectDir && existsSync(join(sourceRoot, projectDir, '.npmrc')));
268+
if (npmrcProjectDir) {
269+
copyNpmrcToCache(cacheDir, join(sourceRoot, npmrcProjectDir));
270+
}
271+
209272
// Try to install dependencies in the cache directory
210273
// Get the first project package.json path for diagnostic purposes
211274
const samplePackageJsonPath = Array.from(dependencyGraph.projects.values()).find(

extractors/cds/tools/src/packageManager/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Export the new robust installer functionality (preferred)
2-
export { cacheInstallDependencies } from './cacheInstaller';
2+
export { cacheInstallDependencies, copyNpmrcToCache, findNearestNpmrc } from './cacheInstaller';
33
export { needsFullDependencyInstallation, projectInstallDependencies } from './projectInstaller';
44
export type { CdsDependencyCombination } from './types';
55
export {

0 commit comments

Comments
 (0)