Skip to content

Commit 5ca57e5

Browse files
authored
feat: add facts to app projects for upsert (#746)
* feat: add container asset facts for CN-555 * fix: remove version * fix: package-lock.json * fix: update snapshots * test: update snapshots * test: update window snapshots * feat: enforce size constraints * fix: lint * feat: generic truncation in res build * feat: pluginwarning fact with truncation vals * fix: update to skip dep graph * fix: address comments * fix: reduce truncation logic * fix: update types to accept null values * fix: update object nulls * fix: add image labels tests * fix: test multiple scan results trunc and fix import * fix: update test to use real response builder * fix: update all tests to check identiy fields and target * fix: update test snapshots * test: update windows snapshot
1 parent 3f80025 commit 5ca57e5

53 files changed

Lines changed: 25901 additions & 11467 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ jobs:
207207
- run: npm run build
208208
- run:
209209
name: Release on GitHub
210-
command: npx semantic-release@19.0.5
210+
command: npx semantic-release
211211

212212
workflows:
213213
version: 2

lib/analyzer/static-analyzer.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@ export async function analyze(
160160
platform,
161161
imageLabels,
162162
imageCreationTime,
163+
containerConfig,
164+
history,
163165
} = await archiveExtractor.extractImageContent(
164166
imageType,
165167
imagePath,
@@ -314,6 +316,8 @@ export async function analyze(
314316
autoDetectedUserInstructions,
315317
imageLabels,
316318
imageCreationTime,
319+
containerConfig,
320+
history,
317321
};
318322
}
319323

lib/analyzer/types.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,25 @@ export interface StaticAnalysis {
8282
manifestFiles: ManifestFile[];
8383
imageLabels?: { [key: string]: string };
8484
imageCreationTime?: string;
85+
containerConfig?: {
86+
User?: string | null;
87+
ExposedPorts?: { [port: string]: object } | null;
88+
Env?: string[] | null;
89+
Entrypoint?: string[] | null;
90+
Cmd?: string[] | null;
91+
Volumes?: { [path: string]: object } | null;
92+
WorkingDir?: string | null;
93+
Labels?: { [key: string]: string };
94+
StopSignal?: string | null;
95+
ArgsEscaped?: boolean | null;
96+
} | null;
97+
history?: Array<{
98+
created?: string | null;
99+
author?: string | null;
100+
created_by?: string | null;
101+
comment?: string | null;
102+
empty_layer?: boolean | null;
103+
}> | null;
85104
}
86105

87106
export interface StaticPackagesAnalysis extends StaticAnalysis {

lib/extractor/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,9 @@ export async function extractImageContent(
148148
archiveContent.imageConfig,
149149
),
150150
platform: getPlatformFromConfig(archiveContent.imageConfig),
151-
imageLabels: archiveContent.imageConfig.config.Labels,
151+
imageLabels: archiveContent.imageConfig.config?.Labels,
152+
containerConfig: archiveContent.imageConfig.config,
153+
history: archiveContent.imageConfig.history,
152154
};
153155
}
154156

lib/extractor/types.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ export interface ExtractionResult {
3434
platform?: string;
3535
imageLabels?: { [key: string]: string };
3636
imageCreationTime?: string;
37+
containerConfig?: ContainerConfig | null;
38+
history?: HistoryEntry[] | null;
3739
}
3840

3941
export interface ExtractedLayers {
@@ -54,14 +56,34 @@ export interface DockerArchiveManifest {
5456
Layers: string[];
5557
}
5658

59+
export interface ContainerConfig {
60+
User?: string | null;
61+
ExposedPorts?: { [port: string]: object } | null;
62+
Env?: string[] | null;
63+
Entrypoint?: string[] | null;
64+
Cmd?: string[] | null;
65+
Volumes?: { [path: string]: object } | null;
66+
WorkingDir?: string | null;
67+
Labels?: { [key: string]: string };
68+
StopSignal?: string | null;
69+
ArgsEscaped?: boolean | null;
70+
}
71+
72+
export interface HistoryEntry {
73+
created?: string | null;
74+
author?: string | null;
75+
created_by?: string | null;
76+
comment?: string | null;
77+
empty_layer?: boolean | null;
78+
}
79+
5780
export interface ImageConfig {
5881
architecture: string;
5982
os: string;
6083
rootfs: { diff_ids: string[] };
61-
config: {
62-
Labels: { [key: string]: string };
63-
};
84+
config: ContainerConfig | null;
6485
created: string;
86+
history?: HistoryEntry[] | null;
6587
}
6688

6789
export interface OciArchiveLayer {

lib/facts.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,51 @@ export interface OCIDistributionMetadataFact {
103103
type: "ociDistributionMetadata";
104104
data: OCIDistributionMetadata;
105105
}
106+
107+
export interface PlatformFact {
108+
type: "platform";
109+
data: string;
110+
}
111+
112+
export interface PluginVersionFact {
113+
type: "pluginVersion";
114+
data: string;
115+
}
116+
117+
export interface ContainerConfigFact {
118+
type: "containerConfig";
119+
data: {
120+
user?: string | null;
121+
exposedPorts?: string[] | null;
122+
env?: string[] | null;
123+
entrypoint?: string[] | null;
124+
cmd?: string[] | null;
125+
volumes?: string[] | null;
126+
workingDir?: string | null;
127+
stopSignal?: string | null;
128+
argsEscaped?: boolean | null;
129+
};
130+
}
131+
132+
export interface HistoryFact {
133+
type: "history";
134+
data: Array<{
135+
created?: string | null;
136+
author?: string | null;
137+
createdBy?: string | null;
138+
comment?: string | null;
139+
emptyLayer?: boolean | null;
140+
}>;
141+
}
142+
143+
export interface PluginWarningsFact {
144+
type: "pluginWarnings";
145+
data: {
146+
truncatedFacts: {
147+
[key: string]: {
148+
type: "array" | "string";
149+
countAboveLimit: number;
150+
};
151+
};
152+
};
153+
}

lib/response-builder.ts

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ import * as facts from "./facts";
77
import { instructionDigest } from "./dockerfile";
88
import { DockerFileAnalysis, DockerFilePackages } from "./dockerfile/types";
99
import { OCIDistributionMetadata } from "./extractor/oci-distribution-metadata";
10+
1011
import * as types from "./types";
12+
import { truncateAdditionalFacts } from "./utils";
13+
import { PLUGIN_VERSION } from "./version";
1114

1215
export { buildResponse };
1316

@@ -81,6 +84,62 @@ async function buildResponse(
8184
additionalFacts.push(imageLabels);
8285
}
8386

87+
if (depsAnalysis.containerConfig) {
88+
const containerConfigFact: facts.ContainerConfigFact = {
89+
type: "containerConfig",
90+
data: {
91+
...(depsAnalysis.containerConfig.User !== undefined && {
92+
user: depsAnalysis.containerConfig.User,
93+
}),
94+
...(depsAnalysis.containerConfig.ExposedPorts !== undefined && {
95+
exposedPorts: depsAnalysis.containerConfig.ExposedPorts
96+
? Object.keys(depsAnalysis.containerConfig.ExposedPorts)
97+
: null,
98+
}),
99+
...(depsAnalysis.containerConfig.Env !== undefined && {
100+
env: depsAnalysis.containerConfig.Env,
101+
}),
102+
...(depsAnalysis.containerConfig.Entrypoint !== undefined && {
103+
entrypoint: depsAnalysis.containerConfig.Entrypoint,
104+
}),
105+
...(depsAnalysis.containerConfig.Cmd !== undefined && {
106+
cmd: depsAnalysis.containerConfig.Cmd,
107+
}),
108+
...(depsAnalysis.containerConfig.Volumes !== undefined && {
109+
volumes: depsAnalysis.containerConfig.Volumes
110+
? Object.keys(depsAnalysis.containerConfig.Volumes)
111+
: null,
112+
}),
113+
...(depsAnalysis.containerConfig.WorkingDir !== undefined && {
114+
workingDir: depsAnalysis.containerConfig.WorkingDir,
115+
}),
116+
...(depsAnalysis.containerConfig.StopSignal !== undefined && {
117+
stopSignal: depsAnalysis.containerConfig.StopSignal,
118+
}),
119+
...(depsAnalysis.containerConfig.ArgsEscaped !== undefined && {
120+
argsEscaped: depsAnalysis.containerConfig.ArgsEscaped,
121+
}),
122+
},
123+
};
124+
additionalFacts.push(containerConfigFact);
125+
}
126+
127+
if (depsAnalysis.history && depsAnalysis.history.length > 0) {
128+
const historyFact: facts.HistoryFact = {
129+
type: "history",
130+
data: depsAnalysis.history.map((entry) => ({
131+
...(entry.created !== undefined && { created: entry.created }),
132+
...(entry.author !== undefined && { author: entry.author }),
133+
...(entry.created_by !== undefined && { createdBy: entry.created_by }),
134+
...(entry.comment !== undefined && { comment: entry.comment }),
135+
...(entry.empty_layer !== undefined && {
136+
emptyLayer: entry.empty_layer,
137+
}),
138+
})),
139+
};
140+
additionalFacts.push(historyFact);
141+
}
142+
84143
if (depsAnalysis.imageCreationTime) {
85144
const imageCreationTimeFact: facts.ImageCreationTimeFact = {
86145
type: "imageCreationTime",
@@ -158,6 +217,28 @@ async function buildResponse(
158217
appDepsScanResult.facts.push(imageIdFact);
159218
}
160219

220+
if (names && names.length > 0) {
221+
const imageNamesFact: facts.ImageNamesFact = {
222+
type: "imageNames",
223+
data: { names },
224+
};
225+
appDepsScanResult.facts.push(imageNamesFact);
226+
}
227+
228+
if (ociDistributionMetadata) {
229+
const metadataFact: facts.OCIDistributionMetadataFact = {
230+
type: "ociDistributionMetadata",
231+
data: ociDistributionMetadata,
232+
};
233+
appDepsScanResult.facts.push(metadataFact);
234+
}
235+
236+
const appPluginVersionFact: facts.PluginVersionFact = {
237+
type: "pluginVersion",
238+
data: PLUGIN_VERSION,
239+
};
240+
appDepsScanResult.facts.push(appPluginVersionFact);
241+
161242
return {
162243
...appDepsScanResult,
163244
target: {
@@ -199,6 +280,20 @@ async function buildResponse(
199280
additionalFacts.push(metadataFact);
200281
}
201282

283+
if (depsAnalysis.platform) {
284+
const platformFact: facts.PlatformFact = {
285+
type: "platform",
286+
data: depsAnalysis.platform,
287+
};
288+
additionalFacts.push(platformFact);
289+
}
290+
291+
const pluginVersionFact: facts.PluginVersionFact = {
292+
type: "pluginVersion",
293+
data: PLUGIN_VERSION,
294+
};
295+
additionalFacts.push(pluginVersionFact);
296+
202297
const scanResults: types.ScanResult[] = [
203298
{
204299
facts: [depGraphFact, ...additionalFacts],
@@ -217,8 +312,13 @@ async function buildResponse(
217312
...applicationDependenciesScanResults,
218313
];
219314

315+
const truncatedScanResults = scanResults.map((result) => ({
316+
...result,
317+
facts: truncateAdditionalFacts(result.facts || []),
318+
}));
319+
220320
return {
221-
scanResults,
321+
scanResults: truncatedScanResults,
222322
};
223323
}
224324

lib/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export type FactType =
5555
| "autoDetectedUserInstructions"
5656
| "depGraph"
5757
| "dockerfileAnalysis"
58+
| "history"
5859
| "imageCreationTime"
5960
| "imageId"
6061
| "imageLabels"
@@ -71,6 +72,10 @@ export type FactType =
7172
| "keyBinariesHashes"
7273
| "loadedPackages"
7374
| "ociDistributionMetadata"
75+
| "containerConfig"
76+
| "platform"
77+
| "pluginVersion"
78+
| "pluginWarnings"
7479
| "rootFs"
7580
// Used for application dependencies scanning; shows which files were used in the analysis of the dependencies.
7681
| "testedFiles"

0 commit comments

Comments
 (0)