|
| 1 | +# AGENTS.md |
| 2 | + |
| 3 | +Library wrapping [`cyclonedx-python-lib`](https://github.com/CycloneDX/cyclonedx-python-lib) to |
| 4 | +read/write Siemens [Standard BOM](https://sbom.siemens.io/latest/format.html) |
| 5 | +(a CycloneDX-compatible SBOM format). Source in [`siemens_standard_bom/`](siemens_standard_bom/). |
| 6 | + |
| 7 | +## Commands (run from repo root) |
| 8 | + |
| 9 | +- Full check (lint + type + tests, Python 3.10-3.14): `poetry run tox run` |
| 10 | +- Lint + types only: `poetry run tox run -e lint,type` |
| 11 | +- Tests on one interpreter: `poetry run tox run -e 3.12` |
| 12 | +- Single test: `poetry run python -m unittest tests.test_v3_parser.SbomV3ParserTestCase.test_read_sunny_day` |
| 13 | + |
| 14 | +Config: |
| 15 | +- [`tox.toml`](tox.toml), |
| 16 | +- [`pyproject.toml`](pyproject.toml), |
| 17 | +- [`.flake8`](.flake8), |
| 18 | +- [`.mypy.ini`](.mypy.ini). |
| 19 | + |
| 20 | +## Testing |
| 21 | + |
| 22 | +- Uses stdlib [`unittest`](https://docs.python.org/3/library/unittest.html) (via `unittest discover`), |
| 23 | + NOT [pytest](https://docs.pytest.org/). |
| 24 | +- Run from repo root only: tests read fixtures by relative path ([`tests/v2/`](tests/v2/), |
| 25 | + [`tests/v3/`](tests/v3/)) and write to `output/` at repo root (gitignored, auto-created). |
| 26 | +- Comparison tests use [`deepdiff`](https://github.com/seperman/deepdiff) and intentionally exclude |
| 27 | + `bom_ref` values from diffs ([`tests/abstract_sbom_compare.py`](tests/abstract_sbom_compare.py)). |
| 28 | + |
| 29 | +## Architecture |
| 30 | + |
| 31 | +- Thin wrapper: `StandardBom` wraps `cyclonedx.model.bom.Bom`; `SbomComponent`/`SourceArtifact` |
| 32 | + /`ExternalComponent` wrap CycloneDX models. Reach the underlying object via `.bom` / `.component`. |
| 33 | + See [`model.py`](siemens_standard_bom/model.py). |
| 34 | +- Siemens-specific fields are NOT native CycloneDX: they're stored as `Property` entries keyed |
| 35 | + `siemens:*` (constants at top of [`model.py`](siemens_standard_bom/model.py)) or as typed |
| 36 | + `ExternalReference`s. Add a field by adding a constant + property getter/setter following existing |
| 37 | + patterns. |
| 38 | +- Reader supports BOTH v2 and v3 Standard BOM (see backward-compat branches in the `tools`/`authors` |
| 39 | + getters); keep both working. |
| 40 | +- Output is always CycloneDX JSON v1.6 (`JsonV1Dot6`). |
| 41 | + [`StandardBomParser.save(..., with_dependencies=False)`](siemens_standard_bom/parser.py) re-reads |
| 42 | + and strips `dependencies` from the file (prohibited in the |
| 43 | + [`external` profile](https://sbom.siemens.io/v3/profiles.html)). |
| 44 | + |
| 45 | +## Conventions |
| 46 | + |
| 47 | +- [mypy](https://mypy.readthedocs.io/en/stable/) `strict = True`, `implicit_reexport = False`; |
| 48 | +- [flake8](https://flake8.pycqa.org/) max line length 140, max complexity 8, doctests checked. |
| 49 | +- Requires Python >=3.10,<4.0 and [Poetry](https://python-poetry.org/) >= 2.0. |
| 50 | +- Release: bump `version` in [`pyproject.toml`](pyproject.toml); pushing a `vX.Y.Z` tag publishes |
| 51 | + to [PyPI](https://pypi.org/p/siemens-standard-bom) (see [`release.yml`](.github/workflows/release.yml)). |
| 52 | +- The self tool-entry version reads from installed package metadata, so `poetry install` |
| 53 | + the package for it to report correctly. |
0 commit comments