-
Notifications
You must be signed in to change notification settings - Fork 1k
Add package vulnerability reporting API #9552
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
Conversation
/cc @di @oliverchang |
Tests are passing, but <100% coverage. Please direct hatred at the changelist |
Woo, I'm seeing a lot of interactions with the Token Disclosure code I contributed :)
|
683ff3d
to
3f01152
Compare
/assign @di |
@di This is in a reviewable state, at least for a first pass. I'll be adding more using tests for 100% coverage of what exists and modeling retrieve_public_key_payload and extract_public_keys after what exists or the token leak API |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Preliminary review
warehouse/packaging/models.py
Outdated
vulnerabilities = orm.relationship( | ||
Vulnerability, | ||
backref="releases", | ||
secondary=lambda: release_vulnerabilities, | ||
passive_deletes=True, | ||
) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should probably define this on the Vulnerability
model instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would we not want both?
class VulnerabilityReport: | ||
def __init__( | ||
self, | ||
project: str, | ||
versions: List[str], | ||
vulnerability_id: str, | ||
advisory_link: str, | ||
aliases: List[str], | ||
): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can probably condense the Vulnerability
database model and this class into a single class. The class can also live at warehouse/integrations/vulnerabilities/models.py
instead, and be imported into warehouse.packaging.models
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As in, do the model representation, report validating, and DB interaction in a single class?
e912f0b
to
1f71f43
Compare
14e463d
to
2eb2332
Compare
@di I'm still finishing up the last few test cases, but please TAL |
f10a17f
to
2e7d51a
Compare
|
||
def test_retrieve_public_key_payload_json_error(self): | ||
response = pretend.stub( | ||
text="Still a non-json teapot", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Is it bad that I laughed at this given this is a copy of a joke I made :D ) (👍)(🍵)
(Finished this round of review. I forgot to make a general comment. I appreciate that there was a lot of code inspired from my PR, but if we need to do this a 3rd time, I'm afraid that will start to make quite a lot of duplication. This is by no means a way to block this PR (https://en.wikipedia.org/wiki/Rule_of_three_(computer_programming)) but we can think already about how we can avoid duplicating that much code next time) |
76e70ff
to
91ae897
Compare
Tagging? |
see the comment that is in reply to #9552 (comment) |
Signed-off-by: Jake Sanders <[email protected]>
Signed-off-by: Jake Sanders <[email protected]>
…tructor Signed-off-by: Jake Sanders <[email protected]>
done |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
one request (the timing metric tag) and some suggestions. none of it strictly critical for merge.
revision = "1dbb95161e5a" | ||
down_revision = "08ccc59d9857" | ||
|
||
# Note: It is VERY important to ensure that a migration does not lock for a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comment(s) from template can be removed (not critical)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
|
||
|
||
def downgrade(): | ||
# ### commands auto generated by Alembic - please adjust! ### |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comment(s) from template can be removed (not critical)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
|
||
|
||
def upgrade(): | ||
# ### commands auto generated by Alembic - please adjust! ### |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comment(s) from template can be removed (not critical)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
def analyze_vulnerability(request, vulnerability_report, origin, metrics): | ||
metrics.increment("warehouse.vulnerabilities.received", tags=[f"origin:{origin}"]) | ||
try: | ||
_analyze_vulnerability( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's wrap this call in with metrics.timed('warehouse.vulnerabilities.analysis', tags=[f"origin:{origin}"]):
this will emit timing metrics so we can keep tabs on this programatically.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done, good idea
Signed-off-by: Jake Sanders <[email protected]>
Signed-off-by: Jake Sanders <[email protected]>
* Add package vulnerability reporting API Signed-off-by: Jake Sanders <[email protected]> * genericize vuln report handling, split osv into a subpackage Signed-off-by: Jake Sanders <[email protected]> * use kwargs instead of positionals for VulnerabilityReportRequest constructor Signed-off-by: Jake Sanders <[email protected]> * use tags rather than namespacing metrics by origin * also load all releases when loading vulnerability records * add description for vuln report model columns * remove comments from vulnerability migration Signed-off-by: Jake Sanders <[email protected]> * instrument `_analyze_vulnerability` Signed-off-by: Jake Sanders <[email protected]> Co-authored-by: Dustin Ingram <[email protected]>
PyPI today does not store information about known vulnerabilities. We’d like to build the necessary changes such that known vulnerabilities can be associated with package releases. The ultimate goal is that users of “pip” will be automatically warned if their dependencies are vulnerable.
See: #9407, https://discuss.python.org/t/proposing-a-community-maintained-database-of-pypi-package-vulnerabilities/8374
Signed-off-by: Jake Sanders [email protected]