snyk-docker-plugin
Version:
Snyk CLI docker plugin
89 lines • 3.95 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getChiselManifestContent = exports.getChiselManifestAction = void 0;
const Debug = require("debug");
const path_1 = require("path");
const compression_utils_1 = require("../../compression-utils");
const extractor_1 = require("../../extractor");
const stream_utils_1 = require("../../stream-utils");
const debug = Debug("snyk");
/**
* Path to the Chisel manifest file within container images.
* This file contains package and slice information for Chisel-built images.
*/
const CHISEL_MANIFEST_PATH = "/var/lib/chisel/manifest.wall";
/**
* Extract action for Ubuntu Chisel manifest files.
*
* Chisel is Ubuntu's tool for creating minimal container images by installing
* only specific "slices" of Debian packages. The manifest.wall file is a
* zstd-compressed NDJSON (newline-delimited JSON) file that records all
* installed packages, slices, and files for integrity verification and SBOM generation.
*
* See: https://documentation.ubuntu.com/chisel/en/latest/reference/manifest/
*/
exports.getChiselManifestAction = {
actionName: "chisel-manifest",
filePathMatches: (filePath) => filePath === (0, path_1.normalize)(CHISEL_MANIFEST_PATH),
callback: stream_utils_1.streamToBuffer,
};
/**
* Extracts and parses Chisel package information from Docker image layers.
*
* Searches for the Chisel manifest file (/var/lib/chisel/manifest.wall), decompresses it,
* and extracts package entries. The manifest uses NDJSON format where each line is a
* separate JSON object with a "kind" field indicating the entry type.
*
* @param extractedLayers - Layers extracted from the Docker image
* @returns Array of Chisel packages found in the manifest, or empty array if not found
*/
function getChiselManifestContent(extractedLayers) {
const compressedManifest = (0, extractor_1.getContentAsBuffer)(extractedLayers, exports.getChiselManifestAction);
if (!compressedManifest) {
return [];
}
try {
const decompressed = (0, compression_utils_1.decompressZstd)(compressedManifest);
const manifestText = decompressed.toString("utf8");
const packages = [];
const lines = manifestText.split("\n");
for (const line of lines) {
if (!line.trim()) {
continue;
}
try {
const entry = JSON.parse(line);
// Only extract package entries; manifest also contains "slice", "path", and "content" entries
if (entry.kind === "package") {
// Validate required fields exist before creating package object
if (!entry.name || !entry.version || !entry.sha256 || !entry.arch) {
debug(`Skipping package entry with missing required fields: ${JSON.stringify(entry)}`);
continue;
}
packages.push({
kind: entry.kind,
name: entry.name,
version: entry.version,
sha256: entry.sha256,
arch: entry.arch,
});
}
}
catch (parseError) {
// Skip malformed JSON lines - manifest may be corrupted or have trailing newlines
debug(`Failed to parse Chisel manifest line: ${parseError instanceof Error
? parseError.message
: String(parseError)}`);
continue;
}
}
debug(`Found ${packages.length} Chisel packages in manifest`);
return packages;
}
catch (error) {
debug(`Failed to process Chisel manifest: ${error instanceof Error ? error.message : String(error)}`);
return [];
}
}
exports.getChiselManifestContent = getChiselManifestContent;
//# sourceMappingURL=static.js.map