Skip to content

Instantly share code, notes, and snippets.

@garethr
Last active February 25, 2022 13:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save garethr/ed4b2848181d7a670e5f42e5fa8ccb25 to your computer and use it in GitHub Desktop.
Save garethr/ed4b2848181d7a670e5f42e5fa8ccb25 to your computer and use it in GitHub Desktop.
A quick example of a shim for PURL for the Snyk APIs
"""
This python scipt is a basic demonstration of providing a shim for the Snyk test APIs for PURL.
This provides a nicer, higher level interface. It was predominantly written to demonstrate
the simplicity of mapping (most of) PURL to the existing Snyk test APIs.
Usage
> purl2snyk test pkg:pypi/django@1.11.1
> purl2snyk test pkg:maven/org.apache.logging.log4j/log4j-core@2.14.0
Things not done here:
* Dealing with qualifiers and subpaths
Note that the Snyk test APIs do support repository for the Maven endpoint, but that isn't
exposed in pysnyk, which is the only reason it's not implemented here.
* No attempt to address output. The output is the straight Snyk API response.
* Covering only the core test APIs. It should be relatively simple with a bit more work to
extend this to deb, rpm, Go and Nuget using the lower-level DepGraph API.
"""
import os
import sys
import urllib.parse
import click
import snyk
from packageurl import PackageURL
class UnsupportedPurlTypeError(Exception):
pass
@click.group()
def cli():
pass
def maven(purl, org):
return org.test_maven(purl.namespace, purl.name, purl.version)
def gem(purl, org):
return org.test_rubygem(purl.name, purl.version)
def pypi(purl, org):
return org.test_python(purl.name, purl.version)
def encode_npm_package_name(purl):
if purl.namespace:
return urllib.parse.quote_plus(f"{purl.namespace}/{purl.name}")
else:
return purl.name
def npm(purl, org):
return org.test_npm(encode_npm_package_name(purl), purl.version)
def tester(repo):
TESTERS = {
"maven": maven,
"gem": gem,
"pypi": pypi,
"npm": npm,
}
try:
return TESTERS[repo]
except KeyError:
raise UnsupportedPurlTypeError
@cli.command()
@click.argument("purl")
def test(purl):
try:
token = os.environ["SNYK_TOKEN"]
except KeyError:
sys.exit("You must provide a SNYK_TOKEN to run purl2snyk")
client = snyk.SnykClient(token)
org = client.organizations.first()
try:
purl_obj = PackageURL.from_string(purl)
except ValueError:
sys.exit(f"You must provide a valid PURL: {purl}")
if purl_obj.qualifiers or purl_obj.subpath:
sys.exit(f"PURL qualifiers and subpaths are currently unsupported")
try:
result = tester(purl_obj.type)(purl_obj, org)
except UnsupportedPurlTypeError:
sys.exit(f"PURLs of type '{purl_obj.type}' are not currently supported")
click.echo(result)
if __name__ == "__main__":
cli()
[tool.poetry]
name = "purl2snyk"
version = "0.1.0"
description = ""
authors = ["Gareth Rushgrove <gareth@morethanseven.net>"]
[tool.poetry.dependencies]
python = "^3.9"
packageurl-python = "^0.9.9"
pysnyk = "^0.7.0"
click = "^8.0.4"
[tool.poetry.dev-dependencies]
pytest = "^6.0"
pytest-black = "^0.3.12"
pytest-isort = "^3.0.0"
[tool.poetry.scripts]
purl2snyk = 'purl2snyk:cli'
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
[tool.pytest.ini_options]
addopts = "--black --isort --verbose"
minversion = "6.0"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment