Add GitHub API importer - #204
Conversation
6a76ddf to
144b555
Compare
pombredanne
left a comment
There was a problem hiding this comment.
Thanks!
Please see my comments inline for your consideration.
| try: | ||
| for entry in json_resp['items'][0]['items']: | ||
| all_versions.add(entry['catalogEntry']['version']) | ||
| # json response for YamlDotNet.Signed triggers this exception |
There was a problem hiding this comment.
What does this means exactly?What about using a cascade of get() instead to understand exactly why there are these key errors? Can you show me the problematic JSON?
There was a problem hiding this comment.
Can you show me the problematic JSON?
This is raising that exception https://api.nuget.org/v3/registration5-semver1/yamldotnet.signed/index.json
All others follow this schema instead https://api.nuget.org/v3/registration5-semver1/sustainsys.saml2/index.json
What about using a cascade of get() instead to understand exactly why there are these key errors?
That can be done, but I thought catching an exception would be more 'pythonic' (EAFP).
There was a problem hiding this comment.
That can be done, but I thought catching an exception would be more 'pythonic' (EAFP).
Well, the key is readability and clarity first: here when I read the code in json_resp['items'][0]['items'] I wonder immediately. What if there is no items or this is not a mapping? What is [0]? Is this a list or a mapping with a key 0? if this is a list, what about the other items in that list? and what is this second items about?
Here we could have something instead like that:
for item in json_resp.get('items', []):
for entry in item.get('items', []):
...
When I read it I get these are mapping that return lists and I have no problem to understand the underlying data structure that I do not know about. Otherwise, I feel I need to do quite a bit of effort to read the code and it assumes that I know about the upstream JSON data structure before hand. So EAFP is fine, but it matters more to think about the readability of the code IMHO and how it will resist to future changes in the API and how that will make it easy to debug or not.
This is raising that exception https://api.nuget.org/v3/registration5-semver1/yamldotnet.signed/index.json
All others follow this schema instead https://api.nuget.org/v3/registration5-semver1/sustainsys.saml2/index.json
This is the kind of comment that is needed in the code :)
There was a problem hiding this comment.
I agree with everything you said.
I am wondering what's the best answer in this context to the question you asked.
how it will resist to future changes in the API and how that will make it easy to debug or not.
Because in this case, during an occurence of API change the outcome of both approaches EAFP(try-except) and LBYL(get cascade) is same. The code won't crash in an event of API changes in both the cases, resulting in not collecting the data, and that will go unnoticed, unless someone decides to look into the db.
There was a problem hiding this comment.
- you can still keep inside your direct items access as
all_versions.add(entry['catalogEntry']['version'])so if that part changes if will fail. - we should have tests too
- we could think about a very limited subset of "canary"-like tests that are doing live queries on the web and fail if the API changes by returning different data.
| all_versions.add(entry['catalogEntry']['version']) | ||
| # json response for YamlDotNet.Signed triggers this exception | ||
| except KeyError: | ||
| return all_versions |
There was a problem hiding this comment.
A pass would be clearer... BUT the reason for swallowing the KeyError is what I would like to understand
There was a problem hiding this comment.
I have no idea how to handle https://api.nuget.org/v3/registration5-semver1/yamldotnet.signed/index.json which is causing the exception, hence the 'swallowing' of the KeyError
|
|
||
| @staticmethod | ||
| def composer_url(pkg_name: str) -> str: | ||
| vendor, name = pkg_name.split('/') |
There was a problem hiding this comment.
always prefer a more robust partition() or rpartition():
>>> vendor, name = pkg_name.split('/')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'pkg_name' is not defined
>>> vendor, _, name = 'foo'.partition('/')
>>> vendor, name
('foo', '')
>>> vendor, _, name = 'foo/bar'.partition('/')
>>> vendor, name
('foo', 'bar')
There was a problem hiding this comment.
always prefer a more robust partition() or rpartition():
I didn't knew about this function. Thanks.
Robust in the sense it doesn't raise ValueError: not enough values to unpack .
But in this case it makes more sense to me to use split because that would raise an exception and crash out VulnerableCode, instead of ending up writing garbage in the DB.
3d2d6a3 to
a51383b
Compare
|
LGTM! |
pombredanne
left a comment
There was a problem hiding this comment.
Thanks! See a few extra nitpickings!
bb93f5d to
28160d8
Compare
|
We will merge this after the PRs dealing with migrations and changes in data models are done with. It's really painful to refactor these. |
pombredanne
left a comment
There was a problem hiding this comment.
All ready to merge... there is one nit on a typo :) 👍
| try: | ||
| self.gh_token = os.environ["GH_TOKEN"] | ||
| except KeyError: | ||
| raise GitHubTokenError("Envirnomental variable GH_TOKEN is missing") |
There was a problem hiding this comment.
nit: Envirnomental -> Environment
|
|
||
| @staticmethod | ||
| def artifact_url(artifact_comps: List[str]) -> str: | ||
| base_url = "https://repo.maven.apache.org/maven2/{}" |
There was a problem hiding this comment.
May be you could reuse that function (with a comment you did) instead?
https://github.com/nexB/scancode-toolkit/blob/develop/src/packagedcode/maven.py#L225
This way we can eventually evolve a common maven library out of ScanCode
https://repo.maven.apache.org/maven2 is not the most common base URL too
There was a problem hiding this comment.
that's minor though and could wait
Signed-off-by: Shivam Sandbhor <shivam.sandbhor@gmail.com>
Signed-off-by: Shivam Sandbhor <shivam.sandbhor@gmail.com>
Signed-off-by: Shivam Sandbhor <shivam.sandbhor@gmail.com>
Signed-off-by: Shivam Sandbhor <shivam.sandbhor@gmail.com>
Signed-off-by: Shivam Sandbhor <shivam.sandbhor@gmail.com>
…ted commas to single inverted commas Signed-off-by: Shivam Sandbhor <shivam.sandbhor@gmail.com>
Signed-off-by: Shivam Sandbhor <shivam.sandbhor@gmail.com>
28160d8 to
fb140dc
Compare
Github API importer was made pre importer_yielder.py era. This commit adds the seed data to importer_yielder.py Signed-off-by: Shivam Sandbhor <shivam.sandbhor@gmail.com>
fb140dc to
fe442bf
Compare
|
|
||
| end_cursor = resp["data"]["securityVulnerabilities"]["pageInfo"]["endCursor"] | ||
| end_cursor_exp = "after: {}".format('"{}"'.format(end_cursor)) | ||
| api_data[ecosystem].append(resp) |
There was a problem hiding this comment.
In general it is often better to yield rather than to accumulate in a list, FWIW
| return vendor, name | ||
|
|
||
| def process_response(self) -> List[Advisory]: | ||
| adv_list = [] |
There was a problem hiding this comment.
Same as above... yielding rather than returning a list is always a good option
pombredanne
left a comment
There was a problem hiding this comment.
I added a few more comments FYI and this is merging now .
Thanks!
TODOs
Add Nuget, Maven and Composer package manager's version API
Add tests for everything
I will file another separate PR to move all these VersionAPI classes to one separate module.
Signed-off-by: Shivam Sandbhor shivam.sandbhor@gmail.com