Skip to content

Commit 5968af1

Browse files
committed
chore: merge branch 'main' into fix/dockerfile-attribution
2 parents eb4c33d + c9cbe4e commit 5968af1

File tree

31 files changed

+7511
-4069
lines changed

31 files changed

+7511
-4069
lines changed

.circleci/config.yml

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -132,17 +132,30 @@ jobs:
132132
- attach_workspace:
133133
at: ~/snyk-docker-plugin
134134
- run: npm run lint
135-
test:
135+
test_unit:
136+
<<: *defaults
137+
resource_class: medium
138+
steps:
139+
- checkout
140+
- attach_workspace:
141+
at: ~/snyk-docker-plugin
142+
- run: npm run test:unit > test-unit-logs.txt 2>&1
143+
- store_artifacts:
144+
path: test-unit-logs.txt
145+
destination: test-unit-logs
146+
test_system:
136147
<<: *defaults
137148
steps:
138149
- checkout
139150
- setup_remote_docker
140151
- attach_workspace:
141152
at: ~/snyk-docker-plugin
142-
- run: npm run test-jest > test-logs.txt 2>&1
153+
- run:
154+
command: npm run test:system > test-system-logs.txt 2>&1
155+
no_output_timeout: 20m
143156
- store_artifacts:
144-
path: test-logs.txt
145-
destination: test-logs
157+
path: test-system-logs.txt
158+
destination: test-system-logs
146159
test_jest_windows_with_docker:
147160
<<: *windows_big
148161
steps:
@@ -252,8 +265,17 @@ workflows:
252265
context: infrasec_container
253266
post-steps:
254267
- *slack-fail-notify
255-
- test:
256-
name: Test
268+
- test_unit:
269+
name: Unit Test
270+
context:
271+
- nodejs-install
272+
- snyk-bot-slack
273+
requires:
274+
- Build
275+
post-steps:
276+
- *slack-fail-notify
277+
- test_system:
278+
name: System Test
257279
context:
258280
- nodejs-install
259281
- snyk-bot-slack
@@ -303,7 +325,8 @@ workflows:
303325
- Lint
304326
- Build
305327
- Security Scans
306-
- Test
328+
- Unit Test
329+
- System Test
307330
- Test Jest Windows with Docker
308331
- Test Jest Windows no Docker
309332
post-steps:

.github/CODEOWNERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# This is a comment.
22
# Each line is a file pattern followed by one or more owners.
33

4-
* @snyk/infrasec_container
4+
* @snyk/infrasec_container @snyk/container_container
55

.snyk

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,8 @@
22
version: v1.25.0
33
# ignores vulnerabilities until expiry date; change duration by modifying expiry date
44
ignore:
5-
SNYK-JS-TAR-15307072:
6-
- 'snyk-nodejs-lockfile-parser > @yarnpkg/core > tar':
7-
reason: 'Indirect dependency from snyk-nodejs-lockfile-parser, waiting for upstream fix'
8-
expires: 2026-03-26T00:00:00.000Z
9-
SNYK-JS-TAR-15416075:
10-
- 'snyk-nodejs-lockfile-parser > @yarnpkg/core > tar':
11-
reason: 'Indirect dependency from snyk-nodejs-lockfile-parser, waiting for upstream fix'
12-
expires: 2026-03-26T00:00:00.000Z
13-
SNYK-JS-TAR-15456201:
14-
- 'snyk-nodejs-lockfile-parser > @yarnpkg/core > tar':
15-
reason: 'Indirect dependency from snyk-nodejs-lockfile-parser, waiting for upstream fix'
16-
expires: 2026-03-26T00:00:00.000Z
5+
SNYK-JS-LODASH-15869625:
6+
- '*':
7+
reason: 'Indirect dependency, waiting for upstream fix'
8+
expires: 2026-04-09T00:00:00.000Z
179
patch: {}

components/common.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ schemas:
1717
enum:
1818
- autoDetectedUserInstructions
1919
- binaries
20+
- baseRuntimes
2021
- depGraph
2122
- dockerfileAnalysis
2223
- dockerLayers

lib/analyzer/applications/node-modules-utils.ts

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as Debug from "debug";
22
import { mkdir, mkdtemp, rm, stat, writeFile } from "fs/promises";
3+
import * as os from "os";
34
import * as path from "path";
45
import { FilePathToContent, FilesByDirMap } from "./types";
56
const debug = Debug("snyk");
@@ -22,7 +23,7 @@ interface ScanPaths {
2223
async function createTempProjectDir(
2324
projectDir: string,
2425
): Promise<{ tmpDir: string; tempProjectRoot: string }> {
25-
const tmpDir = await mkdtemp("snyk");
26+
const tmpDir = await mkdtemp(path.join(os.tmpdir(), "snyk-"));
2627

2728
const tempProjectRoot = path.join(tmpDir, projectDir);
2829

@@ -76,20 +77,23 @@ async function persistNodeModules(
7677
fileNamesGroupedByDirectory: FilesByDirMap,
7778
): Promise<ScanPaths> {
7879
const modules = fileNamesGroupedByDirectory.get(project);
79-
const tmpDir: string = "";
80-
const tempProjectRoot: string = "";
8180

8281
if (!modules || modules.size === 0) {
8382
debug(`Empty application directory tree.`);
84-
85-
return {
86-
tempDir: tmpDir,
87-
tempProjectPath: tempProjectRoot,
88-
};
83+
return { tempDir: "", tempProjectPath: "" };
8984
}
9085

86+
// Create the temp directory first so we can return it in the catch block
87+
// for cleanup. Previously, the outer tmpDir/tempProjectRoot were always
88+
// empty strings, meaning any temp directory created before a failure in
89+
// saveOnDisk or later steps would be leaked (caller couldn't clean it up).
90+
let tmpDir = "";
91+
let tempProjectRoot = "";
92+
9193
try {
92-
const { tmpDir, tempProjectRoot } = await createTempProjectDir(project);
94+
const created = await createTempProjectDir(project);
95+
tmpDir = created.tmpDir;
96+
tempProjectRoot = created.tempProjectRoot;
9397

9498
await saveOnDisk(tmpDir, modules, filePathToContent);
9599

@@ -122,7 +126,10 @@ async function persistNodeModules(
122126
}
123127
}
124128

125-
async function createFile(filePath, fileContent): Promise<void> {
129+
async function createFile(
130+
filePath: string,
131+
fileContent: string,
132+
): Promise<void> {
126133
try {
127134
await mkdir(path.dirname(filePath), { recursive: true });
128135
await writeFile(filePath, fileContent, "utf-8");

lib/analyzer/applications/node.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ async function depGraphFromNodeModules(
136136
}
137137

138138
const depGraph = await legacy.depTreeToGraph(
139-
pkgTree,
139+
pkgTree as any,
140140
pkgTree.type || "npm",
141141
);
142142

@@ -417,7 +417,7 @@ function stripUndefinedLabels(
417417
parserResult: lockFileParser.PkgTree,
418418
): lockFileParser.PkgTree {
419419
const optionalLabels = parserResult.labels;
420-
const mandatoryLabels: Record<string, string> = {};
420+
const mandatoryLabels: Record<string, any> = {};
421421
if (optionalLabels) {
422422
for (const currentLabelName of Object.keys(optionalLabels)) {
423423
if (optionalLabels[currentLabelName] !== undefined) {
@@ -428,7 +428,7 @@ function stripUndefinedLabels(
428428
const parserResultWithProperLabels = Object.assign({}, parserResult, {
429429
labels: mandatoryLabels,
430430
});
431-
return parserResultWithProperLabels;
431+
return parserResultWithProperLabels as lockFileParser.PkgTree;
432432
}
433433

434434
async function buildDepGraph(
@@ -513,7 +513,10 @@ async function buildDepGraphFromDepTree(
513513
// Don't provide a default manifest file name, prefer the parser to infer it.
514514
);
515515
const strippedLabelsParserResult = stripUndefinedLabels(parserResult);
516-
return await legacy.depTreeToGraph(strippedLabelsParserResult, lockfileType);
516+
return await legacy.depTreeToGraph(
517+
strippedLabelsParserResult as any,
518+
lockfileType,
519+
);
517520
}
518521

519522
export function getLockFileVersion(
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { ExtractedLayers } from "../../extractor/types";
2+
import { BaseRuntime } from "../../facts";
3+
import { getJavaRuntimeReleaseContent } from "../../inputs/base-runtimes/static";
4+
import { parseJavaRuntimeRelease } from "./parser";
5+
6+
export function detectJavaRuntime(
7+
extractedLayers: ExtractedLayers,
8+
): BaseRuntime | null {
9+
const releaseContent = getJavaRuntimeReleaseContent(extractedLayers);
10+
return releaseContent ? parseJavaRuntimeRelease(releaseContent) : null;
11+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { BaseRuntime } from "../../facts";
2+
3+
const VALID_VERSION_PATTERN =
4+
/^(?!.*\.\.)[0-9]+(?:[._+a-zA-Z0-9-]*[a-zA-Z0-9])?$/;
5+
6+
const regex = /^\s*JAVA_VERSION\s*=\s*(?:(["'])(.*?)\1|([^#\r\n]+))/gm;
7+
8+
function isValidJavaVersion(version: string): boolean {
9+
if (!version || version.length === 0) {
10+
return false;
11+
}
12+
return VALID_VERSION_PATTERN.test(version);
13+
}
14+
15+
export function parseJavaRuntimeRelease(content: string): BaseRuntime | null {
16+
if (!content || content.trim().length === 0) {
17+
return null;
18+
}
19+
try {
20+
const matches = [...content.matchAll(regex)];
21+
22+
if (matches.length !== 1) {
23+
return null;
24+
}
25+
const version = (matches[0][2] || matches[0][3] || "").trim();
26+
27+
if (!isValidJavaVersion(version)) {
28+
return null;
29+
}
30+
return { type: "java", version };
31+
} catch (error) {
32+
return null;
33+
}
34+
}

lib/analyzer/image-inspector.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import * as Debug from "debug";
22
import * as fs from "fs";
3-
import * as mkdirp from "mkdirp";
43
import * as path from "path";
54

65
import { Docker, DockerOptions } from "../docker";
@@ -200,7 +199,7 @@ async function getImageArchive(
200199
platform?: string,
201200
): Promise<ArchiveResult> {
202201
const docker = new Docker();
203-
mkdirp.sync(imageSavePath);
202+
fs.mkdirSync(imageSavePath, { recursive: true });
204203
const destination: DestinationDir = {
205204
name: imageSavePath,
206205
removeCallback: cleanupCallback(imageSavePath, "image.tar"),

lib/analyzer/static-analyzer.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
getDpkgFileContentAction,
1616
getExtFileContentAction,
1717
} from "../inputs/apt/static";
18+
import { getJavaRuntimeReleaseAction } from "../inputs/base-runtimes/static";
1819
import {
1920
getBinariesHashes,
2021
getNodeBinariesFileContentAction,
@@ -67,6 +68,7 @@ import { jarFilesToScannedResults } from "./applications/java";
6768
import { pipFilesToScannedProjects } from "./applications/python";
6869
import { getApplicationFiles } from "./applications/runtime-common";
6970
import { AppDepsScanResultWithoutTarget } from "./applications/types";
71+
import { detectJavaRuntime } from "./base-runtimes";
7072
import * as osReleaseDetector from "./os-release";
7173
import { analyze as apkAnalyze } from "./package-managers/apk";
7274
import {
@@ -105,6 +107,7 @@ export async function analyze(
105107
...getOsReleaseActions,
106108
getNodeBinariesFileContentAction,
107109
getOpenJDKBinariesFileContentAction,
110+
getJavaRuntimeReleaseAction,
108111
getDpkgPackageFileContentAction,
109112
getRedHatRepositoriesContentAction,
110113
];
@@ -233,6 +236,8 @@ export async function analyze(
233236
}
234237

235238
const binaries = getBinariesHashes(extractedLayers);
239+
const javaRuntime = detectJavaRuntime(extractedLayers);
240+
const baseRuntimes = javaRuntime ? [javaRuntime] : undefined;
236241

237242
const applicationDependenciesScanResults: AppDepsScanResultWithoutTarget[] =
238243
[];
@@ -309,6 +314,7 @@ export async function analyze(
309314
platform,
310315
results,
311316
binaries,
317+
baseRuntimes,
312318
imageLayers: manifestLayers,
313319
rootFsLayers,
314320
applicationDependenciesScanResults,

0 commit comments

Comments
 (0)