Skip to content

Commit 4e492e3

Browse files
committed
Create missing image and layer directory codebase resources
Signed-off-by: tdruez <[email protected]>
1 parent cb0c6e6 commit 4e492e3

File tree

6 files changed

+299
-5
lines changed

6 files changed

+299
-5
lines changed

.github/workflows/sca-integration-cyclonedx-gomod.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ on:
1313
schedule:
1414
# Run once a week (every 7 days) at 00:00 UTC on Sunday
1515
- cron: "0 0 * * 0"
16-
pull_request:
1716

1817
permissions:
1918
contents: read

scanpipe/pipes/docker.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,11 +169,34 @@ def get_layer_tag(image_id, layer_id, layer_index, id_length=6):
169169
return f"img-{short_image_id}-layer-{layer_index:02}-{short_layer_id}"
170170

171171

172-
def create_codebase_resources(project, image):
173-
"""Create the CodebaseResource for an `image` in a `project`."""
172+
def create_codebase_resources(project, image: Image) -> None:
173+
"""
174+
Create codebase resources for the provided image and its layers.
175+
176+
Creates a codebase resource for the extracted image root directory and each
177+
extracted layer directory, ensuring the structure is properly indexed for tree
178+
rendering.
179+
180+
Args:
181+
project: The project instance.
182+
image: The image object with the extracted_location attribute.
183+
184+
"""
185+
pipes.make_codebase_resource(
186+
project=project,
187+
location=str(project.codebase_path / Path(image.extracted_location).name),
188+
)
189+
174190
for layer_index, layer in enumerate(image.layers, start=1):
175191
layer_tag = get_layer_tag(image.image_id, layer.layer_id, layer_index)
176192

193+
pipes.make_codebase_resource(
194+
project=project,
195+
location=str(layer.extracted_location),
196+
tag=layer_tag,
197+
extra_data={"layer": {"created_by": layer.created_by}},
198+
)
199+
177200
for resource in layer.get_resources(with_dir=True):
178201
pipes.make_codebase_resource(
179202
project=project,

scanpipe/tests/data/docker/debian_scan_codebase.json

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,82 @@
439439
],
440440
"dependencies": [],
441441
"files": [
442+
{
443+
"path": "debian.tar.gz-extract",
444+
"type": "directory",
445+
"name": "debian.tar.gz-extract",
446+
"status": "scanned",
447+
"for_packages": [],
448+
"tag": "",
449+
"extension": ".tar.gz-extract",
450+
"programming_language": "",
451+
"detected_license_expression": "",
452+
"detected_license_expression_spdx": "",
453+
"license_detections": [],
454+
"license_clues": [],
455+
"percentage_of_license_text": null,
456+
"copyrights": [],
457+
"holders": [],
458+
"authors": [],
459+
"package_data": [],
460+
"emails": [],
461+
"urls": [],
462+
"md5": "",
463+
"sha1": "",
464+
"sha256": "",
465+
"sha512": "",
466+
"sha1_git": "",
467+
"is_binary": false,
468+
"is_text": false,
469+
"is_archive": false,
470+
"is_media": false,
471+
"is_legal": false,
472+
"is_manifest": false,
473+
"is_readme": false,
474+
"is_top_level": false,
475+
"is_key_file": false,
476+
"extra_data": {}
477+
},
478+
{
479+
"path": "debian.tar.gz-extract/8a63761caf6d45e65b8e6cdc2e0c03c55625fd142ec3356b80a9ea4a34b11b66",
480+
"type": "directory",
481+
"name": "8a63761caf6d45e65b8e6cdc2e0c03c55625fd142ec3356b80a9ea4a34b11b66",
482+
"status": "scanned",
483+
"for_packages": [],
484+
"tag": "img-c19c05-layer-01-8a6376",
485+
"extension": "",
486+
"programming_language": "",
487+
"detected_license_expression": "",
488+
"detected_license_expression_spdx": "",
489+
"license_detections": [],
490+
"license_clues": [],
491+
"percentage_of_license_text": null,
492+
"copyrights": [],
493+
"holders": [],
494+
"authors": [],
495+
"package_data": [],
496+
"emails": [],
497+
"urls": [],
498+
"md5": "",
499+
"sha1": "",
500+
"sha256": "",
501+
"sha512": "",
502+
"sha1_git": "",
503+
"is_binary": false,
504+
"is_text": false,
505+
"is_archive": false,
506+
"is_media": false,
507+
"is_legal": false,
508+
"is_manifest": false,
509+
"is_readme": false,
510+
"is_top_level": false,
511+
"is_key_file": false,
512+
"extra_data": {
513+
"layer": {
514+
"created_by": "/bin/sh -c #(nop) ADD file:37744639836b248c88f6e126619829290b45c233309538310e8fffb82e98eaf8 in / "
515+
}
516+
}
517+
},
442518
{
443519
"path": "debian.tar.gz-extract/8a63761caf6d45e65b8e6cdc2e0c03c55625fd142ec3356b80a9ea4a34b11b66/etc",
444520
"type": "directory",

scanpipe/tests/data/docker/gcr_io_distroless_base_scan_codebase.json

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,82 @@
507507
],
508508
"dependencies": [],
509509
"files": [
510+
{
511+
"path": "gcr_io_distroless_base.tar.gz-extract",
512+
"type": "directory",
513+
"name": "gcr_io_distroless_base.tar.gz-extract",
514+
"status": "scanned",
515+
"for_packages": [],
516+
"tag": "",
517+
"extension": ".tar.gz-extract",
518+
"programming_language": "",
519+
"detected_license_expression": "",
520+
"detected_license_expression_spdx": "",
521+
"license_detections": [],
522+
"license_clues": [],
523+
"percentage_of_license_text": null,
524+
"copyrights": [],
525+
"holders": [],
526+
"authors": [],
527+
"package_data": [],
528+
"emails": [],
529+
"urls": [],
530+
"md5": "",
531+
"sha1": "",
532+
"sha256": "",
533+
"sha512": "",
534+
"sha1_git": "",
535+
"is_binary": false,
536+
"is_text": false,
537+
"is_archive": false,
538+
"is_media": false,
539+
"is_legal": false,
540+
"is_manifest": false,
541+
"is_readme": false,
542+
"is_top_level": false,
543+
"is_key_file": false,
544+
"extra_data": {}
545+
},
546+
{
547+
"path": "gcr_io_distroless_base.tar.gz-extract/cb3279093e638ddfd56bff4d3d89c5a3ed6dd59dbcfbc2f3107045635996b822",
548+
"type": "directory",
549+
"name": "cb3279093e638ddfd56bff4d3d89c5a3ed6dd59dbcfbc2f3107045635996b822",
550+
"status": "scanned",
551+
"for_packages": [],
552+
"tag": "img-f596dc-layer-02-cb3279",
553+
"extension": "",
554+
"programming_language": "",
555+
"detected_license_expression": "",
556+
"detected_license_expression_spdx": "",
557+
"license_detections": [],
558+
"license_clues": [],
559+
"percentage_of_license_text": null,
560+
"copyrights": [],
561+
"holders": [],
562+
"authors": [],
563+
"package_data": [],
564+
"emails": [],
565+
"urls": [],
566+
"md5": "",
567+
"sha1": "",
568+
"sha256": "",
569+
"sha512": "",
570+
"sha1_git": "",
571+
"is_binary": false,
572+
"is_text": false,
573+
"is_archive": false,
574+
"is_media": false,
575+
"is_legal": false,
576+
"is_manifest": false,
577+
"is_readme": false,
578+
"is_top_level": false,
579+
"is_key_file": false,
580+
"extra_data": {
581+
"layer": {
582+
"created_by": "bazel build ..."
583+
}
584+
}
585+
},
510586
{
511587
"path": "gcr_io_distroless_base.tar.gz-extract/cb3279093e638ddfd56bff4d3d89c5a3ed6dd59dbcfbc2f3107045635996b822/etc",
512588
"type": "directory",
@@ -15597,6 +15673,46 @@
1559715673
"is_key_file": false,
1559815674
"extra_data": {}
1559915675
},
15676+
{
15677+
"path": "gcr_io_distroless_base.tar.gz-extract/d92879194ba1c23b840306b007bce6568f71f0e954d63625d48504d533749e30",
15678+
"type": "directory",
15679+
"name": "d92879194ba1c23b840306b007bce6568f71f0e954d63625d48504d533749e30",
15680+
"status": "scanned",
15681+
"for_packages": [],
15682+
"tag": "img-f596dc-layer-01-d92879",
15683+
"extension": "",
15684+
"programming_language": "",
15685+
"detected_license_expression": "",
15686+
"detected_license_expression_spdx": "",
15687+
"license_detections": [],
15688+
"license_clues": [],
15689+
"percentage_of_license_text": null,
15690+
"copyrights": [],
15691+
"holders": [],
15692+
"authors": [],
15693+
"package_data": [],
15694+
"emails": [],
15695+
"urls": [],
15696+
"md5": "",
15697+
"sha1": "",
15698+
"sha256": "",
15699+
"sha512": "",
15700+
"sha1_git": "",
15701+
"is_binary": false,
15702+
"is_text": false,
15703+
"is_archive": false,
15704+
"is_media": false,
15705+
"is_legal": false,
15706+
"is_manifest": false,
15707+
"is_readme": false,
15708+
"is_top_level": false,
15709+
"is_key_file": false,
15710+
"extra_data": {
15711+
"layer": {
15712+
"created_by": "bazel build ..."
15713+
}
15714+
}
15715+
},
1560015716
{
1560115717
"path": "gcr_io_distroless_base.tar.gz-extract/d92879194ba1c23b840306b007bce6568f71f0e954d63625d48504d533749e30/bin",
1560215718
"type": "directory",

scanpipe/tests/data/image-with-symlinks/minitag.tar-expected-scan.json

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,82 @@
8888
"packages": [],
8989
"dependencies": [],
9090
"files": [
91+
{
92+
"path": "minitag.tar-extract",
93+
"type": "directory",
94+
"name": "minitag.tar-extract",
95+
"status": "scanned",
96+
"for_packages": [],
97+
"tag": "",
98+
"extension": ".tar-extract",
99+
"programming_language": "",
100+
"detected_license_expression": "",
101+
"detected_license_expression_spdx": "",
102+
"license_detections": [],
103+
"license_clues": [],
104+
"percentage_of_license_text": null,
105+
"copyrights": [],
106+
"holders": [],
107+
"authors": [],
108+
"package_data": [],
109+
"emails": [],
110+
"urls": [],
111+
"md5": "",
112+
"sha1": "",
113+
"sha256": "",
114+
"sha512": "",
115+
"sha1_git": "",
116+
"is_binary": false,
117+
"is_text": false,
118+
"is_archive": false,
119+
"is_media": false,
120+
"is_legal": false,
121+
"is_manifest": false,
122+
"is_readme": false,
123+
"is_top_level": false,
124+
"is_key_file": false,
125+
"extra_data": {}
126+
},
127+
{
128+
"path": "minitag.tar-extract/887ac3b73f9a48d1324380c8d1ef033873a6cb882a5a9170fba51fa69fd5e5f0",
129+
"type": "directory",
130+
"name": "887ac3b73f9a48d1324380c8d1ef033873a6cb882a5a9170fba51fa69fd5e5f0",
131+
"status": "scanned",
132+
"for_packages": [],
133+
"tag": "img-592e8d-layer-01-887ac3",
134+
"extension": "",
135+
"programming_language": "",
136+
"detected_license_expression": "",
137+
"detected_license_expression_spdx": "",
138+
"license_detections": [],
139+
"license_clues": [],
140+
"percentage_of_license_text": null,
141+
"copyrights": [],
142+
"holders": [],
143+
"authors": [],
144+
"package_data": [],
145+
"emails": [],
146+
"urls": [],
147+
"md5": "",
148+
"sha1": "",
149+
"sha256": "",
150+
"sha512": "",
151+
"sha1_git": "",
152+
"is_binary": false,
153+
"is_text": false,
154+
"is_archive": false,
155+
"is_media": false,
156+
"is_legal": false,
157+
"is_manifest": false,
158+
"is_readme": false,
159+
"is_top_level": false,
160+
"is_key_file": false,
161+
"extra_data": {
162+
"layer": {
163+
"created_by": "/bin/sh -c #(nop) ADD file:783bda715f24a7fcabfe87ca07ae47e5cca3d35b99dd78e3155748e41477acb2 in / "
164+
}
165+
}
166+
},
91167
{
92168
"path": "minitag.tar-extract/887ac3b73f9a48d1324380c8d1ef033873a6cb882a5a9170fba51fa69fd5e5f0/lib",
93169
"type": "directory",

scanpipe/tests/test_pipelines.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,10 +1218,14 @@ def test_scanpipe_docker_pipeline_debian_integration(self):
12181218
exitcode, out = pipeline.execute()
12191219
self.assertEqual(0, exitcode, msg=out)
12201220

1221-
self.assertEqual(16, project1.codebaseresources.count())
1221+
self.assertEqual(18, project1.codebaseresources.count())
12221222
self.assertEqual(2, project1.discoveredpackages.count())
12231223
self.assertEqual(0, project1.discovereddependencies.count())
12241224

1225+
# Ensure all extracted resources exists as CodebaseResource
1226+
fs_resource_count = sum(1 for _ in project1.codebase_path.rglob("*"))
1227+
self.assertEqual(18, fs_resource_count)
1228+
12251229
result_file = output.to_json(project1)
12261230
expected_file = self.data / "docker" / "debian_scan_codebase.json"
12271231
self.assertPipelineResultEqual(expected_file, result_file)
@@ -1241,7 +1245,7 @@ def test_scanpipe_docker_pipeline_distroless_debian_integration(self):
12411245
exitcode, out = pipeline.execute()
12421246
self.assertEqual(0, exitcode, msg=out)
12431247

1244-
self.assertEqual(2458, project1.codebaseresources.count())
1248+
self.assertEqual(2461, project1.codebaseresources.count())
12451249
self.assertEqual(6, project1.discoveredpackages.count())
12461250
self.assertEqual(0, project1.discovereddependencies.count())
12471251

0 commit comments

Comments
 (0)