Skip to content

Commit

Permalink
feat: add new generic payload to process scan results from plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanstanev committed Aug 3, 2020
1 parent 11155ec commit c07744a
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 35 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
"author": "snyk.io",
"license": "Apache-2.0",
"dependencies": {
"@snyk/cli-interface": "2.8.1",
"@snyk/cli-interface": "snyk/snyk-cli-interface#spike/artifacts",
"@snyk/dep-graph": "1.18.3",
"@snyk/gemfile": "1.2.0",
"@snyk/graphlib": "2.1.9-patch",
Expand All @@ -76,7 +76,7 @@
"proxy-from-env": "^1.0.0",
"semver": "^6.0.0",
"snyk-config": "3.1.0",
"snyk-docker-plugin": "3.16.0",
"snyk-docker-plugin": "snyk/snyk-docker-plugin#spike/artifacts",
"snyk-go-plugin": "1.16.0",
"snyk-gradle-plugin": "3.5.1",
"snyk-module": "3.1.0",
Expand Down
32 changes: 22 additions & 10 deletions src/cli/commands/monitor/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,11 @@ async function monitor(...args0: MethodArgs): Promise<any> {
// Post the project dependencies to the Registry
for (const projectDeps of perProjectResult.scannedProjects) {
try {
if (!projectDeps.depGraph && !projectDeps.depTree) {
if (
!projectDeps.depGraph &&
!projectDeps.depTree &&
!projectDeps.artifacts
) {
debug(
'scannedProject is missing depGraph or depTree, cannot run test/monitor',
);
Expand All @@ -204,16 +208,24 @@ async function monitor(...args0: MethodArgs): Promise<any> {

let projectName;

if (projectDeps.depGraph) {
debug(`Processing ${projectDeps.depGraph.rootPkg.name}...`);
maybePrintDepGraph(options, projectDeps.depGraph);
projectName = projectDeps.depGraph.rootPkg.name;
const maybeDepGraphArtifact = projectDeps.artifacts?.find(
(artifact) => artifact.type === 'depGraph',
)?.data;
const maybeDepTreeArtifact = projectDeps.artifacts?.find(
(artifact) => artifact.type === 'depTree',
)?.data;

if (maybeDepGraphArtifact || projectDeps.depGraph) {
const graph = maybeDepGraphArtifact || projectDeps.depGraph;
debug(`Processing ${graph.rootPkg.name}...`);
maybePrintDepGraph(options, graph);
projectName = graph.rootPkg.name;
}

if (projectDeps.depTree) {
debug(`Processing ${projectDeps.depTree.name}...`);
maybePrintDepTree(options, projectDeps.depTree);
projectName = projectDeps.depTree.name;
if (maybeDepTreeArtifact || projectDeps.depTree) {
const tree = maybeDepTreeArtifact || projectDeps.depTree;
debug(`Processing ${tree.name}...`);
maybePrintDepTree(options, tree);
projectName = tree.name;
}

const tFile = projectDeps.targetFile || targetFile;
Expand Down
12 changes: 10 additions & 2 deletions src/lib/monitor/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,11 @@ export async function monitor(
analytics.add('packageManager', packageManager);
analytics.add('isDocker', !!meta.isDocker);

if (scannedProject.depGraph) {
const maybeDepGraphArtifact = scannedProject.artifacts?.find(
(artifact) => artifact.type === 'depGraph',
)?.data;

if (maybeDepGraphArtifact || scannedProject.depGraph) {
return await monitorDepGraph(
root,
meta,
Expand Down Expand Up @@ -352,7 +356,11 @@ export async function monitorDepGraph(
const packageManager = meta.packageManager;
analytics.add('monitorDepGraph', true);

let depGraph = scannedProject.depGraph;
const maybeDepGraphArtifact = scannedProject.artifacts?.find(
(artifact) => artifact.type === 'depGraph',
)?.data;

let depGraph = maybeDepGraphArtifact || scannedProject.depGraph;

if (!depGraph) {
debug(
Expand Down
33 changes: 31 additions & 2 deletions src/lib/plugins/get-deps-from-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,40 @@ export async function getDepsFromPlugin(

return convertSingleResultToMultiCustom(inspectRes, options.packageManager);
}

// ----------
// NOTE: How is projectNames used? Do we need to pull out the names
// ----------

// We are using "options" to store some information returned from plugin that we need to use later,
// but don't want to send to Registry in the Payload.
// TODO(kyegupov): decouple inspect and payload so that we don't need this hack
(options as any).projectNames = inspectRes.scannedProjects.map(
(scannedProject) => scannedProject?.depTree?.name,
const hasScannedProjects = inspectRes.scannedProjects !== undefined;
const scannedProjectDoesNotHaveArtifacts = inspectRes.scannedProjects?.every(
(project) => project.artifacts === undefined,
);
if (hasScannedProjects && scannedProjectDoesNotHaveArtifacts) {
(options as any).projectNames = inspectRes.scannedProjects.map(
(scannedProject) => scannedProject?.depTree?.name,
);
} else {
const projectsWithDepTreeArtifacts = inspectRes.scannedProjects.filter(
(scannedProject) =>
scannedProject.artifacts?.some(
(artifact) => artifact.type === 'depTree',
),
);
(options as any).projectNames = projectsWithDepTreeArtifacts.reduce<
string[]
>((prev, curr) => {
// We have previously identified that this project contains a DepTree, so it can't be null.
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const depTreeArtifact = curr.artifacts!.find(
(artifact) => artifact.type === 'depTree',
)!;
prev.push(depTreeArtifact.data?.name);
return prev;
}, []);
}
return convertMultiResultToMultiCustom(inspectRes, options.packageManager);
}
55 changes: 36 additions & 19 deletions src/lib/snyk-test/run-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -373,9 +373,13 @@ async function assembleLocalPayloads(
}

for (const scannedProject of deps.scannedProjects) {
if (!scannedProject.depTree && !scannedProject.depGraph) {
if (
!scannedProject.depTree &&
!scannedProject.depGraph &&
!scannedProject.artifacts
) {
debug(
'scannedProject is missing depGraph or depTree, cannot run test/monitor',
'scannedProject is missing depGraph, depTree or artifacts, cannot run test/monitor',
);
throw new FailedToRunTestError(
'Your test request could not be completed. Please email support@snyk.io',
Expand All @@ -384,15 +388,23 @@ async function assembleLocalPayloads(

// prefer dep-graph fallback on dep tree
// TODO: clean up once dep-graphs only
const pkg:
| DepTree
| depGraphLib.DepGraph
| undefined = scannedProject.depGraph
? scannedProject.depGraph
: scannedProject.depTree;
const maybeDepGraphArtifact = scannedProject.artifacts?.find(
(artifact) => artifact.type === 'depGraph',
)?.data;
const maybeDepTreeArtifact = scannedProject.artifacts?.find(
(artifact) => artifact.type === 'depTree',
)?.data;
const pkg: DepTree | depGraphLib.DepGraph | undefined =
maybeDepGraphArtifact ||
maybeDepTreeArtifact ||
scannedProject.depGraph ||
scannedProject.depTree;

if (options['print-deps']) {
if (scannedProject.depGraph) {
// NOTE: Lots of these if-statements in the code...
// What if we need to work with a different artifact type like jarList...
// The abstraction starts to leak as we need to work with concrete things.
if (maybeDepGraphArtifact || scannedProject.depGraph) {
await spinner.clear<void>(spinnerLbl)();
maybePrintDepGraph(options, pkg as depGraphLib.DepGraph);
} else {
Expand All @@ -409,6 +421,7 @@ async function assembleLocalPayloads(
(pkg as DepTree).docker.baseImage = options['base-image'];
}

// TODO(ivanstanev)
if (baseImageFromDockerfile && deps.plugin && deps.plugin.imageLayers) {
analytics.add('BaseImage', baseImageFromDockerfile);
analytics.add('imageLayers', deps.plugin.imageLayers);
Expand All @@ -431,6 +444,7 @@ async function assembleLocalPayloads(
targetFileDir = dir;
}

// TODO(ivanstanev)
const policy = await findAndLoadPolicy(
root,
options.docker ? 'docker' : packageManager!,
Expand All @@ -442,29 +456,30 @@ async function assembleLocalPayloads(
);

analytics.add('packageManager', packageManager);
if (scannedProject.depGraph) {
if (maybeDepGraphArtifact || scannedProject.depGraph) {
const depGraph = pkg as depGraphLib.DepGraph;
addPackageAnalytics(depGraph.rootPkg.name, depGraph.rootPkg.version!);
}
if (scannedProject.depTree) {
if (maybeDepTreeArtifact || scannedProject.depTree) {
const depTree = pkg as DepTree;
addPackageAnalytics(depTree.name!, depTree.version!);
}

let target: GitTarget | ContainerTarget | null;
if (scannedProject.depGraph) {
let target: GitTarget | ContainerTarget | null = null;
if (maybeDepGraphArtifact || scannedProject.depGraph) {
target = await projectMetadata.getInfo(scannedProject, options);
} else {
} else if (maybeDepTreeArtifact || scannedProject.depTree) {
target = await projectMetadata.getInfo(
scannedProject,
options,
pkg as DepTree,
);
}

const originalProjectName = scannedProject.depGraph
? (pkg as depGraphLib.DepGraph).rootPkg.name
: (pkg as DepTree).name;
const originalProjectName =
maybeDepGraphArtifact || scannedProject.depGraph
? (pkg as depGraphLib.DepGraph).rootPkg.name
: (pkg as DepTree).name;

let body: PayloadBody = {
// WARNING: be careful changing this as it affects project uniqueness
Expand All @@ -480,15 +495,17 @@ async function assembleLocalPayloads(
docker: (pkg as DepTree).docker,
hasDevDependencies: (pkg as any).hasDevDependencies,
target,

artifacts: project.artifacts,
};

if (options.vulnEndpoint) {
// options.vulnEndpoint is only used by `snyk protect` (i.e. local filesystem tests).
body = { ...body, ...pkg };
} else {
let depGraph: depGraphLib.DepGraph;
if (scannedProject.depGraph) {
depGraph = scannedProject.depGraph;
if (maybeDepGraphArtifact || scannedProject.depGraph) {
depGraph = maybeDepGraphArtifact || scannedProject.depGraph;
} else {
// Graphs are more compact and robust representations.
// Legacy parts of the code are still using trees, but will eventually be fully migrated.
Expand Down
2 changes: 2 additions & 0 deletions src/lib/snyk-test/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import * as depGraphLib from '@snyk/dep-graph';
import { GitTarget, ContainerTarget } from '../project-metadata/types';
import { DepTree } from '../types';
import { IacScan } from './payload-schema';
import { ScannedArtifact } from '@snyk/cli-interface/legacy/common';

export interface PayloadBody {
depGraph?: depGraphLib.DepGraph; // missing for legacy endpoint (options.vulnEndpoint)
artifacts?: ScannedArtifact[]; // NEW
callGraph?: any;
policy?: string;
targetFile?: string;
Expand Down

0 comments on commit c07744a

Please sign in to comment.