1 | ![Snyk logo](https://snyk.io/style/asset/logo/snyk-print.svg)
|
2 |
|
3 | ***
|
4 |
|
5 | [![Known Vulnerabilities](https://snyk.io/test/npm/@snyk/dep-graph/badge.svg)](https://snyk.io/test/npm/@snyk/dep-graph)
|
6 |
|
7 | Snyk helps you find, fix and monitor for known vulnerabilities in your dependencies, both on an ad hoc basis and as part of your CI (Build) system.
|
8 |
|
9 | # Snyk dep-graph
|
10 |
|
11 | This library provides a time and space efficient representation of a resolved package dependency graph, which can be used to construct, query and de/serialize dep-graphs.
|
12 |
|
13 | ## The Graph
|
14 |
|
15 | A directed graph, where a node represents a package instance and an edge from node `foo` to node `bar` means `bar` is a dependency of `foo`.
|
16 |
|
17 | A package (`name@version`) can have several different nodes (i.e. instances) in the graph. This flexibility is useful for some ecosystems, for example:
|
18 |
|
19 | * in `npm` due to conflict-resolutions by duplication. e.g. try to `npm i tap@5.7` and then run `npm ls` and look for `strip-ansi@3.0.1`. You'll see that in some instances it depends on `ansi-regex@2.0.0` while in others on `ansi-regex@2.1.1`.
|
20 | * in `maven` due to "exclusion" rules. A dependency `foo` can be declared in the `pom.xml` such that some of it's sub-dependencies are excluded via the `<exclusions>` tag. If the same dependency is required elsewhere without (or with different) exclusions then `foo` can appear in the tree with different sub-trees.
|
21 |
|
22 | This can also be used to break cycles in the graph, e.g.:
|
23 |
|
24 | instead of:
|
25 | ```
|
26 | A -> B -> C -> A
|
27 | ```
|
28 | can have:
|
29 | ```
|
30 | A -> B -> C -> A'
|
31 | ```
|
32 |
|
33 | ## API Reference
|
34 |
|
35 | ### `DepGraph`
|
36 |
|
37 | #### Interface
|
38 |
|
39 | A dep-graph instance can be queried using the following interface:
|
40 |
|
41 | ```typescript
|
42 | export interface DepGraph {
|
43 | readonly pkgManager: {
|
44 | name: string;
|
45 | version?: string;
|
46 | repositories?: Array<{
|
47 | alias: string;
|
48 | }>;
|
49 | };
|
50 | readonly rootPkg: {
|
51 | name: string;
|
52 | version?: string;
|
53 | purl?: string;
|
54 | };
|
55 | // all unique packages in the graph (including root package)
|
56 | getPkgs(): Array<{
|
57 | name: string;
|
58 | version?: string;
|
59 | purl?: string;
|
60 | }>;
|
61 | // all unique packages in the graph, except the root package
|
62 | getDepPkgs(): Array<{
|
63 | name: string;
|
64 | version?: string;
|
65 | purl?: string;
|
66 | }>;
|
67 | pkgPathsToRoot(pkg: Pkg): Array<Array<{
|
68 | name: string;
|
69 | version?: string;
|
70 | purl?: string;
|
71 | }>>;
|
72 | directDepsLeadingTo(pkg: Pkg): Array<{
|
73 | name: string;
|
74 | version?: string;
|
75 | purl?: string;
|
76 | }>;
|
77 | countPathsToRoot(pkg: Pkg): number;
|
78 | toJSON(): DepGraphData;
|
79 | equals(other: DepGraph, options?: { compareRoot?: boolean }): boolean;
|
80 | }
|
81 | ```
|
82 |
|
83 | ### `DepGraphData`
|
84 |
|
85 | A dep-graph can be serialised into the following format:
|
86 |
|
87 | ```typescript
|
88 | export interface DepGraphData {
|
89 | schemaVersion: string;
|
90 | pkgManager: {
|
91 | name: string;
|
92 | version?: string;
|
93 | repositories?: Array<{
|
94 | alias: string;
|
95 | }>;
|
96 | };
|
97 | pkgs: Array<{
|
98 | id: string;
|
99 | info: {
|
100 | name: string;
|
101 | version?: string;
|
102 | purl?: string;
|
103 | };
|
104 | }>;
|
105 | graph: {
|
106 | rootNodeId: string;
|
107 | nodes: Array<{
|
108 | nodeId: string;
|
109 | pkgId: string;
|
110 | info?: {
|
111 | versionProvenance?: {
|
112 | type: string;
|
113 | location: string;
|
114 | property?: {
|
115 | name: string;
|
116 | };
|
117 | },
|
118 | labels?: {
|
119 | [key: string]: string | undefined;
|
120 | };
|
121 | };
|
122 | deps: Array<{
|
123 | nodeId: string;
|
124 | }>;
|
125 | }>;
|
126 | };
|
127 | }
|
128 | ```
|
129 |
|
130 | ### `createFromJSON`
|
131 |
|
132 | `DepGraphData` can be used to construct a `DepGraph` instance using `createFromJSON`
|
133 |
|
134 | ### `DepGraphBuilder`
|
135 | `DepGraphBuilder` is used to create new `DepGraph` instances by adding packages and their connections.
|
136 |
|
137 | ```typescript
|
138 | /**
|
139 | * Instantiates build for given package manager
|
140 | *
|
141 | * @param pkgManager - package manager for which dependcy graph is created
|
142 | * @param rootPkg - root package information
|
143 | *
|
144 | */
|
145 | public constructor(pkgManager: types.PkgManager, rootPkg?: types.PkgInfo)
|
146 |
|
147 | /**
|
148 | * Adds node to the graph. Every node represents logical instance of the package in the dependency graph.
|
149 | *
|
150 | * @param pkgInfo - name and version of the package
|
151 | * @param nodeId - identifier for node in the graph, e.g. `package@version`.
|
152 | * Must uniquely identify this "instance" of the package in the graph,
|
153 | * so may need to be more than `package@version` for many ecosystems.
|
154 | * If in doubt - ask a contributor!
|
155 | * @param nodeInfo - additional node info, e.g. for version provenance
|
156 | *
|
157 | */
|
158 | public addPkgNode(pkgInfo: types.PkgInfo, nodeId: string, nodeInfo?: types.NodeInfo)
|
159 |
|
160 | /**
|
161 | * Makes a connection between parent and its dependency.
|
162 | *
|
163 | * @param parentNodeId - id of the parent node
|
164 | * @param depNodeId - id of the dependency node
|
165 | *
|
166 | */
|
167 | public connectDep(parentNodeId: string, depNodeId: string)
|
168 |
|
169 | /**
|
170 | * Creates an instance of DepGraph
|
171 | *
|
172 | * @return DepGraph instance built from provided packages and their connections
|
173 | *
|
174 | */
|
175 | public build(): types.DepGraph
|
176 |
|
177 | ```
|
178 | ### The `legacy` module
|
179 |
|
180 | A `DepTree` is a legacy structure used by the Snyk CLI to represent dependency trees. Conversion functions in the `legacy` module ease the gradual migration of code that relies on the legacy format.
|
181 |
|
182 | #### Legacy `DepTree`
|
183 |
|
184 | A `DepTree` is a recursive structure that is quite similar to the output of `npm list --json`, and (omitting some details) looks like:
|
185 |
|
186 | ```typescript
|
187 | interface DepTree {
|
188 | name: string;
|
189 | version: string;
|
190 | dependencies?: {
|
191 | [depName: string]: DepTree
|
192 | };
|
193 | }
|
194 | ```
|
195 |
|
196 | The `legacy` conversion functions aim to maintain extra data that might be attached to the dep-tree and is dependant upon in code that wasn't yet updated to use solely dep-graphs:
|
197 | * `targetOS` which exists on tree roots for Docker scans
|
198 | * `versionProvenance` which might exist on the nodes of maven trees, storing information about the source manifest that caused the specfic version to be resolved
|