Giter Club home page Giter Club logo

pysnyk's Introduction

pysnyk

Build status

A Python client for the Snyk API.

Client

Using the client requires you to provide your Snyk API token.

import snyk
client = snyk.SnykClient("<your-api-token>")

By default the client will connect to the public Snyk service. If you are using a local installation then you can provide the API url as the second argument.

import snyk
client = snyk.SnykClient("<your-api-token>", "<your-instance-of-snyk>")

By default the User-Agent string for the API requests will be pysnyk/<version>. If you would like to send a custom user agent you can do so as follows:

import snyk
client = snyk.SnykClient("<your-api-token>", user_agent="<your-instance-of-snyk>")

By default the requests are not retried. If you would like to retry failed requests with backoff and delay you can do so as follows:

import snyk
client = snyk.SnykClient("<your-api-token>", tries=4, delay=1, backoff=2)
  • tries - the maximum number of attempts. Default: 1 (no retries)
  • delay - initial delay between attempts. Default: 1
  • backoff - multiplier applied to delay between attempts. Default: 2
  • debug - run client in debug mode, useful for debugging API requests. Default: False

Organizations

With the client we can get a list of Snyk organizations you are a member of:

client.organizations.all()

This returns a list of snyk.models.Organization objects.

If you already have the ID of the organization you're after you can grab it directly:

client.organizations.get("<organization-id>")

This will return a single snyk.models.Organization object.

Most of the API is scoped to organizations, so most other methods are found on the snyk.models.Organization objects returned by these two methods.

The snyk.models.Organization object has the following properties related to the API:

  • entitlements - returns the set of Snyk features available to this account
  • dependencies- returns a Manager for packages in use in this organization
  • licenses - returns a Manager for licenses currently in use by projects in this organisation
  • members - returns a Manager for members
  • projects - returns a Manager for associated projects
  • integrations - returns a Manager for active integrations

A note on Managers

Managers provide a consistent API for accessing objects from the Snyk API. Each manager implements the following methods:

  • all() - return a list of all of the relevant objects
  • get("<id>") - return a single instance of the object if it exists
  • first() - grab the first instance of the object if one exists
  • filter(<key>="<value>") - return a list filtered by one or more key/value pairs

Projects

Once you have an organization you're likely to want to grab the related projects:

client.organizations.first().projects.all()

This will return a list of snyk.models.Project objects.

In the case where you want to get all of the projects across all of your organizations then you can use the handy method on the client.

client.projects.all()

The snyk.models.Project object has the following useful properties and methods:

  • delete() - deletes the project in question. Be careful as this will delete all associated data too
  • move(new_org_id) - moves the project to a new organization
  • dependencies - returns a Manager for packages in use in this project
  • dependency_graph - returns a snyk.models.DependencyGraph object which represents the full dependency graph of package dependencies
  • ignores - returns a Manager for ignore rules set on the project
  • vulnerabilities - returns a list of snyk.models.Vulnerability objects with information about vulnerabilities in this project
  • jira_issues - returns a Manager with access to any associated Jira issues
  • licenses - returns a Manager for licenses currently in use by this project
  • settings - returns a Manager for interacting with the current project settings
  • tags - returns a Manager for interacting with the current project tags

You can add and delete tags using the manager:

  • tags.add(key, value) - adds a tag with the provided key/value pair to the project
  • tags.delete(key, value) - deletes a tag with the provided key/value pair from the project

In the case of Projects, as well as filtering by properties (as mentioned above) you can also filter by tag:

client.organizations.first().projects.filter(tags = [{"key": "some-key", "value": "some-value"}])

Note that the settings Manager can also be used to update settings like so, assuming you have a snyk.models.Project object in the variable project.

project.settings.update(pull_request_test_enabled=True)

Importing new projects

The client supports a high-level import_project method on organizations for adding new projects to be monitored by Snyk.

org = client.organizations.first()
org.import_project("github.com/user/project@branch")
org.import_project("docker.io/repository:tag")

If you are targetting a specific manifest file or files you can pass those as an optional argument, for instance:

org.import_project("github.com/user/project@branch", files=["Gemfile.lock"])

This method currently only supports importing projects from GitHub and Docker Hub. For other integrations you will need to grab the lower-level snyk.models.Integration object from the snyk.models.Organization.integrations manager noted above. Other services will be added to this API soon.

Testing for vulnerabilities

The API also exposes methods to discover vulnerability information about individual packages. These methods are found on the Organization object.

  • test_maven(<package_group_id>, <package_artifact_id>, <version>) - returns an IssueSet containing vulnerability information for a Maven artifact
  • test_rubygem(<name>, <version>) - returns an IssueSet containing vulnerability information for a Ruby Gem
  • test_python(<name>, <version>) - returns an IssueSet containing vulnerability information for Python package from PyPi
  • test_npm(<name>, <version>) - returns an IssueSet containing vulnerability information for an NPM package

Here's an example of checking a particular Python package.

>>> org = client.organizations.first()
>>> result = org.test_python("flask", "0.12.2")
>>> assert result.ok
False
# You can access details of the vulnerabilities too, for example
>>> result.issues.vulnerabilities[0].title
'Improper Input Validation'
>>> result.issues.vulnerabilities[0].identifiers
{'CVE': ['CVE-2018-1000656'], 'CWE': ['CWE-20']

As well as testing individual packages you can also test all packages found in various dependency management manifests. The client currently supports the following methods:

  • test_pipfile(<file-handle-or-string>) - returns an IssueSet for all Python dependencies in a Pipfile
  • test_gemfilelock(<file-handle-or-string>) - returns an IssueSet for all Ruby dependencies in a Gemfile
  • test_packagejson(<file-handle-or-string>, (<lock-file-handle-or-string>)) - returns an IssueSet for all Javascript dependencies in a package.json file. Optionally takes a package.lock file
  • test_gradlefile(<file-handle-or-string>) - returns an IssueSet for all dependencies in a Gradlefile
  • test_sbt(<file-handle-or-string>) - returns an IssueSet for all dependencies defined in a .sbt file
  • test_pom(<file-handle-or-string>) - returns an IssueSet for all dependencies in a Maven pom.xml file
  • test_yarn(<file-handle-or-string>, <lock-file-handle-or-string>) - returns an IssueSet for all dependencies in Yarn package.json and yarn.lock files
  • test_composer(<file-handle-or-string>, <lock-file-handle-or-string>) - returns an IssueSet for all dependencies in Composer composer.json and composer.lock files

For example, here we are testing a Python Pipfile.

>>> org = client.organizations.first()
>>> file = open("Pipfile")
>>> org.test_pipfile(file)

Inviting new users

You can invite new users to the organization via the API.

>>> org = client.organizations.first()
>>> org.invite("[email protected]")

You can also invite new users as administrators:

>>> org = client.organizations.first()
>>> org.invite("[email protected]", admin=True)

Low-level client

As well as the high-level API of the Snyk client you can use the HTTP methods directly. For these you simply need to pass the path, and optionally a data payload. The full domain, and the authentication details, are already provided by the client.

client.get("<path>")
client.delete("<path>")
client.put("<path>", <data>)
client.post("<path>", <data>)

Most of the time you shouldn't need to use these. They are mainly useful if new methods are added to the API which are not yet supported in the client. This can also be useful if you want to pass very specific parameters, or to parse the raw JSON output from the API.

Experimental rest low-level client

pysnyk >= 0.9.0 now includes support for basic rest (formerly referred to as v3) compatibility. To switch to use a rest client, pass the rest API url and version when initializing a client. Right now it supports the GET method. Refer to the rest API docs for more information and examples.

Getting the rest information of an organization:

# To get this value, get it from a Snyk organizations settings page
snyk_org = "df734bed-d75c-4f11-bb47-1d119913bcc7"

# to use the rest endpoint you MUST include a version value and the url of the v3 api endpoint as shown below
rest_client = SnykClient(snyk_token, version="2022-02-16~experimental", url="https://api.snyk.io/rest")

print(rest_client.get(f"/orgs/{snyk_org}").json())

# this supports overriding rest versions for a specific GET requests:
user = rest_client.get(f"orgs/{snyk_org}/users/{snyk_user}", version="2022-02-01~experimental").json()

# pass parameters such as how many results per page
params = {"limit": 10}

targets = rest_client.get(f"orgs/{snyk_org}/targets", params=params)

V1 and rest can work at the same time by instantiating two clients:

snyk_org = "df734bed-d75c-4f11-bb47-1d119913bcc7"

v1client = SnykClient(snyk_token)

rest_client = SnykClient(snyk_token, version="2022-02-16~experimental", url="https://api.snyk.io/rest")

v1_org = v1client.organizations.get(snyk_org)

rest_org = rest_client.get(f"/orgs/{snyk_org}").json()

The rest API introduces consistent pagination across all endpoints. The v3 client includes a helper method .get_rest_pages which collects the paginated responses and returns a single list combining the contents of the "data" key from all pages. It takes the same values as the get method.

rest_client = SnykClient(snyk_token, version="2022-02-16~experimental", url="https://api.snyk.io/rest")

params = {"limit": 10}

targets = rest_client.get(f"orgs/{snyk_org}/targets", params=params).json()

print(len(targets["data"]))
# returns 10 targets

all_targets = rest_client.get_rest_pages(f"orgs/{snyk_org}/targets", params=params)

print(len(all_targets))
# returns 33 targets, note we don't have to add .json() to the call or access the "data" key, get_rest_pages does that for us

# Override Content-Type header (or others) as needed for 
response = rest_client.post(f"orgs/{snyk_org}/invites", body={"email": "[email protected]", "role": "f8223479-01a9-4774-8e29-06ce9a0513d6", headers={"Content-Type": "application/vnd.api+json"}})

For backwards compatibility the get_rest_pages method has an alternative name of get_v3_pages to not break code already rewritten replatformed to the 0.9.0 pysnyk module.

pysnyk's People

Contributors

clem-decath avatar colinbarr avatar garethr avatar ianyoung-bo avatar ig596 avatar jacobdichiacchio avatar jdewinne avatar jgresty avatar jlourenc avatar jodawill avatar jrm16020 avatar keiya-nobuta avatar kriti-d avatar lili2311 avatar lirantal avatar maxjeffos avatar milesflo avatar mnimmny avatar mrzarquon avatar nathan-roys avatar nmbro avatar olegshprengelsnyk avatar perfectra1n avatar qmg-drettie avatar rhicksiii91 avatar rrrutledge avatar shawnsnyk avatar v1sion avatar whardier avatar xavierxmorris avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pysnyk's Issues

Field "isMonitored" of type builtins.bool is missing in snyk.models.Project instance

This is with pysnyk 0.6.1 installed via pip3.

$ python3 examples/api-demo-1-list-projects.py --orgId=....
Traceback (most recent call last):
  File "examples/api-demo-1-list-projects.py", line 23, in <module>
    for proj in client.organizations.get(org_id).projects.all():
  File "/home/pohly/.local/lib/python3.7/site-packages/snyk/managers.py", line 168, in all
    return self._query()
  File "/home/pohly/.local/lib/python3.7/site-packages/snyk/managers.py", line 159, in _query
    projects.append(self.klass.from_dict(project_data))
  File "<string>", line 106, in from_dict
mashumaro.exceptions.MissingField: Field "isMonitored" of type builtins.bool is missing in snyk.models.Project instance

Enabling logging shows that the GET /api/org/.../projects HTTP/1.1 succeeded.

Adding Priority Argument to create_jira_issue Fails

When using pysnyk to create a Jira issue with priority as an argument (integer 1-5, with 1 being highest), the response always results in a 422.
jira_issue = project.jira_issues.create( vuln.id, { "project": {"id": config.JIRA.PROJECT_ID}, "issuetype": {"id": config.JIRA.ISSUE_TYPE_ID}, "summary": f"{project.name} - {vuln.title} in {vuln.package}", "description": generate_jira_description(project.id, vuln), "priority": determine_jira_priority(vuln.severity, vuln.cvssScore) }, )
However, the UI manages to set the designated priority successfully.
Screen Shot 2020-01-08 at 6 37 57 PM
Screen Shot 2020-01-08 at 6 38 07 PM

Add "branch" name to Project model object

"branch" property was added to the API output when retrieving a project, let's add it as a property of the Project object...

will be especially useful when re-importing a project that has a default branch other than master by passing the same branch name to the import function...

I plan to try adding on my own and submit a PR at some point in the near future unless someone else gets to it first

image

[BUG]: Exception Raised When Getting Dependency Graph for Project That Isn't Using a Supported Package Manager

Is there an existing issue for this?

  • I have searched the existing issues

Description of the bug

I was using the pysnyk package to pull a dependency graph for a project that had a project type of dockerfile, and it raised this exception:

ValueError: Argument for snyk.models.DependencyGraph.from_dict method should be a dict instance

This exception isn't intuitive, and at first glance it appears that the Snyk SDK wasn't compatible with the response from the Snyk API.

I raised a ticket with Snyk support, and I was told that the reason the exception was being raised was because the dependency graph API endpoint only supports specific package managers (see here).

The Snyk API should raise a more helpful exception to help end users understand that the project they are trying to get the dependency graph for isn't currently supported.

Steps To Reproduce

import snyk # from https://pypi.org/project/pysnyk/
snyk_client = snyk.SnykClient("<put-snyk-api-token-here>")
org = snyk_client.organizations.get("<put-org-id-with-project-that-has-dockerfile-as-type>")
[p.dependency_graph for p in org.projects.all()]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <listcomp>
  File "/Path/to/virtual_env/.venv/lib/python3.9/site-packages/snyk/models.py", line 647, in dependency_graph
    return Manager.factory(DependencyGraph, self.organization.client, self).all()
  File "/Path/to/virtual_env/.venv/lib/python3.9/site-packages/snyk/managers.py", line 377, in all
    return self.klass.from_dict(dependency_data["depGraph"])
  File "<string>", line 43, in from_dict
ValueError: Argument for snyk.models.DependencyGraph.from_dict method should be a dict instance

Additional Information

No response

Getting certificate issue while creating the Snyk Client

HTTPSConnectionPool(host='snyk.io', port=443): Max retries exceeded with url: /api/v1/orgs (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1129)'))), retrying in 1 seconds...
HTTPSConnectionPool(host='snyk.io', port=443): Max retries exceeded with url: /api/v1/orgs (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1129)'))), retrying in 2 seconds...
HTTPSConnectionPool(host='snyk.io', port=443): Max retries exceeded with url: /api/v1/orgs (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1129)'))), retrying in 4 seconds...

When we try to add the certs

import requests
s = requests.Session()
s.cert = 'snyk_cert.pem'

Please assist.

pysnyk doesn't work with Python 3.10

After updating from Python 3.9 to Python 3.10 I've ran into the issue that my pysnyk based scripts wouldn't work anymore, e.g.:

$ ./list-vulnerabilities.py --from 2021-12-14 --to 2021-12-15  
Traceback (most recent call last):
  File "/home/lukasgr/Documents/Vontobel/git/snyk-helpers/./list-vulnerabilities.py", line 7, in <module>
    import snyk
  File "/home/lukasgr/Documents/Vontobel/git/snyk-helpers/.venv/lib/python3.10/site-packages/snyk/__init__.py", line 23, in <module>
    from .client import SnykClient
  File "/home/lukasgr/Documents/Vontobel/git/snyk-helpers/.venv/lib/python3.10/site-packages/snyk/client.py", line 10, in <module>
    from .models import Organization, Project
  File "/home/lukasgr/Documents/Vontobel/git/snyk-helpers/.venv/lib/python3.10/site-packages/snyk/models.py", line 6, in <module>
    from mashumaro import DataClassJSONMixin  # type: ignore
  File "/home/lukasgr/Documents/Vontobel/git/snyk-helpers/.venv/lib/python3.10/site-packages/mashumaro/__init__.py", line 4, in <module>
    from mashumaro.serializer.json import DataClassJSONMixin
  File "/home/lukasgr/Documents/Vontobel/git/snyk-helpers/.venv/lib/python3.10/site-packages/mashumaro/serializer/json.py", line 28, in <module>
    class DataClassJSONMixin(DataClassDictMixin):
  File "/home/lukasgr/Documents/Vontobel/git/snyk-helpers/.venv/lib/python3.10/site-packages/mashumaro/serializer/base/dict.py", line 21, in __init_subclass__
    raise exc
  File "/home/lukasgr/Documents/Vontobel/git/snyk-helpers/.venv/lib/python3.10/site-packages/mashumaro/serializer/base/dict.py", line 17, in __init_subclass__
    builder.add_to_dict()
  File "/home/lukasgr/Documents/Vontobel/git/snyk-helpers/.venv/lib/python3.10/site-packages/mashumaro/serializer/base/metaprogramming.py", line 330, in add_to_dict
    pre_serialize = self.get_declared_hook(__PRE_SERIALIZE__)
  File "/home/lukasgr/Documents/Vontobel/git/snyk-helpers/.venv/lib/python3.10/site-packages/mashumaro/serializer/base/metaprogramming.py", line 196, in get_declared_hook
    if type_name(cls) != DataClassDictMixinPath:
  File "/home/lukasgr/Documents/Vontobel/git/snyk-helpers/.venv/lib/python3.10/site-packages/mashumaro/meta/helpers.py", line 28, in type_name
    if is_generic(t):
  File "/home/lukasgr/Documents/Vontobel/git/snyk-helpers/.venv/lib/python3.10/site-packages/mashumaro/meta/helpers.py", line 54, in is_generic
    raise NotImplementedError
NotImplementedError

I was able to fix it by updating the mashumaro dependency to mashumaro = "^2.0" in pyproject.toml, but wasn't sure how your release processes work, so I didn't provide a PR.

FixInfo doesn't handle optional fixedIn value

In FixInfo, the pysnyk model for FixInfo has fixedIn as required.

In processing, I encountered this:

`File "", line 67, in from_dict
File "", line 51, in from_dict
mashumaro.exceptions.MissingField: Field "fixedIn" of type List[str] is missing in FixInfo instance

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "", line 12, in from_dict
File "", line 12, in
File "", line 69, in from_dict
mashumaro.exceptions.InvalidFieldValue: Field "fixInfo" of type FixInfo in AggregatedIssue has invalid value {'isUpgradable': True, 'isPinnable': False, 'isPatchable': False, 'isFixable': True, 'isPartiallyFixable': True, 'nearestFixedInVersion': '2:1.1.1k-6.ksplice1.el8_5'}
`

The element which caused this exception is
{'id': 'SNYK-ORACLE8-OPENSSLLIBS-2605508', 'issueType': 'vuln', 'pkgName': 'openssl-libs', 'pkgVersions': ['1: 1.1.1c-15.el8' ], 'priorityScore': 733, 'priority': {'score': 733, 'factors': [ {'name': 'socialTrends', 'description': 'Currently trending on Twitter' }, {'name': 'isFresh', 'description': 'Recently disclosed' }, {'name': 'isFixable', 'description': 'Has a fix available' }, {'name': 'severity', 'description': 'High severity' } ] }, 'issueData': {'id': 'SNYK-ORACLE8-OPENSSLLIBS-2605508', 'title': "Loop with Unreachable Exit Condition ('Infinite Loop')", 'severity': 'high', 'url': 'https: //snyk.io/vuln/SNYK-ORACLE8-OPENSSLLIBS-2605508', 'identifiers': {'CVE': ['CVE-2022-0778'], 'CWE': [], 'ALTERNATIVE': []}, 'credit': [''], 'exploitMaturity': 'no-known-exploit', 'semver': {'vulnerable': ['<2:1.1.1k-6.ksplice1.el8_5']}, 'publicationTime': '2022-04-10T09:10:28.648629Z', 'disclosureTime': '2022-03-15T17:15:00Z', 'CVSSv3': 'CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H', 'cvssScore': 7.5, 'language': 'linux', 'patches': [], 'nearestFixedInVersion': '2:1.1.1k-6.ksplice1.el8_5', 'isMaliciousPackage': False}, 'isPatched': False, 'isIgnored': False, 'fixInfo': {'isUpgradable': True, 'isPinnable': False, 'isPatchable': False, 'isFixable': True, 'isPartiallyFixable': True, 'nearestFixedInVersion': '2: 1.1.1k-6.ksplice1.el8_5' }, 'links': {'paths': 'https://app.snyk.io/api/v1/org/b25f6d47-bfd9-4af6-9229-c432e6ae654b/project/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/history/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/issue/SNYK-ORACLE8-OPENSSLLIBS-2605508/paths'}}

[BUG]: 'NoneType' object has no attribute 'get' ProjectManager._rest_to_v1_response_format

Is there an existing issue for this?

  • I have searched the existing issues

Description of the bug

Following version 0.9.7 release, which contains this PR, there is a bug when a project doesn't have "meta.latest_issue_counts` property.
The following line change is missing handling the missing property case.
Therefore the entire call raises an exception, and all projects, even valid ones with the expected property, don't get returned.

To fix this issue, adding default values and two places is necessary.

The following is a fix suggestion:

    def _rest_to_v1_response_format(self, project):
        attributes = project.get("attributes", {})
        settings = attributes.get("settings", {})
        recurring_tests = settings.get("recurring_tests", {})
        issue_counts = project.get("meta", {}).get("latest_issue_counts", {})  # default value for None `latest_issue_counts`

        return {
            "name": attributes.get("name"),
            "id": project.get("id"),
            "created": attributes.get("created"),
            "origin": attributes.get("origin"),
            "type": attributes.get("type"),
            "readOnly": attributes.get("read_only"),
            "testFrequency": recurring_tests.get("frequency"),
            "isMonitored": True if attributes.get("status") == "active" else False,
            "issueCountsBySeverity": {
                "low": issue_counts.get("low", 0), # default value for None `issue_counts` (and for the below as well)
                "medium": issue_counts.get("medium", 0),
                "high": issue_counts.get("high", 0),
                "critical": issue_counts.get("critical"),
            },
            "targetReference": attributes.get("target_reference"),
            "_tags": attributes.get("tags", []),
            "importingUserId": project.get("relationships", {})
            .get("importer", {})
            .get("data", {})
            .get("id"),
            "owningUserId": project.get("relationships", {})
            .get("owner", {})
            .get("data", {})
            .get("id"),
        }

The second default value is needed because Project.issueCountsBySeverity.low, Project.issueCountsBySeverity.medium, and Project.issueCountsBySeverity.high are mandatory fields.

Steps To Reproduce

import snyk
snyk_client = snyk.SnykClient("<put-snyk-api-token-here>")
orgs = snyk_client.organizations.all()
for org in orgs:
    org.projects.all() # exception here

Additional Information

No response

support for issue paths

support AggregatedIssue.Paths to reflect the current API as path data was lost with deprecation of issues

[BUG]: Pagination with the REST API fails when iterating on several orgs

Is there an existing issue for this?

  • I have searched the existing issues

Description of the bug

I have an issue using pysnyk and the REST API with the Projects endpoint. I get a 500 error when iterating over more than 1 org. The 1st org is returning all the info I need, but when I start with the 2nd one, I get a 500 error.

Steps To Reproduce

My code is:

import snyk

snyk_token = [redacted]

rest_client = snyk.SnykClient(
    snyk_token,
    version="2023-08-21",
    url="https://api.eu.snyk.io/rest",
    debug=True,
)

params = {
    "limit": 100,
    "meta.latest_issue_counts": "true",
    "meta.latest_dependency_total": "true",
}

snyk_org_ids = [
    "244abf0b-b3e9-42ad-9e1a-2fe04727da04",
    "ae0fc237-016c-4fb5-98b7-b983d578fa37",
    "0b13ac20-8a88-4608-a822-ac5afad6c106"
]

for org_id in snyk_org_ids:
    print("Org:", org_id)
    targets = rest_client.get_rest_pages(f"orgs/{org_id}/projects", params=params)
    print("# of projects:", len(targets))

The 1st org is returning all the info I need, but when I start with the 2nd one, I get the error. End of debug shows:

...
DEBUG:snyk.client:GET_REST_PAGES: Added another 100 items to the response
DEBUG:snyk.client:GET_REST_PAGES: Another link exists: /orgs/244abf0b-b3e9-42ad-9e1a-2fe04727da04/projects?limit=100&meta.latest_issue_counts=true&meta.latest_dependency_total=true&version=2023-08-21~experimental&starting_after=v1.eyJpZCI6MTU4NDY3fQ%3D%3D
DEBUG:snyk.client:GET: https://api.eu.snyk.io/rest/orgs/244abf0b-b3e9-42ad-9e1a-2fe04727da04/projects&limit=100&meta.latest_issue_counts=%5B%27true%27%5D&meta.latest_dependency_total=%5B%27true%27%5D&version=%5B%272023-08-21~experimental%27%5D&starting_after=%5B%27v1.eyJpZCI6MTU4NDY3fQ%3D%3D%27%5D
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.eu.snyk.io:443
DEBUG:urllib3.connectionpool:[https://api.eu.snyk.io:443](https://api.eu.snyk.io/) "GET /rest/orgs/244abf0b-b3e9-42ad-9e1a-2fe04727da04/projects?limit=100&meta.latest_issue_counts=true&meta.latest_dependency_total=true&version=2023-08-21~experimental&starting_after=v1.eyJpZCI6MTU4NDY3fQ%3D%3D HTTP/1.1" 200 8518
DEBUG:snyk.client:GET_REST_PAGES: Added another 87 items to the response
DEBUG:snyk.client:GET: https://api.eu.snyk.io/rest/orgs/ae0fc237-016c-4fb5-98b7-b983d578fa37/projects&limit=100&meta.latest_issue_counts=%5B%27true%27%5D&meta.latest_dependency_total=%5B%27true%27%5D&version=%5B%272023-08-21~experimental%27%5D&starting_after=%5B%27v1.eyJpZCI6MTU4NDY3fQ%3D%3D%27%5D
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.eu.snyk.io:443
DEBUG:urllib3.connectionpool:[https://api.eu.snyk.io:443](https://api.eu.snyk.io/) "GET /rest/orgs/ae0fc237-016c-4fb5-98b7-b983d578fa37/projects?limit=100&meta.latest_issue_counts=true&meta.latest_dependency_total=true&version=2023-08-21~experimental&starting_after=v1.eyJpZCI6MTU4NDY3fQ%3D%3D HTTP/1.1" 500 198
WARNING:snyk.client:Retrying: {"jsonapi":{"version":"1.0"},"errors":[{"id":"d0d3a8a6-5fc3-4704-811f-12533f917538","detail":"An unknown error was encountered while handling your request. Please contact support.","status":"500"}]}
Traceback (most recent call last):
  File "/Users/tim/Sites/pysnyk-playground/pysnyk.py", line 48, in <module>
    targets = rest_client.get_rest_pages(f"orgs/{org_id}/projects", params=params)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/snyk/client.py", line 223, in get_rest_pages
    page = self.get(path, params).json()
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/snyk/client.py", line 173, in get
    resp = retry_call(
           ^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/retry/api.py", line 101, in retry_call
    return __retry_internal(partial(f, *args, **kwargs), exceptions, tries, delay, max_delay, backoff, jitter, logger)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/retry/api.py", line 33, in __retry_internal
    return f()
           ^^^
  File "/opt/homebrew/lib/python3.11/site-packages/snyk/client.py", line 77, in request
    raise SnykHTTPError(resp)

Additional Information

Further notes from @garethr:

This succeeds:

GET /rest/orgs/244abf0b-b3e9-42ad-9e1a-2fe04727da04/projects?limit=100&meta.latest_issue_counts=true&meta.latest_dependency_total=true&version=2023-08-21~experimental&starting_after=v1.eyJpZCI6MTU4NDY3fQ%3D%3D

and this fails:

GET /rest/orgs/ae0fc237-016c-4fb5-98b7-b983d578fa37/projects?limit=100&meta.latest_issue_counts=true&meta.latest_dependency_total=true&version=2023-08-21~experimental&starting_after=v1.eyJpZCI6MTU4NDY3fQ%3D%3D

Note the org ID changes, as you’re iterating over orgs, but the starting_after value is the same. It doesn't seem right.

It’s debugging

pysnyk/snyk/client.py

Lines 207 to 248 in 92b8973

def get_rest_pages(self, path: str, params: dict = {}) -> List:
"""
Helper function to collect paginated responses from the rest API into a single
list.
This collects the "data" list from the first reponse and then appends the
any further "data" lists if a next link is found in the links field.
"""
# this is a raw primative but a higher level module might want something that does an
# arbitrary path + origin=foo + limit=100 url construction instead before being sent here
limit = params["limit"]
data = list()
page = self.get(path, params).json()
data.extend(page["data"])
while "next" in page["links"].keys():
logger.debug(
f"GET_REST_PAGES: Another link exists: {page['links']['next']}"
)
next_url = urllib.parse.urlsplit(page["links"]["next"])
query = urllib.parse.parse_qs(next_url.query)
for k, v in query.items():
params[k] = v
params["limit"] = limit
page = self.get(next_url.path, params).json()
data.extend(page["data"])
logger.debug(
f"GET_REST_PAGES: Added another {len(page['data'])} items to the response"
)
return data

My guess is someone could write a unit test that demonstrates the problem.

[BUG]: Tags Manager does not work properly

Is there an existing issue for this?

  • I have searched the existing issues

Description of the bug

The PySnyk Tag Manager fails to properly manage tags. Calling the client.projects.get(project_id).tags.all() command produces an empty list.

Steps To Reproduce

client=snyk.SnykClient(token)
project=client.organizations.get(org_id).projects.get(project_id)
tags=project.tags.all()
real_tags=client.get(f"org/{org_id}/project/{project_id}").json().get("tags")
assert len(tags)>0
assert len(tags)==len(real_tags)

Additional Information

No response

[BUG]: SAST Projects causing InvalidFieldValue error when getting all projects for an org

Is there an existing issue for this?

  • I have searched the existing issues

Description of the bug

When using the Snyk client to get an individual org, then get all projects for that org an error is returned. This error seems to be because the SAST/Code Analysis projects return null/None for the totalDependencies value.

Steps To Reproduce

Create a python script with the following code and run it against any org that includes projects of type SAST/Code Analysis.

import snyk
client = snyk.SnykClient('api-key-here', tries=5, debug=True)
print(client.organizations.get('org-id-here').projects.all())

Additional Information

The full error messages (with file paths and org IDs removed) is as follows:

DEBUG:snyk.client:GET: https://snyk.io/api/v1/orgs
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): snyk.io:443
DEBUG:urllib3.connectionpool:https://snyk.io:443 "GET /api/v1/orgs HTTP/1.1" 200 2050
DEBUG:snyk.client:GET: https://snyk.io/api/v1/org/org-id-here/projects
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): snyk.io:443
DEBUG:urllib3.connectionpool:https://snyk.io:443 "GET /api/v1/org/org-id-here/projects HTTP/1.1" 200 1665
Traceback (most recent call last):
  File "<string>", line 78, in from_dict
TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/path-here/script.py", line 7, in <module>
    print(client.organizations.get('org-id-here').projects.all())
  File "/path-here/Library/Python/3.9/lib/python/site-packages/snyk/managers.py", line 172, in all
    return self._query()
  File "/path-here/Library/Python/3.9/lib/python/site-packages/snyk/managers.py", line 163, in _query
    projects.append(self.klass.from_dict(project_data))
  File "<string>", line 85, in from_dict
mashumaro.exceptions.InvalidFieldValue: Field "totalDependencies" of type int in Project has invalid value None

Build failing on master

https://github.com/snyk-labs/pysnyk/runs/877511123?check_suite_focus=true

Run poetry run pytest
The virtual environment found in /home/runner/.virtualenvs/pysnyk-Fsq_c0fo-py3.7 seems to be broken.
Recreating virtualenv pysnyk-Fsq_c0fo-py3.7 in /home/runner/.virtualenvs/pysnyk-Fsq_c0fo-py3.7

[FileNotFoundError]
[Errno 2] No such file or directory
##[error]Process completed with exit code 1.

Tried re-running and it failed again. Appears unrelated to the change.

0.9.6 availability

Is there an existing feature request for this?

  • I have searched the existing feature requests

Description

I wanted to upgrade to the latest version 0.9.6 - it does not seem to be available in standard "pip install" locations

`root@5dc9abe678c7:/app# pip download --no-cache-dir "pysnyk==0.9.6"

ERROR: Could not find a version that satisfies the requirement pysnyk==0.9.6 (from versions: 0.1.2, 0.1.3, 0.2.0, 0.3.1, 0.4.0, 0.4.1, 0.4.2, 0.5.0, 0.6.0, 0.6.1, 0.6.2, 0.6.3, 0.7.0, 0.8.0, 0.8.1, 0.9.0, 0.9.1, 0.9.2, 0.9.3, 0.9.4, 0.9.5)

ERROR: No matching distribution found for pysnyk==0.9.6`

Additional Information

No response

Adding copyright information to the dependency information

Looking at https://snyk.docs.apiary.io/#reference/dependencies/dependencies-by-organization/list-all-dependencies, the copyright array is returned with each dependency, but that information is not exposed in the data returned by the client.

Would it be possible to extend the Dependency manager to include that information? I'd be happy to add support if it was just a matter of extending the model, but I havne't managed to create a debuggable version of the client on my side to evaluate what changes would be required.

For now, I'm just using the client.post to workaround the issue.

first, get, etc methods of the managers are very inefficient

It seems like the Manager classes default to the behavior of fetching all data. However, the .first(), and .get() functions just call .all(), and then filter the data. In my case just syncing dependencies can take minutes, so if I didn't inspect the code and used .get() on dependency IDs, it would take minutes per call.

importlib-metadata dependency issue

When using poetry to install dependencies an error is throw for importlib_metadata.

Currently the poetry file calls for importlib_metadata = "^1.6.1" but current version is on 4.10.x. This is causing conflicts with other libraries since poetry will only allow the version to be ">=1.6.1" but "<2.0.0" based on the "^"

Poetry documentation here

[BUG]: Example 1 projects.all() produces an unhandled exception.

Is there an existing issue for this?

  • I have searched the existing issues

Description of the bug

In the example 'api-demo-1-list-projects.py ' (https://github.com/snyk-labs/pysnyk/blob/master/examples/api-demo-1-list-projects.py) the following line produces an invalid field exception.

for proj in client.organizations.get(org_id).projects.all():

This may be an access restriction, but the exception should be properly handled and respond with some indication of what the issue actually is.

Exception:

Exception has occurred: InvalidFieldValue
Field "totalDependencies" of type int in Project has invalid value None
  File "<string>", line 78, in from_dict

Python 3.10.4
pysnyk==0.9.4

Steps To Reproduce

Run the example code, possibly with limited access.

Additional Information

No response

Field "version" of type builtins.str is missing in snyk.models.DependencyGraphPackageInfo

When calling on the dependency_graph property for a Snyk project, sometimes I get the following exception;

__init__.py", line 94, in main
    dep_graph = snyk_project.dependency_graph
  File "..../python3.7/site-packages/snyk/models.py", line 459, in dependency_graph
    return Manager.factory(DependencyGraph, self.organization.client, self).all()
  File "..../python3.7/site-packages/snyk/managers.py", line 297, in all
    return self.klass.from_dict(dependency_data["depGraph"])
  File "<string>", line 36, in from_dict
  File "<string>", line 36, in <listcomp>
  File "<string>", line 28, in from_dict
  File "<string>", line 22, in from_dict
mashumaro.exceptions.MissingField: Field "version" of type builtins.str is missing in snyk.models.DependencyGraphPackageInfo instance

I believe this suggests that there's a package in response to https://snyk.docs.apiary.io/#reference/projects/project-dependency-graph/get-project-dependency-graph API call that has no version field set.

Calling the raw endpoint returned the following for an internal project. Admittedly the version hasn't been specified. Either pysnyk accommodates with default values if missing, or internally at Snyk a default value is set if the item is missing?


  "depGraph": {
    "schemaVersion": "1.2.0",
    "pkgManager": {
      "name": "npm"
    },
    "pkgs": [
      {
        "id": "project-name@",
        "info": {
          "name": "project-name"
        }
      }
    ],
    "graph": {
      "rootNodeId": "root-node",
      "nodes": [
        {
          "nodeId": "root-node",
          "pkgId": "project-name@",
          "deps": []
        }
      ]
    }
  }
}

[BUG]: Improper Handling of Version and Limit Parameters on Get Rest Pages in v0.9.12

Is there an existing issue for this?

  • I have searched the existing issues

Description of the bug

This commit appears to have adjusted the behavior of get_rest_pages(), resulting in appending duplicate query params that result in an invalid query.
?limit=100&version=experimental?limit=100&version=experimental&

Steps To Reproduce

Run the following code on an organization containing a large number of projects

import snyk
org_id="xxxxxx"
snyk_token="xxxxx"
snyk_client=snyk.SnykClient(token=snyk_token,
            delay=60,
            backoff=1,
            tries=3,
            version="experimental",
            url="https://api.snyk.io/rest/",
            debug=True)
projects=snyk_client.get_rest_pages(f"/orgs/{org_id}/projects", params={"limit": 100})

Additional Information

Version Experiencing Bug

[[package]]
name = "pysnyk"
version = "0.9.12"
description = "A Python client for the Snyk API"
optional = false
python-versions = ">=3.7,<4.0"
files = [
    {file = "pysnyk-0.9.12-py3-none-any.whl", hash = "sha256:aa1c2d6ee1664548942072eeb6c1221ee9e4e76eb0341631b5c54f9efc64cb34"},
    {file = "pysnyk-0.9.12.tar.gz", hash = "sha256:28515236ec4e63e0146e6a0eec82437aa89a48182e5d9832f799f80931584db0"},
]

Performing a simple get orgs causes [SSL: CERTIFICATE_VERIFY_FAILED]

import snyk

client = snyk.SnykClient(Secrettoken)
org=client.organizations.all()
print(org)
exit()

raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='snyk.io', port=443): Max retries exceeded with url: /api/v1/orgs (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1129)')))

[BUG]: Example2 Needs updated to issueset_addregated.all(), issueset.all() returns 404.

Is there an existing issue for this?

  • I have searched the existing issues

Description of the bug

In the example2 (https://github.com/snyk-labs/pysnyk/blob/master/examples/api-demo-2-list-issues.py), it is still using the deprecated issueset.all() [api-demo-2-list-issues.py:60]. This example needs updated to use the new issueset_aggregated.all(). It looks like the old endpoint has been sunset as it now returns a 404.

The additional variables inside the returned object will be different so the print and excel [api-demo-2-list-issues.py:83-81] functions need updated as well.

If you don't get this updated, I can look into forking and rewriting that example and submit a pull request. I just don't know when I will have time.

Steps To Reproduce

Run https://github.com/snyk-labs/pysnyk/blob/master/examples/api-demo-2-list-issues.py

Additional Information

No response

Support critical field

As described here: https://support.snyk.io/hc/en-us/articles/360020021058-Critical-severity-migration?mkt_tok=Njc3LVRIUC00MTUAAAF9iuXeqVX-urX0aUZCbQ3DTlvwdMXdAJ49ROq8OmdfkP2iHJSJPLOIFr-YJMXgtSIci5rNu_oiZP92c3WJyGMo5UQh-6Xq3LZvEhxJCqfJ

Snyk will introduce a new severity level (it is still optional for now, but will be enforced starting 28th of june).

As of today issueCountsBySeverity returns something like IssueCounts(low=0, high=3, medium=7), would be cool to add the newly introduced critical field as well.

issueset: client is None

Python: 3.7.3
pysnyk: I installed the API with pip3 install pysnyk, which installed 0.4.2.

When running the examples/api-demo-2-list-issues.py script, I get an exception:

Traceback (most recent call last):
  File "examples/api-demo-2-list-issues.py", line 67, in <module>
    issue_set = project.issueset.all()
  File "/home/pohly/.local/lib/python3.7/site-packages/snyk/managers.py", line 370, in all
    return self.filter()
  File "/home/pohly/.local/lib/python3.7/site-packages/snyk/managers.py", line 387, in filter
    resp = self.client.post(path, post_body)
AttributeError: 'NoneType' object has no attribute 'post'

Org ID, project ID and API token are okay. Enabling debug logging shows that communication with the server works and printing project confirms that it looks valid (= has data). It's just the project.issueset that isn't getting constructed properly.

[BUG]: Nested objects not decoded with to_dict() or to_json()

Is there an existing issue for this?

  • I have searched the existing issues

Description of the bug

When using the to_dict() or to_json() of the DataClassJSONMixin object you get a bound method error unless you are at the very bottom level.

Each class that is inheriting DataClassJSONMixin needs to implement to_dict() and to_json() and decode the subsequent classes. This needs to be done for every object type that contains other objects of type DataClassJSONMixin so that the bottom level all the way to the top can be serialized.

Currently what happens is you are returning a dict or json that contains a SnyKClient object.

Steps To Reproduce

import json

from snyk import SnykClient
from snyk.models import Organization, Project

from utils import get_default_token_path, get_token


def get_client() -> SnykClient:
    snyk_token_path = get_default_token_path()
    snyk_token = get_token(snyk_token_path)
    client = SnykClient(token=snyk_token)
    return client


def demo_bug(snyk_client: SnykClient, org_id: str, project_id: str):
    organization: Organization = snyk_client.organizations.get(org_id)
    project: Project = organization.projects.get(project_id)
    with open(file='organization_output.json',
              mode='w', encoding='utf-8') as file:
        file.write(json.dumps(organization.to_dict(), indent=4))
        file.close()
    with open(file='project_output.json', mode='w', encoding='utf-8') as file:
        file.write(json.dumps(project.to_json(), indent=4))
        file.close()


def run(function):
    function(snyk_client=get_client(),
             org_id='',
             project_id='')


if __name__ == '__main__':
    run(demo_bug)

Additional Information

[updated with correct error message]

Exception has occurred: TypeError
Object of type SnykClient is not JSON serializable
  File "/Users/cn263376/gitrepos-local/DSOSNYK/src/DSOSNYK/bug_report.py", line 21, in demo_bug
    file.write(json.dumps(organization.to_dict(), indent=4))
  File "/Users/cn263376/gitrepos-local/DSOSNYK/src/DSOSNYK/bug_report.py", line 29, in run
    function(snyk_client=get_client(),
  File "/Users/cn263376/gitrepos-local/DSOSNYK/src/DSOSNYK/bug_report.py", line 35, in <module>
    run(demo_bug)
TypeError: Object of type SnykClient is not JSON serializable

Incorrect path when retrieving individual project from org

I'm getting the following error:

    project = org.projects.get(project_id)
  File "/[Redacted]/Python/3.7/lib/python/site-packages/snyk/managers.py", line 179, in get
    resp = self.client.get(path)
  File "/[Redacted]/Python/3.7/lib/python/site-packages/snyk/client.py", line 55, in get
    raise SnykHTTPError(resp)

It seems this is caused by the wrong path being defined in the ProjectManager class

    def get(self, id: str):
        if self.instance:
            path = "org/%s/projects/%s" % (self.instance.id, id)
            resp = self.client.get(path)
            project_data = resp.json()
            project_data["organization"] = self.instance.to_dict()
            return self.klass.from_dict(project_data)
        else:
            return super().get(id)

It should be:

path = "org/%s/project/%s"% (self.instance.id, id)

SettingManager missing fields from API schema

I'd like to be able to modify GHE integration settings (in this case, to enable pullRequestFailOnlyForIssuesWithFix and pullRequestFailOnAnyVulns on projects where they're certified clean), but the SettingsManager doesn't appear to account for the listing of parameters per API. I'm not sure if this is GHE specific, but would be useful to get a Manager for these settings as there's only three settings currently defined currently:

pysnyk/snyk/managers.py

Lines 272 to 275 in fb6b386

settings = [
"pull_request_test_enabled",
"pull_request_fail_on_vuln",
"pull_request_fail_only_for_high_severity",

[BUG]: importlib-metadata version requirement several major versions behind.

Is there an existing issue for this?

  • I have searched the existing issues

Description of the bug

Can you increase the scope for importlib-metadata and matrix test against 4.x, 5.x and 6.x if you need to support 4.x or 5.x for any reason.

If you need to use an older importlib-metadata it is VERY easy to vendor using vendorize and I can provide a pyproject.toml config section for how to enable that.

Steps To Reproduce

Modern opentelemetry - some flake8 tooling (that uses importlib-metadata for entrypoint solving) and others require ~=6.0

Additional Information

No response

Error running "pip install pysnyk"

I get the following error when running "pip install pysnyk":
ERROR: Could not find a version that satisfies the requirement pysnyk (from versions: none)
ERROR: No matching distribution found for pysnyk

I am somewhat new to Python. Am I doing something wrong?

[FEAT]: Prepare PySnyk for deprecation of V1 List All Projects

Is there an existing feature request for this?

  • I have searched the existing feature requests

Description

Snyk has brought this PSA:

We are reaching out to inform you about an upcoming change to our API services. As part of our ongoing efforts to improve our platform and provide you with the best possible API experience, we are deprecating the List all Projects v1 API and migrating to new GA REST List all projects API.

The decision to deprecate this API is part and parcel of Snyk’s wider initiative to gradually migrate all v1 API endpoints to a new REST API designed to provide a more consistent, friendly, and easy-to-use API framework.

PySnyk will be using a deprecated API without an update

Additional Information

No response

Importing projects that work with a broker

Hi,

How would one go about working with the Python client or the low-level API to import projects that use a broker for locally-hosted SCM? Should we provide the Broker as URL endpoint or the local SCM instance?

Stop using the project issues endpoint

The project issues endpoint (/api/v1/org/<orgId>/project/<projectId>/issues) has been turned off for most users of the API, and will be removed entirely in the near future.

This means that many users of issueset (and maybe other parts of pysnyk) will get errors as the underlying API call will return a 410 response.

issueset_aggregated provides an alternative, but ideally issueset should be updated to use the currently-supported endpoints described here:

Add project tags to data model

With the release of project tags on API, would be great to get pysnyk's Project data class and associated Tags data class updated. Currently have to do a low level API call with pysnyk to pull back tagging data. Thanks!

[BUG]: Support for `owner` and `importingUser` in Project Class

Is there an existing issue for this?

  • I have searched the existing issues

Description of the bug

My apologies if this should be an enhancement instead, but #125 implied that the Projects class should now have support for the .owner and importingUser attributes as per https://snyk.docs.apiary.io/#reference/projects/individual-project/retrieve-a-single-project, however, #150 appears just to have added the remediation attribute.

Could the owner and importingUser attributes be added please?

Steps To Reproduce

>>> client = snyk.SnykClient(SNYK_TOKEN)
>>> projects = client.projects.all()
1.id
>>> project1 = projects[0]
>>> project1.id
'XXXXX'
>>> project1.name
'name'
>>> project1.importingUser
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Project' object has no attribute 'importingUser'
>>> project1.owner
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Project' object has no attribute 'owner'
>>> 

Additional Information

No response

Slug and url properties are missing from organizations

Both slug and url are exposed in the api from snyk: https://snyk.docs.apiary.io/#reference/organizations/the-snyk-organization-for-a-request/list-all-the-organizations-a-user-belongs-to and https://snyk.docs.apiary.io/#reference/groups/list-all-organizations-in-a-group/list-all-organizations-in-a-group

{
  "orgs": [
    {
      "name": "defaultOrg",
      "id": "689ce7f9-7943-4a71-b704-2ba575f01089",
      "slug": "default-org",
      "url": "https://api.snyk.io/org/default-org",
      "group": null
    },
    {
      "name": "My Other Org",
      "id": "a04d9cbd-ae6e-44af-b573-0556b0ad4bd2",
      "slug": "my-other-org",
      "url": "https://api.snyk.io/org/my-other-org",
      "group": {
        "name": "ACME Inc.",
        "id": "a060a49f-636e-480f-9e14-38e773b2a97f"
      }
    }
  ]
}

I ran into a use-case where I would put the direct link back to an organization, but realized that I couldn't link directly to the id, and I'm guessing that's what the slug is for, but unfortunately it wasn't exposed in pysnyk.

[FEAT]: The main client should be able to return all API fields.

Is there an existing feature request for this?

  • I have searched the existing feature requests

Description

The low level client will return all API fields, however the main client does not. For example, it does not return the functions field. Alternatively, is it possible to get the raw HTTP response from the vulnerability object so that if new fields come out, users are not blocked by the client?

Thank you!

Additional Information

No response

Low Level Client functions should accept fully qualified endpoints

These functions expect a relative path to the resource:

client.get("<path>")
client.delete("<path>")
client.put("<path>", <data>)
client.post("<path>", <data>)

In my initial tests I was passing in a fully qualified URL and getting back 404, but it was unclear why. Reviewing the docs and then passing in only the path element got the right result, but it should be possible to pass either, especially if you improve the API to provide links to the resources (and not just the bare ID's) in the future. This would let a client just nab the links and come right back in through the library without having to assemble the paths, etc.

[BUG]: Packages can be missing the version field

Is there an existing issue for this?

  • I have searched the existing issues

Description of the bug

When trying the load the vulnerabilities for a project I get the exception pasted below, which I believe is occuring because the Package object requires a version field, but the Snyk API is not returning one.

Traceback (most recent call last):
  File "<string>", line 15, in from_dict
  File "<string>", line 15, in <listcomp>
  File "<string>", line 15, in <listcomp>
  File "<string>", line 18, in from_dict
mashumaro.exceptions.MissingField: Field "version" of type str is missing in Package instance

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "...bin/snyk_deps.py", line 93, in <module>
    main(sys.argv[1] == "--dry-run" if len(sys.argv) > 1 else False)
  File "...bin/snyk_deps.py", line 59, in main
    vulns = {(v.package, None if hasattr(v, "version") else None): float(v.cvssScore) if v.cvssScore is not None else None for v in snyk_proj.vulnerabilities}
  File "../homebrew/lib/python3.10/site-packages/snyk/models.py", line 641, in vulnerabilities
    foo = flat_map(self._aggregated_issue_to_vulnerabily, aggregated_vulns)
  File ".../homebrew/lib/python3.10/site-packages/snyk/utils.py", line 18, in flat_map
    return list(chain(*mapped))
  File ".../homebrew/lib/python3.10/site-packages/snyk/models.py", line 662, in _aggregated_issue_to_vulnerabily
    ).all()
  File ".../homebrew/lib/python3.10/site-packages/snyk/managers.py", line 450, in all
    return self.klass.from_dict(resp.json())
  File "<string>", line 22, in from_dict
mashumaro.exceptions.InvalidFieldValue: Field "paths" of type List[List[Package]] in IssuePaths has invalid value [[{'name': 'root'}, {'name': 'net.logstash.logback:logstash-logback-encoder', 'version': '4.11'}, {'name': 'com.fasterxml.jackson.core:jackson-databind', 'version': '2.8.9'}]]

Steps To Reproduce

I'm not sure how to reproduce this, I presume need a Snyk project with a particular set of dependencies.

Additional Information

No response

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.