Skip to content

Commit 0decf90

Browse files
committed
Merge remote-tracking branch 'origin/main' into track-current-url
2 parents 3ce8f76 + 2af8198 commit 0decf90

16 files changed

+1861
-92
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: Generate SBOM with ORT and load into ScanCode.io
2+
3+
# This workflow:
4+
# 1. Generates a CycloneDX SBOM for a requirement.txt file using ORT.
5+
# 2. Uploads the SBOM as a GitHub artifact for future inspection.
6+
# 3. Loads the SBOM into ScanCode.io for further analysis.
7+
# 4. Runs assertions to verify that the SBOM was properly processed in ScanCode.io.
8+
#
9+
# It runs on demand, and once a week (scheduled).
10+
11+
on:
12+
workflow_dispatch:
13+
schedule:
14+
# Run once a week (every 7 days) at 00:00 UTC on Sunday
15+
- cron: "0 0 * * 0"
16+
pull_request:
17+
push:
18+
branches:
19+
- main
20+
21+
permissions:
22+
contents: read
23+
24+
jobs:
25+
generate-and-load-sbom:
26+
runs-on: ubuntu-24.04
27+
steps:
28+
- name: Create a Python requirements.txt
29+
run: |
30+
cat << 'EOF' > requirements.txt
31+
amqp==5.1.1
32+
appdirs==1.4.4
33+
asgiref==3.5.2
34+
urllib3==1.26.0
35+
EOF
36+
37+
- name: Run GitHub Action for ORT
38+
uses: oss-review-toolkit/ort-ci-github-action@v1
39+
40+
- name: Import SBOM into ScanCode.io
41+
uses: aboutcode-org/scancode-action@main
42+
with:
43+
pipelines: "load_sbom"
44+
inputs-path: "${{ env.ORT_RESULTS_PATH }}/bom.cyclonedx.json"
45+
scancodeio-repo-branch: "main"
46+
47+
- name: Verify SBOM Analysis Results in ScanCode.io
48+
shell: bash
49+
run: |
50+
scanpipe shell --command "from scanpipe.models import DiscoveredPackage, DiscoveredDependency; package_manager = DiscoveredPackage.objects; assert package_manager.count() >= 5; assert package_manager.vulnerable().count() >= 1; assert DiscoveredDependency.objects.count() >= 1"

docs/faq.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,9 +376,10 @@ are actively supported and tested::
376376
- Anchore: https://anchore.com/sbom/
377377
- CycloneDX cdxgen: https://cyclonedx.github.io/cdxgen/
378378
- OWASP dep-scan: https://owasp.org/www-project-dep-scan/
379+
- OSS Review Toolkit (ORT): https://oss-review-toolkit.org/ort/
380+
- OSV-Scanner: https://osv.dev/
379381
- SBOM tool: https://github.com/microsoft/sbom-tool/
380382
- Trivy: https://trivy.dev/
381-
- OSV-Scanner: https://osv.dev/
382383

383384
.. note:: Imported SBOMs must follow the SPDX or CycloneDX standards, in JSON format.
384385
You can use the ``load_sbom`` pipeline to process and enhance these SBOMs in your

scanpipe/pipes/benchmark.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,6 @@ def compare_purls(project, expected_purls):
7070
- Lines starting with '+' are unexpected in the project.
7171
"""
7272
sorted_project_purls = get_unique_project_purls(project)
73-
print(sorted_project_purls)
74-
7573
diff_result = difflib.ndiff(sorted_project_purls, expected_purls)
7674

7775
# Keep only lines that are diffs (- or +)
Lines changed: 102 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,110 @@
11
{% load humanize %}
22

3-
{% if resources %}
4-
<table class="table is-bordered is-striped is-narrow is-fullwidth">
5-
<thead class="is-sticky">
6-
<tr>
7-
<th>Name</th>
8-
<th>Status</th>
9-
<th>Language</th>
10-
<th>License</th>
11-
<th>Alert</th>
12-
</tr>
13-
</thead>
14-
<tbody>
15-
{% for resource in resources %}
3+
<div class="mb-4">
4+
<div class="has-text-weight-semibold is-flex is-align-items-center is-family-monospace">
5+
{% if path_segments %}
6+
<span id="resource-path" class="has-text-weight-medium">
7+
{% spaceless %}
8+
{% for subpath, segment in path_segments %}
9+
{% if not forloop.first %}<span class="mx-1">/</span>{% endif %}
10+
{% if not forloop.last %}
11+
<a href="#" class="expand-in-tree has-text-link" data-path="{{ subpath }}" hx-get="{% url 'codebase_resource_table' project.slug %}?path={{ subpath }}" hx-target="#right-pane" hx-push-url="{% url 'codebase_resource_tree' project.slug %}?path={{ subpath }}">{{ segment }}</a>
12+
{% else %}
13+
<span>{{ segment }}</span>
14+
{% endif %}
15+
{% endfor %}
16+
{% endspaceless %}
17+
</span>
18+
<button class="copy-to-clipboard ml-2 is-size-6 is-shadowless is-white" aria-label="Copy path" data-copy="{{ path }}" data-copy-feedback="Path copied!">
19+
<i class="fa-regular fa-copy"></i>
20+
</button>
21+
{% else %}
22+
<span id="resource-path" class="has-text-weight-medium">/</span>
23+
<button class="copy-to-clipboard ml-2 is-size-6 is-shadowless is-white" aria-label="Copy path" data-copy="/" data-copy-feedback="Path copied!">
24+
<i class="fa-regular fa-copy"></i>
25+
</button>
26+
{% endif %}
27+
</div>
28+
</div>
29+
30+
<div class="table-scroll-area">
31+
{% if resources %}
32+
<table class="table is-bordered is-striped is-narrow is-fullwidth">
33+
<thead class="is-sticky">
1634
<tr>
17-
<td class="is-flex is-align-items-center break-all" style="min-width: 100px;">
18-
<span class="icon is-small mr-2">
35+
<th>Name</th>
36+
<th>Status</th>
37+
<th>Language</th>
38+
<th>License</th>
39+
<th>Alert</th>
40+
</tr>
41+
</thead>
42+
<tbody>
43+
{% for resource in resources %}
44+
<tr>
45+
<td class="is-flex is-align-items-center break-all" style="min-width: 100px;">
46+
<span class="icon is-small mr-2">
47+
{% if resource.is_dir %}
48+
<i class="fas fa-folder"></i>
49+
{% else %}
50+
<i class="far fa-file"></i>
51+
{% endif %}
52+
</span>
1953
{% if resource.is_dir %}
20-
<i class="fas fa-folder"></i>
54+
<a href="#" class="expand-in-tree" data-path="{{ resource.path }}" hx-get="{% url 'codebase_resource_table' project.slug %}?path={{ resource.path }}" hx-target="#right-pane" hx-push-url="{% url 'codebase_resource_tree' project.slug %}?path={{ resource.path }}">{{ resource.name }}</a>
2155
{% else %}
22-
<i class="far fa-file"></i>
56+
<a href="{% url 'resource_detail' project.slug resource.path %}">{{ resource.name }}</a>
2357
{% endif %}
24-
</span>
25-
{% if resource.is_dir %}
26-
<a href="#" class="expand-in-tree" data-path="{{ resource.path }}" hx-get="{% url 'codebase_resource_table' project.slug %}?path={{ resource.path }}" hx-target="#right-pane" hx-push-url="{% url 'codebase_resource_tree' project.slug %}?path={{ resource.path }}">{{ resource.name }}</a>
27-
{% else %}
28-
<a href="{% url 'resource_detail' project.slug resource.path %}">{{ resource.name }}</a>
29-
{% endif %}
30-
{% if resource.tag %}
31-
<span class="tag is-rounded ml-2">{{ resource.tag }}</span>
32-
{% endif %}
33-
</td>
34-
<td>
35-
{{ resource.status }}
36-
</td>
37-
<td class="break-all">
38-
{{ resource.programming_language }}
39-
</td>
40-
<td>
41-
{{ resource.detected_license_expression }}
42-
</td>
43-
<td>
44-
{{ resource.compliance_alert }}
45-
</td>
46-
</tr>
47-
{% endfor %}
48-
</tbody>
49-
</table>
58+
{% if resource.tag %}
59+
<span class="tag is-rounded ml-2">{{ resource.tag }}</span>
60+
{% endif %}
61+
</td>
62+
<td>
63+
{{ resource.status }}
64+
</td>
65+
<td class="break-all">
66+
{{ resource.programming_language }}
67+
</td>
68+
<td>
69+
{{ resource.detected_license_expression }}
70+
</td>
71+
<td>
72+
{{ resource.compliance_alert }}
73+
</td>
74+
</tr>
75+
{% endfor %}
76+
</tbody>
77+
</table>
5078

51-
{% if is_paginated %}
52-
<nav class="pagination is-centered mt-4" role="navigation">
53-
{% if page_obj.has_previous %}
54-
<a class="pagination-previous" hx-get="{% url 'codebase_resource_table' project.slug %}?path={{ path }}&page={{ page_obj.previous_page_number }}" hx-target="#right-pane">Previous</a>
55-
{% endif %}
56-
{% if page_obj.has_next %}
57-
<a class="pagination-next" hx-get="{% url 'codebase_resource_table' project.slug %}?path={{ path }}&page={{ page_obj.next_page_number }}" hx-target="#right-pane">Next page</a>
58-
{% endif %}
59-
<ul class="pagination-list">
60-
<li>
61-
<span class="pagination-ellipsis">
62-
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}
63-
</span>
64-
</li>
65-
</ul>
66-
</nav>
67-
{% endif %}
68-
{% else %}
69-
<div class="has-text-centered p-6">
70-
<div class="icon is-large has-text-grey-light mb-3">
71-
<i class="fas fa-folder-open fa-3x"></i>
79+
{% if is_paginated %}
80+
<nav class="pagination is-centered mt-4" role="navigation">
81+
{% if page_obj.has_previous %}
82+
<a class="pagination-previous" hx-get="{% url 'codebase_resource_table' project.slug %}?path={{ path }}&page={{ page_obj.previous_page_number }}" hx-target="#right-pane" hx-push-url="{% url 'codebase_resource_tree' project.slug %}?path={{ path }}&page={{ page_obj.previous_page_number }}">Previous</a>
83+
{% endif %}
84+
{% if page_obj.has_next %}
85+
<a class="pagination-next" hx-get="{% url 'codebase_resource_table' project.slug %}?path={{ path }}&page={{ page_obj.next_page_number }}" hx-target="#right-pane" hx-push-url="{% url 'codebase_resource_tree' project.slug %}?path={{ path }}&page={{ page_obj.next_page_number }}">Next page</a>
86+
{% endif %}
87+
<ul class="pagination-list">
88+
<li>
89+
<span class="pagination-ellipsis">
90+
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}
91+
</span>
92+
</li>
93+
</ul>
94+
</nav>
95+
{% endif %}
96+
{% else %}
97+
<div class="has-text-centered p-6">
98+
<div class="icon is-large has-text-grey-light mb-3">
99+
<i class="fas fa-folder-open fa-3x"></i>
100+
</div>
101+
<p class="has-text-grey">
102+
{% if path %}
103+
No resources found in this directory.
104+
{% else %}
105+
Select a file or folder from the tree to view its contents.
106+
{% endif %}
107+
</p>
72108
</div>
73-
<p class="has-text-grey">
74-
{% if path %}
75-
No resources found in this directory.
76-
{% else %}
77-
Select a file or folder from the tree to view its contents.
78-
{% endif %}
79-
</p>
80-
</div>
81-
{% endif %}
109+
{% endif %}
110+
</div>

scanpipe/templates/scanpipe/resource_tree.html

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,16 @@
5454
}
5555
.right-pane {
5656
flex: 1;
57-
overflow-y: auto;
58-
overflow-x: hidden;
5957
min-width: 0;
6058
transition: opacity 0.2s ease;
59+
display: flex;
60+
flex-direction: column;
61+
height: 100%;
62+
}
63+
.right-pane .table-scroll-area {
64+
flex: 1;
65+
overflow-y: auto;
66+
overflow-x: hidden;
6167
}
6268
.right-pane.collapsed {
6369
opacity: 0;
@@ -109,6 +115,14 @@
109115

110116
{% block scripts %}
111117
<script>
118+
document.body.addEventListener('htmx:afterSwap', function(evt) {
119+
if (evt.target && evt.target.id === 'right-pane') {
120+
if (typeof enableCopyToClipboard === 'function') {
121+
enableCopyToClipboard('.copy-to-clipboard');
122+
}
123+
}
124+
});
125+
112126
async function toggleFolderNode(folderNode, forceExpand = false) {
113127
const targetId = folderNode.dataset.target;
114128
const url = folderNode.dataset.url;

0 commit comments

Comments
 (0)