snyk-docker-plugin
Version:
Snyk CLI docker plugin
170 lines • 8.95 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseProvenanceAttestations = void 0;
const Debug = require("debug");
const dockerfile_1 = require("../dockerfile");
const debug = Debug("snyk");
const MAX_ATTESTATIONS_PER_IMAGE = 10;
function getDecodedDockerfileContents(infos, dockerfileName) {
const match = infos === null || infos === void 0 ? void 0 : infos.find((info) => info.filename === dockerfileName);
if (!(match === null || match === void 0 ? void 0 : match.data)) {
return null;
}
return Buffer.from(match.data, "base64").toString("utf8");
}
async function analyseDecodedDockerfile(infos, dockerfileName) {
const contents = getDecodedDockerfileContents(infos, dockerfileName);
if (contents === null) {
return null;
}
return (0, dockerfile_1.analyseDockerfile)(contents);
}
function getConfigSourceCommit(digest) {
var _a;
if (!digest) {
return null;
}
const [algorithm, value] = (_a = Object.entries(digest)[0]) !== null && _a !== void 0 ? _a : [];
if (!algorithm || !value) {
return null;
}
return `${algorithm}:${value}`;
}
async function extractFieldsSlsaV0_2(predicate, attestedManifestDigest, attestationManifestDigest) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
const buildTimestamp = ((_a = predicate.metadata) === null || _a === void 0 ? void 0 : _a.buildStartedOn) || null;
const buildkitMeta = (_b = predicate.metadata) === null || _b === void 0 ? void 0 : _b["https://mobyproject.org/buildkit@v1#metadata"];
const remoteCommit = getConfigSourceCommit((_d = (_c = predicate.invocation) === null || _c === void 0 ? void 0 : _c.configSource) === null || _d === void 0 ? void 0 : _d.digest);
const localCommit = (_e = buildkitMeta === null || buildkitMeta === void 0 ? void 0 : buildkitMeta.vcs) === null || _e === void 0 ? void 0 : _e.revision;
const buildConfigDigest = remoteCommit || localCommit || null;
const buildConfigDigestSource = remoteCommit
? "remote"
: localCommit
? "local"
: null;
const buildConfigSourceUri = ((_g = (_f = predicate.invocation) === null || _f === void 0 ? void 0 : _f.configSource) === null || _g === void 0 ? void 0 : _g.uri) || null;
const builderId = ((_h = predicate.builder) === null || _h === void 0 ? void 0 : _h.id) || "";
const buildType = predicate.buildType || "";
const dockerfileName = ((_k = (_j = predicate.invocation) === null || _j === void 0 ? void 0 : _j.configSource) === null || _k === void 0 ? void 0 : _k.entryPoint) || "Dockerfile";
const dockerfileAnalysis = await analyseDecodedDockerfile((_l = buildkitMeta === null || buildkitMeta === void 0 ? void 0 : buildkitMeta.source) === null || _l === void 0 ? void 0 : _l.infos, dockerfileName);
return {
buildTimestamp,
buildConfigDigest,
buildConfigDigestSource,
attestedManifestDigest,
attestationManifestDigest,
buildConfigSourceUri,
builderId,
buildType,
dockerfileMetadata: {
name: dockerfileName,
analysis: dockerfileAnalysis,
},
};
}
async function extractFieldsSlsaV1_0(predicate, attestedManifestDigest, attestationManifestDigest) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
const runDetails = predicate.runDetails;
const buildDefinition = predicate.buildDefinition;
const buildTimestamp = ((_a = runDetails === null || runDetails === void 0 ? void 0 : runDetails.metadata) === null || _a === void 0 ? void 0 : _a.startedOn) || null;
const remoteCommit = getConfigSourceCommit((_c = (_b = buildDefinition === null || buildDefinition === void 0 ? void 0 : buildDefinition.externalParameters) === null || _b === void 0 ? void 0 : _b.configSource) === null || _c === void 0 ? void 0 : _c.digest);
const localCommit = (_f = (_e = (_d = runDetails === null || runDetails === void 0 ? void 0 : runDetails.metadata) === null || _d === void 0 ? void 0 : _d.buildkit_metadata) === null || _e === void 0 ? void 0 : _e.vcs) === null || _f === void 0 ? void 0 : _f.revision;
const buildConfigDigest = remoteCommit || localCommit || null;
const buildConfigDigestSource = remoteCommit
? "remote"
: localCommit
? "local"
: null;
const buildConfigSourceUri = ((_h = (_g = buildDefinition === null || buildDefinition === void 0 ? void 0 : buildDefinition.externalParameters) === null || _g === void 0 ? void 0 : _g.configSource) === null || _h === void 0 ? void 0 : _h.uri) || null;
const builderId = ((_j = runDetails === null || runDetails === void 0 ? void 0 : runDetails.builder) === null || _j === void 0 ? void 0 : _j.id) || "";
const buildType = (buildDefinition === null || buildDefinition === void 0 ? void 0 : buildDefinition.buildType) || "";
const dockerfileName = ((_l = (_k = buildDefinition === null || buildDefinition === void 0 ? void 0 : buildDefinition.externalParameters) === null || _k === void 0 ? void 0 : _k.configSource) === null || _l === void 0 ? void 0 : _l.path) || "Dockerfile";
const dockerfileAnalysis = await analyseDecodedDockerfile((_p = (_o = (_m = runDetails === null || runDetails === void 0 ? void 0 : runDetails.metadata) === null || _m === void 0 ? void 0 : _m.buildkit_metadata) === null || _o === void 0 ? void 0 : _o.source) === null || _p === void 0 ? void 0 : _p.infos, dockerfileName);
return {
buildTimestamp,
buildConfigDigest,
buildConfigDigestSource,
attestedManifestDigest,
attestationManifestDigest,
buildConfigSourceUri,
builderId,
buildType,
dockerfileMetadata: {
name: dockerfileName,
analysis: dockerfileAnalysis,
},
};
}
function getAttestedManifestDigest(statement) {
var _a, _b, _c;
const digest = (_b = (_a = statement.subject) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.digest;
if (!digest) {
return null;
}
const [algorithm, value] = (_c = Object.entries(digest)[0]) !== null && _c !== void 0 ? _c : [];
if (!algorithm || !value) {
return null;
}
return `${algorithm}:${value}`;
}
function getSlsaProvenanceVersion(predicateType) {
switch (predicateType) {
case "https://slsa.dev/provenance/v0.2":
case "https://slsa.dev/provenance/v1":
return predicateType;
default:
return null;
}
}
async function parseStatement(statement, attestationManifestDigest, attestedManifestDigest) {
const predicate = statement.predicate;
if (!predicate) {
debug("[provenance] No predicate found in in-toto statement");
return null;
}
const resolvedAttestedManifestDigest = attestedManifestDigest || getAttestedManifestDigest(statement);
if (!resolvedAttestedManifestDigest) {
debug("[provenance] Could not determine the attested manifest digest");
return null;
}
const predicateType = statement.predicateType;
const version = getSlsaProvenanceVersion(predicateType);
if (version === null) {
debug(`[provenance] Unsupported SLSA predicate type: ${predicateType}`);
return null;
}
switch (version) {
case "https://slsa.dev/provenance/v0.2":
return extractFieldsSlsaV0_2(predicate, resolvedAttestedManifestDigest, attestationManifestDigest);
case "https://slsa.dev/provenance/v1":
return extractFieldsSlsaV1_0(predicate, resolvedAttestedManifestDigest, attestationManifestDigest);
default: {
const _exhaustiveCheck = version;
return _exhaustiveCheck;
}
}
}
async function parseProvenanceAttestations(attestationManifests) {
const results = [];
const sortedManifests = [...attestationManifests].sort((a, b) => a.manifestDigest.localeCompare(b.manifestDigest));
for (const attestation of sortedManifests) {
const sortedLayers = [...attestation.manifest.layers].sort((a, b) => a.digest.localeCompare(b.digest));
for (const layer of sortedLayers) {
if (results.length >= MAX_ATTESTATIONS_PER_IMAGE) {
debug(`[provenance] Reached max attestation limit (${MAX_ATTESTATIONS_PER_IMAGE}), skipping remaining`);
return results;
}
const inTotoStatement = attestation.inTotoStatements[layer.digest];
if (!inTotoStatement) {
continue;
}
const parsed = await parseStatement(inTotoStatement, attestation.manifestDigest, attestation.attestedManifestDigest);
if (parsed) {
results.push(parsed);
}
}
}
return results;
}
exports.parseProvenanceAttestations = parseProvenanceAttestations;
//# sourceMappingURL=provenance-parser.js.map