Skip to content

Commit f7bcb4c

Browse files
committed
fix: exclude UV dev dependencies from SBOMs
Implements TC-4096
1 parent 3621bb7 commit f7bcb4c

6 files changed

Lines changed: 378 additions & 1 deletion

File tree

src/providers/python_uv.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export default class Python_uv extends Base_pyproject {
4444
return Buffer.from(process.env['TRUSTIFY_DA_UV_EXPORT'], 'base64').toString('ascii')
4545
}
4646
let uvBin = getCustomPath('uv', opts)
47-
return invokeCommand(uvBin, ['export', '--format', 'requirements.txt', '--frozen', '--no-hashes'], { cwd: manifestDir }).toString()
47+
return invokeCommand(uvBin, ['export', '--format', 'requirements.txt', '--frozen', '--no-hashes', '--no-dev'], { cwd: manifestDir }).toString()
4848
}
4949

5050
/**

test/providers/python_pyproject.test.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,30 @@ suite('testing the python-pyproject data provider', () => {
9494
}).timeout(TIMEOUT)
9595
})
9696

97+
suite('uv projects - dev dependencies excluded (TC-4096)', () => {
98+
test('dev dependencies excluded from stack analysis', async () => {
99+
let expectedSbom = fs.readFileSync('test/providers/tst_manifests/pyproject/uv_dev_deps/expected_stack_sbom.json').toString()
100+
expectedSbom = JSON.stringify(JSON.parse(expectedSbom))
101+
let result = await uvProvider.provideStack('test/providers/tst_manifests/pyproject/uv_dev_deps/pyproject.toml')
102+
expect(result).to.deep.equal({
103+
ecosystem: 'pip',
104+
contentType: 'application/vnd.cyclonedx+json',
105+
content: expectedSbom
106+
})
107+
}).timeout(TIMEOUT)
108+
109+
test('dev dependencies excluded from component analysis', async () => {
110+
let expectedSbom = fs.readFileSync('test/providers/tst_manifests/pyproject/uv_dev_deps/expected_component_sbom.json').toString().trim()
111+
expectedSbom = JSON.stringify(JSON.parse(expectedSbom))
112+
let result = await uvProvider.provideComponent('test/providers/tst_manifests/pyproject/uv_dev_deps/pyproject.toml')
113+
expect(result).to.deep.equal({
114+
ecosystem: 'pip',
115+
contentType: 'application/vnd.cyclonedx+json',
116+
content: expectedSbom
117+
})
118+
}).timeout(TIMEOUT)
119+
})
120+
97121
suite('uv projects - uv_lock manifest', () => {
98122
test('verify pyproject.toml sbom provided for stack analysis with uv_lock', async () => {
99123
let expectedSbom = fs.readFileSync('test/providers/tst_manifests/pyproject/uv_lock/expected_stack_sbom.json').toString()
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"bomFormat": "CycloneDX",
3+
"specVersion": "1.4",
4+
"version": 1,
5+
"metadata": {
6+
"timestamp": "2023-10-01T00:00:00.000Z",
7+
"component": {
8+
"name": "uv-dev-deps-project",
9+
"version": "1.0.0",
10+
"purl": "pkg:pypi/uv-dev-deps-project@1.0.0",
11+
"type": "application",
12+
"bom-ref": "pkg:pypi/uv-dev-deps-project@1.0.0"
13+
}
14+
},
15+
"components": [
16+
{
17+
"name": "requests",
18+
"version": "2.33.1",
19+
"purl": "pkg:pypi/requests@2.33.1",
20+
"type": "library",
21+
"bom-ref": "pkg:pypi/requests@2.33.1"
22+
}
23+
],
24+
"dependencies": [
25+
{
26+
"ref": "pkg:pypi/uv-dev-deps-project@1.0.0",
27+
"dependsOn": [
28+
"pkg:pypi/requests@2.33.1"
29+
]
30+
},
31+
{
32+
"ref": "pkg:pypi/requests@2.33.1",
33+
"dependsOn": []
34+
}
35+
]
36+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
{
2+
"bomFormat": "CycloneDX",
3+
"specVersion": "1.4",
4+
"version": 1,
5+
"metadata": {
6+
"timestamp": "2023-10-01T00:00:00.000Z",
7+
"component": {
8+
"name": "uv-dev-deps-project",
9+
"version": "1.0.0",
10+
"purl": "pkg:pypi/uv-dev-deps-project@1.0.0",
11+
"type": "application",
12+
"bom-ref": "pkg:pypi/uv-dev-deps-project@1.0.0"
13+
}
14+
},
15+
"components": [
16+
{
17+
"name": "requests",
18+
"version": "2.33.1",
19+
"purl": "pkg:pypi/requests@2.33.1",
20+
"type": "library",
21+
"bom-ref": "pkg:pypi/requests@2.33.1"
22+
},
23+
{
24+
"name": "certifi",
25+
"version": "2026.2.25",
26+
"purl": "pkg:pypi/certifi@2026.2.25",
27+
"type": "library",
28+
"bom-ref": "pkg:pypi/certifi@2026.2.25"
29+
},
30+
{
31+
"name": "charset-normalizer",
32+
"version": "3.4.7",
33+
"purl": "pkg:pypi/charset-normalizer@3.4.7",
34+
"type": "library",
35+
"bom-ref": "pkg:pypi/charset-normalizer@3.4.7"
36+
},
37+
{
38+
"name": "idna",
39+
"version": "3.11",
40+
"purl": "pkg:pypi/idna@3.11",
41+
"type": "library",
42+
"bom-ref": "pkg:pypi/idna@3.11"
43+
},
44+
{
45+
"name": "urllib3",
46+
"version": "2.6.3",
47+
"purl": "pkg:pypi/urllib3@2.6.3",
48+
"type": "library",
49+
"bom-ref": "pkg:pypi/urllib3@2.6.3"
50+
}
51+
],
52+
"dependencies": [
53+
{
54+
"ref": "pkg:pypi/uv-dev-deps-project@1.0.0",
55+
"dependsOn": [
56+
"pkg:pypi/requests@2.33.1"
57+
]
58+
},
59+
{
60+
"ref": "pkg:pypi/requests@2.33.1",
61+
"dependsOn": [
62+
"pkg:pypi/certifi@2026.2.25",
63+
"pkg:pypi/charset-normalizer@3.4.7",
64+
"pkg:pypi/idna@3.11",
65+
"pkg:pypi/urllib3@2.6.3"
66+
]
67+
},
68+
{
69+
"ref": "pkg:pypi/certifi@2026.2.25",
70+
"dependsOn": []
71+
},
72+
{
73+
"ref": "pkg:pypi/charset-normalizer@3.4.7",
74+
"dependsOn": []
75+
},
76+
{
77+
"ref": "pkg:pypi/idna@3.11",
78+
"dependsOn": []
79+
},
80+
{
81+
"ref": "pkg:pypi/urllib3@2.6.3",
82+
"dependsOn": []
83+
}
84+
]
85+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[project]
2+
name = "uv-dev-deps-project"
3+
version = "1.0.0"
4+
requires-python = ">=3.11"
5+
dependencies = [
6+
"requests>=2.31.0",
7+
]
8+
9+
[dependency-groups]
10+
dev = [
11+
"black==22.10.0",
12+
]

0 commit comments

Comments
 (0)