forked from guacsec/trustify-da-javascript-client
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpython_pip.test.js
More file actions
155 lines (133 loc) · 7.78 KB
/
Copy pathpython_pip.test.js
File metadata and controls
155 lines (133 loc) · 7.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import fs from 'fs'
import { expect } from 'chai'
import { useFakeTimers } from "sinon";
import pythonPip from "../../src/providers/python_pip.js"
import {getCustomPath, invokeCommand } from "../../src/tools.js"
let clock
async function sharedComponentAnalysisTestFlow(testCase, usePipDepTreeUtility) {
// load the expected list for tsharedComponentAnalysisTestFlowhe scenario
let expectedSbom = fs.readFileSync(`test/providers/tst_manifests/pip/${testCase}/expected_component_sbom.json`).toString().trim()
expectedSbom = JSON.stringify(JSON.parse(expectedSbom))
// invoke sut stack analysis for scenario manifest
let opts = { TRUSTIFY_DA_PIP_USE_DEP_TREE: usePipDepTreeUtility.toString() }
let providedDatForComponent = await pythonPip.provideComponent(`test/providers/tst_manifests/pip/${testCase}/requirements.txt`, opts)
// verify returned data matches expectation
expect(providedDatForComponent).to.deep.equal({
ecosystem: 'pip',
contentType: 'application/vnd.cyclonedx+json',
content: expectedSbom
})
}
async function sharedStackAnalysisTestFlow(testCase, usePipDepTreeUtility) {
// load the expected graph for the scenario
let expectedSbom = fs.readFileSync(`test/providers/tst_manifests/pip/${testCase}/expected_stack_sbom.json`).toString()
expectedSbom = JSON.stringify(JSON.parse(expectedSbom))
// invoke sut stack analysis for scenario manifest
let pipPath = getCustomPath("pip3");
try {
invokeCommand(pipPath, ['install', '-r', `test/providers/tst_manifests/pip/${testCase}/requirements.txt`])
} catch (error) {
throw new Error('fail installing requirements.txt manifest in created virtual python environment', {cause: error})
}
let opts = { TRUSTIFY_DA_PIP_USE_DEP_TREE: usePipDepTreeUtility.toString() }
let providedDataForStack = await pythonPip.provideStack(`test/providers/tst_manifests/pip/${testCase}/requirements.txt`, opts)
// new(year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number): Date
// providedDataForStack.content = providedDataForStack.content.replaceAll("\"timestamp\":\"[a-zA-Z0-9\\-\\:]+\"","")
// verify returned data matches expectation
expect(providedDataForStack).to.deep.equal({
ecosystem: 'pip',
contentType: 'application/vnd.cyclonedx+json',
content: expectedSbom
})
}
suite('testing the python-pip data provider', () => {
[
{name: 'requirements.txt', expected: true},
{name: 'some_other.file', expected: false}
].forEach(testCase => {
test(`verify isSupported returns ${testCase.expected} for ${testCase.name}`, () =>
expect(pythonPip.isSupported(testCase.name)).to.equal(testCase.expected)
)
});
[
// "pip_requirements_txt_no_ignore",
"pip_requirements_txt_ignore"
].forEach(testCase => {
let scenario = testCase.replace('pip_requirements_', '').replaceAll('_', ' ')
test(`verify requirements.txt sbom provided for stack analysis with scenario ${scenario}`, async () => {
await sharedStackAnalysisTestFlow(testCase, false);
// these test cases takes ~2500-2700 ms each pr >10000 in CI (for the first test-case)
}).timeout(process.env.GITHUB_ACTIONS ? 30000 : 10000)
test(`verify requirements.txt sbom provided for component analysis with scenario ${scenario}`, async () => {
await sharedComponentAnalysisTestFlow(testCase, false);
// these test cases takes ~1400-2000 ms each pr >10000 in CI (for the first test-case)
}).timeout(process.env.GITHUB_ACTIONS ? 15000 : 10000)
test(`verify requirements.txt sbom provided for stack analysis using pipdeptree utility with scenario ${scenario}`, async () => {
await sharedStackAnalysisTestFlow(testCase, true);
// these test cases takes ~2500-2700 ms each pr >10000 in CI (for the first test-case)
}).timeout(process.env.GITHUB_ACTIONS ? 30000 : 10000)
test(`verify requirements.txt sbom provided for component analysis using pipdeptree utility with scenario ${scenario}`, async () => {
await sharedComponentAnalysisTestFlow(testCase, true);
// these test cases takes ~1400-2000 ms each pr >10000 in CI (for the first test-case)
}).timeout(process.env.GITHUB_ACTIONS ? 15000 : 10000)
});
}).beforeAll(() => clock = useFakeTimers(new Date('2023-10-01T00:00:00.000Z'))).afterAll(()=> clock.restore());
suite('testing the python-pip data provider with virtual environment', () => {
[
"pip_requirements_virtual_env_txt_no_ignore",
"pip_requirements_virtual_env_with_ignore"
].forEach(testCase => {
let scenario = testCase.replace('pip_requirements_', '').replaceAll('_', ' ')
test(`verify requirements.txt sbom provided for stack analysis using virutal python environment, with scenario ${scenario}`, async () => {
// load the expected sbom stack analysis
let expectedSbom = fs.readFileSync(`test/providers/tst_manifests/pip/${testCase}/expected_stack_sbom.json`,).toString()
expectedSbom = JSON.stringify(JSON.parse(expectedSbom), null, 4)
// invoke sut stack analysis for scenario manifest
let providedDataForStack = await pythonPip.provideStack(`test/providers/tst_manifests/pip/${testCase}/requirements.txt`, {
TRUSTIFY_DA_PYTHON_VIRTUAL_ENV: "true"
})
// new(year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number): Date
// providedDataForStack.content = providedDataForStack.content.replaceAll("\"timestamp\":\"[a-zA-Z0-9\\-\\:]+\"","")
// verify returned data matches expectation
providedDataForStack.content = JSON.stringify(JSON.parse(providedDataForStack.content), null, 4)
expect(providedDataForStack.content).to.deep.equal(expectedSbom)
// expect(providedDataForStack).to.deep.equal({
// ecosystem: 'pip',
// contentType: 'application/vnd.cyclonedx+json',
// content: expectedSbom
// })
// these test cases takes ~2500-2700 ms each pr >10000 in CI (for the first test-case)
}).timeout(process.env.GITHUB_ACTIONS ? 60000 : 30000)
})
}).beforeAll(() => {clock = useFakeTimers(new Date('2023-10-01T00:00:00.000Z'))}).afterAll(()=> clock.restore());
suite('testing python-pip PEP 508 marker handling', () => {
const markerTestCase = 'pip_requirements_txt_marker_skip'
/** Verify that packages with environment markers (PEP 508) that are not installed
* in the current environment are silently skipped, while marker-constrained
* packages that ARE installed are still included in the SBOM. */
test('verify marker-constrained uninstalled packages are skipped in component analysis', async () => {
// given: pip environment where only six and certifi are installed (pywin32 is Windows-only)
const pipFreezeOutput = 'six==1.16.0\ncertifi==2023.7.22\n'
const pipShowOutput =
'Name: certifi\nVersion: 2023.7.22\nSummary: Python package for providing Mozilla\'s CA Bundle.\nRequires: \nRequired-by: ' +
'\n---\n' +
'Name: six\nVersion: 1.16.0\nSummary: Python 2 and 3 compatibility utilities\nRequires: \nRequired-by: '
process.env['TRUSTIFY_DA_PIP_FREEZE'] = Buffer.from(pipFreezeOutput).toString('base64')
process.env['TRUSTIFY_DA_PIP_SHOW'] = Buffer.from(pipShowOutput).toString('base64')
try {
// when: component analysis is run against a manifest with a Windows-only marker package
let expectedSbom = fs.readFileSync(`test/providers/tst_manifests/pip/${markerTestCase}/expected_component_sbom.json`).toString().trim()
expectedSbom = JSON.stringify(JSON.parse(expectedSbom))
let result = await pythonPip.provideComponent(`test/providers/tst_manifests/pip/${markerTestCase}/requirements.txt`, {})
// then: SBOM contains six and certifi but not pywin32
expect(result).to.deep.equal({
ecosystem: 'pip',
contentType: 'application/vnd.cyclonedx+json',
content: expectedSbom
})
} finally {
delete process.env['TRUSTIFY_DA_PIP_FREEZE']
delete process.env['TRUSTIFY_DA_PIP_SHOW']
}
}).timeout(10000)
}).beforeAll(() => clock = useFakeTimers(new Date('2023-10-01T00:00:00.000Z'))).afterAll(() => clock.restore());