Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2.5.0 regression: SortedSet assumes comparability of members, but Vulnerability model is not comparable #245

Closed
woodruffw opened this issue Jun 10, 2022 · 17 comments

Comments

@woodruffw
Copy link
Contributor

Hi there! Thanks a ton for this library.

We currently use it to generate SBOMs in pip-audit, and I noticed an interested regression upon upgrading to 2.5.0: it looks like Component.add_vulnerability attempts to add the underlying Vulnerability model to a SortedSet, which in turn fails because Vulnerability doesn't appear to implement the standard comparable operators (e.g. __lt__).

Here's the failing code on our side, which worked in 2.4.0:

        for (dep, vulns) in result.items():
            if dep.is_skipped():
                continue
            dep = cast(service.ResolvedDependency, dep)

            c = Component(name=dep.name, version=str(dep.version))
            for vuln in vulns:
                c.add_vulnerability(
                    Vulnerability(
                        id=vuln.id,
                        description=vuln.description,
                        recommendation="Upgrade",
                    )
                )

            self._components.append(c)

and the failing CI tests on 2.5.0: https://github.com/trailofbits/pip-audit/runs/6832431942?check_suite_focus=true

In my estimation, this looks like a bug/regression, rather than a SemVer breakage -- the Vulnerability model also comes from CycloneDX, so it probably should have been made comparable at the same time that comparability was assumed by introducing SortedSet.

xref pypa/pip-audit#292

@woodruffw
Copy link
Contributor Author

woodruffw commented Jun 10, 2022

If I'm right, the only fix needed here is to add a Vulnerability.__lt__ implementation. I can look into that now.

Edit: Looking at the model more closely, it's not clear to me what the sorting semantics should be -- nearly every field is optional, and many are lists (which means that comparing between instances might entail comparing overlapping ranges, which is both unlikely to be semantically coherent and has bad worst-case performance).

@madpah
Copy link
Collaborator

madpah commented Jun 10, 2022

@woodruffw - thanks for reporting this - let me take a look. In the mean time, are you able to pin your usage to >= 2.4.0?

@woodruffw
Copy link
Contributor Author

Thanks for looking into it!

In the mean time, are you able to pin your usage to >= 2.4.0?

Yep, and I've confirmed that doing so avoids the bug.

@RodneyRichardson
Copy link
Contributor

Ah! I'm not sure how I missed that. I thought I'd covered all classes that are used in a SortedSet.

If I'm right, the only fix needed here is to add a Vulnerability.__lt__ implementation. I can look into that now.

It looks like VulnerabilityCredits and OrganizationalEntity also need __lt__. And test_sort functions to the corresponding TestModelXXX classes.

Edit: Looking at the model more closely, it's not clear to me what the sorting semantics should be -- nearly every field is optional, and many are lists (which means that comparing between instances might entail comparing overlapping ranges, which is both unlikely to be semantically coherent and has bad worst-case performance).

I would suggest sort order for Vulnerability: id, description, detail, source, created, published

@jkowalleck
Copy link
Member

jkowalleck commented Jun 10, 2022

Regarding a camparator on the model, here are my 2ct:
It does not matter how you implement the comparison, as long as it is deterministic.
Just define a algorithm, implement it, add a unit test so it does not change over time unintended.

RodneyRichardson added a commit to RodneyRichardson/cyclonedx-python-lib that referenced this issue Jun 10, 2022
Partial fix for CycloneDX#245.

Signed-off-by: Rodney Richardson <rodney.richardson@cambridgeconsultants.com>
@RodneyRichardson
Copy link
Contributor

I've added a partial fix (#246), that should work in this particular situation (when credits are not set). I'm afraid I don't have time to work on this in the next week.

@woodruffw
Copy link
Contributor Author

Thanks @RodneyRichardson!

FWIW, I'd suggest yanking the current release (2.5.0) from PyPI -- IMO the regression here violates SemVer's minor version rules, so users with semantic ranges might experience breakage.

jkowalleck pushed a commit that referenced this issue Jun 10, 2022
Partial fix for #245.

Signed-off-by: Rodney Richardson <rodney.richardson@cambridgeconsultants.com>
@jkowalleck
Copy link
Member

jkowalleck commented Jun 11, 2022

Thanks @RodneyRichardson!

FWIW, I'd suggest yanking the current release (2.5.0) from PyPI -- IMO the regression here violates SemVer's minor version rules, so users with semantic ranges might experience breakage.

my 2ct: i do not see sorted lists as a breaking change but a bachwards compatible feature. no method signatures (api) was changed backwards-incompatible. Some return types did change in backwards-compatible manner, the returned content did not change in its meaning.
The content of sets are commutative: order of these data never mattered, no matter if a component is listed first or last as long as it is in the list(set).
Even typing should be fine according to grantjenks/python-sortedcontainers#107 (comment)

What is your POV? Are there breaking changes for you?

@woodruffw
Copy link
Contributor Author

woodruffw commented Jun 11, 2022 via email

@woodruffw
Copy link
Contributor Author

woodruffw commented Jun 11, 2022 via email

@RodneyRichardson
Copy link
Contributor

FWIW, I'd suggest yanking the current release (2.5.0) from PyPI

I agree - I don't think it's a breaking change in the API, but I think it's a broken release that should be recalled. Sorry I don't have time to add __lt__ operators on the other two classes to fix this fully.

@jkowalleck
Copy link
Member

reviewed all classes that are pumped into a SortedSet - all seamed to have a proper __lt__() now, after 2.5.1 was released .
yanking 2.5.0 - still in discussion.

@woodruffw
Copy link
Contributor Author

Thanks a ton for the patch release!

I don't want to be a nag about the yank, but IMO the sooner the better 🙂 -- most users are unlikely to hit it now that there's a patch version, but those who do (and have similar codepaths to pip-audit) are likely to experience similar problems.

@RodneyRichardson
Copy link
Contributor

RodneyRichardson commented Jun 15, 2022

reviewed all classes that are pumped into a SortedSet - all seamed to have a proper __lt__() now, after 2.5.1 was released

@jkowalleck It looked like VulnerabilityCredits and OrganizationalEntity also need __lt__

@jkowalleck
Copy link
Member

jkowalleck commented Jun 15, 2022

reviewed all classes that are pumped into a SortedSet - all seamed to have a proper __lt__() now, after 2.5.1 was released

@jkowalleck It looked like VulnerabilityCredits and OrganizationalEntity also need __lt__

what am i missing, @RodneyRichardson ?
I do not see any usage of VulnerabilityCredits in a SortedSet.
OrganizationalEntity actually was used in a sorted set and was lacking the __lt__() - you are right. Missed this one in previous code reviews.

however, will come up with PR to add the method to both, soon.

@RodneyRichardson
Copy link
Contributor

RodneyRichardson commented Jun 17, 2022

what am i missing, @RodneyRichardson ? I do not see any usage of VulnerabilityCredits in a SortedSet.

Ah - I didn't have access to the code when I wrote that - I think I was planning to have credits as part of the sort criteria for the Vulnerability (which would mean it needs a comparator) but I didn't. I guess we should check for use in the ComparableTuple too (but the tests should pick that up).

@jkowalleck
Copy link
Member

I will leave everything as is, for now. Additional bug reports will show further need for tests or improvements.

Therefore, i will close this issue, for now.

See you next time, when we open the gates of this issue again, and continue our discussions :-)

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

No branches or pull requests

4 participants