Skip to content

feat: add cyclonedx.model.dependency.Dependency.provides - #735

Draft
uzairchhapra wants to merge 10 commits into
CycloneDX:mainfrom
uzairchhapra:feat/691-uzair-provides
Draft

uzairchhapra wants to merge 10 commits into
CycloneDX:mainfrom
uzairchhapra:feat/691-uzair-provides

Conversation

@uzairchhapra

Copy link
Copy Markdown

Fixes #691

Signed-off-by: Uzair Chhapra <uzairchhapra@gmail.com>
@uzairchhapra
uzairchhapra force-pushed the feat/691-uzair-provides branch from f2ad0ed to fb4598d Compare November 5, 2024 19:11
Signed-off-by: Uzair Chhapra <uzairchhapra@gmail.com>
@uzairchhapra
uzairchhapra marked this pull request as ready for review November 5, 2024 21:47
@uzairchhapra
uzairchhapra requested a review from a team as a code owner November 5, 2024 21:47
@uzairchhapra

Copy link
Copy Markdown
Author

@jkowalleck PR is ready for review.
I am not too sure about the test cases so any guidance here would help. Thanks!

@jkowalleck jkowalleck changed the title [WIP] feat: add cyclonedx.model.dependency.Dependency.provides feat: add cyclonedx.model.dependency.Dependency.provides Nov 5, 2024
@jkowalleck

Copy link
Copy Markdown
Member

thank you for your contribution, @uzairchhapra .

the implementation looks promising.

Regarding tests, we tend to go with an integration-test snapshot-solution, over detailed unit tests.
Please add new fixtures to https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/tests/_data/models.py. your new function must start with get_bom_.
After adding new test data, please recreate the snapshots as described here: https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/tests/_data/snapshots/README.md

Signed-off-by: Uzair Chhapra <uzairchhapra@gmail.com>
Signed-off-by: Uzair Chhapra <uzairchhapra@gmail.com>
Signed-off-by: Uzair Chhapra <uzairchhapra@gmail.com>
@jkowalleck

This comment was marked as outdated.

Comment thread cyclonedx/model/bom.py
self,
target: Dependable,
depends_on: Optional[Iterable[Dependable]] = None,
provides: Optional[Iterable[Dependable]] = None,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of adding a new parameter here, how about adding a new method instead: register_provision(self, target: Dependable, provides: Optional[Iterable[Dependable]] = None).

what do you think about this?
this would fit the original architectural plans better.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll give this a try

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jkowalleck
How should this function work register_provision for the example mentioned pin models.py?

A -- requires -> C
B -- provides -> C

Considering register_dependency and register_provision will be called for all A, B and C, should I look for existing dependencies added in register_provision to avoid creating a new Dependency?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is still open.
could you consider adding a new method?

Comment thread tests/_data/models.py Resolved
@jkowalleck
jkowalleck self-requested a review November 12, 2024 12:54
Signed-off-by: Uzair Chhapra <uzairchhapra@gmail.com>
Comment thread tests/_data/models.py Resolved
@jkowalleck

Copy link
Copy Markdown
Member

@uzairchhapra, I just wanted to ask how things are going.
Do you need any help with one of the open discussions/points?

@uzairchhapra

Copy link
Copy Markdown
Author

@uzairchhapra, I just wanted to ask how things are going. Do you need any help with one of the open discussions/points?

Apologies for the delayed response. I will get to this this weekend. If I remember correctly, I was stuck in making the test function work get_bom_v1_6_with_provides. I see my PR has some conflicts now, so will try to address that too.

@aespogom

Copy link
Copy Markdown

Hi everyone,
Thanks a lot for your amazing work!!
Just wanted to check in—I'm currently waiting on this fix to be released, as it's blocking some of our work. Really appreciate all the efforts from the maintainers and contributors here. Is there any estimated timeline for when this might be included in a release? Thanks in advance!

@robertlagrant

Copy link
Copy Markdown

@aespogom I'm not affiliated, but it looks as though the author has abandoned this PR. If it's blocking you, would you consider picking it up?

…ides

Signed-off-by: Uzair Chhapra <uzairchhapra@gmail.com>
Signed-off-by: Uzair Chhapra <uzairchhapra@gmail.com>
Signed-off-by: Uzair Chhapra <uzairchhapra@gmail.com>
Comment thread tests/_data/models.py Resolved
Signed-off-by: Uzair Chhapra <uzairchhapra@gmail.com>
Comment thread cyclonedx/model/bom.py
self,
target: Dependable,
depends_on: Optional[Iterable[Dependable]] = None,
provides: Optional[Iterable[Dependable]] = None,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is still open.
could you consider adding a new method?

@jkowalleck
jkowalleck marked this pull request as draft April 23, 2025 09:52

jkowalleck commented Nov 6, 2026 •

Copy link
Copy Markdown
Member

review done by Claude Fable 5.1, prompt: "do a review, comment your findings"


I pulled the branch (39a5f8f), ran the test suite, flake8 and mypy, did a few behavioural checks (serialization round-trip, validate()), and attempted a merge with current main.

Summary

The core implementation is sound: provides is modelled consistently with dependsOn (nested Dependency objects, ref-only serialization via _DependencyRepositorySerializationHelper), the 1.6 JSON/XML output matches the schema, pre-1.6 outputs correctly omit provides, validate() rejects provides refs that are not in the BOM, and JSON deserialization round-trips. 5334 tests pass locally, flake8 is clean. However, the PR is currently not mergeable and has one functional gap that appeared since the branch was last updated.

🔴 Blocking

  1. Merge conflict with main (cyclonedx/model/dependency.py). The branch is ~180 commits behind. When rebasing, note that main has since:

    • dropped Python 3.8 → use builtin generics (set[BomRef], not typing.Set),
    • removed the # type:ignore[assignment] comments on self.dependencies = dependencies or [] (keep the new self.provides = ... line consistent),
    • updated the docstring link to https://cyclonedx.org/docs/1.7/xml/#type_dependencyType.
  2. provides is silently dropped for CycloneDX 1.7. main now supports schema 1.7, but the property is only decorated with @serializable.view(SchemaVersion1Dot6). Every other 1.6+ field in the codebase stacks both views (e.g. bom.py):

    @serializable.view(SchemaVersion1Dot6)
    @serializable.view(SchemaVersion1Dot7)

    Without this, provides will be emitted for 1.6 but vanish when outputting 1.7 (the current default). After adding the view, regenerate the snapshots so tests/_data/snapshots/get_bom_with_provides-1.7.{json,xml}.bin are created (CDX_TEST_RECREATE_SNAPSHOTS=1).

  3. Open maintainer request still unresolved. @jkowalleck's "changes requested" review asks for a dedicated Bom.register_provision(target, provides) method instead of a new provides kwarg on register_dependency(). That thread is still open and should be answered/implemented before merge. (If kept as-is, the recursive registration of provided targets via register_dependency(target=_p2, depends_on=None, provides=None) is correct — it mirrors the depends_on handling and does not create cycles.)

🟡 Should fix

  1. Import style: from cyclonedx.schema.schema import SchemaVersion1Dot6 is an absolute self-import; the rest of the package uses relative imports (from ..schema.schema import ...). Also, the import should sit with the other relative imports, not between third-party and local blocks.

  2. Method ordering: provides_as_bom_refs() is placed after __comparable_tuple(), splitting it from its sibling dependencies_as_bom_refs(). Move it directly below dependencies_as_bom_refs().

  3. Stray inline comment in bom.validate(): # Include provides refs here adds no information — the surrounding comment already says "dependencies and provides". Suggest removing it.

  4. Docs: docs/schema-support.rst → row bom.dependencies could note that provides is supported (since the release this lands in), similar to the Since 2.3.0 note already present.

⚪ Nits / observations

  1. test_dependency_with_provides in tests/test_model_dependency.py is quite thin (only checks lengths/hash inequality). The snapshot fixture get_bom_with_provides is the real coverage and is fine; consider extending test_sort so the ordering impact of provides in __comparable_tuple is exercised, or drop the unit test in favour of the snapshot test, per the maintainers' stated preference.

  2. Nested dependencies/provides on an entry inside provides are silently dropped on output. This is the same pre-existing behaviour as for dependsOn, so it is acceptable, just noting it is unchanged.

  3. mypy reports "unused type: ignore" on the new self.provides = ... # type:ignore[assignment] line — this is a toolchain-version artefact that main has already resolved by removing those comments (see item 1).

Verification performed

  • python -m unittest discover -t . -s tests → Ran 5334 tests … OK
  • flake8 cyclonedx/ tests/ → clean
  • Round-trip check: register_dependency(B, provides=[C]) → 1.6 JSON {"provides": ["C"], "ref": "B"} → Bom.from_json() restores provides correctly.
  • validate() with a provides ref not in the BOM → raises UnknownComponentDependencyException ✅
  • git merge main → CONFLICT (content): Merge conflict in cyclonedx/model/dependency.py

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: add cyclonedx.model.dependency.Dependency.provides

4 participants