@@ -61,8 +61,8 @@ var _ = Describe("ToCatalogers", func() {
6161 },
6262 },
6363 []scanner.Cataloger {
64- {Name : "go-module-file-cataloger" , SourcePaths : []string {"/app/api/go.mod" , "/app/api/go.sum" }},
65- {Name : "go-module-file-cataloger" , SourcePaths : []string {"/app/cli/go.mod" , "/app/cli/go.sum" }},
64+ {Name : "go-module-file-cataloger" , FilterMode : scanner . CatalogerFilterExactPath , SourcePaths : []string {"/app/api/go.mod" , "/app/api/go.sum" }, Workdir : "/app/api" },
65+ {Name : "go-module-file-cataloger" , FilterMode : scanner . CatalogerFilterExactPath , SourcePaths : []string {"/app/cli/go.mod" , "/app/cli/go.sum" }, Workdir : "/app/cli" },
6666 },
6767 ),
6868
@@ -120,7 +120,7 @@ var _ = Describe("FilterBOMBySourcePaths", func() {
120120 },
121121 },
122122 []scanner.Cataloger {
123- {Name : "go-module-file-cataloger" , SourcePaths : []string {"/app/api/go.mod" , "/app/api/go.sum" }},
123+ {Name : "go-module-file-cataloger" , FilterMode : scanner . CatalogerFilterExactPath , SourcePaths : []string {"/app/api/go.mod" , "/app/api/go.sum" }, Workdir : "/app/api" },
124124 },
125125 []string {"github.com/foo/bar" },
126126 ),
@@ -137,7 +137,7 @@ var _ = Describe("FilterBOMBySourcePaths", func() {
137137
138138 Entry ("does nothing when BOM is nil" ,
139139 (* cdx .BOM )(nil ),
140- []scanner.Cataloger {{Name : "x" , SourcePaths : []string {"/app/go.mod" }}},
140+ []scanner.Cataloger {{Name : "x" , FilterMode : scanner . CatalogerFilterExactPath , SourcePaths : []string {"/app/go.mod" }, Workdir : "/app" }},
141141 []string (nil ),
142142 ),
143143 )
@@ -157,7 +157,7 @@ var _ = Describe("ToCatalogers python", func() {
157157 },
158158 },
159159 []scanner.Cataloger {
160- {Name : "python-package-cataloger" , SourcePaths : []string {"/app/requirements.txt" }},
160+ {Name : "python-package-cataloger" , FilterMode : scanner . CatalogerFilterWorkdirPrefix , SourcePaths : []string {"/app/requirements.txt" }, Workdir : "/app" },
161161 },
162162 ),
163163
@@ -169,7 +169,7 @@ var _ = Describe("ToCatalogers python", func() {
169169 },
170170 },
171171 []scanner.Cataloger {
172- {Name : "python-package-cataloger" , SourcePaths : []string {"/app/pyproject.toml" , "/app/uv.lock" }},
172+ {Name : "python-package-cataloger" , FilterMode : scanner . CatalogerFilterWorkdirPrefix , SourcePaths : []string {"/app/pyproject.toml" , "/app/uv.lock" }, Workdir : "/app" },
173173 },
174174 ),
175175
@@ -181,20 +181,21 @@ var _ = Describe("ToCatalogers python", func() {
181181 },
182182 },
183183 []scanner.Cataloger {
184- {Name : "python-package-cataloger" , SourcePaths : []string {"/svc/pyproject.toml" , "/svc/poetry.lock" }},
184+ {Name : "python-package-cataloger" , FilterMode : scanner . CatalogerFilterWorkdirPrefix , SourcePaths : []string {"/svc/pyproject.toml" , "/svc/poetry.lock" }, Workdir : "/svc" },
185185 },
186186 ),
187187 )
188188})
189189
190190var _ = Describe ("FilterBOMBySourcePaths python declared" , func () {
191- pythonProps := func (paths ... string ) * []cdx.Property {
191+ distInfoProps := func (workdir , pkgName string , extraPaths ... string ) * []cdx.Property {
192192 props := []cdx.Property {
193193 {Name : "syft:package:foundBy" , Value : "python-package-cataloger" },
194+ {Name : "syft:location:0:path" , Value : workdir + "/.venv/lib/python3.12/site-packages/" + pkgName + ".dist-info/METADATA" },
194195 }
195- for i , p := range paths {
196+ for i , p := range extraPaths {
196197 props = append (props , cdx.Property {
197- Name : fmt .Sprintf ("syft:location:%d:path" , i ),
198+ Name : fmt .Sprintf ("syft:location:%d:path" , i + 1 ),
198199 Value : p ,
199200 })
200201 }
@@ -208,7 +209,7 @@ var _ = Describe("FilterBOMBySourcePaths python declared", func() {
208209 }
209210 }
210211
211- DescribeTable ("exact-match path filtering for python and go-mod" ,
212+ DescribeTable ("workdir-prefix filtering for python, exact-match for go-mod" ,
212213 func (bom * cdx.BOM , catalogers []scanner.Cataloger , expectedNames []string ) {
213214 FilterBOMBySourcePaths (bom , catalogers )
214215 Expect (* bom .Components ).To (HaveLen (len (expectedNames )))
@@ -217,31 +218,56 @@ var _ = Describe("FilterBOMBySourcePaths python declared", func() {
217218 }
218219 },
219220
220- Entry ("python pip component with matching requirements.txt path is kept " ,
221+ Entry ("python-uv: keeps dist-info components under workdir, drops components from other workdirs " ,
221222 & cdx.BOM {
222223 Components : & []cdx.Component {
223- {Name : "requests" , Properties : pythonProps ("/app/requirements.txt " )},
224- {Name : "flask" , Properties : pythonProps ("/other/requirements.txt " )},
224+ {Name : "requests" , Properties : distInfoProps ("/app" , "requests-2.32.3 " )},
225+ {Name : "flask" , Properties : distInfoProps ("/other" , "flask-3.0.0 " )},
225226 },
226227 },
227228 []scanner.Cataloger {
228- {Name : "python-package-cataloger" , SourcePaths : []string {"/app/requirements.txt" } },
229+ {Name : "python-package-cataloger" , FilterMode : scanner . CatalogerFilterWorkdirPrefix , SourcePaths : []string {"/app/pyproject.toml" , "/app/uv.lock" }, Workdir : "/app" },
229230 },
230231 []string {"requests" },
231232 ),
232233
233- Entry ("python uv component is kept when both spec and lock paths match " ,
234+ Entry ("python-pip: keeps dist-info components under workdir " ,
234235 & cdx.BOM {
235236 Components : & []cdx.Component {
236- {Name : "requests" , Properties : pythonProps ("/svc/pyproject.toml" )},
237- {Name : "requests" , Properties : pythonProps ("/svc/uv.lock" )},
238- {Name : "flask" , Properties : pythonProps ("/other/pyproject.toml" )},
237+ {Name : "requests" , Properties : distInfoProps ("/app" , "requests-2.32.3" )},
238+ {Name : "flask" , Properties : distInfoProps ("/other" , "flask-3.0.0" )},
239239 },
240240 },
241241 []scanner.Cataloger {
242- {Name : "python-package-cataloger" , SourcePaths : []string {"/svc/pyproject.toml" , "/svc/uv.lock" } },
242+ {Name : "python-package-cataloger" , FilterMode : scanner . CatalogerFilterWorkdirPrefix , SourcePaths : []string {"/app/requirements.txt" }, Workdir : "/app" },
243243 },
244- []string {"requests" , "requests" },
244+ []string {"requests" },
245+ ),
246+
247+ Entry ("python-poetry: keeps dist-info components under workdir" ,
248+ & cdx.BOM {
249+ Components : & []cdx.Component {
250+ {Name : "requests" , Properties : distInfoProps ("/svc" , "requests-2.32.3" )},
251+ {Name : "flask" , Properties : distInfoProps ("/app" , "flask-3.0.0" )},
252+ },
253+ },
254+ []scanner.Cataloger {
255+ {Name : "python-package-cataloger" , FilterMode : scanner .CatalogerFilterWorkdirPrefix , SourcePaths : []string {"/svc/pyproject.toml" , "/svc/poetry.lock" }, Workdir : "/svc" },
256+ },
257+ []string {"requests" },
258+ ),
259+
260+ Entry ("workdir prefix does not match exact workdir path (no trailing slash confusion)" ,
261+ & cdx.BOM {
262+ Components : & []cdx.Component {
263+ {Name : "requests" , Properties : distInfoProps ("/app" , "requests-2.32.3" )},
264+ {Name : "flask" , Properties : distInfoProps ("/appother" , "flask-3.0.0" )},
265+ },
266+ },
267+ []scanner.Cataloger {
268+ {Name : "python-package-cataloger" , FilterMode : scanner .CatalogerFilterWorkdirPrefix , SourcePaths : []string {"/app/pyproject.toml" }, Workdir : "/app" },
269+ },
270+ []string {"requests" },
245271 ),
246272
247273 Entry ("regression: go-mod exact-match still works alongside python cataloger" ,
@@ -252,7 +278,7 @@ var _ = Describe("FilterBOMBySourcePaths python declared", func() {
252278 },
253279 },
254280 []scanner.Cataloger {
255- {Name : "go-module-file-cataloger" , SourcePaths : []string {"/app/go.mod" , "/app/go.sum" }},
281+ {Name : "go-module-file-cataloger" , FilterMode : scanner . CatalogerFilterExactPath , SourcePaths : []string {"/app/go.mod" , "/app/go.sum" }, Workdir : "/app" },
256282 },
257283 []string {"github.com/foo/bar" },
258284 ),
0 commit comments