|
| 1 | +--- |
| 2 | +status: migrated |
| 3 | +feature: python-packages |
| 4 | +created: 2026-07-10 |
| 5 | +source: branch feat-sbom-get-python-sbom |
| 6 | +--- |
| 7 | + |
| 8 | +# Tasks: Python Package Ecosystems |
| 9 | + |
| 10 | +All tasks are completed — this feature was built incrementally on the branch and is now fully implemented. |
| 11 | + |
| 12 | +## Task Group 1: Core Types and Ecosystem Registry |
| 13 | + |
| 14 | +- [x] **T1.1** Add `PythonPackageEcosystem` types: `PackagesDirectiveTypePythonUV`, `PackagesDirectiveTypePythonPip`, `PackagesDirectiveTypePythonPoetry` |
| 15 | + - Files: `pkg/config/packages_directive.go` |
| 16 | + - Status: Constants added with canonical naming `python-{uv,pip,poetry}` |
| 17 | + |
| 18 | +- [x] **T1.2** Rename `GoModSpec` to `FileBasedSpec` and update all references |
| 19 | + - Files: `pkg/config/packages_directive.go` + all callers |
| 20 | + - Status: Struct used for Go-mod and all Python ecosystems |
| 21 | + |
| 22 | +- [x] **T1.3** Implement `PackageEcosystem` struct and `ecosystems` map registry |
| 23 | + - Files: `pkg/config/packages_directive.go` |
| 24 | + - Status: Registry with Type, Aliases, DefaultSpec, DefaultLock, InstallCmd, CatalogerName |
| 25 | + |
| 26 | +- [x] **T1.4** Implement alias resolution (`aliasToType` index) and `Ecosystems()` accessor |
| 27 | + - Files: `pkg/config/packages_directive.go` |
| 28 | + - Status: Aliases `uv/pip/poetry` canonicalized at parse time |
| 29 | + |
| 30 | +## Task Group 2: Config Parsing and Validation |
| 31 | + |
| 32 | +- [x] **T2.1** Refactor `rawPackagesDirective.toDirective()` with alias resolution and ecosystem dispatch |
| 33 | + - Files: `pkg/config/raw_packages_directive.go` |
| 34 | + - Status: OSPM handled via `if`; file-based types delegated to `fillFileBasedSpec` |
| 35 | + |
| 36 | +- [x] **T2.2** Implement `fillFileBasedSpec` (replaces `fillGoModSpec`) |
| 37 | + - Files: `pkg/config/raw_packages_directive.go` |
| 38 | + - Status: Reads defaults from ecosystem registry; validates spec type (must be string); rejects lock for lockless ecosystems (pip) |
| 39 | + |
| 40 | +- [x] **T2.3** Update `PackagesDirective.validate()` for ecosystem-based validation |
| 41 | + - Files: `pkg/config/packages_directive.go` |
| 42 | + - Status: OSPM checks packages non-empty; file-based checks workdir non-empty; unknown types rejected |
| 43 | + |
| 44 | +## Task Group 3: Command Generation |
| 45 | + |
| 46 | +- [x] **T3.1** Refactor `GeneratePackagesCommands` to use ecosystem registry |
| 47 | + - Files: `pkg/config/packages_commands.go` |
| 48 | + - Status: OSPM has dedicated `if`; other types dispatch via `ecosystems[pkg.Type].InstallCmd` |
| 49 | + |
| 50 | +- [x] **T3.2** Add Python install commands with `--frozen` determinism for uv and `--no-root` for poetry |
| 51 | + - Files: `pkg/config/packages_directive.go` (ecosystem entries) |
| 52 | + - Status: `uv sync --frozen`, `pip install --no-cache-dir -r <spec>`, `poetry install --no-root` |
| 53 | + |
| 54 | +## Task Group 4: SBOM Integration |
| 55 | + |
| 56 | +- [x] **T4.1** Refactor `buildResolvers` to construct cataloger resolvers from `config.Ecosystems()` |
| 57 | + - Files: `pkg/sbom/managedinput/managedinput.go` |
| 58 | + - Status: Dynamic, deterministic sorting by type name |
| 59 | + |
| 60 | +- [x] **T4.2** Update `ToCatalogers` to handle python-package-cataloger |
| 61 | + - Files: `pkg/sbom/managedinput/managedinput.go` |
| 62 | + - Status: Python directives map to `python-package-cataloger` with correct source paths (spec + lock when available) |
| 63 | + |
| 64 | +- [x] **T4.3** Ensure `FilterBOMBySourcePaths` works with python property paths (syft location keys) |
| 65 | + - Files: `pkg/sbom/managedinput/managedinput.go` |
| 66 | + - Status: Uses prefix matching against `syft:location:*:path` properties; works identically for go and python components |
| 67 | + |
| 68 | +## Task Group 5: Unit Tests |
| 69 | + |
| 70 | +- [x] **T5.1** Extract `directivesFromYaml` shared test helper |
| 71 | + - Files: `pkg/config/helpers_test.go` |
| 72 | + - Status: Shared between go-mod and python test files |
| 73 | + |
| 74 | +- [x] **T5.2** Write `packages_directive_python_test.go` — unmarshal, defaults, aliases, error cases |
| 75 | + - Files: `pkg/config/packages_directive_python_test.go` |
| 76 | + - Status: 14 entries covering all types, aliases, explicit overrides, missing workdir, invalid spec type, unknown type, lock rejection for pip |
| 77 | + |
| 78 | +- [x] **T5.3** Refactor `packages_directive_go_mod_test.go` to use `FileBasedSpec` and shared helper |
| 79 | + - Files: `pkg/config/packages_directive_go_mod_test.go` |
| 80 | + - Status: All existing tests pass with new struct |
| 81 | + |
| 82 | +- [x] **T5.4** Refactor `raw_packages_directive_test.go` to use DescribeTable for normalizePackages |
| 83 | + - Files: `pkg/config/raw_packages_directive_test.go` |
| 84 | + - Status: 6 entries replacing individual It blocks; python smoke test added |
| 85 | + |
| 86 | +- [x] **T5.5** Add python-specific `ToCatalogers` and `FilterBOMBySourcePaths` tests |
| 87 | + - Files: `pkg/sbom/managedinput/managedinput_test.go` |
| 88 | + - Status: 5 entries testing python-package-cataloger mapping, pip lockless, uv+poetry lock paths, path filtering, go-mod regression |
| 89 | + |
| 90 | +- [x] **T5.6** Add `buildResolvers` determinism test |
| 91 | + - Files: `pkg/sbom/managedinput/managedinput_test.go` |
| 92 | + - Status: Verifies deterministic ordering across 20 invocations and alphabetical sort |
| 93 | + |
| 94 | +## Task Group 6: E2E Tests |
| 95 | + |
| 96 | +- [x] **T6.1** Create pip e2e test with fixture (`pip_simple`) |
| 97 | + - Files: `test/e2e/sbom/pip_test.go` + `_fixtures/inject/pip_simple/` |
| 98 | + - Status: Validates `requests@2.32.3` in BOM after `pip install -r requirements.txt` |
| 99 | + |
| 100 | +- [x] **T6.2** Create poetry e2e test with fixture (`poetry_simple`) |
| 101 | + - Files: `test/e2e/sbom/poetry_test.go` + `_fixtures/inject/poetry_simple/` |
| 102 | + - Status: Validates `requests@2.32.3` in BOM after `poetry install --no-root` |
| 103 | + |
| 104 | +- [x] **T6.3** Create uv e2e test with fixture (`uv_simple`) |
| 105 | + - Files: `test/e2e/sbom/uv_test.go` + `_fixtures/inject/uv_simple/` |
| 106 | + - Status: Validates `requests@2.32.3` in BOM after `uv sync --frozen` |
| 107 | + |
| 108 | +## Task Group 7: Documentation |
| 109 | + |
| 110 | +- [x] **T7.1** Update `docs/_data/werf_yaml.yml` with Python type descriptions, aliases, defaults |
| 111 | + - Files: `docs/_data/werf_yaml.yml` |
| 112 | + - Status: `type`, `workdir`, `spec`, `lock` fields updated for all three Python ecosystems |
| 113 | + |
| 114 | +## Task Group 8: Incidental Cleanup (extracted from PR) |
| 115 | + |
| 116 | +- [x] **T8.1** Remove `serviceLabelsConfigMutation` from `verity_annotation.go` and simplify `SignStage.MutateImage` |
| 117 | + - Files: `pkg/build/stage/verity_annotation.go`, `pkg/build/stage/sign.go` |
| 118 | + - Status: Service labels propagation moved into the registry mutation flow |
| 119 | + |
| 120 | +- [x] **T8.2** Clean up `mutateImage` in docker_registry (remove stale cf snapshot logic) |
| 121 | + - Files: `pkg/docker_registry/api/mutate.go` |
| 122 | + - Status: Removed `cfBeforeLayerMutation` read that was no longer needed |
| 123 | + |
| 124 | +- [x] **T8.3** Delete obsolete mutate tests |
| 125 | + - Files: `pkg/docker_registry/api/mutate_test.go`, `pkg/docker_registry/api/suite_test.go` |
| 126 | + - Status: Tests removed as they tested removed behavior |
| 127 | + |
| 128 | +## Gaps Identified |
| 129 | + |
| 130 | +1. ⚠️ **poetry lock enforcement** — Unlike `uv --frozen`, poetry's `install --no-root` doesn't have a built-in flag to reject a missing or outdated `poetry.lock`. The lock file existence is expected but not enforced at the package manager level. |
| 131 | +2. ⚠️ **E2E tests with native Buildah** — The e2e tests have `XEntry` (pending) for `native-chroot` and `native-rootless` container backends, indicating these aren't yet validated for Python SBOM scenarios. |
0 commit comments