Skip to content
Draft
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
24 changes: 24 additions & 0 deletions lib/analyzer/java-runtime/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { JavaRuntimeMetadata } from "../../facts";
import { ExtractedLayers } from "../../extractor/types";
import { getJavaRuntimeReleaseContent } from "../../inputs/java-runtime/static";
import { parseJavaRuntimeRelease } from "./parser";

/**
* Detects Java runtime metadata from the /opt/java/openjdk/release file.
* This provides version, implementor, image type (JRE/JDK), and modules information,
*
* @param extractedLayers - Extracted image layers containing file contents
* @returns Parsed Java runtime metadata or null if not found/parseable
*/
export function detectJavaRuntime(
extractedLayers: ExtractedLayers,
): JavaRuntimeMetadata | null {
const releaseContent = getJavaRuntimeReleaseContent(extractedLayers);

if (!releaseContent) {
return null;
}

return parseJavaRuntimeRelease(releaseContent);
}

39 changes: 39 additions & 0 deletions lib/analyzer/java-runtime/parser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { JavaRuntimeMetadata } from "../../facts";

/**
* Parses the Java runtime release file content into structured metadata.
*
* The release file format is key="value" pairs, one per line:
* IMPLEMENTOR="Eclipse Adoptium"
* JAVA_VERSION="17.0.11"
* IMAGE_TYPE="JRE"
* MODULES="java.base java.logging java.xml ..."
*
* @param content - Raw content of /opt/java/openjdk/release file
* @returns Parsed metadata or null if parsing fails
*/
export function parseJavaRuntimeRelease(
content: string,
): JavaRuntimeMetadata | null {
if (!content || content.trim().length === 0) {
return null;
}

try {
// TODO: Implement actual parsing logic
// For now, return null to indicate parsing not yet implemented
//
// Implementation should:
// 1. Split content by newlines
// 2. Parse each line as KEY="VALUE" or KEY=VALUE
// 3. Extract JAVA_VERSION, IMPLEMENTOR, IMAGE_TYPE, MODULES
// 4. Split MODULES by spaces into an array
// 5. Return JavaRuntimeMetadata object with the extracted information

return null;
} catch (error) {
// If parsing fails, return null
return null;
}
}

5 changes: 5 additions & 0 deletions lib/analyzer/static-analyzer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import {
getJarFileContentAction,
getUsrLibJarFileContentAction,
} from "../inputs/java/static";
import { getJavaRuntimeReleaseAction } from "../inputs/java-runtime/static";
import { detectJavaRuntime } from "./java-runtime";
import {
getNodeAppFileContentAction,
getNodeJsTsAppFileContentAction,
Expand Down Expand Up @@ -99,6 +101,7 @@ export async function analyze(
...getOsReleaseActions,
getNodeBinariesFileContentAction,
getOpenJDKBinariesFileContentAction,
getJavaRuntimeReleaseAction,
getDpkgPackageFileContentAction,
getRedHatRepositoriesContentAction,
];
Expand Down Expand Up @@ -222,6 +225,7 @@ export async function analyze(
}

const binaries = getBinariesHashes(extractedLayers);
const javaRuntimeMetadata = detectJavaRuntime(extractedLayers) || undefined;

const applicationDependenciesScanResults: AppDepsScanResultWithoutTarget[] =
[];
Expand Down Expand Up @@ -298,6 +302,7 @@ export async function analyze(
platform,
results,
binaries,
javaRuntimeMetadata,
imageLayers: manifestLayers,
rootFsLayers,
applicationDependenciesScanResults,
Expand Down
2 changes: 2 additions & 0 deletions lib/analyzer/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ImageName } from "../extractor/image";
import { AutoDetectedUserInstructions, ManifestFile } from "../types";
import { JavaRuntimeMetadata } from "../facts";
import {
AppDepsScanResultWithoutTarget,
JarCoords,
Expand Down Expand Up @@ -74,6 +75,7 @@ export interface StaticAnalysis {
osRelease: OSRelease;
results: ImageAnalysis[];
binaries: string[];
javaRuntimeMetadata?: JavaRuntimeMetadata;
imageLayers: string[];
rootFsLayers?: string[];
autoDetectedUserInstructions?: AutoDetectedUserInstructions;
Expand Down
16 changes: 16 additions & 0 deletions lib/facts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,19 @@ export interface OCIDistributionMetadataFact {
type: "ociDistributionMetadata";
data: OCIDistributionMetadata;
}

export interface JavaRuntimeMetadata {
version: string;
// the vendor/organization that provided the Java runtime (needed because sometimes CVEs are vendor specific)
implementor?: string;
// the type of Java runtime (JRE or JDK)
imageType?: "JRE" | "JDK";
// the modules that are included in the Java runtime
modules?: string[];
releaseFilePath: string;
}

export interface JavaRuntimeMetadataFact {
type: "javaRuntimeMetadata";
data: JavaRuntimeMetadata;
}
32 changes: 32 additions & 0 deletions lib/inputs/java-runtime/static.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { normalize as normalizePath } from "path";
import { getContentAsString } from "../../extractor";
import { ExtractAction, ExtractedLayers } from "../../extractor/types";
import { streamToString } from "../../stream-utils";

/**
* Extract action to detect and read the Java runtime release file.
* This file contains metadata about the Java installation including version,
* implementor, image type (JRE/JDK), and modules (important for jlink custom JREs).
*/
export const getJavaRuntimeReleaseAction: ExtractAction = {
actionName: "java-runtime-release",
// using this specific path for Java runtime metadata for now, but might want to expand this to other paths in the future.
filePathMatches: (filePath) =>
filePath === normalizePath("/opt/java/openjdk/release"),
callback: streamToString,
};

/**
* Retrieves the Java runtime release file content from extracted layers.
* Returns the raw file content as a string, or an empty string if not found.
*/
export function getJavaRuntimeReleaseContent(
extractedLayers: ExtractedLayers,
): string {
const content = getContentAsString(
extractedLayers,
getJavaRuntimeReleaseAction,
);
return content || "";
}

8 changes: 8 additions & 0 deletions lib/response-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ async function buildResponse(
};
additionalFacts.push(keyBinariesHashesFact);
}
// add the Java Runtime Metadata fact as a part of the first scan result
if (depsAnalysis.javaRuntimeMetadata) {
const javaRuntimeMetadataFact: facts.JavaRuntimeMetadataFact = {
type: "javaRuntimeMetadata",
data: depsAnalysis.javaRuntimeMetadata,
};
additionalFacts.push(javaRuntimeMetadataFact);
}

if (dockerfileAnalysis !== undefined) {
const dockerfileAnalysisFact: facts.DockerfileAnalysisFact = {
Expand Down
2 changes: 2 additions & 0 deletions lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ export type FactType =
| "jarFingerprints"
// Hashes of executables not installed by a package manager (e.g. if they were copied straight onto the image).
| "keyBinariesHashes"
// Java runtime metadata extracted from /opt/java/openjdk/release file
| "javaRuntimeMetadata"
| "loadedPackages"
| "ociDistributionMetadata"
| "rootFs"
Expand Down
Loading