diff --git a/.github/workflows/generate-index-and-docs.yml b/.github/workflows/generate-index-and-docs.yml new file mode 100644 index 00000000..f6937aa9 --- /dev/null +++ b/.github/workflows/generate-index-and-docs.yml @@ -0,0 +1,45 @@ +name: Check and generate PURL Type Docs and Index + +on: + push: + paths: + - "types/*.json" + - "schemas/*.json" + - "etc/" + branches: + - main + workflow_dispatch: +# All permissions should be specified at the job level +permissions: { } + +jobs: + generate-index-and-docs: + runs-on: ubuntu-latest + permissions: + content: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.x' + + - name: Install dependencies + run: make conf + + - name: Validate code and data formats + run: make check + + - name: Generate index and docs + run: make gendocs + + - name: Commit and push changes + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git add types/ types-doc/ + git commit -s -m "Generate updated PURL type documentation" || echo "No changes to commit" + git push diff --git a/.gitignore b/.gitignore index 82520ca1..ee46ef8e 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ /tmp/ +/venv/ +/.python-version +.ruff_cache/ diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..0290b529 --- /dev/null +++ b/Makefile @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: MIT +# Copyright (c) the purl authors +# Visit https://github.com/package-url/purl-spec and https://packageurl.org for support + +PYTHON_EXE?=python3 +VENV_LOCATION=venv +ACTIVATE?=. ${VENV_LOCATION}/bin/activate; + +CODEGEN?=datamodel-codegen \ + --target-python-version 3.10 \ + --use-double-quotes \ + --use-exact-imports \ + --use-standard-collections \ + --wrap-string-literal \ + --enum-field-as-literal all \ + --formatters ruff-format \ + --field-constraints \ + --disable-timestamp \ + --keep-model-order \ + --custom-file-header-path LICENSE \ + --input-file-type jsonschema \ + --output-model-type pydantic_v2.BaseModel + +virtualenv: + @echo "-> Bootstrap the virtualenv with PYTHON_EXE=${PYTHON_EXE}" + ${PYTHON_EXE} -m venv ${VENV_LOCATION} + +conf: virtualenv + @echo "-> Install dependencies" + @${ACTIVATE} pip install -r etc/scripts/requirements.txt + +formatcode: + @echo "-> Run Ruff format" + @${ACTIVATE} ruff check --select I --fix + @${ACTIVATE} ruff format + @echo "-> Run Ruff linter" + @${ACTIVATE} ruff check --fix + +formatjson: + @echo "-> Format JSON files" + @${ACTIVATE} python etc/scripts/format_json.py schemas/ + @${ACTIVATE} python etc/scripts/format_json.py types/ + @${ACTIVATE} python etc/scripts/format_json.py tests/ + +format: formatcode formatjson + @echo "-> Format all files" + +checkjson: + @echo "-> Validate JSON schemas" + @${ACTIVATE} check-jsonschema --check-metaschema --verbose schemas/*.json + @echo "-> Validate JSON data files against the schemas" + @${ACTIVATE} check-jsonschema --schemafile schemas/purl-types-index.schema.json --verbose purl-types-index.json + @${ACTIVATE} check-jsonschema --schemafile schemas/purl-type-definition.schema.json --verbose types/*-definition.json + @${ACTIVATE} check-jsonschema --schemafile schemas/purl-test.schema.json --verbose tests/*/*-test.json + +checkcode: + @echo "-> Run Ruff linter validation (pycodestyle, bandit, isort, and more)" + @${ACTIVATE} ruff --config etc/scripts/pyproject.toml check + @echo "-> Run Ruff format validation" + @${ACTIVATE} ruff --config etc/scripts/pyproject.toml format --check + +check: checkjson checkcode + @echo "-> Run all checks" + +clean: + @echo "-> Clean the Python env" + rm -rf .venv/ + find . -type f -name '*.py[co]' -delete + +gencode: + @echo "-> Generate Python code from schemas" + @${ACTIVATE} ${CODEGEN} \ + --input schemas/purl-types-index.schema.json \ + --output etc/scripts/purl_types_index.py + @${ACTIVATE} ${CODEGEN} \ + --input schemas/purl-type-definition.schema.json \ + --output etc/scripts/purl_type_definition.py + @${ACTIVATE} ${CODEGEN} \ + --input schemas/purl-test.schema.json \ + --output etc/scripts/purl_test.py + @echo "-> Run Black format for generated code" + @${ACTIVATE} black -l 100 --preview --enable-unstable-feature string_processing etc/scripts/*.py + +gendocs: + @${ACTIVATE} python etc/scripts/generate_index_and_docs.py + + +.PHONY: virtualenv conf formatcode formatjson format checkcode checkjson check clean gencode gendocs diff --git a/PURL-TYPES.rst b/PURL-TYPES.rst index 2385c760..6ef81c07 100644 --- a/PURL-TYPES.rst +++ b/PURL-TYPES.rst @@ -1,588 +1,75 @@ -Package URL Type definitions +Package-URL Type definitions ============================ Each package manager, platform, type, or ecosystem has its own conventions and protocols to identify, locate, and provision software packages. -The package **type** is the component of a package URL that is used to capture +The package **type** is the component of a Package-URL that is used to capture this information with a short string such as ``maven``, ``npm``, ``nuget``, ``gem``, ``pypi``, etc. - -These are known ``purl`` package type definitions. - -Known ``purl`` type definitions are formalized here independent of the core -Package URL specification. See also a candidate list further down. +These are known ``PURL`` package type definitions. Definitions can also include types reserved for future use. See also https://github.com/package-url/purl-spec and ``_ for the Package URL specification. +This document no longer contains a manually maintained list of PURL types. -Known ``purl`` types -~~~~~~~~~~~~~~~~~~~~ - -alpm ----- -``alpm`` for Arch Linux and other users of the libalpm/pacman package manager. - -- There is no default package repository: this should be implied either from - the ``distro`` qualifiers key or using a repository base url as - ``repository_url`` qualifiers key. -- The ``namespace`` is the vendor such as ``arch``, ``arch32``, ``archarm``, - ``manjaro`` or ``msys``. It is not case sensitive and must be lowercased. -- The ``name`` is the package name. It is not case sensitive and must be lowercased. -- The ``version`` is the version of the package as specified in [`vercmp(8)`](https://man.archlinux.org/man/vercmp.8#DESCRIPTION) as part of alpm. -- The ``arch`` is the qualifiers key for a package architecture. -- Examples:: - - pkg:alpm/arch/pacman@6.0.1-1?arch=x86_64 - pkg:alpm/arch/python-pip@21.0-1?arch=any - pkg:alpm/arch/containers-common@1:0.47.4-4?arch=x86_64 - -apk ---- -``apk`` for APK-based packages: - -- There is no default package repository: this should be implied either from - the ``distro`` qualifiers key or using a repository base url as - ``repository_url`` qualifiers key. -- The ``namespace`` is the vendor such as ``alpine`` or ``openwrt``. It is not - case sensitive and must be lowercased. -- The ``name`` is the package name. It is not case sensitive and must be - lowercased. -- The ``version`` is a package version as expected by apk. -- The ``arch`` is the qualifiers key for a package architecture. -- Examples:: - - pkg:apk/alpine/curl@7.83.0-r0?arch=x86 - pkg:apk/alpine/apk@2.12.9-r3?arch=x86 - -bitbucket ---------- -``bitbucket`` for Bitbucket-based packages: - -- The default repository is ``https://bitbucket.org``. -- The ``namespace`` is the user or organization. It is not case sensitive and - must be lowercased. -- The ``name`` is the repository name. It is not case sensitive and must be - lowercased. -- The ``version`` is a commit or tag. -- Examples:: - - pkg:bitbucket/birkenfeld/pygments-main@244fd47e07d1014f0aed9c - -bitnami -------- -``bitnami`` for Bitnami-based packages: - -- The default repository is ``https://downloads.bitnami.com/files/stacksmith``. -- The ``name`` is the component name. It must be lowercased. -- The ``version`` is the full Bitnami package version, including version and revision. -- The ``arch`` is the qualifiers key for a package architecture. Available values: ``amd64`` (default) and ``arm64``. -- The ``distro`` is the qualifiers key for the distribution associated to the package. -- Examples:: - - pkg:bitnami/wordpress?distro=debian-12 - pkg:bitnami/wordpress@6.2.0?distro=debian-12 - pkg:bitnami/wordpress@6.2.0?arch=arm64&distro=debian-12 - pkg:bitnami/wordpress@6.2.0?arch=arm64&distro=photon-4 - -cargo ------ -``cargo`` for Rust: - -- The default repository is ``https://crates.io/``. -- The ``name`` is the repository name. -- The ``version`` is the package version. -- Examples:: - - pkg:cargo/rand@0.7.2 - pkg:cargo/clap@2.33.0 - pkg:cargo/structopt@0.3.11 - -cocoapods ---------- -``cocoapods`` for CocoaPods: - -- The default repository is ``https://cdn.cocoapods.org/``. -- The ``name`` is the pod name and is case sensitive, cannot contain whitespace, a plus (`+`) character, or begin with a period (`.`). -- The ``version`` is the package version. -- The purl subpath is used to represent a pods subspec (if present). -- Examples:: - - pkg:cocoapods/AFNetworking@4.0.1 - pkg:cocoapods/MapsIndoors@3.24.0 - pkg:cocoapods/ShareKit@2.0#Twitter - pkg:cocoapods/GoogleUtilities@7.5.2#NSData+zlib - -composer --------- -``composer`` for Composer PHP packages: - -- The default repository is ``https://packagist.org``. -- The ``namespace`` is the vendor. -- The ``namespace`` and ``name`` are not case sensitive and must be lowercased. -- Note: private, local packages may have no name. In this case you cannot - create a ``purl`` for these. -- Examples:: - - pkg:composer/laravel/laravel@5.5.0 - -conan ------ -``conan`` for Conan C/C++ packages. The purl is designed to closely resemble the Conan-native `/@/` `syntax for package references `_. - -- ``name``: The Conan ````. -- ``version``: The Conan ````. -- ``namespace``: The vendor of the package. -- Qualifier ``user``: The Conan ````. Only required if the Conan package was published with ````. -- Qualifier ``channel``: The Conan ````. Only required if the Conan package was published with Conan ````. -- Qualifier ``rrev``: The Conan recipe revision (optional). If omitted, the purl refers to the latest recipe revision available for the given version. -- Qualifier ``prev``: The Conan package revision (optional). If omitted, the purl refers to the latest package revision available for the given version and recipe revision. -- Qualifier ``repository_url``: The Conan repository where the package is available (optional). If omitted, ``https://center.conan.io`` as default repository is assumed. - -Additional qualifiers can be used to distinguish Conan packages with different settings or options, e.g. ``os=Linux``, ``build_type=Debug`` or ``shared=True``. - -If no additional qualifiers are used to distinguish Conan packages build with different settings or options, then the purl is ambiguous and it is up to the user to work out which package is being referred to (e.g. with context information). - -Examples:: - - pkg:conan/openssl@3.0.3 - pkg:conan/openssl.org/openssl@3.0.3?user=bincrafters&channel=stable - pkg:conan/openssl.org/openssl@3.0.3?arch=x86_64&build_type=Debug&compiler=Visual%20Studio&compiler.runtime=MDd&compiler.version=16&os=Windows&shared=True&rrev=93a82349c31917d2d674d22065c7a9ef9f380c8e&prev=b429db8a0e324114c25ec387bfd8281f330d7c5c - -conda ------ -``conda`` for Conda packages: - -- The default repository is ``https://repo.anaconda.com``. -- The ``name`` is the package name. -- The ``version`` is the package version. -- The qualifiers: ``build`` is the build string. - ``channel`` is the package stored location. - ``subdir`` is the associated platform. - ``type`` is the package type. -- Examples:: - - pkg:conda/absl-py@0.4.1?build=py36h06a4308_0&channel=main&subdir=linux-64&type=tar.bz2 - -cpan ----- -``cpan`` for CPAN Perl packages: - -- The default repository is ``https://www.cpan.org/``. -- The ``namespace``: - - To refer to a CPAN distribution name, the ``namespace`` MUST be present. In this case, the namespace is the CPAN id of the author/publisher. It MUST be written uppercase, followed by the distribution name in the ``name`` component. A distribution name MUST NOT contain the string ``::``. - - To refer to a CPAN module, the ``namespace`` MUST be absent. The module name MAY contain zero or more ``::`` strings, and the module name MUST NOT contain a ``-`` - -- The ``name`` is the module or distribution name and is case sensitive. -- The ``version`` is the module or distribution version. -- Optional qualifiers may include: - - - ``repository_url``: CPAN/MetaCPAN/BackPAN/DarkPAN repository base URL (default is ``https://www.cpan.org``) - - ``download_url``: URL of package or distribution - - ``vcs_url``: extra URL for a package version control system - - ``ext``: file extension (default is ``tar.gz``) - -- Examples:: - - pkg:cpan/Perl::Version@1.013 - pkg:cpan/DROLSKY/DateTime@1.55 - pkg:cpan/DateTime@1.55 - pkg:cpan/GDT/URI-PackageURL - pkg:cpan/LWP::UserAgent - pkg:cpan/OALDERS/libwww-perl@6.76 - pkg:cpan/URI - -cran ------ -``cran`` for CRAN R packages: - -- The default repository is ``https://cran.r-project.org``. -- The ``name`` is the package name and is case sensitive, but there cannot be two packages on CRAN with the same name ignoring case. -- The ``version`` is the package version. -- Examples:: - - pkg:cran/A3@1.0.0 - pkg:cran/rJava@1.0-4 - pkg:cran/caret@6.0-88 - -deb ---- -``deb`` for Debian, Debian derivatives, and Ubuntu packages: - -- There is no default package repository: this should be implied either from - the ``distro`` qualifiers key or using a base url as a ``repository_url`` - qualifiers key. -- The ``namespace`` is the "vendor" name such as "debian" or "ubuntu". - It is not case sensitive and must be lowercased. -- The ``name`` is not case sensitive and must be lowercased. -- The ``version`` is the version of the binary (or source) package. -- ``arch`` is the qualifiers key for a package architecture. The special value - ``arch=source`` identifies a Debian source package that usually consists of a - Debian Source control file (.dsc) and corresponding upstream and Debian - sources. The ``dpkg-query`` command can print the ``name`` and ``version`` of - the corresponding source package of a binary package:: - - dpkg-query -f '${source:Package} ${source:Version}' -W - -- Examples:: - - pkg:deb/debian/curl@7.50.3-1?arch=i386&distro=jessie - pkg:deb/debian/dpkg@1.19.0.4?arch=amd64&distro=stretch - pkg:deb/ubuntu/dpkg@1.19.0.4?arch=amd64 - pkg:deb/debian/attr@1:2.4.47-2?arch=source - pkg:deb/debian/attr@1:2.4.47-2%2Bb1?arch=amd64 - -docker ------- -``docker`` for Docker images: - -- The default repository is ``https://hub.docker.com``. -- The ``namespace`` is the registry/user/organization if present. -- The version should be the image id sha256 or a tag. Since tags can be moved, - a sha256 image id is preferred. -- Examples:: - - pkg:docker/cassandra@latest - pkg:docker/smartentry/debian@dc437cc87d10 - pkg:docker/customer/dockerimage@sha256%3A244fd47e07d10?repository_url=gcr.io - -gem ---- -``gem`` for RubyGems: - -- The default repository is ``https://rubygems.org``. -- The ``platform`` qualifiers key is used to specify an alternative platform. - such as ``java`` for JRuby. The implied default is ``ruby`` for Ruby MRI. -- Examples:: - - pkg:gem/ruby-advisory-db-check@0.12.4 - pkg:gem/jruby-launcher@1.1.2?platform=java - -generic -------- -``generic`` for plain, generic packages that do not fit anywhere else such as -for "upstream-from-distro" packages. In particular this is handy for a plain -version control repository such as a bare git repo. - -- There is no default repository. A ``download_url`` and ``checksum`` may be - provided in `qualifiers` or as separate attributes outside of a ``purl`` for - proper identification and location. -- When possible another or a new purl ``type`` should be used instead of using - the ``generic`` type and eventually contributed back to this specification. -- as for other ``type``, the ``name`` component is mandatory. In the worst case - it can be a file or directory name. -- Examples (truncated for brevity):: - - pkg:generic/openssl@1.1.10g - pkg:generic/openssl@1.1.10g?download_url=https://openssl.org/source/openssl-1.1.0g.tar.gz&checksum=sha256:de4d501267da - pkg:generic/bitwarderl?vcs_url=git%2Bhttps://git.fsfe.org/dxtr/bitwarderl%40cc55108da32 - -github ------- -``github`` for GitHub-based packages: - -- The default repository is ``https://github.com``. -- The ``namespace`` is the user or organization. It is not case sensitive and - must be lowercased. -- The ``name`` is the repository name. It is not case sensitive and must be - lowercased. -- The ``version`` is a commit or tag. -- Examples:: - - pkg:github/package-url/purl-spec@244fd47e07d1004 - pkg:github/package-url/purl-spec@244fd47e07d1004#everybody/loves/dogs - -golang ------- -``golang`` for Go packages: - -- There is no default package repository: this is implied in the namespace - using the ``go get`` command conventions. -- The ``namespace`` and `name` must be lowercased. -- The ``subpath`` is used to point to a subpath inside a package. -- The ``version`` is often empty when a commit is not specified and should be - the commit in most cases when available. -- Examples:: - - pkg:golang/github.com/gorilla/context@234fd47e07d1004f0aed9c - pkg:golang/google.golang.org/genproto#googleapis/api/annotations - pkg:golang/github.com/gorilla/context@234fd47e07d1004f0aed9c#api - -hackage -------- -``hackage`` for Haskell packages: - -- The default repository is `https://hackage.haskell.org`. -- The `version` is package version. -- The `name` is case sensitive and use kebab-case. -- Examples:: - - pkg:hackage/a50@0.5 - pkg:hackage/AC-HalfInteger@1.2.1 - pkg:hackage/3d-graphics-examples@0.0.0.2 - -hex ---- -``hex`` for Hex packages: - -- The default repository is ``https://repo.hex.pm``. -- The ``namespace`` is optional; it may be used to specify the organization for - private packages on hex.pm. It is not case sensitive and must be lowercased. -- The ``name`` is not case sensitive and must be lowercased. -- Examples:: - - pkg:hex/jason@1.1.2 - pkg:hex/acme/foo@2.3. - pkg:hex/phoenix_html@2.13.3#priv/static/phoenix_html.js - pkg:hex/bar@1.2.3?repository_url=https://myrepo.example.com - - -huggingface ------- -``huggingface`` for Hugging Face ML models - -- The default repository is ``https://huggingface.co``. -- The ``namespace`` is the model repository username or organization, if present. It is case sensitive. -- The ``name`` is the model repository name. It is case sensitive. -- The ``version`` is the model revision Git commit hash. It is case insensitive and must be lowercased in the package URL. -- Examples:: - - pkg:huggingface/distilbert-base-uncased@043235d6088ecd3dd5fb5ca3592b6913fd516027 - pkg:huggingface/microsoft/deberta-v3-base@559062ad13d311b87b2c455e67dcd5f1c8f65111?repository_url=https://hub-ci.huggingface.co - - -luarocks --------- -``luarocks`` for Lua packages installed with LuaRocks: - -- ``namespace``: The user manifest under which the package is registered. - If not given, the root manifest is assumed. - It is case insensitive, but lowercase is encouraged since namespaces - are normalized to ASCII lowercase. -- ``name``: The LuaRocks package name. - It is case insensitive, but lowercase is encouraged since package names - are normalized to ASCII lowercase. -- ``version``: The full LuaRocks package version, including module version - and rockspec revision. - It is case sensitive, and lowercase must be used to avoid - compatibility issues with older LuaRocks versions. - The full version number is required to uniquely identify a version. -- Qualifier ``repository_url``: The LuaRocks rocks server to be used; - useful in case a private server is used (optional). - If omitted, ``https://luarocks.org`` as default server is assumed. - -Examples:: - - pkg:luarocks/luasocket@3.1.0-1 - pkg:luarocks/hisham/luafilesystem@1.8.0-1 - pkg:luarocks/username/packagename@0.1.0-1?repository_url=https://example.com/private_rocks_server/ - -maven ------ -``maven`` for Maven JARs and related artifacts: - -- The default ``repository_url`` is ``https://repo.maven.apache.org/maven2``. -- The group id is the ``namespace`` and the artifact id is the ``name``. -- Known qualifiers keys are: ``classifier`` and ``type`` as defined in the - POM documentation. Note that Maven uses a concept / coordinate called packaging - which does not map directly 1:1 to a file extension. In this use case, we need - to construct a link to one of many possible artifacts. Maven itself uses type - in a dependency declaration when needed to disambiguate between them. -- Examples:: - - pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1 - pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?type=pom - pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?classifier=sources - pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?type=zip&classifier=dist - pkg:maven/net.sf.jacob-projec/jacob@1.14.3?classifier=x86&type=dll - pkg:maven/net.sf.jacob-projec/jacob@1.14.3?classifier=x64&type=dll - pkg:maven/groovy/groovy@1.0?repository_url=https://maven.google.com - -mlflow ------- -``mlflow`` for MLflow ML models (Azure ML, Databricks, etc.) - -- The repository is the MLflow tracking URI. There is no default. Examples: - - - Azure ML: ``https://.api.azureml.ms/mlflow/v1.0/subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/`` - - Azure Databricks: ``https://adb-..azuredatabricks.net/api/2.0/mlflow`` - - AWS Databricks: ``https://dbc--.cloud.databricks.com/api/2.0/mlflow`` - - GCP Databricks: ``https://..gcp.databricks.com/api/2.0/mlflow`` - -- The ``namespace`` is empty. -- The ``name`` is the model name. Case sensitivity depends on the server implementation: - - - Azure ML: it is case sensitive and must be kept as-is in the package URL. - - Databricks: it is case insensitive and must be lowercased in the package URL. - -- The ``version`` is the model version. -- Known qualifiers keys are: ``model_uuid`` and ``run_id`` as defined in the MLflow documentation. -- Examples:: - - pkg:mlflow/creditfraud@3?repository_url=https://westus2.api.azureml.ms/mlflow/v1.0/subscriptions/a50f2011-fab8-4164-af23-c62881ef8c95/resourceGroups/TestResourceGroup/providers/Microsoft.MachineLearningServices/workspaces/TestWorkspace - pkg:mlflow/trafficsigns@10?model_uuid=36233173b22f4c89b451f1228d700d49&run_id=410a3121-2709-4f88-98dd-dba0ef056b0a&repository_url=https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow - -npm ---- -``npm`` for Node NPM packages: - -- The default repository is ``https://registry.npmjs.org``. -- The ``namespace`` is used for the scope of a scoped NPM package. -- Per the package.json specification, new package "must not have uppercase letters in - the name", therefore they must be lowercased. -- Examples:: - - pkg:npm/foobar@12.3.1 - pkg:npm/%40angular/animation@12.3.1 - pkg:npm/mypackage@12.4.5?vcs_url=git://host.com/path/to/repo.git%404345abcd34343 - -nuget ------ -``nuget`` for NuGet .NET packages: - -- The default repository is ``https://www.nuget.org``. -- There is no ``namespace`` per se even if the common convention is to use - dot-separated package names where the first segment is ``namespace``-like. -- Examples:: - - pkg:nuget/EnterpriseLibrary.Common@6.0.1304 - -oci ------------- -``oci`` for all artifacts stored in registries that conform to the -`OCI Distribution Specification `_, -including container images built by Docker and others: - -- There is no canonical package repository for OCI artifacts. Therefore - ``oci`` purls must be registry agnostic by default. To specify the repository, - provide a ``repository_url`` value. -- OCI purls do not contain a ``namespace``, although, ``repository_url`` may - contain a namespace as part of the physical location of the package. -- The ``name`` is not case sensitive and must be lowercased. The name is the - last fragment of the repository name. For example if the repository - name is ``library/debian`` then the ``name`` is ``debian``. -- The ``version`` is the ``sha256:hex_encoded_lowercase_digest`` of the - artifact and is used to uniquely identify the artifact. -- Optional qualifiers may include: - - - ``arch``: key for a package architecture, when relevant. - - ``repository_url``: A repository URL where the artifact may be found, but not - intended as the only location. This value is encouraged to identify a - location the content may be fetched. - - ``tag``: artifact tag that may have been associated with the digest at the time. -- Examples:: - - pkg:oci/debian@sha256%3A244fd47e07d10?repository_url=docker.io/library/debian&arch=amd64&tag=latest - pkg:oci/debian@sha256%3A244fd47e07d10?repository_url=ghcr.io/debian&tag=bullseye - pkg:oci/static@sha256%3A244fd47e07d10?repository_url=gcr.io/distroless/static&tag=latest - pkg:oci/hello-wasm@sha256%3A244fd47e07d10?tag=v1 - -pub ----- -``pub`` for Dart and Flutter packages: - -- The default repository is ``https://pub.dartlang.org``. -- Pub normalizes all package names to be lowercase and using underscores. The only allowed characters are `[a-z0-9_]`. -- More information on pub naming and versioning is available in the [pubspec documentation](https://dart.dev/tools/pub/pubspec) -- Examples:: - - pkg:pub/characters@1.2.0 - pkg:pub/flutter@0.0.0 +Instead, all PURL type definitions are now maintained in a simple JSON document with +automatically generated documentation. -pypi ----- -``pypi`` for Python packages: -- The default repository is ``https://pypi.org``. (Previously ``https://pypi.python.org``.) -- PyPI treats ``-`` and ``_`` as the same character and is not case sensitive. - Therefore a PyPI package ``name`` must be lowercased and underscore ``_`` - replaced with a dash ``-``. -- The ``file_name`` qualifier selects a particular distribution file - (case-sensitive). For naming convention, see the Python Packaging User Guide on - `source distributions `_, - `binary distributions `_, - and `platform compatibility tags `_. -- Examples:: +Where to find PURL Type information +-------------------------------------- - pkg:pypi/django@1.11.1 - pkg:pypi/django@1.11.1?file_name=Django-1.11.1.tar.gz - pkg:pypi/django@1.11.1?file_name=Django-1.11.1-py2.py3-none-any.whl - pkg:pypi/django-allauth@12.23 +- In the JSON Index listing of all defined PURL types at: + `/purl-types-index.json `_ -qpkg ----- -``qpkg`` for QNX packages: +- In individual JSON files, one for each PURL type definition at: + `/types `_ -- There is no default package repository: this should be implied either from - the ``namespace`` or using a repository base URL as ``repository_url`` - qualifiers key. -- The ``namespace`` is the vendor of the package. It is not case sensitive and must be - lowercased. -- Examples:: +- As Markdown documentation, generated from for each PURL type JSON definition at: + `/types-doc `_ - pkg:qpkg/blackberry/com.qnx.sdp@7.0.0.SGA201702151847 - pkg:qpkg/blackberry/com.qnx.qnx710.foo.bar.qux@0.0.4.01449T202205040833L -rpm ---- -``rpm`` for RPMs: +How PURL Types are maintained +------------------------------ -- There is no default package repository: this should be implied either from - the ``distro`` qualifiers key or using a repository base URL as - ``repository_url`` qualifiers key. -- The ``namespace`` is the vendor such as Fedora or OpenSUSE. - It is not case sensitive and must be lowercased. -- The ``name`` is the RPM name and is case sensitive. -- The ``version`` is the combined version and release of an RPM. -- ``epoch`` (optional for RPMs) is a qualifier as it's not required for - unique identification, but when the epoch exists we strongly - encourage using it. -- ``arch`` is the qualifiers key for a package architecture. -- Examples:: +All PURL type definitions are maintained as JSON definition files and JSON test files in the PURL +specification repository. These JSON files serve as the source of truth and define the +structure of each PURL type, including: - pkg:rpm/fedora/curl@7.50.3-1.fc25?arch=i386&distro=fedora-25 - pkg:rpm/centerim@4.22.10-1.el6?arch=i686&epoch=1&distro=fedora-25 +- Namespace and name formatting rules +- Supported qualifiers +- Repository requirements +- Mapping of PURL concepts to the native ecosystem concepts -swid ------ -``swid`` for ISO-IEC 19770-2 Software Identification (SWID) tags: +On commit, a job automatically: -- There is no default package repository. -- The ``namespace`` is the optional name and regid of the entity with a role of softwareCreator. If specified, name is required and is the first segment in the namespace. If regid is known, it must be specified as the second segment in the namespace. A maximum of two segments are supported. -- The ``name`` is the name as defined in the SWID SoftwareIdentity element. -- The ``version`` is the version as defined in the SWID SoftwareIdentity element. -- The qualifier ``tag_id`` must not be empty and corresponds to the tagId as defined in the SWID SoftwareIdentity element. Per the SWID specification, GUIDs are recommended. If a GUID is used, it must be lowercase. If a GUID is not used, the tag_id qualifier is case aware but not case sensitive. -- The qualifier ``tag_version`` is an optional integer and corresponds to the tagVersion as defined in the SWID SoftwareIdentity element. If not specified, defaults to 0. -- The qualifier ``patch`` is optional and corresponds to the patch as defined in the SWID SoftwareIdentity element. If not specified, defaults to false. -- The qualifier ``tag_creator_name`` is optional. If the tag creator is different from the software creator, the tag_creator_name qualifier should be specified. -- The qualifier ``tag_creator_regid`` is optional. If the tag creator is different from the software creator, the tag_creator_regid qualifier should be specified. +- Checks that all JSON files are schema-valid +- Formats all the JSON files +- Generates the ``purl-types-index.json`` file containing a list of defined known PURL types +- Generates human-readable documentation for each type -Use of known qualifiers key/value pairs such as ``download_url`` can be used to specify where the package was retrieved from. -- Examples:: +How to Propose a New PURL Type +------------------------------ - pkg:swid/Acme/example.com/Enterprise+Server@1.0.0?tag_id=75b8c285-fa7b-485b-b199-4745e3004d0d - pkg:swid/Fedora@29?tag_id=org.fedoraproject.Fedora-29 - pkg:swid/Adobe+Systems+Incorporated/Adobe+InDesign@CC?tag_id=CreativeCloud-CS6-Win-GM-MUL +To propose a new PURL type, create an **issue** and a corresponding **pull request** to the +repository with: -swift ------ -``swift`` for Swift packages: + - a new JSON definition file under `types/`. + - a new JSON test file file under `tests/types/`. + + +Ensure that your proposal follows the **PURL Type Definition Schema** and includes all required +fields. For this see the README-dev.rst for details to run local checks. -- There is no default package repository: this should be implied from ``namespace``. -- The ``namespace`` is source host and user/organization and is required. -- The ``name`` is the repository name. -- The ``version`` is the package version and is required. -- Examples:: - pkg:swift/github.com/Alamofire/Alamofire@5.4.3 - pkg:swift/github.com/RxSwiftCommunity/RxFlow@2.12.4 -Other candidate types to define: +Other candidate types to define ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - ``android`` for Android apk packages: diff --git a/README-dev.rst b/README-dev.rst new file mode 100644 index 00000000..79f2ed16 --- /dev/null +++ b/README-dev.rst @@ -0,0 +1,33 @@ +Development setup and instructions +===================================== + +We use some code: + +- to validate the JSON schemas for correctness and format them, and +- to validate that the test suite data files are schema-valid. + +To setup an environment to contribute to the Package-URL spec and standard, follow these +instructions:: + +Setup +------- + +1. Ensure that you have a recent Python version 3 and Make installed. +2. Configure your environment:: + + make conf + +Usage +------- + +To validate that the schemas and data files are correct, run:: + + make check + + +To regenerate the Python utility model code from the JSON schemas, then regenerate the +PURL type documentation from the JSON PURL type definition files, run:: + + make generate + make docs + diff --git a/etc/scripts/.gitignore b/etc/scripts/.gitignore new file mode 100644 index 00000000..a348e504 --- /dev/null +++ b/etc/scripts/.gitignore @@ -0,0 +1 @@ +/__pycache__/ diff --git a/etc/scripts/format_json.py b/etc/scripts/format_json.py new file mode 100644 index 00000000..151b5774 --- /dev/null +++ b/etc/scripts/format_json.py @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: MIT +# Copyright (c) the purl authors +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Visit https://github.com/package-url/purl-spec and https://packageurl.org for support + +import json +from pathlib import Path + + +def format_json(path: Path): + """ + Format in place and recursively all the files with a .json extension at ``path``. + """ + for json_file in path.rglob("**/*.json"): + if not json_file.is_file(): + continue + try: + unformatted = json.loads(json_file.read_text()) + # note the trailing LF + formatted = json.dumps(unformatted, indent=2) + "\n" + json_file.write_text(formatted) + except Exception as e: + print(f"Failed to format JSON file: {json_file!r}: {e!r}") + + +if __name__ == "__main__": + import sys + + path = sys.argv[1] + format_json(Path(path)) diff --git a/etc/scripts/generate_index_and_docs.py b/etc/scripts/generate_index_and_docs.py new file mode 100644 index 00000000..f50df2e2 --- /dev/null +++ b/etc/scripts/generate_index_and_docs.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python + +import json +from pathlib import Path + +""" +Generate Markdown documents, one for each PURL type definition JSON document. +""" + + +def generate_purl_syntax(definition) -> str: + """ + Return a PURL syntax template generated dynamically from a definition object, using required, + optional, and prohibited component definitions. + """ + + namespace = definition.get("namespace_definition", {}).get("requirement", "optional") + if namespace in ["required", "optional"]: + namespace = "/" + else: + namespace = "" + + purl_syntax = f"pkg:{definition['type']}{namespace}/@?#" + + return purl_syntax + + +def get_yes_no(value): + """Return a human-readable yes/no from a boolean value""" + return "Yes" if value else "No" + + +def generate_documentation(definition) -> str: + """ + Return a documentation for a PURL type definition. + """ + lines = [] + lines.append("") + lines.append("") + + lines.append(f"# PURL Type Definition: {definition['type']}") + lines.append("") + lines.append(f"- **Type Name:** {definition['type_name']}") + lines.append(f"- **Description:** {definition['description']}") + lines.append(f"- **Schema ID:** `{definition['$id']}`") + lines.append("") + + # Generate PURL Syntax + purl_syntax = generate_purl_syntax(definition) + lines.append("## PURL Syntax") + lines.append("") + lines.append("The structure of a PURL for this package type is:") + lines.append("") + lines.append(f" {purl_syntax}") + lines.append("") + + # Repository comes 1st + lines.append("## Repository Information") + lines.append("") + repository = definition["repository"] + use_repository = repository["use_repository"] + lines.append(f"- **Use Repository:** {get_yes_no(use_repository)}") + if default_repository_url := repository.get("default_repository_url"): + lines.append(f"- **Default Repository URL:** {default_repository_url}") + if note := repository.get("note"): + lines.append(f"- **Note:** {note}") + lines.append("") + + # PURL Components (Each gets its own section) + for key in [ + "namespace_definition", + "name_definition", + "version_definition", + "subpath_definition", + ]: + component = definition.get(key) + if not component: + continue + + component_label = (" ".join(key.split("_"))).capitalize() + lines.append(f"## {component_label}") + lines.append("") + + if req := component.get("requirement"): + # only for namespace + lines.append(f"- **Requirement:** {req.capitalize()}") + + if permitted_characters := component.get("permitted_characters"): + lines.append(f"- **Permitted Characters:** `{permitted_characters}`") + + if case_sensitive := component.get("case_sensitive"): + lines.append(f"- **Case Sensitive:** {get_yes_no(case_sensitive)}") + + if normalization_rules := component.get("normalization_rules"): + lines.append(f"- **Normalization rules:**") + for rule in normalization_rules: + lines.append(f" - {rule}") + + if native_name := component.get("native_name"): + lines.append(f"- **Native Label:** {native_name}") + + if note := component.get("note"): + lines.append(f"- **Note:** `{note}`") + + lines.append("") + + if qualifiers := definition.get("qualifiers_definition"): + lines.append("## Qualifiers Definition") + lines.append("") + lines.append("| Key | Requirement | Native name | Default Value | Description |") + lines.append("|------|-------------|-------------|---------------|-------------|") + for qualifier in qualifiers: + key = qualifier["key"] + req = qualifier.get("requirement", "optional").capitalize() + native = qualifier.get("native_name", "") + default = qualifier.get("default_value", "") + description = qualifier.get("description", "") + lines.append(f"| {key} | {req} | {native} | {default} | {description} |") + lines.append("") + + lines.append("## Examples") + lines.append("") + for example in definition["examples"]: + lines.append(f"- `{example}`") + lines.append("") + + if reference_urls := definition.get("reference_urls"): + lines.append("## Reference URLs") + lines.append("") + for url in reference_urls: + lines.append(f"- `{url}`") + lines.append("") + + if note := definition.get("note"): + lines.append("## Note") + lines.append("") + lines.append(note) + lines.append("") + + return "\n".join(lines) + + +if __name__ == "__main__": + import sys + + if len(sys.argv) == 2: + selected_types = f"{sys.argv[1]}-definition.json" + else: + selected_types = "*-definition.json" + + types = [] + types_dir = Path("types") + + for filepath in types_dir.glob(selected_types): + data = json.loads(filepath.read_text()) + ptype = data["type"] + types.append(ptype) + md = generate_documentation(data) + mddoc = Path("types-doc") / f"{ptype}-definition.md" + mddoc.write_text(md, newline="\n") + print(f"PURL Type Documentation generated for {mddoc}") + + idxdoc = Path("purl-types-index.json") + idx = json.dumps(sorted(types), indent=2) + "\n" + idxdoc.write_text(idx, newline="\n") + print(f"PURL Types Index generated at {idxdoc}") diff --git a/etc/scripts/git-split-file.sh b/etc/scripts/git-split-file.sh new file mode 100755 index 00000000..630b0cf7 --- /dev/null +++ b/etc/scripts/git-split-file.sh @@ -0,0 +1,67 @@ +#!/bin/bash +# +# from https://gitlab.inria.fr/-/snippets/520 + +# Git: copy files keeping history +# +# Authored by David SHERMAN +# +# Make copies of a file while preserving git history, so that git blame can find the original commits. +# +# git blame heuristically walks the history to recover which commits were responsible for different +# parts of a file. Its heuristics usually work if you move a file, but doesn't if you copy it: the +# copy will appear to have been created ex nihilo by the commit. This script makes copies of a file +# using git mv but keeps the original, which is then moved back to its original name. By keeping +# this complete history, git blame is able to walk back to the original commits, in both the copies +# and the original. +# +# Note that this will add N+3 commits to the history, where N is the number of new copies. +# +# The use case is when you need to split a file into pieces: make a history-preserving copy of the +# original for each piece, then delete the extraneous parts in each copy. + + + +if [ ! \( -f "$1" -a $# -ge 2 -a -d $(dirname "$2") \) ]; then + cat 1>&2 <<-"EOF" + Usage: $0 ORIGINAL copy1 [... copyN] + + Copy ORIGINAL, preserving history for git blame + New history will have N+3 commits + EOF + exit 1 +fi + +ORIGINAL="$1"; shift +KEEP=$(mktemp ./"$1".XXXXXXXX) +MESSAGE="Copy $ORIGINAL to $@ keep history" +SPLIT="" + +# Remember current commit +ROOT=$(git rev-parse HEAD) + +# Create branch where $2 has $ORIGINAL's history +for f in "$@"; do + git reset --soft $ROOT + git checkout $ROOT "$ORIGINAL" + git mv -f "$ORIGINAL" "$f" + git commit --signoff -n -m "$MESSAGE: create $f" + SPLIT="$(git rev-parse HEAD) $SPLIT" +done + +# Go back to initial branch and move $ORIGINAL out of the way +git reset --hard HEAD^ +git mv "$ORIGINAL" -f "$KEEP" +git commit --signoff -n -m "* $MESSAGE: keep $ORIGINAL" + +# Merge $2's branch back into the original +git merge $SPLIT -m "* $MESSAGE: merge" +git commit --signoff -a -n -m "$MESSAGE: merge" + +# Move $ORIGINAL back where it was +git mv "$KEEP" "$ORIGINAL" +git commit --signoff -n -m "$MESSAGE" + +# Report +echo -e \\nNew history $(git rev-parse --short $ROOT)..$(git rev-parse --short HEAD) +exit 0 diff --git a/etc/scripts/purl_test.py b/etc/scripts/purl_test.py new file mode 100644 index 00000000..00e81107 --- /dev/null +++ b/etc/scripts/purl_test.py @@ -0,0 +1,96 @@ +# SPDX-License-Identifier: MIT +# Copyright (c) the purl authors +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Visit https://github.com/package-url/purl-spec and https://packageurl.org for support + + +from __future__ import annotations + +from typing import Any +from typing import Literal +from typing import Optional + +from pydantic import BaseModel +from pydantic import ConfigDict +from pydantic import Field + + +class PurlComponents(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + type: Optional[str] = Field(None, description="Package-URL type component.", title="PURL type") + namespace: Optional[str] = Field( + None, description="Package-URL namespace decoded component.", title="PURL namespace" + ) + name: Optional[str] = Field( + None, description="Package-URL name decoded component.", title="PURL name" + ) + version: Optional[str] = Field( + None, description="Package-URL version decoded component.", title="PURL version" + ) + qualifiers: Optional[dict[str, Any]] = Field( + None, + description="Package-URL qualifiers decoded component as an object.", + title="PURL qualifiers", + ) + subpath: Optional[str] = Field( + None, description="Package-URL subpath decoded component.", title="PURL subpath" + ) + + +class PurlTest(BaseModel): + description: str = Field( + ..., description="A description for this test.", title="Test description" + ) + test_group: Literal["base", "advanced"] = Field( + ..., description="The group of this test like 'base' or 'advanced'.", title="Test group" + ) + test_type: Literal["build", "parse", "roundtrip"] = Field( + ..., description="The type of this test like 'build' or 'parse'.", title="Test type" + ) + expected_failure: Optional[bool] = Field( + False, + description="true if this test input is expected to fail to be processed.", + title="Expected failure", + ) + expected_failure_reason: Optional[str] = Field( + None, + description="The reason why this test is is expected to fail if expected_failure is true.", + title="Expected failure reason", + ) + + +class PurlTestDefinition(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + field_schema: Optional[Any] = Field( + None, + alias="$schema", + description="Contains the URL of the JSON schema for Package-URL tests.", + title="JSON schema", + ) + tests: Optional[list[PurlTest]] = Field( + None, + description="A list of Package-URL build and parse tests.", + min_length=1, + title="Test suite", + ) diff --git a/etc/scripts/purl_type_definition.py b/etc/scripts/purl_type_definition.py new file mode 100644 index 00000000..ec560aa1 --- /dev/null +++ b/etc/scripts/purl_type_definition.py @@ -0,0 +1,199 @@ +# SPDX-License-Identifier: MIT +# Copyright (c) the purl authors +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Visit https://github.com/package-url/purl-spec and https://packageurl.org for support + + +from __future__ import annotations + +from typing import Any +from typing import Literal +from typing import Optional + +from pydantic import AnyUrl +from pydantic import BaseModel +from pydantic import ConfigDict +from pydantic import Field +from pydantic import RootModel + + +class Example(RootModel[str]): + root: str = Field(..., pattern="^pkg:[a-z][a-z0-9-\\.]+/.*$") + + +class PackageUrlTypeDefinition(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + field_schema: Optional[Any] = Field( + None, + alias="$schema", + description="Contains the URL of the JSON schema for Package-URL type definition.", + title="JSON schema", + ) + field_id: str = Field( + ..., + alias="$id", + description="The unique identifier URI for this PURL type definition.", + pattern="^https:\\/\\/packageurl\\.org/types/[a-z0-9-]+-definition\\.json$", + title="PURL type definition id", + ) + type: str = Field( + ..., + description="The type string for this Package-URL type.", + examples=["maven", "npm", "pypi"], + pattern="^[a-z][a-z0-9-\\.]+$", + title="PURL type", + ) + type_name: str = Field( + ..., + description="The name for this PURL type.", + examples=["Apache Maven", "Python Package"], + title="Type name", + ) + description: str = Field( + ..., description="The description of this PURL type.", title="Description" + ) + repository: Repository = Field( + ..., description="Package repository usage for this PURL type.", title="Repository" + ) + namespace_definition: NamespaceDefinition = Field( + ..., + description="Definition of the namespace component for this PURL type.", + title="Namespace definition", + ) + name_definition: PurlComponentDefinition = Field( + ..., + description="Definition of the name component for this PURL type.", + title="Name definition", + ) + version_definition: Optional[PurlComponentDefinition] = Field( + None, + description="Definition of the version component for this PURL type.", + title="Version definition", + ) + qualifiers_definition: Optional[list[QualifiersDefinitionItem]] = Field( + None, + description="Definition for the qualifiers specific to this PURL type.", + title="Qualifiers definition", + ) + subpath_definition: Optional[PurlComponentDefinition] = Field( + None, + description="Definition for the subpath for this PURL type.", + title="Subpath definition", + ) + examples: list[Example] = Field( + ..., + description="Example of valid, canonical PURLs for this package type.", + min_length=1, + title="PURL examples", + ) + note: Optional[str] = Field(None, description="Note about this PURL type.", title="Note") + reference_urls: Optional[list[AnyUrl]] = Field( + None, + description="Optional list of informational reference URLs about this PURL type.", + title="Reference URLs", + ) + + +class PurlComponentDefinition(BaseModel): + permitted_characters: Optional[str] = Field( + None, + description=( + "Regular expression (ECMA-262 dialect) defining the 'Permitted characters' for this" + " component of this Package-URL type. If provided, this must be a subset of the" + " 'Permitted characters' defined in the PURL specification." + ), + title="Permitted characters in this PURL component", + ) + case_sensitive: Optional[bool] = Field( + True, + description=( + "true if this PURL component is case sensitive. If false, the canonical form must be" + " lowercased." + ), + title="Case sensitive", + ) + normalization_rules: Optional[list[str]] = Field( + None, + description=( + "List of rules to normalize this component for this PURL type. These are plain text," + " unstructured rules as some require programming and cannot be enforced only with a" + " schema. Tools are expected to apply these rules programmatically." + ), + title="Normalization rules", + ) + native_name: Optional[str] = Field( + None, + description=( + "The native name of this PURL component in the package ecosystem. For instance, the" + " 'namespace' for the 'maven' type is 'groupId', and 'scope' for the 'npm' PURL type." + ), + title="Native name", + ) + note: Optional[str] = Field(None, description="Extra note text.", title="Note") + + +class QualifiersDefinitionItem(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + key: str = Field(..., description="The key for the qualifier.", title="Qualifier key") + requirement: Optional[Requirement] = None + description: str = Field( + ..., description="The description of this qualifier.", title="Description" + ) + default_value: Optional[str] = Field( + None, + description="The optional default value of this qualifier if not provided.", + title="Default value", + ) + native_name: Optional[str] = Field( + None, description="The equivalent native name for this qualifier key.", title="Native name" + ) + + +class Repository(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + use_repository: bool = Field( + ..., + description="true if this PURL type use a public package repository.", + title="Use repository", + ) + default_repository_url: Optional[AnyUrl] = Field( + None, + description="The default public repository URL for this PURL type", + title="Default repository URL", + ) + note: Optional[str] = Field(None, description="Extra note text.", title="Note") + + +class Requirement(RootModel[Literal["required", "optional", "prohibited"]]): + root: Literal["required", "optional", "prohibited"] = Field( + ..., + description="States if this PURL component is required, optional, or prohibited.", + title="Component requirement", + ) + + +class NamespaceDefinition(PurlComponentDefinition): + requirement: Requirement diff --git a/etc/scripts/purl_types_index.py b/etc/scripts/purl_types_index.py new file mode 100644 index 00000000..168f8052 --- /dev/null +++ b/etc/scripts/purl_types_index.py @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: MIT +# Copyright (c) the purl authors +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Visit https://github.com/package-url/purl-spec and https://packageurl.org for support + + +from __future__ import annotations + +from pydantic import Field +from pydantic import RootModel + + +class PackageUrlTypesList(RootModel[list[str]]): + root: list[str] = Field( + ..., + description="A list of the registered Package-URL types.", + title="Package-URL types list.", + ) diff --git a/etc/scripts/pyproject.toml b/etc/scripts/pyproject.toml new file mode 100644 index 00000000..963c64ab --- /dev/null +++ b/etc/scripts/pyproject.toml @@ -0,0 +1,45 @@ +[tool.ruff] +line-length = 100 +extend-exclude = [] +target-version = "py310" +include = [ + "pyproject.toml", + "etc/**/*.py", +] + + +[tool.ruff.lint] +# Rules: https://docs.astral.sh/ruff/rules/ +select = [ + "E", # pycodestyle + "W", # pycodestyle warnings + "D", # pydocstyle +# "F", # Pyflakes +# "UP", # pyupgrade +# "S", # flake8-bandit + "I", # isort +# "C9", # McCabe complexity +] +ignore = ["D1", "D200", "D202", "D203", "D205", "D212", "D400", "D415", "I001"] + + +[tool.ruff.format] +docstring-code-format = true + + +[tool.ruff.lint.isort] +force-single-line = true +lines-after-imports = 1 +default-section = "first-party" +known-first-party = ["etc/scripts/*.py"] + +section-order = [ + "future", + "standard-library", + "third-party", + "first-party", + "local-folder", +] + +[tool.ruff.lint.mccabe] +max-complexity = 10 diff --git a/etc/scripts/remove_duplicate_tests.py b/etc/scripts/remove_duplicate_tests.py new file mode 100644 index 00000000..d9f49e3b --- /dev/null +++ b/etc/scripts/remove_duplicate_tests.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) the purl authors +# SPDX-License-Identifier: MIT +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# Visit https://github.com/package-url/packageurl-python for support and +# download. + +import json +from pathlib import Path + + +def remove_duplicates(test_dir: Path): + """Remove duplicates""" + + for test_file in test_dir.glob("*.json"): + try: + test_data = json.loads(test_file.read_text()) + except Exception as e: + raise Exception(test_file) from e + + new_tests = [] + + for test in test_data["tests"]: + if test in new_tests: + continue + else: + new_tests.append(test) + + test_data["tests"] = new_tests + test_file.write_text(json.dumps(test_data, indent=2) + "\n") + + +if __name__ == "__main__": + import sys + + test_dir = sys.argv[1] + remove_duplicates(Path(test_dir)) diff --git a/etc/scripts/requirements.txt b/etc/scripts/requirements.txt new file mode 100644 index 00000000..c2b7ea93 --- /dev/null +++ b/etc/scripts/requirements.txt @@ -0,0 +1,8 @@ +datamodel-code-generator==0.31.2 +jsonschema[formats] +check-jsonschema +ruff +black +Jinja2 +pydantic +packageurl-python \ No newline at end of file diff --git a/mit.LICENSE b/mit.LICENSE index 0751c2ca..bb98b1f8 100644 --- a/mit.LICENSE +++ b/mit.LICENSE @@ -1,18 +1,21 @@ -Copyright (c) the purl authors - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file +# SPDX-License-Identifier: MIT +# Copyright (c) the purl authors +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Visit https://github.com/package-url/purl-spec and https://packageurl.org for support diff --git a/purl-types-index.json b/purl-types-index.json new file mode 100644 index 00000000..d7c170fa --- /dev/null +++ b/purl-types-index.json @@ -0,0 +1,34 @@ +[ + "alpm", + "apk", + "bitbucket", + "bitnami", + "cargo", + "cocoapods", + "composer", + "conan", + "conda", + "cpan", + "cran", + "deb", + "docker", + "gem", + "generic", + "github", + "golang", + "hackage", + "hex", + "huggingface", + "luarocks", + "maven", + "mlflow", + "npm", + "nuget", + "oci", + "pub", + "pypi", + "qpkg", + "rpm", + "swid", + "swift" +] diff --git a/schemas/purl-test.schema.json b/schemas/purl-test.schema.json new file mode 100644 index 00000000..dcc6ecfc --- /dev/null +++ b/schemas/purl-test.schema.json @@ -0,0 +1,310 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "title": "PURL test definition", + "description": "Schema for Package-URL building and parsing tests with input and expected output.", + "type": "object", + "additionalProperties": false, + "definitions": { + "purl_components": { + "title": "PURL decoded components", + "description": "Individual decoded PURL components to use as a test input or expected output.", + "type": "object", + "additionalProperties": false, + "properties": { + "type": { + "title": "PURL type", + "description": "Package-URL type component.", + "default": null, + "type": [ + "string", + "null" + ] + }, + "namespace": { + "title": "PURL namespace", + "description": "Package-URL namespace decoded component.", + "default": null, + "type": [ + "string", + "null" + ] + }, + "name": { + "title": "PURL name", + "description": "Package-URL name decoded component.", + "default": null, + "type": [ + "string", + "null" + ] + }, + "version": { + "title": "PURL version", + "description": "Package-URL version decoded component.", + "default": null, + "type": [ + "string", + "null" + ] + }, + "qualifiers": { + "title": "PURL qualifiers", + "description": "Package-URL qualifiers decoded component as an object.", + "default": null, + "type": [ + "object", + "null" + ] + }, + "subpath": { + "title": "PURL subpath", + "description": "Package-URL subpath decoded component.", + "default": null, + "type": [ + "string", + "null" + ] + } + } + }, + "purl_test": { + "title": "PURL test", + "description": "A PURL test with input and expected output.", + "type": "object", + "required": [ + "description", + "test_group", + "test_type", + "input" + ], + "properties": { + "description": { + "title": "Test description", + "description": "A description for this test.", + "type": "string" + }, + "test_group": { + "title": "Test group", + "description": "The group of this test like 'base' or 'advanced'.", + "type": "string", + "enum": [ + "base", + "advanced" + ], + "meta:enum": { + "base": "Test group for base conformance tests for PURL building and parsing.", + "advanced": "Test group for advanced tests to support flexible PURL building and parsing." + } + }, + "test_type": { + "title": "Test type", + "description": "The type of this test like 'build' or 'parse'.", + "type": "string", + "enum": [ + "build", + "parse", + "roundtrip" + ], + "meta:enum": { + "build": "A PURL building test from decoded components to a canonical PURL string.", + "parse": "A PURL building test from decoded components to a canonical PURL string.", + "roundtrip": "A PURL routrip test, parsing then building back a PURL from a canonical string input." + } + }, + "expected_failure": { + "title": "Expected failure", + "description": "true if this test input is expected to fail to be processed.", + "type": "boolean", + "default": false + }, + "expected_failure_reason": { + "title": "Expected failure reason", + "description": "The reason why this test is is expected to fail if expected_failure is true.", + "default": null, + "type": [ + "string", + "null" + ] + } + }, + "allOf": [ + { + "if": { + "properties": { + "test_type": { + "const": "parse" + }, + "expected_failure": { + "const": false + } + }, + "required": [ + "test_type", + "expected_failure" + ] + }, + "then": { + "properties": { + "input": { + "title": "Input test PURL", + "description": "A PURL string to use as a test input (canonical or not).", + "type": "string" + }, + "expected_output": { + "title": "Expected output decoded PURL components", + "description": "Test output as an object decoded PURL components, unless expected_failure.", + "$ref": "#/definitions/purl_components" + } + }, + "required": [ + "input", + "expected_output" + ] + } + }, + { + "if": { + "properties": { + "test_type": { + "const": "build" + }, + "expected_failure": { + "const": false + } + }, + "required": [ + "test_type", + "expected_failure" + ] + }, + "then": { + "properties": { + "input": { + "title": "Expected output decoded PURL components", + "description": "Test output as an object decoded PURL components, unless expected_failure.", + "$ref": "#/definitions/purl_components" + }, + "expected_output": { + "title": "Expected canonical PURL", + "description": "A canonical PURL string to use as a test ouput.", + "type": "string" + } + }, + "required": [ + "input", + "expected_output" + ] + } + }, + { + "if": { + "properties": { + "test_type": { + "const": "roundtrip" + } + }, + "required": [ + "test_type" + ] + }, + "then": { + "properties": { + "input": { + "title": "Input test PURL", + "description": "A PURL string to use as a test input (canonical or not).", + "type": "string" + }, + "expected_output": { + "title": "Expected canonical PURL", + "description": "A canonical PURL string to use as a test ouput.", + "type": "string" + } + }, + "required": [ + "input", + "expected_output" + ] + } + }, + { + "if": { + "properties": { + "test_type": { + "const": "parse" + }, + "expected_failure": { + "const": true + } + }, + "required": [ + "test_type", + "expected_failure" + ] + }, + "then": { + "properties": { + "input": { + "title": "Input test PURL", + "description": "A PURL string to use as a test input (canonical or not).", + "type": "string" + } + }, + "required": [ + "input", + "expected_failure_reason" + ] + } + }, + { + "if": { + "properties": { + "test_type": { + "const": "build" + }, + "expected_failure": { + "const": true + } + }, + "required": [ + "test_type", + "expected_failure" + ] + }, + "then": { + "properties": { + "input": { + "title": "Expected output decoded PURL components", + "description": "Test output as an object decoded PURL components, unless expected_failure.", + "$ref": "#/definitions/purl_components" + } + }, + "required": [ + "input", + "expected_failure_reason" + ] + } + } + ] + } + }, + "properties": { + "$schema": { + "title": "JSON schema", + "description": "Contains the URL of the JSON schema for Package-URL tests.", + "constant": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "format": "uri" + }, + "tests": { + "title": "Test suite", + "description": "A list of Package-URL build and parse tests.", + "additionalItems": false, + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { + "$ref": "#/definitions/purl_test" + } + } + } +} diff --git a/schemas/purl-type-definition.schema.json b/schemas/purl-type-definition.schema.json new file mode 100644 index 00000000..06b55359 --- /dev/null +++ b/schemas/purl-type-definition.schema.json @@ -0,0 +1,256 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "title": "Package-URL Type Definition", + "description": "Schema to specify a Package-URL (PURL) type as a structured definition.", + "type": "object", + "additionalProperties": false, + "definitions": { + "requirement": { + "title": "Component requirement", + "description": "States if this PURL component is required, optional, or prohibited.", + "type": "string", + "enum": [ + "required", + "optional", + "prohibited" + ], + "meta:enum": { + "required": "This PURL component is required for this PURL type.", + "optional": "This PURL component is optional for this PURL type.", + "prohibited": "This PURL component is prohibited: it must not be present for this PURL type." + } + }, + "purl_component_definition": { + "title": "PURL component definition", + "description": "PURL component definition properties that apply to most PURL components", + "type": "object", + "properties": { + "permitted_characters": { + "title": "Permitted characters in this PURL component", + "description": "Regular expression (ECMA-262 dialect) defining the 'Permitted characters' for this component of this Package-URL type. If provided, this must be a subset of the 'Permitted characters' defined in the PURL specification.", + "type": "string", + "format": "regex" + }, + "case_sensitive": { + "title": "Case sensitive", + "description": "true if this PURL component is case sensitive. If false, the canonical form must be lowercased.", + "type": "boolean", + "default": true + }, + "normalization_rules": { + "title": "Normalization rules", + "description": "List of rules to normalize this component for this PURL type. These are plain text, unstructured rules as some require programming and cannot be enforced only with a schema. Tools are expected to apply these rules programmatically.", + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + } + }, + "native_name": { + "title": "Native name", + "description": "The native name of this PURL component in the package ecosystem. For instance, the 'namespace' for the 'maven' type is 'groupId', and 'scope' for the 'npm' PURL type.", + "type": "string" + }, + "note": { + "title": "Note", + "description": "Extra note text.", + "type": "string" + } + } + } + }, + "required": [ + "$id", + "type", + "type_name", + "description", + "repository", + "namespace_definition", + "name_definition", + "examples" + ], + "properties": { + "$schema": { + "title": "JSON schema", + "description": "Contains the URL of the JSON schema for Package-URL type definition.", + "constant": "https://packageurl.org/schemas/purl-type.schema-1.0.json", + "format": "uri" + }, + "$id": { + "title": "PURL type definition id", + "description": "The unique identifier URI for this PURL type definition.", + "type": "string", + "pattern": "^https:\\/\\/packageurl\\.org/types/[a-z0-9-]+-definition\\.json$" + }, + "type": { + "title": "PURL type", + "description": "The type string for this Package-URL type.", + "type": "string", + "pattern": "^[a-z][a-z0-9-\\.]+$", + "examples": [ + "maven", + "npm", + "pypi" + ] + }, + "type_name": { + "title": "Type name", + "description": "The name for this PURL type.", + "type": "string", + "examples": [ + "Apache Maven", + "Python Package" + ] + }, + "description": { + "title": "Description", + "description": "The description of this PURL type.", + "type": "string" + }, + "repository": { + "title": "Repository", + "description": "Package repository usage for this PURL type.", + "type": "object", + "additionalProperties": false, + "required": [ + "use_repository" + ], + "properties": { + "use_repository": { + "title": "Use repository", + "description": "true if this PURL type use a public package repository.", + "type": "boolean", + "default": false + }, + "default_repository_url": { + "title": "Default repository URL", + "description": "The default public repository URL for this PURL type", + "type": "string", + "format": "uri" + }, + "note": { + "title": "Note", + "description": "Extra note text.", + "type": "string" + } + } + }, + "namespace_definition": { + "title": "Namespace definition", + "description": "Definition of the namespace component for this PURL type.", + "type": "object", + "required": [ + "requirement" + ], + "properties": { + "requirement": { + "$ref": "#/definitions/requirement" + } + }, + "allOf": [ + { + "$ref": "#/definitions/purl_component_definition" + } + ] + }, + "name_definition": { + "title": "Name definition", + "description": "Definition of the name component for this PURL type.", + "type": "object", + "allOf": [ + { + "$ref": "#/definitions/purl_component_definition" + } + ] + }, + "version_definition": { + "title": "Version definition", + "description": "Definition of the version component for this PURL type.", + "type": "object", + "allOf": [ + { + "$ref": "#/definitions/purl_component_definition" + } + ] + }, + "qualifiers_definition": { + "title": "Qualifiers definition", + "description": "Definition for the qualifiers specific to this PURL type.", + "type": "array", + "additionalItems": false, + "uniqueItems": true, + "items": { + "title": "Qualifiers definition", + "description": "Definition of a qualifier specific to this PURL type.", + "type": "object", + "additionalProperties": false, + "required": [ + "key", + "description" + ], + "properties": { + "key": { + "title": "Qualifier key", + "description": "The key for the qualifier.", + "type": "string" + }, + "requirement": { + "$ref": "#/definitions/requirement" + }, + "description": { + "title": "Description", + "description": "The description of this qualifier.", + "type": "string" + }, + "default_value": { + "title": "Default value", + "description": "The optional default value of this qualifier if not provided.", + "type": "string" + }, + "native_name": { + "title": "Native name", + "description": "The equivalent native name for this qualifier key.", + "type": "string" + } + } + } + }, + "subpath_definition": { + "title": "Subpath definition", + "description": "Definition for the subpath for this PURL type.", + "type": "object", + "allOf": [ + { + "$ref": "#/definitions/purl_component_definition" + } + ] + }, + "examples": { + "title": "PURL examples", + "description": "Example of valid, canonical PURLs for this package type.", + "type": "array", + "uniqueItems": true, + "minItems": 1, + "items": { + "type": "string", + "pattern": "^pkg:[a-z][a-z0-9-\\.]+/.*$" + } + }, + "note": { + "title": "Note", + "description": "Note about this PURL type.", + "type": "string" + }, + "reference_urls": { + "title": "Reference URLs", + "description": "Optional list of informational reference URLs about this PURL type.", + "type": "array", + "uniqueItems": true, + "items": { + "type": "string", + "format": "uri" + } + } + } +} diff --git a/schemas/purl-types-index.schema.json b/schemas/purl-types-index.schema.json new file mode 100644 index 00000000..4ea932c1 --- /dev/null +++ b/schemas/purl-types-index.schema.json @@ -0,0 +1,11 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://purl-spec.org/schemas/purl-type-index.schema-1.0.json", + "title": "Package-URL types list.", + "description": "A list of the registered Package-URL types.", + "type": "array", + "additionalItems": false, + "items": { + "type": "string" + } +} diff --git a/test-suite-data.json b/test-suite-data.json deleted file mode 100644 index ca500959..00000000 --- a/test-suite-data.json +++ /dev/null @@ -1,710 +0,0 @@ -[ - { - "description": "valid maven purl", - "purl": "pkg:maven/org.apache.commons/io@1.3.4", - "canonical_purl": "pkg:maven/org.apache.commons/io@1.3.4", - "type": "maven", - "namespace": "org.apache.commons", - "name": "io", - "version": "1.3.4", - "qualifiers": null, - "subpath": null, - "is_invalid": false - }, - { - "description": "basic valid maven purl without version", - "purl": "pkg:maven/org.apache.commons/io", - "canonical_purl": "pkg:maven/org.apache.commons/io", - "type": "maven", - "namespace": "org.apache.commons", - "name": "io", - "version": null, - "qualifiers": null, - "subpath": null, - "is_invalid": false - }, - { - "description": "valid go purl without version and with subpath", - "purl": "pkg:GOLANG/google.golang.org/genproto#/googleapis/api/annotations/", - "canonical_purl": "pkg:golang/google.golang.org/genproto#googleapis/api/annotations", - "type": "golang", - "namespace": "google.golang.org", - "name": "genproto", - "version": null, - "qualifiers": null, - "subpath": "googleapis/api/annotations", - "is_invalid": false - }, - { - "description": "valid go purl with version and subpath", - "purl": "pkg:GOLANG/google.golang.org/genproto@abcdedf#/googleapis/api/annotations/", - "canonical_purl": "pkg:golang/google.golang.org/genproto@abcdedf#googleapis/api/annotations", - "type": "golang", - "namespace": "google.golang.org", - "name": "genproto", - "version": "abcdedf", - "qualifiers": null, - "subpath": "googleapis/api/annotations", - "is_invalid": false - }, - { - "description": "invalid subpath - unencoded subpath cannot contain '..'", - "purl": "pkg:GOLANG/google.golang.org/genproto@abcdedf#/googleapis/%2E%2E/api/annotations/", - "canonical_purl": "pkg:golang/google.golang.org/genproto@abcdedf#googleapis/api/annotations", - "type": "golang", - "namespace": "google.golang.org", - "name": "genproto", - "version": "abcdedf", - "qualifiers": null, - "subpath": "googleapis/../api/annotations", - "is_invalid": false - }, - { - "description": "invalid subpath - unencoded subpath cannot contain '.'", - "purl": "pkg:GOLANG/google.golang.org/genproto@abcdedf#/googleapis/%2E/api/annotations/", - "canonical_purl": "pkg:golang/google.golang.org/genproto@abcdedf#googleapis/api/annotations", - "type": "golang", - "namespace": "google.golang.org", - "name": "genproto", - "version": "abcdedf", - "qualifiers": null, - "subpath": "googleapis/./api/annotations", - "is_invalid": false - }, - { - "description": "bitbucket namespace and name should be lowercased", - "purl": "pkg:bitbucket/birKenfeld/pyGments-main@244fd47e07d1014f0aed9c", - "canonical_purl": "pkg:bitbucket/birkenfeld/pygments-main@244fd47e07d1014f0aed9c", - "type": "bitbucket", - "namespace": "birkenfeld", - "name": "pygments-main", - "version": "244fd47e07d1014f0aed9c", - "qualifiers": null, - "subpath": null, - "is_invalid": false - }, - { - "description": "github namespace and name should be lowercased", - "purl": "pkg:github/Package-url/purl-Spec@244fd47e07d1004f0aed9c", - "canonical_purl": "pkg:github/package-url/purl-spec@244fd47e07d1004f0aed9c", - "type": "github", - "namespace": "package-url", - "name": "purl-spec", - "version": "244fd47e07d1004f0aed9c", - "qualifiers": null, - "subpath": null, - "is_invalid": false - }, - { - "description": "debian can use qualifiers", - "purl": "pkg:deb/debian/curl@7.50.3-1?arch=i386&distro=jessie", - "canonical_purl": "pkg:deb/debian/curl@7.50.3-1?arch=i386&distro=jessie", - "type": "deb", - "namespace": "debian", - "name": "curl", - "version": "7.50.3-1", - "qualifiers": {"arch": "i386", "distro": "jessie"}, - "subpath": null, - "is_invalid": false - }, - { - "description": "docker uses qualifiers and hash image id as versions", - "purl": "pkg:docker/customer/dockerimage@sha256:244fd47e07d1004f0aed9c?repository_url=gcr.io", - "canonical_purl": "pkg:docker/customer/dockerimage@sha256:244fd47e07d1004f0aed9c?repository_url=gcr.io", - "type": "docker", - "namespace": "customer", - "name": "dockerimage", - "version": "sha256:244fd47e07d1004f0aed9c", - "qualifiers": {"repository_url": "gcr.io"}, - "subpath": null, - "is_invalid": false - }, - { - "description": "Java gem can use a qualifier", - "purl": "pkg:gem/jruby-launcher@1.1.2?Platform=java", - "canonical_purl": "pkg:gem/jruby-launcher@1.1.2?platform=java", - "type": "gem", - "namespace": null, - "name": "jruby-launcher", - "version": "1.1.2", - "qualifiers": {"platform": "java"}, - "subpath": null, - "is_invalid": false - }, - { - "description": "maven often uses qualifiers", - "purl": "pkg:Maven/org.apache.xmlgraphics/batik-anim@1.9.1?classifier=sources&repositorY_url=repo.spring.io/release", - "canonical_purl": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?classifier=sources&repository_url=repo.spring.io/release", - "type": "maven", - "namespace": "org.apache.xmlgraphics", - "name": "batik-anim", - "version": "1.9.1", - "qualifiers": {"classifier": "sources", "repository_url": "repo.spring.io/release"}, - "subpath": null, - "is_invalid": false - }, - { - "description": "maven pom reference", - "purl": "pkg:Maven/org.apache.xmlgraphics/batik-anim@1.9.1?extension=pom&repositorY_url=repo.spring.io/release", - "canonical_purl": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?extension=pom&repository_url=repo.spring.io/release", - "type": "maven", - "namespace": "org.apache.xmlgraphics", - "name": "batik-anim", - "version": "1.9.1", - "qualifiers": {"extension": "pom", "repository_url": "repo.spring.io/release"}, - "subpath": null, - "is_invalid": false - }, - { - "description": "maven can come with a type qualifier", - "purl": "pkg:Maven/net.sf.jacob-project/jacob@1.14.3?classifier=x86&type=dll", - "canonical_purl": "pkg:maven/net.sf.jacob-project/jacob@1.14.3?classifier=x86&type=dll", - "type": "maven", - "namespace": "net.sf.jacob-project", - "name": "jacob", - "version": "1.14.3", - "qualifiers": {"classifier": "x86", "type": "dll"}, - "subpath": null, - "is_invalid": false - }, - { - "description": "npm can be scoped", - "purl": "pkg:npm/%40angular/animation@12.3.1", - "canonical_purl": "pkg:npm/%40angular/animation@12.3.1", - "type": "npm", - "namespace": "@angular", - "name": "animation", - "version": "12.3.1", - "qualifiers": null, - "subpath": null, - "is_invalid": false - }, - { - "description": "nuget names are case sensitive", - "purl": "pkg:Nuget/EnterpriseLibrary.Common@6.0.1304", - "canonical_purl": "pkg:nuget/EnterpriseLibrary.Common@6.0.1304", - "type": "nuget", - "namespace": null, - "name": "EnterpriseLibrary.Common", - "version": "6.0.1304", - "qualifiers": null, - "subpath": null, - "is_invalid": false - }, - { - "description": "pypi names have special rules and not case sensitive", - "purl": "pkg:PYPI/Django_package@1.11.1.dev1", - "canonical_purl": "pkg:pypi/django-package@1.11.1.dev1", - "type": "pypi", - "namespace": null, - "name": "django-package", - "version": "1.11.1.dev1", - "qualifiers": null, - "subpath": null, - "is_invalid": false - }, - { - "description": "rpm often use qualifiers", - "purl": "pkg:Rpm/fedora/curl@7.50.3-1.fc25?Arch=i386&Distro=fedora-25", - "canonical_purl": "pkg:rpm/fedora/curl@7.50.3-1.fc25?arch=i386&distro=fedora-25", - "type": "rpm", - "namespace": "fedora", - "name": "curl", - "version": "7.50.3-1.fc25", - "qualifiers": {"arch": "i386", "distro": "fedora-25"}, - "subpath": null, - "is_invalid": false - }, - { - "description": "a scheme is always required", - "purl": "EnterpriseLibrary.Common@6.0.1304", - "canonical_purl": "EnterpriseLibrary.Common@6.0.1304", - "type": null, - "namespace": null, - "name": "EnterpriseLibrary.Common", - "version": null, - "qualifiers": null, - "subpath": null, - "is_invalid": true - }, - { - "description": "a type is always required", - "purl": "pkg:EnterpriseLibrary.Common@6.0.1304", - "canonical_purl": "pkg:EnterpriseLibrary.Common@6.0.1304", - "type": null, - "namespace": null, - "name": "EnterpriseLibrary.Common", - "version": "6.0.1304", - "qualifiers": null, - "subpath": null, - "is_invalid": true - }, - { - "description": "a name is required", - "purl": "pkg:maven/@1.3.4", - "canonical_purl": "pkg:maven/@1.3.4", - "type": "maven", - "namespace": null, - "name": null, - "version": null, - "qualifiers": null, - "subpath": null, - "is_invalid": true - }, - { - "description": "slash / after scheme is not significant", - "purl": "pkg:/maven/org.apache.commons/io", - "canonical_purl": "pkg:maven/org.apache.commons/io", - "type": "maven", - "namespace": "org.apache.commons", - "name": "io", - "version": null, - "qualifiers": null, - "subpath": null, - "is_invalid": false - }, - { - "description": "double slash // after scheme is not significant", - "purl": "pkg://maven/org.apache.commons/io", - "canonical_purl": "pkg:maven/org.apache.commons/io", - "type": "maven", - "namespace": "org.apache.commons", - "name": "io", - "version": null, - "qualifiers": null, - "subpath": null, - "is_invalid": false - }, - { - "description": "slash /// after scheme is not significant", - "purl": "pkg:///maven/org.apache.commons/io", - "canonical_purl": "pkg:maven/org.apache.commons/io", - "type": "maven", - "namespace": "org.apache.commons", - "name": "io", - "version": null, - "qualifiers": null, - "subpath": null, - "is_invalid": false - }, - { - "description": "valid maven purl with case sensitive namespace and name", - "purl": "pkg:maven/HTTPClient/HTTPClient@0.3-3", - "canonical_purl": "pkg:maven/HTTPClient/HTTPClient@0.3-3", - "type": "maven", - "namespace": "HTTPClient", - "name": "HTTPClient", - "version": "0.3-3", - "qualifiers": null, - "subpath": null, - "is_invalid": false - }, - { - "description": "valid maven purl containing a space in the version and qualifier", - "purl": "pkg:maven/mygroup/myartifact@1.0.0%20Final?mykey=my%20value", - "canonical_purl": "pkg:maven/mygroup/myartifact@1.0.0%20Final?mykey=my%20value", - "type": "maven", - "namespace": "mygroup", - "name": "myartifact", - "version": "1.0.0 Final", - "qualifiers": {"mykey": "my value"}, - "subpath": null, - "is_invalid": false - }, - { - "description": "checks for invalid qualifier keys", - "purl": "pkg:npm/myartifact@1.0.0?in%20production=true", - "canonical_purl": null, - "type": "npm", - "namespace": null, - "name": "myartifact", - "version": "1.0.0", - "qualifiers": {"in production": "true"}, - "subpath": null, - "is_invalid": true - }, - { - "description": "valid conan purl", - "purl": "pkg:conan/cctz@2.3", - "canonical_purl": "pkg:conan/cctz@2.3", - "type": "conan", - "namespace": null, - "name": "cctz", - "version": "2.3", - "qualifiers": null, - "subpath": null, - "is_invalid": false - }, - { - "description": "valid conan purl with namespace and qualifier channel", - "purl": "pkg:conan/bincrafters/cctz@2.3?channel=stable", - "canonical_purl": "pkg:conan/bincrafters/cctz@2.3?channel=stable", - "type": "conan", - "namespace": "bincrafters", - "name": "cctz", - "version": "2.3", - "qualifiers": {"channel": "stable"}, - "subpath": null, - "is_invalid": false - }, - { - "description": "invalid conan purl only namespace", - "purl": "pkg:conan/bincrafters/cctz@2.3", - "canonical_purl": "pkg:conan/bincrafters/cctz@2.3", - "type": "conan", - "namespace": "bincrafters", - "name": "cctz", - "version": "2.3", - "qualifiers": null, - "subpath": null, - "is_invalid": true - }, - { - "description": "invalid conan purl only channel qualifier", - "purl": "pkg:conan/cctz@2.3?channel=stable", - "canonical_purl": "pkg:conan/cctz@2.3?channel=stable", - "type": "conan", - "namespace": null, - "name": "cctz", - "version": "2.3", - "qualifiers": {"channel": "stable"}, - "subpath": null, - "is_invalid": true - }, - { - "description": "valid conda purl with qualifiers", - "purl": "pkg:conda/absl-py@0.4.1?build=py36h06a4308_0&channel=main&subdir=linux-64&type=tar.bz2", - "canonical_purl": "pkg:conda/absl-py@0.4.1?build=py36h06a4308_0&channel=main&subdir=linux-64&type=tar.bz2", - "type": "conda", - "namespace": null, - "name": "absl-py", - "version": "0.4.1", - "qualifiers": {"build": "py36h06a4308_0", "channel": "main", "subdir": "linux-64", "type": "tar.bz2"}, - "subpath": null, - "is_invalid": false - }, - { - "description": "valid cran purl", - "purl": "pkg:cran/A3@0.9.1", - "canonical_purl": "pkg:cran/A3@0.9.1", - "type": "cran", - "namespace": null, - "name": "A3", - "version": "0.9.1", - "qualifiers": null, - "subpath": null, - "is_invalid": false - }, - { - "description": "invalid cran purl without name", - "purl": "pkg:cran/@0.9.1", - "canonical_purl": "pkg:cran/@0.9.1", - "type": "cran", - "namespace": null, - "name": null, - "version": "0.9.1", - "qualifiers": null, - "subpath": null, - "is_invalid": true - }, - { - "description": "invalid cran purl without version", - "purl": "pkg:cran/A3", - "canonical_purl": "pkg:cran/A3", - "type": "cran", - "namespace": null, - "name": "A3", - "version": null, - "qualifiers": null, - "subpath": null, - "is_invalid": true - }, - { - "description": "valid swift purl", - "purl": "pkg:swift/github.com/Alamofire/Alamofire@5.4.3", - "canonical_purl": "pkg:swift/github.com/Alamofire/Alamofire@5.4.3", - "type": "swift", - "namespace": "github.com/Alamofire", - "name": "Alamofire", - "version": "5.4.3", - "qualifiers": null, - "subpath": null, - "is_invalid": false - }, - { - "description": "invalid swift purl without namespace", - "purl": "pkg:swift/Alamofire@5.4.3", - "canonical_purl": "pkg:swift/Alamofire@5.4.3", - "type": "swift", - "namespace": null, - "name": "Alamofire", - "version": "5.4.3", - "qualifiers": null, - "subpath": null, - "is_invalid": true - }, - { - "description": "invalid swift purl without name", - "purl": "pkg:swift/github.com/Alamofire/@5.4.3", - "canonical_purl": "pkg:swift/github.com/Alamofire/@5.4.3", - "type": "swift", - "namespace": "github.com/Alamofire", - "name": null, - "version": "5.4.3", - "qualifiers": null, - "subpath": null, - "is_invalid": true - }, - { - "description": "invalid swift purl without version", - "purl": "pkg:swift/github.com/Alamofire/Alamofire", - "canonical_purl": "pkg:swift/github.com/Alamofire/Alamofire", - "type": "swift", - "namespace": "github.com/Alamofire", - "name": "Alamofire", - "version": null, - "qualifiers": null, - "subpath": null, - "is_invalid": true - }, - { - "description": "valid hackage purl", - "purl": "pkg:hackage/AC-HalfInteger@1.2.1", - "canonical_purl": "pkg:hackage/AC-HalfInteger@1.2.1", - "type": "hackage", - "namespace": null, - "name": "AC-HalfInteger", - "version": "1.2.1", - "qualifiers": null, - "subpath": null, - "is_invalid": false - }, - { - "description": "name and version are always required", - "purl": "pkg:hackage", - "canonical_purl": "pkg:hackage", - "type": "hackage", - "namespace": null, - "name": null, - "version": null, - "qualifiers": null, - "subpath": null, - "is_invalid": true - }, - { - "description": "minimal Hugging Face model", - "purl": "pkg:huggingface/distilbert-base-uncased@043235d6088ecd3dd5fb5ca3592b6913fd516027", - "canonical_purl": "pkg:huggingface/distilbert-base-uncased@043235d6088ecd3dd5fb5ca3592b6913fd516027", - "type": "huggingface", - "namespace": null, - "name": "distilbert-base-uncased", - "version": "043235d6088ecd3dd5fb5ca3592b6913fd516027", - "qualifiers": null, - "subpath": null, - "is_invalid": false - }, - { - "description": "Hugging Face model with staging endpoint", - "purl": "pkg:huggingface/microsoft/deberta-v3-base@559062ad13d311b87b2c455e67dcd5f1c8f65111?repository_url=https://hub-ci.huggingface.co", - "canonical_purl": "pkg:huggingface/microsoft/deberta-v3-base@559062ad13d311b87b2c455e67dcd5f1c8f65111?repository_url=https://hub-ci.huggingface.co", - "type": "huggingface", - "namespace": "microsoft", - "name": "deberta-v3-base", - "version": "559062ad13d311b87b2c455e67dcd5f1c8f65111", - "qualifiers": {"repository_url": "https://hub-ci.huggingface.co"}, - "subpath": null, - "is_invalid": false - }, - { - "description": "Hugging Face model with various cases", - "purl": "pkg:huggingface/EleutherAI/gpt-neo-1.3B@797174552AE47F449AB70B684CABCB6603E5E85E", - "canonical_purl": "pkg:huggingface/EleutherAI/gpt-neo-1.3B@797174552ae47f449ab70b684cabcb6603e5e85e", - "type": "huggingface", - "namespace": "EleutherAI", - "name": "gpt-neo-1.3B", - "version": "797174552ae47f449ab70b684cabcb6603e5e85e", - "qualifiers": null, - "subpath": null, - "is_invalid": false - }, - { - "description": "MLflow model tracked in Azure Databricks (case insensitive)", - "purl": "pkg:mlflow/CreditFraud@3?repository_url=https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow", - "canonical_purl": "pkg:mlflow/creditfraud@3?repository_url=https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow", - "type": "mlflow", - "namespace": null, - "name": "creditfraud", - "version": "3", - "qualifiers": {"repository_url": "https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow"}, - "subpath": null, - "is_invalid": false - }, - { - "description": "MLflow model tracked in Azure ML (case sensitive)", - "purl": "pkg:mlflow/CreditFraud@3?repository_url=https://westus2.api.azureml.ms/mlflow/v1.0/subscriptions/a50f2011-fab8-4164-af23-c62881ef8c95/resourceGroups/TestResourceGroup/providers/Microsoft.MachineLearningServices/workspaces/TestWorkspace", - "canonical_purl": "pkg:mlflow/CreditFraud@3?repository_url=https://westus2.api.azureml.ms/mlflow/v1.0/subscriptions/a50f2011-fab8-4164-af23-c62881ef8c95/resourceGroups/TestResourceGroup/providers/Microsoft.MachineLearningServices/workspaces/TestWorkspace", - "type": "mlflow", - "namespace": null, - "name": "CreditFraud", - "version": "3", - "qualifiers": {"repository_url": "https://westus2.api.azureml.ms/mlflow/v1.0/subscriptions/a50f2011-fab8-4164-af23-c62881ef8c95/resourceGroups/TestResourceGroup/providers/Microsoft.MachineLearningServices/workspaces/TestWorkspace"}, - "subpath": null, - "is_invalid": false - }, - { - "description": "MLflow model with unique identifiers", - "purl": "pkg:mlflow/trafficsigns@10?model_uuid=36233173b22f4c89b451f1228d700d49&run_id=410a3121-2709-4f88-98dd-dba0ef056b0a&repository_url=https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow", - "canonical_purl": "pkg:mlflow/trafficsigns@10?model_uuid=36233173b22f4c89b451f1228d700d49&repository_url=https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow&run_id=410a3121-2709-4f88-98dd-dba0ef056b0a", - "type": "mlflow", - "namespace": null, - "name": "trafficsigns", - "version": "10", - "qualifiers": {"model_uuid": "36233173b22f4c89b451f1228d700d49", "run_id": "410a3121-2709-4f88-98dd-dba0ef056b0a", "repository_url": "https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow"}, - "subpath": null, - "is_invalid": false - }, - { - "description": "composer names are not case sensitive", - "purl": "pkg:composer/Laravel/Laravel@5.5.0", - "canonical_purl": "pkg:composer/laravel/laravel@5.5.0", - "type": "composer", - "namespace": "laravel", - "name": "laravel", - "version": "5.5.0", - "qualifiers": null, - "subpath": null, - "is_invalid": false - }, - { - "description": "cpan distribution name are case sensitive", - "purl": "pkg:cpan/DROLSKY/DateTime@1.55", - "canonical_purl": "pkg:cpan/DROLSKY/DateTime@1.55", - "type": "cpan", - "namespace": "DROLSKY", - "name": "DateTime", - "version": "1.55", - "qualifiers": null, - "subpath": null, - "is_invalid": false - }, - { - "description": "cpan module name are case sensitive", - "purl": "pkg:cpan/URI::PackageURL@2.11", - "canonical_purl": "pkg:cpan/URI::PackageURL@2.11", - "type": "cpan", - "namespace": null, - "name": "URI::PackageURL", - "version": "2.11", - "qualifiers": null, - "subpath": null, - "is_invalid": false - }, - { - "description": "cpan module name like distribution name", - "purl": "pkg:cpan/Perl-Version@1.013", - "canonical_purl": "pkg:cpan/Perl-Version@1.013", - "type": "cpan", - "namespace": null, - "name": "Perl-Version", - "version": "1.013", - "qualifiers": null, - "subpath": null, - "is_invalid": true - }, - { - "description": "cpan distribution name like module name", - "purl": "pkg:cpan/GDT/URI::PackageURL@2.11", - "canonical_purl": "pkg:cpan/GDT/URI::PackageURL", - "type": "cpan", - "namespace": "GDT", - "name": "URI::PackageURL", - "version": null, - "qualifiers": null, - "subpath": null, - "is_invalid": true - }, - { - "description": "cpan valid module name", - "purl": "pkg:cpan/DateTime@1.55", - "canonical_purl": "pkg:cpan/DateTime@1.55", - "type": "cpan", - "namespace": null, - "name": "DateTime", - "version": "1.55", - "qualifiers": null, - "subpath": null, - "is_invalid": false - }, - { - "description": "cpan valid module name without version", - "purl": "pkg:cpan/URI", - "canonical_purl": "pkg:cpan/URI", - "type": "cpan", - "namespace": null, - "name": "URI", - "version": null, - "qualifiers": null, - "subpath": null, - "is_invalid": false - }, - { - "description": "ensure namespace allows multiple segments", - "purl": "pkg:bintray/apache/couchdb/couchdb-mac@2.3.0", - "canonical_purl": "pkg:bintray/apache/couchdb/couchdb-mac@2.3.0", - "type": "bintray", - "namespace": "apache/couchdb", - "name": "couchdb-mac", - "version": "2.3.0", - "qualifiers": null, - "subpath": null, - "is_invalid": false - }, - { - "description": "invalid encoded colon : between scheme and type", - "purl": "pkg%3Amaven/org.apache.commons/io", - "canonical_purl": null, - "type": "maven", - "namespace": "org.apache.commons", - "name": "io", - "version": null, - "qualifiers": null, - "subpath": null, - "is_invalid": true - }, - { - "description": "check for invalid character in type", - "purl": "pkg:n&g?inx/nginx@0.8.9", - "canonical_purl": null, - "type": null, - "namespace": null, - "name": "nginx", - "version": "0.8.9", - "qualifiers": null, - "subpath": null, - "is_invalid": true - }, - { - "description": "check for type that starts with number", - "purl": "pkg:3nginx/nginx@0.8.9", - "canonical_purl": null, - "type": null, - "namespace": null, - "name": "nginx", - "version": "0.8.9", - "qualifiers": null, - "subpath": null, - "is_invalid": true - }, - { - "description": "check for colon in type", - "purl": "pkg:nginx:a/nginx@0.8.9", - "canonical_purl": null, - "type": null, - "namespace": null, - "name": "nginx", - "version": "0.8.9", - "qualifiers": null, - "subpath": null, - "is_invalid": true - } -] diff --git a/tests/spec/specification-test.json b/tests/spec/specification-test.json new file mode 100644 index 00000000..fcf0d87a --- /dev/null +++ b/tests/spec/specification-test.json @@ -0,0 +1,148 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "a scheme is always required", + "test_group": "base", + "test_type": "parse", + "input": "EnterpriseLibrary.Common@6.0.1304", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid purl input" + }, + { + "description": "a scheme is always required", + "test_group": "base", + "test_type": "parse", + "input": "EnterpriseLibrary.Common@6.0.1304", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid canonical purl input" + }, + { + "description": "a scheme is always required", + "test_group": "base", + "test_type": "build", + "input": { + "type": null, + "namespace": null, + "name": "EnterpriseLibrary.Common", + "version": null, + "qualifiers": null, + "subpath": null + }, + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to build a PURL from invalid input components" + }, + { + "description": "a type is always required", + "test_group": "base", + "test_type": "parse", + "input": "pkg:EnterpriseLibrary.Common@6.0.1304", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid purl input" + }, + { + "description": "a type is always required", + "test_group": "base", + "test_type": "parse", + "input": "pkg:EnterpriseLibrary.Common@6.0.1304", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid canonical purl input" + }, + { + "description": "a type is always required", + "test_group": "base", + "test_type": "build", + "input": { + "type": null, + "namespace": null, + "name": "EnterpriseLibrary.Common", + "version": "6.0.1304", + "qualifiers": null, + "subpath": null + }, + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to build a PURL from invalid input components" + }, + { + "description": "check for invalid character in type", + "test_group": "base", + "test_type": "parse", + "input": "pkg:n&g?inx/nginx@0.8.9", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid purl input" + }, + { + "description": "check for null type", + "test_group": "base", + "test_type": "build", + "input": { + "type": null, + "namespace": null, + "name": "nginx", + "version": "0.8.9", + "qualifiers": null, + "subpath": null + }, + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to build a PURL from null type" + }, + { + "description": "check for type that starts with number", + "test_group": "base", + "test_type": "parse", + "input": "pkg:3nginx/nginx@0.8.9", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid purl type (cannot start with number)" + }, + { + "description": "check for type that starts with number", + "test_group": "base", + "test_type": "build", + "input": { + "type": null, + "namespace": null, + "name": "nginx", + "version": "0.8.9", + "qualifiers": null, + "subpath": null + }, + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to build a PURL from invalid input components" + }, + { + "description": "check for colon in type", + "test_group": "base", + "test_type": "parse", + "input": "pkg:nginx:a/nginx@0.8.9", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid purl input" + }, + { + "description": "check for colon in type", + "test_group": "base", + "test_type": "build", + "input": { + "type": null, + "namespace": null, + "name": "nginx", + "version": "0.8.9", + "qualifiers": null, + "subpath": null + }, + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to build a PURL from invalid input components" + } + ] +} diff --git a/tests/types/alpm-test.json b/tests/types/alpm-test.json new file mode 100644 index 00000000..92d75e74 --- /dev/null +++ b/tests/types/alpm-test.json @@ -0,0 +1,140 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:alpm/arch/pacman@6.0.1-1?arch=x86_64", + "expected_output": { + "type": "alpm", + "namespace": "arch", + "name": "pacman", + "version": "6.0.1-1", + "qualifiers": { + "arch": "x86_64" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:alpm/arch/pacman@6.0.1-1?arch=x86_64", + "expected_output": "pkg:alpm/arch/pacman@6.0.1-1?arch=x86_64", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "alpm", + "namespace": "arch", + "name": "pacman", + "version": "6.0.1-1", + "qualifiers": { + "arch": "x86_64" + }, + "subpath": null + }, + "expected_output": "pkg:alpm/arch/pacman@6.0.1-1?arch=x86_64", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:alpm/arch/python-pip@21.0-1?arch=any", + "expected_output": { + "type": "alpm", + "namespace": "arch", + "name": "python-pip", + "version": "21.0-1", + "qualifiers": { + "arch": "any" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:alpm/arch/python-pip@21.0-1?arch=any", + "expected_output": "pkg:alpm/arch/python-pip@21.0-1?arch=any", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "alpm", + "namespace": "arch", + "name": "python-pip", + "version": "21.0-1", + "qualifiers": { + "arch": "any" + }, + "subpath": null + }, + "expected_output": "pkg:alpm/arch/python-pip@21.0-1?arch=any", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:alpm/arch/containers-common@1:0.47.4-4?arch=x86_64", + "expected_output": { + "type": "alpm", + "namespace": "arch", + "name": "containers-common", + "version": "1:0.47.4-4", + "qualifiers": { + "arch": "x86_64" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:alpm/arch/containers-common@1:0.47.4-4?arch=x86_64", + "expected_output": "pkg:alpm/arch/containers-common@1:0.47.4-4?arch=x86_64", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "alpm", + "namespace": "arch", + "name": "containers-common", + "version": "1:0.47.4-4", + "qualifiers": { + "arch": "x86_64" + }, + "subpath": null + }, + "expected_output": "pkg:alpm/arch/containers-common@1:0.47.4-4?arch=x86_64", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/apk-test.json b/tests/types/apk-test.json new file mode 100644 index 00000000..a2f4506e --- /dev/null +++ b/tests/types/apk-test.json @@ -0,0 +1,95 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:apk/alpine/curl@7.83.0-r0?arch=x86", + "expected_output": { + "type": "apk", + "namespace": "alpine", + "name": "curl", + "version": "7.83.0-r0", + "qualifiers": { + "arch": "x86" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:apk/alpine/curl@7.83.0-r0?arch=x86", + "expected_output": "pkg:apk/alpine/curl@7.83.0-r0?arch=x86", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "apk", + "namespace": "alpine", + "name": "curl", + "version": "7.83.0-r0", + "qualifiers": { + "arch": "x86" + }, + "subpath": null + }, + "expected_output": "pkg:apk/alpine/curl@7.83.0-r0?arch=x86", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:apk/alpine/apk@2.12.9-r3?arch=x86", + "expected_output": { + "type": "apk", + "namespace": "alpine", + "name": "apk", + "version": "2.12.9-r3", + "qualifiers": { + "arch": "x86" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:apk/alpine/apk@2.12.9-r3?arch=x86", + "expected_output": "pkg:apk/alpine/apk@2.12.9-r3?arch=x86", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "apk", + "namespace": "alpine", + "name": "apk", + "version": "2.12.9-r3", + "qualifiers": { + "arch": "x86" + }, + "subpath": null + }, + "expected_output": "pkg:apk/alpine/apk@2.12.9-r3?arch=x86", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/bintray-test.json b/tests/types/bintray-test.json new file mode 100644 index 00000000..d6a56c1f --- /dev/null +++ b/tests/types/bintray-test.json @@ -0,0 +1,55 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "ensure namespace allows multiple segments. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:bintray/apache/couchdb/couchdb-mac@2.3.0", + "expected_output": "pkg:bintray/apache/couchdb/couchdb-mac@2.3.0", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "ensure namespace allows multiple segments. Input is not a valida PURL", + "test_group": "advanced", + "test_type": "parse", + "input": "pkg:bintray/apache/couchdb/couchdb-mac@2.3.0", + "expected_output": { + "type": "bintray", + "namespace": "apache/couchdb", + "name": "couchdb-mac", + "version": "2.3.0", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "ensure namespace allows multiple segments. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:bintray/apache/couchdb/couchdb-mac@2.3.0", + "expected_output": "pkg:bintray/apache/couchdb/couchdb-mac@2.3.0", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "ensure namespace allows multiple segments", + "test_group": "base", + "test_type": "build", + "input": { + "type": "bintray", + "namespace": "apache/couchdb", + "name": "couchdb-mac", + "version": "2.3.0", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:bintray/apache/couchdb/couchdb-mac@2.3.0", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/bitbucket-test.json b/tests/types/bitbucket-test.json new file mode 100644 index 00000000..8bc5c017 --- /dev/null +++ b/tests/types/bitbucket-test.json @@ -0,0 +1,96 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "bitbucket namespace and name should be lowercased. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:bitbucket/birKenfeld/pyGments-main@244fd47e07d1014f0aed9c", + "expected_output": "pkg:bitbucket/birkenfeld/pygments-main@244fd47e07d1014f0aed9c", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "bitbucket namespace and name should be lowercased", + "test_group": "base", + "test_type": "parse", + "input": "pkg:bitbucket/birKenfeld/pyGments-main@244fd47e07d1014f0aed9c", + "expected_output": { + "type": "bitbucket", + "namespace": "birkenfeld", + "name": "pygments-main", + "version": "244fd47e07d1014f0aed9c", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "bitbucket namespace and name should be lowercased. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:bitbucket/birkenfeld/pygments-main@244fd47e07d1014f0aed9c", + "expected_output": "pkg:bitbucket/birkenfeld/pygments-main@244fd47e07d1014f0aed9c", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "bitbucket namespace and name should be lowercased", + "test_group": "base", + "test_type": "build", + "input": { + "type": "bitbucket", + "namespace": "birkenfeld", + "name": "pygments-main", + "version": "244fd47e07d1014f0aed9c", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:bitbucket/birkenfeld/pygments-main@244fd47e07d1014f0aed9c", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:bitbucket/birkenfeld/pygments-main@244fd47e07d1014f0aed9c", + "expected_output": { + "type": "bitbucket", + "namespace": "birkenfeld", + "name": "pygments-main", + "version": "244fd47e07d1014f0aed9c", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:bitbucket/birkenfeld/pygments-main@244fd47e07d1014f0aed9c", + "expected_output": "pkg:bitbucket/birkenfeld/pygments-main@244fd47e07d1014f0aed9c", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "bitbucket", + "namespace": "birkenfeld", + "name": "pygments-main", + "version": "244fd47e07d1014f0aed9c", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:bitbucket/birkenfeld/pygments-main@244fd47e07d1014f0aed9c", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/bitnami-test.json b/tests/types/bitnami-test.json new file mode 100644 index 00000000..497e7f1e --- /dev/null +++ b/tests/types/bitnami-test.json @@ -0,0 +1,189 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:bitnami/wordpress?distro=debian-12", + "expected_output": { + "type": "bitnami", + "namespace": null, + "name": "wordpress", + "version": null, + "qualifiers": { + "distro": "debian-12" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:bitnami/wordpress?distro=debian-12", + "expected_output": "pkg:bitnami/wordpress?distro=debian-12", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "bitnami", + "namespace": null, + "name": "wordpress", + "version": null, + "qualifiers": { + "distro": "debian-12" + }, + "subpath": null + }, + "expected_output": "pkg:bitnami/wordpress?distro=debian-12", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:bitnami/wordpress@6.2.0?distro=debian-12", + "expected_output": { + "type": "bitnami", + "namespace": null, + "name": "wordpress", + "version": "6.2.0", + "qualifiers": { + "distro": "debian-12" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:bitnami/wordpress@6.2.0?distro=debian-12", + "expected_output": "pkg:bitnami/wordpress@6.2.0?distro=debian-12", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "bitnami", + "namespace": null, + "name": "wordpress", + "version": "6.2.0", + "qualifiers": { + "distro": "debian-12" + }, + "subpath": null + }, + "expected_output": "pkg:bitnami/wordpress@6.2.0?distro=debian-12", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:bitnami/wordpress@6.2.0?arch=arm64&distro=debian-12", + "expected_output": { + "type": "bitnami", + "namespace": null, + "name": "wordpress", + "version": "6.2.0", + "qualifiers": { + "arch": "arm64", + "distro": "debian-12" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:bitnami/wordpress@6.2.0?arch=arm64&distro=debian-12", + "expected_output": "pkg:bitnami/wordpress@6.2.0?arch=arm64&distro=debian-12", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "bitnami", + "namespace": null, + "name": "wordpress", + "version": "6.2.0", + "qualifiers": { + "arch": "arm64", + "distro": "debian-12" + }, + "subpath": null + }, + "expected_output": "pkg:bitnami/wordpress@6.2.0?arch=arm64&distro=debian-12", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:bitnami/wordpress@6.2.0?arch=arm64&distro=photon-4", + "expected_output": { + "type": "bitnami", + "namespace": null, + "name": "wordpress", + "version": "6.2.0", + "qualifiers": { + "arch": "arm64", + "distro": "photon-4" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:bitnami/wordpress@6.2.0?arch=arm64&distro=photon-4", + "expected_output": "pkg:bitnami/wordpress@6.2.0?arch=arm64&distro=photon-4", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "bitnami", + "namespace": null, + "name": "wordpress", + "version": "6.2.0", + "qualifiers": { + "arch": "arm64", + "distro": "photon-4" + }, + "subpath": null + }, + "expected_output": "pkg:bitnami/wordpress@6.2.0?arch=arm64&distro=photon-4", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/cargo-test.json b/tests/types/cargo-test.json new file mode 100644 index 00000000..d29d89f8 --- /dev/null +++ b/tests/types/cargo-test.json @@ -0,0 +1,128 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cargo/rand@0.7.2", + "expected_output": { + "type": "cargo", + "namespace": null, + "name": "rand", + "version": "0.7.2", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:cargo/rand@0.7.2", + "expected_output": "pkg:cargo/rand@0.7.2", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "cargo", + "namespace": null, + "name": "rand", + "version": "0.7.2", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:cargo/rand@0.7.2", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cargo/clap@2.33.0", + "expected_output": { + "type": "cargo", + "namespace": null, + "name": "clap", + "version": "2.33.0", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:cargo/clap@2.33.0", + "expected_output": "pkg:cargo/clap@2.33.0", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "cargo", + "namespace": null, + "name": "clap", + "version": "2.33.0", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:cargo/clap@2.33.0", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cargo/structopt@0.3.11", + "expected_output": { + "type": "cargo", + "namespace": null, + "name": "structopt", + "version": "0.3.11", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:cargo/structopt@0.3.11", + "expected_output": "pkg:cargo/structopt@0.3.11", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "cargo", + "namespace": null, + "name": "structopt", + "version": "0.3.11", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:cargo/structopt@0.3.11", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/cocoapods-test.json b/tests/types/cocoapods-test.json new file mode 100644 index 00000000..3bbfa6db --- /dev/null +++ b/tests/types/cocoapods-test.json @@ -0,0 +1,169 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cocoapods/AFNetworking@4.0.1", + "expected_output": { + "type": "cocoapods", + "namespace": null, + "name": "AFNetworking", + "version": "4.0.1", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:cocoapods/AFNetworking@4.0.1", + "expected_output": "pkg:cocoapods/AFNetworking@4.0.1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "cocoapods", + "namespace": null, + "name": "AFNetworking", + "version": "4.0.1", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:cocoapods/AFNetworking@4.0.1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cocoapods/MapsIndoors@3.24.0", + "expected_output": { + "type": "cocoapods", + "namespace": null, + "name": "MapsIndoors", + "version": "3.24.0", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:cocoapods/MapsIndoors@3.24.0", + "expected_output": "pkg:cocoapods/MapsIndoors@3.24.0", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "cocoapods", + "namespace": null, + "name": "MapsIndoors", + "version": "3.24.0", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:cocoapods/MapsIndoors@3.24.0", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cocoapods/ShareKit@2.0#Twitter", + "expected_output": { + "type": "cocoapods", + "namespace": null, + "name": "ShareKit", + "version": "2.0", + "qualifiers": null, + "subpath": "Twitter" + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:cocoapods/ShareKit@2.0#Twitter", + "expected_output": "pkg:cocoapods/ShareKit@2.0#Twitter", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "cocoapods", + "namespace": null, + "name": "ShareKit", + "version": "2.0", + "qualifiers": null, + "subpath": "Twitter" + }, + "expected_output": "pkg:cocoapods/ShareKit@2.0#Twitter", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cocoapods/GoogleUtilities@7.5.2#NSData+zlib", + "expected_output": { + "type": "cocoapods", + "namespace": null, + "name": "GoogleUtilities", + "version": "7.5.2", + "qualifiers": null, + "subpath": "NSData+zlib" + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:cocoapods/GoogleUtilities@7.5.2#NSData+zlib", + "expected_output": "pkg:cocoapods/GoogleUtilities@7.5.2#NSData+zlib", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "cocoapods", + "namespace": null, + "name": "GoogleUtilities", + "version": "7.5.2", + "qualifiers": null, + "subpath": "NSData+zlib" + }, + "expected_output": "pkg:cocoapods/GoogleUtilities@7.5.2#NSData+zlib", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/composer-test.json b/tests/types/composer-test.json new file mode 100644 index 00000000..9e37fd22 --- /dev/null +++ b/tests/types/composer-test.json @@ -0,0 +1,121 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "valid packagist purl", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:composer/guzzlehttp/promises@2.0.2", + "expected_output": "pkg:composer/guzzlehttp/promises@2.0.2", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid packagist purl", + "test_group": "base", + "test_type": "parse", + "input": "pkg:composer/guzzlehttp/promises@2.0.2", + "expected_output": { + "type": "composer", + "namespace": "guzzlehttp", + "name": "promises", + "version": "2.0.2", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "composer names are not case sensitive. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:composer/Laravel/Laravel@5.5.0", + "expected_output": "pkg:composer/laravel/laravel@5.5.0", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "composer names are not case sensitive", + "test_group": "base", + "test_type": "parse", + "input": "pkg:composer/Laravel/Laravel@5.5.0", + "expected_output": { + "type": "composer", + "namespace": "laravel", + "name": "laravel", + "version": "5.5.0", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "composer names are not case sensitive. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:composer/laravel/laravel@5.5.0", + "expected_output": "pkg:composer/laravel/laravel@5.5.0", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "composer names are not case sensitive", + "test_group": "base", + "test_type": "build", + "input": { + "type": "composer", + "namespace": "laravel", + "name": "laravel", + "version": "5.5.0", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:composer/laravel/laravel@5.5.0", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:composer/laravel/laravel@5.5.0", + "expected_output": { + "type": "composer", + "namespace": "laravel", + "name": "laravel", + "version": "5.5.0", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:composer/laravel/laravel@5.5.0", + "expected_output": "pkg:composer/laravel/laravel@5.5.0", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "composer", + "namespace": "laravel", + "name": "laravel", + "version": "5.5.0", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:composer/laravel/laravel@5.5.0", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/conan-test.json b/tests/types/conan-test.json new file mode 100644 index 00000000..4a3ba694 --- /dev/null +++ b/tests/types/conan-test.json @@ -0,0 +1,328 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "valid conan purl. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:conan/cctz@2.3", + "expected_output": "pkg:conan/cctz@2.3", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid conan purl", + "test_group": "base", + "test_type": "parse", + "input": "pkg:conan/cctz@2.3", + "expected_output": { + "type": "conan", + "namespace": null, + "name": "cctz", + "version": "2.3", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid conan purl. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:conan/cctz@2.3", + "expected_output": "pkg:conan/cctz@2.3", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid conan purl", + "test_group": "base", + "test_type": "build", + "input": { + "type": "conan", + "namespace": null, + "name": "cctz", + "version": "2.3", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:conan/cctz@2.3", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid conan purl with namespace and qualifier channel. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:conan/bincrafters/cctz@2.3?channel=stable", + "expected_output": "pkg:conan/bincrafters/cctz@2.3?channel=stable", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid conan purl with namespace and qualifier channel", + "test_group": "base", + "test_type": "parse", + "input": "pkg:conan/bincrafters/cctz@2.3?channel=stable", + "expected_output": { + "type": "conan", + "namespace": "bincrafters", + "name": "cctz", + "version": "2.3", + "qualifiers": { + "channel": "stable" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid conan purl with namespace and qualifier channel. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:conan/bincrafters/cctz@2.3?channel=stable", + "expected_output": "pkg:conan/bincrafters/cctz@2.3?channel=stable", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid conan purl with namespace and qualifier channel", + "test_group": "base", + "test_type": "build", + "input": { + "type": "conan", + "namespace": "bincrafters", + "name": "cctz", + "version": "2.3", + "qualifiers": { + "channel": "stable" + }, + "subpath": null + }, + "expected_output": "pkg:conan/bincrafters/cctz@2.3?channel=stable", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "invalid conan purl only namespace", + "test_group": "base", + "test_type": "parse", + "input": "pkg:conan/bincrafters/cctz@2.3", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid purl input" + }, + { + "description": "invalid conan purl only namespace", + "test_group": "base", + "test_type": "parse", + "input": "pkg:conan/bincrafters/cctz@2.3", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid canonical purl input" + }, + { + "description": "invalid conan purl only namespace", + "test_group": "base", + "test_type": "build", + "input": { + "type": "conan", + "namespace": "bincrafters", + "name": "cctz", + "version": "2.3", + "qualifiers": null, + "subpath": null + }, + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to build a PURL from invalid input components" + }, + { + "description": "invalid conan purl only channel qualifier", + "test_group": "base", + "test_type": "parse", + "input": "pkg:conan/cctz@2.3?channel=stable", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid purl input" + }, + { + "description": "invalid conan purl only channel qualifier", + "test_group": "base", + "test_type": "parse", + "input": "pkg:conan/cctz@2.3?channel=stable", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid canonical purl input" + }, + { + "description": "invalid conan purl only channel qualifier", + "test_group": "base", + "test_type": "build", + "input": { + "type": "conan", + "namespace": null, + "name": "cctz", + "version": "2.3", + "qualifiers": { + "channel": "stable" + }, + "subpath": null + }, + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to build a PURL from invalid input components" + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:conan/openssl@3.0.3", + "expected_output": { + "type": "conan", + "namespace": null, + "name": "openssl", + "version": "3.0.3", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:conan/openssl@3.0.3", + "expected_output": "pkg:conan/openssl@3.0.3", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "conan", + "namespace": null, + "name": "openssl", + "version": "3.0.3", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:conan/openssl@3.0.3", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:conan/openssl.org/openssl@3.0.3?user=bincrafters&channel=stable", + "expected_output": { + "type": "conan", + "namespace": "openssl.org", + "name": "openssl", + "version": "3.0.3", + "qualifiers": { + "channel": "stable", + "user": "bincrafters" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:conan/openssl.org/openssl@3.0.3?user=bincrafters&channel=stable", + "expected_output": "pkg:conan/openssl.org/openssl@3.0.3?user=bincrafters&channel=stable", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "conan", + "namespace": "openssl.org", + "name": "openssl", + "version": "3.0.3", + "qualifiers": { + "channel": "stable", + "user": "bincrafters" + }, + "subpath": null + }, + "expected_output": "pkg:conan/openssl.org/openssl@3.0.3?user=bincrafters&channel=stable", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:conan/openssl.org/openssl@3.0.3?arch=x86_64&build_type=Debug&compiler=Visual%20Studio&compiler.runtime=MDd&compiler.version=16&os=Windows&shared=True&rrev=93a82349c31917d2d674d22065c7a9ef9f380c8e&prev=b429db8a0e324114c25ec387bfd8281f330d7c5c", + "expected_output": { + "type": "conan", + "namespace": "openssl.org", + "name": "openssl", + "version": "3.0.3", + "qualifiers": { + "arch": "x86_64", + "build_type": "Debug", + "compiler": "Visual Studio", + "compiler.runtime": "MDd", + "compiler.version": "16", + "os": "Windows", + "prev": "b429db8a0e324114c25ec387bfd8281f330d7c5c", + "rrev": "93a82349c31917d2d674d22065c7a9ef9f380c8e", + "shared": "True" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:conan/openssl.org/openssl@3.0.3?arch=x86_64&build_type=Debug&compiler=Visual%20Studio&compiler.runtime=MDd&compiler.version=16&os=Windows&shared=True&rrev=93a82349c31917d2d674d22065c7a9ef9f380c8e&prev=b429db8a0e324114c25ec387bfd8281f330d7c5c", + "expected_output": "pkg:conan/openssl.org/openssl@3.0.3?arch=x86_64&build_type=Debug&compiler=Visual%20Studio&compiler.runtime=MDd&compiler.version=16&os=Windows&shared=True&rrev=93a82349c31917d2d674d22065c7a9ef9f380c8e&prev=b429db8a0e324114c25ec387bfd8281f330d7c5c", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "conan", + "namespace": "openssl.org", + "name": "openssl", + "version": "3.0.3", + "qualifiers": { + "arch": "x86_64", + "build_type": "Debug", + "compiler": "Visual Studio", + "compiler.runtime": "MDd", + "compiler.version": "16", + "os": "Windows", + "prev": "b429db8a0e324114c25ec387bfd8281f330d7c5c", + "rrev": "93a82349c31917d2d674d22065c7a9ef9f380c8e", + "shared": "True" + }, + "subpath": null + }, + "expected_output": "pkg:conan/openssl.org/openssl@3.0.3?arch=x86_64&build_type=Debug&compiler=Visual%20Studio&compiler.runtime=MDd&compiler.version=16&os=Windows&shared=True&rrev=93a82349c31917d2d674d22065c7a9ef9f380c8e&prev=b429db8a0e324114c25ec387bfd8281f330d7c5c", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/conda-test.json b/tests/types/conda-test.json new file mode 100644 index 00000000..a148142e --- /dev/null +++ b/tests/types/conda-test.json @@ -0,0 +1,116 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "valid conda purl with qualifiers. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:conda/absl-py@0.4.1?build=py36h06a4308_0&channel=main&subdir=linux-64&type=tar.bz2", + "expected_output": "pkg:conda/absl-py@0.4.1?build=py36h06a4308_0&channel=main&subdir=linux-64&type=tar.bz2", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid conda purl with qualifiers", + "test_group": "base", + "test_type": "parse", + "input": "pkg:conda/absl-py@0.4.1?build=py36h06a4308_0&channel=main&subdir=linux-64&type=tar.bz2", + "expected_output": { + "type": "conda", + "namespace": null, + "name": "absl-py", + "version": "0.4.1", + "qualifiers": { + "build": "py36h06a4308_0", + "channel": "main", + "subdir": "linux-64", + "type": "tar.bz2" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid conda purl with qualifiers. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:conda/absl-py@0.4.1?build=py36h06a4308_0&channel=main&subdir=linux-64&type=tar.bz2", + "expected_output": "pkg:conda/absl-py@0.4.1?build=py36h06a4308_0&channel=main&subdir=linux-64&type=tar.bz2", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid conda purl with qualifiers", + "test_group": "base", + "test_type": "build", + "input": { + "type": "conda", + "namespace": null, + "name": "absl-py", + "version": "0.4.1", + "qualifiers": { + "build": "py36h06a4308_0", + "channel": "main", + "subdir": "linux-64", + "type": "tar.bz2" + }, + "subpath": null + }, + "expected_output": "pkg:conda/absl-py@0.4.1?build=py36h06a4308_0&channel=main&subdir=linux-64&type=tar.bz2", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:conda/absl-py@0.4.1?build=py36h06a4308_0&channel=main&subdir=linux-64&type=tar.bz2", + "expected_output": { + "type": "conda", + "namespace": null, + "name": "absl-py", + "version": "0.4.1", + "qualifiers": { + "build": "py36h06a4308_0", + "channel": "main", + "subdir": "linux-64", + "type": "tar.bz2" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:conda/absl-py@0.4.1?build=py36h06a4308_0&channel=main&subdir=linux-64&type=tar.bz2", + "expected_output": "pkg:conda/absl-py@0.4.1?build=py36h06a4308_0&channel=main&subdir=linux-64&type=tar.bz2", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "conda", + "namespace": null, + "name": "absl-py", + "version": "0.4.1", + "qualifiers": { + "build": "py36h06a4308_0", + "channel": "main", + "subdir": "linux-64", + "type": "tar.bz2" + }, + "subpath": null + }, + "expected_output": "pkg:conda/absl-py@0.4.1?build=py36h06a4308_0&channel=main&subdir=linux-64&type=tar.bz2", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/cpan-test.json b/tests/types/cpan-test.json new file mode 100644 index 00000000..b48e64a5 --- /dev/null +++ b/tests/types/cpan-test.json @@ -0,0 +1,560 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "cpan distribution name are case sensitive. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:cpan/DROLSKY/DateTime@1.55", + "expected_output": "pkg:cpan/DROLSKY/DateTime@1.55", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "cpan distribution name are case sensitive", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cpan/DROLSKY/DateTime@1.55", + "expected_output": { + "type": "cpan", + "namespace": "DROLSKY", + "name": "DateTime", + "version": "1.55", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "cpan distribution name are case sensitive. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:cpan/DROLSKY/DateTime@1.55", + "expected_output": "pkg:cpan/DROLSKY/DateTime@1.55", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "cpan distribution name are case sensitive", + "test_group": "base", + "test_type": "build", + "input": { + "type": "cpan", + "namespace": "DROLSKY", + "name": "DateTime", + "version": "1.55", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:cpan/DROLSKY/DateTime@1.55", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "cpan module name are case sensitive. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:cpan/URI::PackageURL@2.11", + "expected_output": "pkg:cpan/URI::PackageURL@2.11", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "cpan module name are case sensitive", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cpan/URI::PackageURL@2.11", + "expected_output": { + "type": "cpan", + "namespace": null, + "name": "URI::PackageURL", + "version": "2.11", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "cpan module name are case sensitive. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:cpan/URI::PackageURL@2.11", + "expected_output": "pkg:cpan/URI::PackageURL@2.11", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "cpan module name are case sensitive", + "test_group": "base", + "test_type": "build", + "input": { + "type": "cpan", + "namespace": null, + "name": "URI::PackageURL", + "version": "2.11", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:cpan/URI::PackageURL@2.11", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "cpan module name like distribution name", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cpan/Perl-Version@1.013", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid purl input" + }, + { + "description": "cpan module name like distribution name", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cpan/Perl-Version@1.013", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid canonical purl input" + }, + { + "description": "cpan module name like distribution name", + "test_group": "base", + "test_type": "build", + "input": { + "type": "cpan", + "namespace": null, + "name": "Perl-Version", + "version": "1.013", + "qualifiers": null, + "subpath": null + }, + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to build a PURL from invalid input components" + }, + { + "description": "cpan distribution name like module name", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cpan/GDT/URI::PackageURL@2.11", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid purl input" + }, + { + "description": "cpan distribution name like module name", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cpan/GDT/URI::PackageURL", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid canonical purl input" + }, + { + "description": "cpan distribution name like module name", + "test_group": "base", + "test_type": "build", + "input": { + "type": "cpan", + "namespace": "GDT", + "name": "URI::PackageURL", + "version": null, + "qualifiers": null, + "subpath": null + }, + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to build a PURL from invalid input components" + }, + { + "description": "cpan valid module name. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:cpan/DateTime@1.55", + "expected_output": "pkg:cpan/DateTime@1.55", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "cpan valid module name", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cpan/DateTime@1.55", + "expected_output": { + "type": "cpan", + "namespace": null, + "name": "DateTime", + "version": "1.55", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "cpan valid module name. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:cpan/DateTime@1.55", + "expected_output": "pkg:cpan/DateTime@1.55", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "cpan valid module name", + "test_group": "base", + "test_type": "build", + "input": { + "type": "cpan", + "namespace": null, + "name": "DateTime", + "version": "1.55", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:cpan/DateTime@1.55", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "cpan valid module name without version. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:cpan/URI", + "expected_output": "pkg:cpan/URI", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "cpan valid module name without version", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cpan/URI", + "expected_output": { + "type": "cpan", + "namespace": null, + "name": "URI", + "version": null, + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "cpan valid module name without version. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:cpan/URI", + "expected_output": "pkg:cpan/URI", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "cpan valid module name without version", + "test_group": "base", + "test_type": "build", + "input": { + "type": "cpan", + "namespace": null, + "name": "URI", + "version": null, + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:cpan/URI", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cpan/Perl::Version@1.013", + "expected_output": { + "type": "cpan", + "namespace": null, + "name": "perl::Version", + "version": "1.013", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:cpan/Perl::Version@1.013", + "expected_output": "pkg:cpan/Perl::Version@1.013", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "cpan", + "namespace": null, + "name": "perl::Version", + "version": "1.013", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:cpan/Perl::Version@1.013", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cpan/DROLSKY/DateTime@1.55", + "expected_output": { + "type": "cpan", + "namespace": "DROLSKY", + "name": "DateTime", + "version": "1.55", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:cpan/DROLSKY/DateTime@1.55", + "expected_output": "pkg:cpan/DROLSKY/DateTime@1.55", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "cpan", + "namespace": "DROLSKY", + "name": "DateTime", + "version": "1.55", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:cpan/DROLSKY/DateTime@1.55", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cpan/DateTime@1.55", + "expected_output": { + "type": "cpan", + "namespace": null, + "name": "DateTime", + "version": "1.55", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:cpan/DateTime@1.55", + "expected_output": "pkg:cpan/DateTime@1.55", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "cpan", + "namespace": null, + "name": "DateTime", + "version": "1.55", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:cpan/DateTime@1.55", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cpan/GDT/URI-PackageURL", + "expected_output": { + "type": "cpan", + "namespace": "GDT", + "name": "URI-PackageURL", + "version": null, + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:cpan/GDT/URI-PackageURL", + "expected_output": "pkg:cpan/GDT/URI-PackageURL", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "cpan", + "namespace": "GDT", + "name": "URI-PackageURL", + "version": null, + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:cpan/GDT/URI-PackageURL", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cpan/LWP::UserAgent", + "expected_output": { + "type": "cpan", + "namespace": null, + "name": "lwp::UserAgent", + "version": null, + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:cpan/LWP::UserAgent", + "expected_output": "pkg:cpan/LWP::UserAgent", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "cpan", + "namespace": null, + "name": "lwp::UserAgent", + "version": null, + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:cpan/LWP::UserAgent", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cpan/OALDERS/libwww-perl@6.76", + "expected_output": { + "type": "cpan", + "namespace": "OALDERS", + "name": "libwww-perl", + "version": "6.76", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:cpan/OALDERS/libwww-perl@6.76", + "expected_output": "pkg:cpan/OALDERS/libwww-perl@6.76", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "cpan", + "namespace": "OALDERS", + "name": "libwww-perl", + "version": "6.76", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:cpan/OALDERS/libwww-perl@6.76", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cpan/URI", + "expected_output": { + "type": "cpan", + "namespace": null, + "name": "URI", + "version": null, + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:cpan/URI", + "expected_output": "pkg:cpan/URI", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "cpan", + "namespace": null, + "name": "URI", + "version": null, + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:cpan/URI", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/cran-test.json b/tests/types/cran-test.json new file mode 100644 index 00000000..d027639a --- /dev/null +++ b/tests/types/cran-test.json @@ -0,0 +1,246 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "valid cran purl. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:cran/A3@0.9.1", + "expected_output": "pkg:cran/A3@0.9.1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid cran purl", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cran/A3@0.9.1", + "expected_output": { + "type": "cran", + "namespace": null, + "name": "A3", + "version": "0.9.1", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid cran purl. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:cran/A3@0.9.1", + "expected_output": "pkg:cran/A3@0.9.1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid cran purl", + "test_group": "base", + "test_type": "build", + "input": { + "type": "cran", + "namespace": null, + "name": "A3", + "version": "0.9.1", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:cran/A3@0.9.1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "invalid cran purl without name", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cran/@0.9.1", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid purl input" + }, + { + "description": "invalid cran purl without name", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cran/@0.9.1", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid canonical purl input" + }, + { + "description": "invalid cran purl without name", + "test_group": "base", + "test_type": "build", + "input": { + "type": "cran", + "namespace": null, + "name": null, + "version": "0.9.1", + "qualifiers": null, + "subpath": null + }, + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to build a PURL from invalid input components" + }, + { + "description": "invalid cran purl without version", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cran/A3", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid purl input" + }, + { + "description": "invalid cran purl without version", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cran/A3", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid canonical purl input" + }, + { + "description": "invalid cran purl without version", + "test_group": "base", + "test_type": "build", + "input": { + "type": "cran", + "namespace": null, + "name": "A3", + "version": null, + "qualifiers": null, + "subpath": null + }, + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to build a PURL from invalid input components" + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cran/A3@1.0.0", + "expected_output": { + "type": "cran", + "namespace": null, + "name": "A3", + "version": "1.0.0", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:cran/A3@1.0.0", + "expected_output": "pkg:cran/A3@1.0.0", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "cran", + "namespace": null, + "name": "A3", + "version": "1.0.0", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:cran/A3@1.0.0", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cran/rJava@1.0-4", + "expected_output": { + "type": "cran", + "namespace": null, + "name": "rJava", + "version": "1.0-4", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:cran/rJava@1.0-4", + "expected_output": "pkg:cran/rJava@1.0-4", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "cran", + "namespace": null, + "name": "rJava", + "version": "1.0-4", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:cran/rJava@1.0-4", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:cran/caret@6.0-88", + "expected_output": { + "type": "cran", + "namespace": null, + "name": "caret", + "version": "6.0-88", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:cran/caret@6.0-88", + "expected_output": "pkg:cran/caret@6.0-88", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "cran", + "namespace": null, + "name": "caret", + "version": "6.0-88", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:cran/caret@6.0-88", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/deb-test.json b/tests/types/deb-test.json new file mode 100644 index 00000000..55b5fb90 --- /dev/null +++ b/tests/types/deb-test.json @@ -0,0 +1,290 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "debian can use qualifiers. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:deb/debian/curl@7.50.3-1?arch=i386&distro=jessie", + "expected_output": "pkg:deb/debian/curl@7.50.3-1?arch=i386&distro=jessie", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "debian can use qualifiers", + "test_group": "base", + "test_type": "parse", + "input": "pkg:deb/debian/curl@7.50.3-1?arch=i386&distro=jessie", + "expected_output": { + "type": "deb", + "namespace": "debian", + "name": "curl", + "version": "7.50.3-1", + "qualifiers": { + "arch": "i386", + "distro": "jessie" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "debian can use qualifiers. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:deb/debian/curl@7.50.3-1?arch=i386&distro=jessie", + "expected_output": "pkg:deb/debian/curl@7.50.3-1?arch=i386&distro=jessie", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "debian can use qualifiers", + "test_group": "base", + "test_type": "build", + "input": { + "type": "deb", + "namespace": "debian", + "name": "curl", + "version": "7.50.3-1", + "qualifiers": { + "arch": "i386", + "distro": "jessie" + }, + "subpath": null + }, + "expected_output": "pkg:deb/debian/curl@7.50.3-1?arch=i386&distro=jessie", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:deb/debian/curl@7.50.3-1?arch=i386&distro=jessie", + "expected_output": { + "type": "deb", + "namespace": "debian", + "name": "curl", + "version": "7.50.3-1", + "qualifiers": { + "arch": "i386", + "distro": "jessie" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:deb/debian/curl@7.50.3-1?arch=i386&distro=jessie", + "expected_output": "pkg:deb/debian/curl@7.50.3-1?arch=i386&distro=jessie", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "deb", + "namespace": "debian", + "name": "curl", + "version": "7.50.3-1", + "qualifiers": { + "arch": "i386", + "distro": "jessie" + }, + "subpath": null + }, + "expected_output": "pkg:deb/debian/curl@7.50.3-1?arch=i386&distro=jessie", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:deb/debian/dpkg@1.19.0.4?arch=amd64&distro=stretch", + "expected_output": { + "type": "deb", + "namespace": "debian", + "name": "dpkg", + "version": "1.19.0.4", + "qualifiers": { + "arch": "amd64", + "distro": "stretch" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:deb/debian/dpkg@1.19.0.4?arch=amd64&distro=stretch", + "expected_output": "pkg:deb/debian/dpkg@1.19.0.4?arch=amd64&distro=stretch", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "deb", + "namespace": "debian", + "name": "dpkg", + "version": "1.19.0.4", + "qualifiers": { + "arch": "amd64", + "distro": "stretch" + }, + "subpath": null + }, + "expected_output": "pkg:deb/debian/dpkg@1.19.0.4?arch=amd64&distro=stretch", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:deb/ubuntu/dpkg@1.19.0.4?arch=amd64", + "expected_output": { + "type": "deb", + "namespace": "ubuntu", + "name": "dpkg", + "version": "1.19.0.4", + "qualifiers": { + "arch": "amd64" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:deb/ubuntu/dpkg@1.19.0.4?arch=amd64", + "expected_output": "pkg:deb/ubuntu/dpkg@1.19.0.4?arch=amd64", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "deb", + "namespace": "ubuntu", + "name": "dpkg", + "version": "1.19.0.4", + "qualifiers": { + "arch": "amd64" + }, + "subpath": null + }, + "expected_output": "pkg:deb/ubuntu/dpkg@1.19.0.4?arch=amd64", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:deb/debian/attr@1:2.4.47-2?arch=source", + "expected_output": { + "type": "deb", + "namespace": "debian", + "name": "attr", + "version": "1:2.4.47-2", + "qualifiers": { + "arch": "source" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:deb/debian/attr@1:2.4.47-2?arch=source", + "expected_output": "pkg:deb/debian/attr@1:2.4.47-2?arch=source", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "deb", + "namespace": "debian", + "name": "attr", + "version": "1:2.4.47-2", + "qualifiers": { + "arch": "source" + }, + "subpath": null + }, + "expected_output": "pkg:deb/debian/attr@1:2.4.47-2?arch=source", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:deb/debian/attr@1:2.4.47-2%2Bb1?arch=amd64", + "expected_output": { + "type": "deb", + "namespace": "debian", + "name": "attr", + "version": "1:2.4.47-2+b1", + "qualifiers": { + "arch": "amd64" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:deb/debian/attr@1:2.4.47-2%2Bb1?arch=amd64", + "expected_output": "pkg:deb/debian/attr@1:2.4.47-2%2Bb1?arch=amd64", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "deb", + "namespace": "debian", + "name": "attr", + "version": "1:2.4.47-2+b1", + "qualifiers": { + "arch": "amd64" + }, + "subpath": null + }, + "expected_output": "pkg:deb/debian/attr@1:2.4.47-2%2Bb1?arch=amd64", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/docker-test.json b/tests/types/docker-test.json new file mode 100644 index 00000000..0ecb38df --- /dev/null +++ b/tests/types/docker-test.json @@ -0,0 +1,186 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "docker uses qualifiers and hash image id as versions. Rountrip an input purl wrongly percent encoded to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:docker/customer/dockerimage@sha256%3A244fd47e07d1004f0aed9c?repository_url=gcr.io", + "expected_output": "pkg:docker/customer/dockerimage@sha256:244fd47e07d1004f0aed9c?repository_url=gcr.io", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "docker uses qualifiers and hash image id as versions", + "test_group": "base", + "test_type": "parse", + "input": "pkg:docker/customer/dockerimage@sha256:244fd47e07d1004f0aed9c?repository_url=gcr.io", + "expected_output": { + "type": "docker", + "namespace": "customer", + "name": "dockerimage", + "version": "sha256:244fd47e07d1004f0aed9c", + "qualifiers": { + "repository_url": "gcr.io" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "docker uses qualifiers and hash image id as versions. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:docker/customer/dockerimage@sha256:244fd47e07d1004f0aed9c?repository_url=gcr.io", + "expected_output": "pkg:docker/customer/dockerimage@sha256:244fd47e07d1004f0aed9c?repository_url=gcr.io", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "docker uses qualifiers and hash image id as versions", + "test_group": "base", + "test_type": "build", + "input": { + "type": "docker", + "namespace": "customer", + "name": "dockerimage", + "version": "sha256:244fd47e07d1004f0aed9c", + "qualifiers": { + "repository_url": "gcr.io" + }, + "subpath": null + }, + "expected_output": "pkg:docker/customer/dockerimage@sha256:244fd47e07d1004f0aed9c?repository_url=gcr.io", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:docker/cassandra@latest", + "expected_output": { + "type": "docker", + "namespace": null, + "name": "cassandra", + "version": "latest", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:docker/cassandra@latest", + "expected_output": "pkg:docker/cassandra@latest", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "docker", + "namespace": null, + "name": "cassandra", + "version": "latest", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:docker/cassandra@latest", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:docker/smartentry/debian@dc437cc87d10", + "expected_output": { + "type": "docker", + "namespace": "smartentry", + "name": "debian", + "version": "dc437cc87d10", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:docker/smartentry/debian@dc437cc87d10", + "expected_output": "pkg:docker/smartentry/debian@dc437cc87d10", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "docker", + "namespace": "smartentry", + "name": "debian", + "version": "dc437cc87d10", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:docker/smartentry/debian@dc437cc87d10", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:docker/customer/dockerimage@sha256:244fd47e07d10?repository_url=gcr.io", + "expected_output": { + "type": "docker", + "namespace": "customer", + "name": "dockerimage", + "version": "sha256:244fd47e07d10", + "qualifiers": { + "repository_url": "gcr.io" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:docker/customer/dockerimage@sha256:244fd47e07d10?repository_url=gcr.io", + "expected_output": "pkg:docker/customer/dockerimage@sha256:244fd47e07d10?repository_url=gcr.io", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "docker", + "namespace": "customer", + "name": "dockerimage", + "version": "sha256:244fd47e07d10", + "qualifiers": { + "repository_url": "gcr.io" + }, + "subpath": null + }, + "expected_output": "pkg:docker/customer/dockerimage@sha256:244fd47e07d10?repository_url=gcr.io", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/gem-test.json b/tests/types/gem-test.json new file mode 100644 index 00000000..0f2df1bd --- /dev/null +++ b/tests/types/gem-test.json @@ -0,0 +1,145 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "Java gem can use a qualifier. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:gem/jruby-launcher@1.1.2?Platform=java", + "expected_output": "pkg:gem/jruby-launcher@1.1.2?platform=java", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Java gem can use a qualifier", + "test_group": "base", + "test_type": "parse", + "input": "pkg:gem/jruby-launcher@1.1.2?Platform=java", + "expected_output": { + "type": "gem", + "namespace": null, + "name": "jruby-launcher", + "version": "1.1.2", + "qualifiers": { + "platform": "java" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Java gem can use a qualifier. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:gem/jruby-launcher@1.1.2?platform=java", + "expected_output": "pkg:gem/jruby-launcher@1.1.2?platform=java", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Java gem can use a qualifier", + "test_group": "base", + "test_type": "build", + "input": { + "type": "gem", + "namespace": null, + "name": "jruby-launcher", + "version": "1.1.2", + "qualifiers": { + "platform": "java" + }, + "subpath": null + }, + "expected_output": "pkg:gem/jruby-launcher@1.1.2?platform=java", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:gem/ruby-advisory-db-check@0.12.4", + "expected_output": { + "type": "gem", + "namespace": null, + "name": "ruby-advisory-db-check", + "version": "0.12.4", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:gem/ruby-advisory-db-check@0.12.4", + "expected_output": "pkg:gem/ruby-advisory-db-check@0.12.4", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "gem", + "namespace": null, + "name": "ruby-advisory-db-check", + "version": "0.12.4", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:gem/ruby-advisory-db-check@0.12.4", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:gem/jruby-launcher@1.1.2?platform=java", + "expected_output": { + "type": "gem", + "namespace": null, + "name": "jruby-launcher", + "version": "1.1.2", + "qualifiers": { + "platform": "java" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:gem/jruby-launcher@1.1.2?platform=java", + "expected_output": "pkg:gem/jruby-launcher@1.1.2?platform=java", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "gem", + "namespace": null, + "name": "jruby-launcher", + "version": "1.1.2", + "qualifiers": { + "platform": "java" + }, + "subpath": null + }, + "expected_output": "pkg:gem/jruby-launcher@1.1.2?platform=java", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/generic-test.json b/tests/types/generic-test.json new file mode 100644 index 00000000..4f6f6423 --- /dev/null +++ b/tests/types/generic-test.json @@ -0,0 +1,138 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:generic/openssl@1.1.10g", + "expected_output": { + "type": "generic", + "namespace": null, + "name": "openssl", + "version": "1.1.10g", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:generic/openssl@1.1.10g", + "expected_output": "pkg:generic/openssl@1.1.10g", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "generic", + "namespace": null, + "name": "openssl", + "version": "1.1.10g", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:generic/openssl@1.1.10g", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:generic/openssl@1.1.10g?download_url=https://openssl.org/source/openssl-1.1.0g.tar.gz&checksum=sha256:de4d501267da", + "expected_output": { + "type": "generic", + "namespace": null, + "name": "openssl", + "version": "1.1.10g", + "qualifiers": { + "checksum": "sha256:de4d501267da", + "download_url": "https://openssl.org/source/openssl-1.1.0g.tar.gz" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:generic/openssl@1.1.10g?download_url=https://openssl.org/source/openssl-1.1.0g.tar.gz&checksum=sha256:de4d501267da", + "expected_output": "pkg:generic/openssl@1.1.10g?download_url=https://openssl.org/source/openssl-1.1.0g.tar.gz&checksum=sha256:de4d501267da", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "generic", + "namespace": null, + "name": "openssl", + "version": "1.1.10g", + "qualifiers": { + "checksum": "sha256:de4d501267da", + "download_url": "https://openssl.org/source/openssl-1.1.0g.tar.gz" + }, + "subpath": null + }, + "expected_output": "pkg:generic/openssl@1.1.10g?download_url=https://openssl.org/source/openssl-1.1.0g.tar.gz&checksum=sha256:de4d501267da", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:generic/bitwarderl?vcs_url=git%2Bhttps://git.fsfe.org/dxtr/bitwarderl%40cc55108da32", + "expected_output": { + "type": "generic", + "namespace": null, + "name": "bitwarderl", + "version": null, + "qualifiers": { + "vcs_url": "git+https://git.fsfe.org/dxtr/bitwarderl@cc55108da32" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:generic/bitwarderl?vcs_url=git%2Bhttps://git.fsfe.org/dxtr/bitwarderl%40cc55108da32", + "expected_output": "pkg:generic/bitwarderl?vcs_url=git%2Bhttps://git.fsfe.org/dxtr/bitwarderl%40cc55108da32", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "generic", + "namespace": null, + "name": "bitwarderl", + "version": null, + "qualifiers": { + "vcs_url": "git+https://git.fsfe.org/dxtr/bitwarderl@cc55108da32" + }, + "subpath": null + }, + "expected_output": "pkg:generic/bitwarderl?vcs_url=git%2Bhttps://git.fsfe.org/dxtr/bitwarderl%40cc55108da32", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/github-test.json b/tests/types/github-test.json new file mode 100644 index 00000000..fa2c8811 --- /dev/null +++ b/tests/types/github-test.json @@ -0,0 +1,137 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "github namespace and name should be lowercased. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:github/Package-url/purl-Spec@244fd47e07d1004f0aed9c", + "expected_output": "pkg:github/package-url/purl-spec@244fd47e07d1004f0aed9c", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "github namespace and name should be lowercased", + "test_group": "base", + "test_type": "parse", + "input": "pkg:github/Package-url/purl-Spec@244fd47e07d1004f0aed9c", + "expected_output": { + "type": "github", + "namespace": "package-url", + "name": "purl-spec", + "version": "244fd47e07d1004f0aed9c", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "github namespace and name should be lowercased. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:github/package-url/purl-spec@244fd47e07d1004f0aed9c", + "expected_output": "pkg:github/package-url/purl-spec@244fd47e07d1004f0aed9c", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "github namespace and name should be lowercased", + "test_group": "base", + "test_type": "build", + "input": { + "type": "github", + "namespace": "package-url", + "name": "purl-spec", + "version": "244fd47e07d1004f0aed9c", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:github/package-url/purl-spec@244fd47e07d1004f0aed9c", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:github/package-url/purl-spec@244fd47e07d1004", + "expected_output": { + "type": "github", + "namespace": "package-url", + "name": "purl-spec", + "version": "244fd47e07d1004", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:github/package-url/purl-spec@244fd47e07d1004", + "expected_output": "pkg:github/package-url/purl-spec@244fd47e07d1004", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "github", + "namespace": "package-url", + "name": "purl-spec", + "version": "244fd47e07d1004", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:github/package-url/purl-spec@244fd47e07d1004", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:github/package-url/purl-spec@244fd47e07d1004#everybody/loves/dogs", + "expected_output": { + "type": "github", + "namespace": "package-url", + "name": "purl-spec", + "version": "244fd47e07d1004", + "qualifiers": null, + "subpath": "everybody/loves/dogs" + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:github/package-url/purl-spec@244fd47e07d1004#everybody/loves/dogs", + "expected_output": "pkg:github/package-url/purl-spec@244fd47e07d1004#everybody/loves/dogs", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "github", + "namespace": "package-url", + "name": "purl-spec", + "version": "244fd47e07d1004", + "qualifiers": null, + "subpath": "everybody/loves/dogs" + }, + "expected_output": "pkg:github/package-url/purl-spec@244fd47e07d1004#everybody/loves/dogs", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/golang-test.json b/tests/types/golang-test.json new file mode 100644 index 00000000..11da72b4 --- /dev/null +++ b/tests/types/golang-test.json @@ -0,0 +1,228 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "valid go purl without version and with subpath. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:GOLANG/google.golang.org/genproto#/googleapis/api/annotations/", + "expected_output": "pkg:golang/google.golang.org/genproto#googleapis/api/annotations", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid go purl without version and with subpath", + "test_group": "base", + "test_type": "parse", + "input": "pkg:GOLANG/google.golang.org/genproto#/googleapis/api/annotations/", + "expected_output": { + "type": "golang", + "namespace": "google.golang.org", + "name": "genproto", + "version": null, + "qualifiers": null, + "subpath": "googleapis/api/annotations" + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid go purl without version and with subpath. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:golang/google.golang.org/genproto#googleapis/api/annotations", + "expected_output": "pkg:golang/google.golang.org/genproto#googleapis/api/annotations", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid go purl without version and with subpath", + "test_group": "base", + "test_type": "build", + "input": { + "type": "golang", + "namespace": "google.golang.org", + "name": "genproto", + "version": null, + "qualifiers": null, + "subpath": "googleapis/api/annotations" + }, + "expected_output": "pkg:golang/google.golang.org/genproto#googleapis/api/annotations", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid go purl with version and subpath. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:GOLANG/google.golang.org/genproto@abcdedf#/googleapis/api/annotations/", + "expected_output": "pkg:golang/google.golang.org/genproto@abcdedf#googleapis/api/annotations", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid go purl with version and subpath", + "test_group": "base", + "test_type": "parse", + "input": "pkg:GOLANG/google.golang.org/genproto@abcdedf#/googleapis/api/annotations/", + "expected_output": { + "type": "golang", + "namespace": "google.golang.org", + "name": "genproto", + "version": "abcdedf", + "qualifiers": null, + "subpath": "googleapis/api/annotations" + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid go purl with version and subpath. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:golang/google.golang.org/genproto@abcdedf#googleapis/api/annotations", + "expected_output": "pkg:golang/google.golang.org/genproto@abcdedf#googleapis/api/annotations", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid go purl with version and subpath", + "test_group": "base", + "test_type": "build", + "input": { + "type": "golang", + "namespace": "google.golang.org", + "name": "genproto", + "version": "abcdedf", + "qualifiers": null, + "subpath": "googleapis/api/annotations" + }, + "expected_output": "pkg:golang/google.golang.org/genproto@abcdedf#googleapis/api/annotations", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:golang/github.com/gorilla/context@234fd47e07d1004f0aed9c", + "expected_output": { + "type": "golang", + "namespace": "github.com/gorilla", + "name": "context", + "version": "234fd47e07d1004f0aed9c", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:golang/github.com/gorilla/context@234fd47e07d1004f0aed9c", + "expected_output": "pkg:golang/github.com/gorilla/context@234fd47e07d1004f0aed9c", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "golang", + "namespace": "github.com/gorilla", + "name": "context", + "version": "234fd47e07d1004f0aed9c", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:golang/github.com/gorilla/context@234fd47e07d1004f0aed9c", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:golang/google.golang.org/genproto#googleapis/api/annotations", + "expected_output": { + "type": "golang", + "namespace": "google.golang.org", + "name": "genproto", + "version": null, + "qualifiers": null, + "subpath": "googleapis/api/annotations" + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:golang/google.golang.org/genproto#googleapis/api/annotations", + "expected_output": "pkg:golang/google.golang.org/genproto#googleapis/api/annotations", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "golang", + "namespace": "google.golang.org", + "name": "genproto", + "version": null, + "qualifiers": null, + "subpath": "googleapis/api/annotations" + }, + "expected_output": "pkg:golang/google.golang.org/genproto#googleapis/api/annotations", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:golang/github.com/gorilla/context@234fd47e07d1004f0aed9c#api", + "expected_output": { + "type": "golang", + "namespace": "github.com/gorilla", + "name": "context", + "version": "234fd47e07d1004f0aed9c", + "qualifiers": null, + "subpath": "api" + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:golang/github.com/gorilla/context@234fd47e07d1004f0aed9c#api", + "expected_output": "pkg:golang/github.com/gorilla/context@234fd47e07d1004f0aed9c#api", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "golang", + "namespace": "github.com/gorilla", + "name": "context", + "version": "234fd47e07d1004f0aed9c", + "qualifiers": null, + "subpath": "api" + }, + "expected_output": "pkg:golang/github.com/gorilla/context@234fd47e07d1004f0aed9c#api", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/hackage-test.json b/tests/types/hackage-test.json new file mode 100644 index 00000000..d8d88cfe --- /dev/null +++ b/tests/types/hackage-test.json @@ -0,0 +1,212 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "valid hackage purl. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:hackage/AC-HalfInteger@1.2.1", + "expected_output": "pkg:hackage/AC-HalfInteger@1.2.1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid hackage purl", + "test_group": "base", + "test_type": "parse", + "input": "pkg:hackage/AC-HalfInteger@1.2.1", + "expected_output": { + "type": "hackage", + "namespace": null, + "name": "AC-HalfInteger", + "version": "1.2.1", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid hackage purl. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:hackage/AC-HalfInteger@1.2.1", + "expected_output": "pkg:hackage/AC-HalfInteger@1.2.1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid hackage purl", + "test_group": "base", + "test_type": "build", + "input": { + "type": "hackage", + "namespace": null, + "name": "AC-HalfInteger", + "version": "1.2.1", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:hackage/AC-HalfInteger@1.2.1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "name and version are always required", + "test_group": "base", + "test_type": "parse", + "input": "pkg:hackage", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid purl input" + }, + { + "description": "name and version are always required", + "test_group": "base", + "test_type": "parse", + "input": "pkg:hackage", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid canonical purl input" + }, + { + "description": "name and version are always required", + "test_group": "base", + "test_type": "build", + "input": { + "type": "hackage", + "namespace": null, + "name": null, + "version": null, + "qualifiers": null, + "subpath": null + }, + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to build a PURL from invalid input components" + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:hackage/a50@0.5", + "expected_output": { + "type": "hackage", + "namespace": null, + "name": "a50", + "version": "0.5", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:hackage/a50@0.5", + "expected_output": "pkg:hackage/a50@0.5", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "hackage", + "namespace": null, + "name": "a50", + "version": "0.5", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:hackage/a50@0.5", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:hackage/AC-HalfInteger@1.2.1", + "expected_output": { + "type": "hackage", + "namespace": null, + "name": "AC-HalfInteger", + "version": "1.2.1", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:hackage/AC-HalfInteger@1.2.1", + "expected_output": "pkg:hackage/AC-HalfInteger@1.2.1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "hackage", + "namespace": null, + "name": "AC-HalfInteger", + "version": "1.2.1", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:hackage/AC-HalfInteger@1.2.1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:hackage/3d-graphics-examples@0.0.0.2", + "expected_output": { + "type": "hackage", + "namespace": null, + "name": "3d-graphics-examples", + "version": "0.0.0.2", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:hackage/3d-graphics-examples@0.0.0.2", + "expected_output": "pkg:hackage/3d-graphics-examples@0.0.0.2", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "hackage", + "namespace": null, + "name": "3d-graphics-examples", + "version": "0.0.0.2", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:hackage/3d-graphics-examples@0.0.0.2", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/hex-test.json b/tests/types/hex-test.json new file mode 100644 index 00000000..5d58d636 --- /dev/null +++ b/tests/types/hex-test.json @@ -0,0 +1,173 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:hex/jason@1.1.2", + "expected_output": { + "type": "hex", + "namespace": null, + "name": "jason", + "version": "1.1.2", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:hex/jason@1.1.2", + "expected_output": "pkg:hex/jason@1.1.2", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "hex", + "namespace": null, + "name": "jason", + "version": "1.1.2", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:hex/jason@1.1.2", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:hex/acme/foo@2.3.", + "expected_output": { + "type": "hex", + "namespace": "acme", + "name": "foo", + "version": "2.3.", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:hex/acme/foo@2.3.", + "expected_output": "pkg:hex/acme/foo@2.3.", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "hex", + "namespace": "acme", + "name": "foo", + "version": "2.3.", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:hex/acme/foo@2.3.", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:hex/phoenix_html@2.13.3#priv/static/phoenix_html.js", + "expected_output": { + "type": "hex", + "namespace": null, + "name": "phoenix_html", + "version": "2.13.3", + "qualifiers": null, + "subpath": "priv/static/phoenix_html.js" + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:hex/phoenix_html@2.13.3#priv/static/phoenix_html.js", + "expected_output": "pkg:hex/phoenix_html@2.13.3#priv/static/phoenix_html.js", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "hex", + "namespace": null, + "name": "phoenix_html", + "version": "2.13.3", + "qualifiers": null, + "subpath": "priv/static/phoenix_html.js" + }, + "expected_output": "pkg:hex/phoenix_html@2.13.3#priv/static/phoenix_html.js", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:hex/bar@1.2.3?repository_url=https://myrepo.example.com", + "expected_output": { + "type": "hex", + "namespace": null, + "name": "bar", + "version": "1.2.3", + "qualifiers": { + "repository_url": "https://myrepo.example.com" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:hex/bar@1.2.3?repository_url=https://myrepo.example.com", + "expected_output": "pkg:hex/bar@1.2.3?repository_url=https://myrepo.example.com", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "hex", + "namespace": null, + "name": "bar", + "version": "1.2.3", + "qualifiers": { + "repository_url": "https://myrepo.example.com" + }, + "subpath": null + }, + "expected_output": "pkg:hex/bar@1.2.3?repository_url=https://myrepo.example.com", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/huggingface-test.json b/tests/types/huggingface-test.json new file mode 100644 index 00000000..4849193a --- /dev/null +++ b/tests/types/huggingface-test.json @@ -0,0 +1,245 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "minimal Hugging Face model. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:huggingface/distilbert-base-uncased@043235d6088ecd3dd5fb5ca3592b6913fd516027", + "expected_output": "pkg:huggingface/distilbert-base-uncased@043235d6088ecd3dd5fb5ca3592b6913fd516027", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "minimal Hugging Face model", + "test_group": "base", + "test_type": "parse", + "input": "pkg:huggingface/distilbert-base-uncased@043235d6088ecd3dd5fb5ca3592b6913fd516027", + "expected_output": { + "type": "huggingface", + "namespace": null, + "name": "distilbert-base-uncased", + "version": "043235d6088ecd3dd5fb5ca3592b6913fd516027", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "minimal Hugging Face model. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:huggingface/distilbert-base-uncased@043235d6088ecd3dd5fb5ca3592b6913fd516027", + "expected_output": "pkg:huggingface/distilbert-base-uncased@043235d6088ecd3dd5fb5ca3592b6913fd516027", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "minimal Hugging Face model", + "test_group": "base", + "test_type": "build", + "input": { + "type": "huggingface", + "namespace": null, + "name": "distilbert-base-uncased", + "version": "043235d6088ecd3dd5fb5ca3592b6913fd516027", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:huggingface/distilbert-base-uncased@043235d6088ecd3dd5fb5ca3592b6913fd516027", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Hugging Face model with staging endpoint. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:huggingface/microsoft/deberta-v3-base@559062ad13d311b87b2c455e67dcd5f1c8f65111?repository_url=https://hub-ci.huggingface.co", + "expected_output": "pkg:huggingface/microsoft/deberta-v3-base@559062ad13d311b87b2c455e67dcd5f1c8f65111?repository_url=https://hub-ci.huggingface.co", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Hugging Face model with staging endpoint", + "test_group": "base", + "test_type": "parse", + "input": "pkg:huggingface/microsoft/deberta-v3-base@559062ad13d311b87b2c455e67dcd5f1c8f65111?repository_url=https://hub-ci.huggingface.co", + "expected_output": { + "type": "huggingface", + "namespace": "microsoft", + "name": "deberta-v3-base", + "version": "559062ad13d311b87b2c455e67dcd5f1c8f65111", + "qualifiers": { + "repository_url": "https://hub-ci.huggingface.co" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Hugging Face model with staging endpoint. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:huggingface/microsoft/deberta-v3-base@559062ad13d311b87b2c455e67dcd5f1c8f65111?repository_url=https://hub-ci.huggingface.co", + "expected_output": "pkg:huggingface/microsoft/deberta-v3-base@559062ad13d311b87b2c455e67dcd5f1c8f65111?repository_url=https://hub-ci.huggingface.co", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Hugging Face model with staging endpoint", + "test_group": "base", + "test_type": "build", + "input": { + "type": "huggingface", + "namespace": "microsoft", + "name": "deberta-v3-base", + "version": "559062ad13d311b87b2c455e67dcd5f1c8f65111", + "qualifiers": { + "repository_url": "https://hub-ci.huggingface.co" + }, + "subpath": null + }, + "expected_output": "pkg:huggingface/microsoft/deberta-v3-base@559062ad13d311b87b2c455e67dcd5f1c8f65111?repository_url=https://hub-ci.huggingface.co", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Hugging Face model with various cases. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:huggingface/EleutherAI/gpt-neo-1.3B@797174552AE47F449AB70B684CABCB6603E5E85E", + "expected_output": "pkg:huggingface/EleutherAI/gpt-neo-1.3B@797174552ae47f449ab70b684cabcb6603e5e85e", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Hugging Face model with various cases", + "test_group": "base", + "test_type": "parse", + "input": "pkg:huggingface/EleutherAI/gpt-neo-1.3B@797174552AE47F449AB70B684CABCB6603E5E85E", + "expected_output": { + "type": "huggingface", + "namespace": "EleutherAI", + "name": "gpt-neo-1.3B", + "version": "797174552ae47f449ab70b684cabcb6603e5e85e", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Hugging Face model with various cases. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:huggingface/EleutherAI/gpt-neo-1.3B@797174552ae47f449ab70b684cabcb6603e5e85e", + "expected_output": "pkg:huggingface/EleutherAI/gpt-neo-1.3B@797174552ae47f449ab70b684cabcb6603e5e85e", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Hugging Face model with various cases", + "test_group": "base", + "test_type": "build", + "input": { + "type": "huggingface", + "namespace": "EleutherAI", + "name": "gpt-neo-1.3B", + "version": "797174552ae47f449ab70b684cabcb6603e5e85e", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:huggingface/EleutherAI/gpt-neo-1.3B@797174552ae47f449ab70b684cabcb6603e5e85e", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:huggingface/distilbert-base-uncased@043235d6088ecd3dd5fb5ca3592b6913fd516027", + "expected_output": { + "type": "huggingface", + "namespace": null, + "name": "distilbert-base-uncased", + "version": "043235d6088ecd3dd5fb5ca3592b6913fd516027", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:huggingface/distilbert-base-uncased@043235d6088ecd3dd5fb5ca3592b6913fd516027", + "expected_output": "pkg:huggingface/distilbert-base-uncased@043235d6088ecd3dd5fb5ca3592b6913fd516027", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "huggingface", + "namespace": null, + "name": "distilbert-base-uncased", + "version": "043235d6088ecd3dd5fb5ca3592b6913fd516027", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:huggingface/distilbert-base-uncased@043235d6088ecd3dd5fb5ca3592b6913fd516027", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:huggingface/microsoft/deberta-v3-base@559062ad13d311b87b2c455e67dcd5f1c8f65111?repository_url=https://hub-ci.huggingface.co", + "expected_output": { + "type": "huggingface", + "namespace": "microsoft", + "name": "deberta-v3-base", + "version": "559062ad13d311b87b2c455e67dcd5f1c8f65111", + "qualifiers": { + "repository_url": "https://hub-ci.huggingface.co" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:huggingface/microsoft/deberta-v3-base@559062ad13d311b87b2c455e67dcd5f1c8f65111?repository_url=https://hub-ci.huggingface.co", + "expected_output": "pkg:huggingface/microsoft/deberta-v3-base@559062ad13d311b87b2c455e67dcd5f1c8f65111?repository_url=https://hub-ci.huggingface.co", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "huggingface", + "namespace": "microsoft", + "name": "deberta-v3-base", + "version": "559062ad13d311b87b2c455e67dcd5f1c8f65111", + "qualifiers": { + "repository_url": "https://hub-ci.huggingface.co" + }, + "subpath": null + }, + "expected_output": "pkg:huggingface/microsoft/deberta-v3-base@559062ad13d311b87b2c455e67dcd5f1c8f65111?repository_url=https://hub-ci.huggingface.co", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/luarocks-test.json b/tests/types/luarocks-test.json new file mode 100644 index 00000000..a822563f --- /dev/null +++ b/tests/types/luarocks-test.json @@ -0,0 +1,132 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:luarocks/luasocket@3.1.0-1", + "expected_output": { + "type": "luarocks", + "namespace": null, + "name": "luasocket", + "version": "3.1.0-1", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:luarocks/luasocket@3.1.0-1", + "expected_output": "pkg:luarocks/luasocket@3.1.0-1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "luarocks", + "namespace": null, + "name": "luasocket", + "version": "3.1.0-1", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:luarocks/luasocket@3.1.0-1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:luarocks/hisham/luafilesystem@1.8.0-1", + "expected_output": { + "type": "luarocks", + "namespace": "hisham", + "name": "luafilesystem", + "version": "1.8.0-1", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:luarocks/hisham/luafilesystem@1.8.0-1", + "expected_output": "pkg:luarocks/hisham/luafilesystem@1.8.0-1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "luarocks", + "namespace": "hisham", + "name": "luafilesystem", + "version": "1.8.0-1", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:luarocks/hisham/luafilesystem@1.8.0-1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:luarocks/username/packagename@0.1.0-1?repository_url=https://example.com/private_rocks_server/", + "expected_output": { + "type": "luarocks", + "namespace": "username", + "name": "packagename", + "version": "0.1.0-1", + "qualifiers": { + "repository_url": "https://example.com/private_rocks_server/" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:luarocks/username/packagename@0.1.0-1?repository_url=https://example.com/private_rocks_server/", + "expected_output": "pkg:luarocks/username/packagename@0.1.0-1?repository_url=https://example.com/private_rocks_server/", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "luarocks", + "namespace": "username", + "name": "packagename", + "version": "0.1.0-1", + "qualifiers": { + "repository_url": "https://example.com/private_rocks_server/" + }, + "subpath": null + }, + "expected_output": "pkg:luarocks/username/packagename@0.1.0-1?repository_url=https://example.com/private_rocks_server/", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/maven-test.json b/tests/types/maven-test.json new file mode 100644 index 00000000..e8ad9f64 --- /dev/null +++ b/tests/types/maven-test.json @@ -0,0 +1,903 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "valid maven purl. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:maven/org.apache.commons/io@1.3.4", + "expected_output": "pkg:maven/org.apache.commons/io@1.3.4", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid maven purl", + "test_group": "base", + "test_type": "parse", + "input": "pkg:maven/org.apache.commons/io@1.3.4", + "expected_output": { + "type": "maven", + "namespace": "org.apache.commons", + "name": "io", + "version": "1.3.4", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid maven purl. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:maven/org.apache.commons/io@1.3.4", + "expected_output": "pkg:maven/org.apache.commons/io@1.3.4", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid maven purl", + "test_group": "base", + "test_type": "build", + "input": { + "type": "maven", + "namespace": "org.apache.commons", + "name": "io", + "version": "1.3.4", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:maven/org.apache.commons/io@1.3.4", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "basic valid maven purl without version. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:maven/org.apache.commons/io", + "expected_output": "pkg:maven/org.apache.commons/io", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "basic valid maven purl without version", + "test_group": "base", + "test_type": "parse", + "input": "pkg:maven/org.apache.commons/io", + "expected_output": { + "type": "maven", + "namespace": "org.apache.commons", + "name": "io", + "version": null, + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "basic valid maven purl without version. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:maven/org.apache.commons/io", + "expected_output": "pkg:maven/org.apache.commons/io", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "basic valid maven purl without version", + "test_group": "base", + "test_type": "build", + "input": { + "type": "maven", + "namespace": "org.apache.commons", + "name": "io", + "version": null, + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:maven/org.apache.commons/io", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "maven often uses qualifiers. Rountrip an input purl to canonical using mixedcase type", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:Maven/org.apache.xmlgraphics/batik-anim@1.9.1?classifier=sources&repositorY_url=https://repo.spring.io/release", + "expected_output": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?classifier=sources&repository_url=https://repo.spring.io/release", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "maven often uses qualifiers here mixedcase type", + "test_group": "advanced", + "test_type": "parse", + "input": "pkg:Maven/org.apache.xmlgraphics/batik-anim@1.9.1?classifier=sources&repositorY_url=https://repo.spring.io/release", + "expected_output": { + "type": "maven", + "namespace": "org.apache.xmlgraphics", + "name": "batik-anim", + "version": "1.9.1", + "qualifiers": { + "classifier": "sources", + "repository_url": "https://repo.spring.io/release" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "maven often uses qualifiers. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?classifier=sources&repository_url=repo.spring.io/release", + "expected_output": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?classifier=sources&repository_url=repo.spring.io/release", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "maven often uses qualifiers", + "test_group": "base", + "test_type": "build", + "input": { + "type": "maven", + "namespace": "org.apache.xmlgraphics", + "name": "batik-anim", + "version": "1.9.1", + "qualifiers": { + "classifier": "sources", + "repository_url": "repo.spring.io/release" + }, + "subpath": null + }, + "expected_output": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?classifier=sources&repository_url=repo.spring.io/release", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "maven pom reference. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:Maven/org.apache.xmlgraphics/batik-anim@1.9.1?type=pom&repositorY_url=repo.spring.io/release", + "expected_output": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?repository_url=repo.spring.io/release&type=pom", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "maven pom reference", + "test_group": "base", + "test_type": "parse", + "input": "pkg:Maven/org.apache.xmlgraphics/batik-anim@1.9.1?type=pom&repositorY_url=repo.spring.io/release", + "expected_output": { + "type": "maven", + "namespace": "org.apache.xmlgraphics", + "name": "batik-anim", + "version": "1.9.1", + "qualifiers": { + "type": "pom", + "repository_url": "repo.spring.io/release" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "maven pom reference. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?type=war&repository_url=https://repo.spring.io/release", + "expected_output": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?repository_url=https://repo.spring.io/release&type=war", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "maven pom reference", + "test_group": "base", + "test_type": "build", + "input": { + "type": "maven", + "namespace": "org.apache.xmlgraphics", + "name": "batik-anim", + "version": "1.9.1", + "qualifiers": { + "classifier": "foo", + "repository_url": "repo.spring.io/release" + }, + "subpath": null + }, + "expected_output": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?classifier=foo&repository_url=repo.spring.io/release", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "maven can come with a type qualifier. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:Maven/net.sf.jacob-project/jacob@1.14.3?classifier=x86&type=dll", + "expected_output": "pkg:maven/net.sf.jacob-project/jacob@1.14.3?classifier=x86&type=dll", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "maven can come with a type qualifier", + "test_group": "base", + "test_type": "parse", + "input": "pkg:Maven/net.sf.jacob-project/jacob@1.14.3?classifier=x86&type=dll", + "expected_output": { + "type": "maven", + "namespace": "net.sf.jacob-project", + "name": "jacob", + "version": "1.14.3", + "qualifiers": { + "classifier": "x86", + "type": "dll" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "maven can come with a type qualifier. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:maven/net.sf.jacob-project/jacob@1.14.3?classifier=x86&type=dll", + "expected_output": "pkg:maven/net.sf.jacob-project/jacob@1.14.3?classifier=x86&type=dll", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "maven can come with a type qualifier", + "test_group": "base", + "test_type": "build", + "input": { + "type": "maven", + "namespace": "net.sf.jacob-project", + "name": "jacob", + "version": "1.14.3", + "qualifiers": { + "classifier": "x86", + "type": "dll" + }, + "subpath": null + }, + "expected_output": "pkg:maven/net.sf.jacob-project/jacob@1.14.3?classifier=x86&type=dll", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "a name is required", + "test_group": "base", + "test_type": "parse", + "input": "pkg:maven/@1.3.4", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid purl input" + }, + { + "description": "a name is required", + "test_group": "base", + "test_type": "parse", + "input": "pkg:maven/@1.3.4", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid canonical purl input" + }, + { + "description": "a name is required", + "test_group": "base", + "test_type": "build", + "input": { + "type": "maven", + "namespace": null, + "name": null, + "version": null, + "qualifiers": null, + "subpath": null + }, + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to build a PURL from invalid input components" + }, + { + "description": "slash / after type is not significant. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:/maven/org.apache.commons/io", + "expected_output": "pkg:maven/org.apache.commons/io", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "slash / after type is not significant", + "test_group": "base", + "test_type": "parse", + "input": "pkg:/maven/org.apache.commons/io", + "expected_output": { + "type": "maven", + "namespace": "org.apache.commons", + "name": "io", + "version": null, + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "slash / after type is not significant. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:maven/org.apache.commons/io", + "expected_output": "pkg:maven/org.apache.commons/io", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "slash / after type is not significant", + "test_group": "base", + "test_type": "build", + "input": { + "type": "maven", + "namespace": "org.apache.commons", + "name": "io", + "version": null, + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:maven/org.apache.commons/io", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "double slash // after type is not significant. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg://maven/org.apache.commons/io", + "expected_output": "pkg:maven/org.apache.commons/io", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "double slash // after type is not significant", + "test_group": "base", + "test_type": "parse", + "input": "pkg://maven/org.apache.commons/io", + "expected_output": { + "type": "maven", + "namespace": "org.apache.commons", + "name": "io", + "version": null, + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "double slash // after type is not significant. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:maven/org.apache.commons/io", + "expected_output": "pkg:maven/org.apache.commons/io", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "double slash // after type is not significant", + "test_group": "base", + "test_type": "build", + "input": { + "type": "maven", + "namespace": "org.apache.commons", + "name": "io", + "version": null, + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:maven/org.apache.commons/io", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "slash /// after type is not significant. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:///maven/org.apache.commons/io", + "expected_output": "pkg:maven/org.apache.commons/io", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "slash /// after type is not significant", + "test_group": "base", + "test_type": "parse", + "input": "pkg:///maven/org.apache.commons/io", + "expected_output": { + "type": "maven", + "namespace": "org.apache.commons", + "name": "io", + "version": null, + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "slash /// after type is not significant. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:maven/org.apache.commons/io", + "expected_output": "pkg:maven/org.apache.commons/io", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "slash /// after type is not significant", + "test_group": "base", + "test_type": "build", + "input": { + "type": "maven", + "namespace": "org.apache.commons", + "name": "io", + "version": null, + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:maven/org.apache.commons/io", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid maven purl with case sensitive namespace and name. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:maven/HTTPClient/HTTPClient@0.3-3", + "expected_output": "pkg:maven/HTTPClient/HTTPClient@0.3-3", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid maven purl with case sensitive namespace and name", + "test_group": "base", + "test_type": "parse", + "input": "pkg:maven/HTTPClient/HTTPClient@0.3-3", + "expected_output": { + "type": "maven", + "namespace": "HTTPClient", + "name": "HTTPClient", + "version": "0.3-3", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid maven purl with case sensitive namespace and name. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:maven/HTTPClient/HTTPClient@0.3-3", + "expected_output": "pkg:maven/HTTPClient/HTTPClient@0.3-3", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid maven purl with case sensitive namespace and name", + "test_group": "base", + "test_type": "build", + "input": { + "type": "maven", + "namespace": "HTTPClient", + "name": "HTTPClient", + "version": "0.3-3", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:maven/HTTPClient/HTTPClient@0.3-3", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid maven purl containing a space in the version and qualifier. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:maven/mygroup/myartifact@1.0.0%20Final?mykey=my%20value", + "expected_output": "pkg:maven/mygroup/myartifact@1.0.0%20Final?mykey=my%20value", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid maven purl containing a space in the version and qualifier", + "test_group": "base", + "test_type": "parse", + "input": "pkg:maven/mygroup/myartifact@1.0.0%20Final?mykey=my%20value", + "expected_output": { + "type": "maven", + "namespace": "mygroup", + "name": "myartifact", + "version": "1.0.0 Final", + "qualifiers": { + "mykey": "my value" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid maven purl containing a space in the version and qualifier. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:maven/mygroup/myartifact@1.0.0%20Final?mykey=my%20value", + "expected_output": "pkg:maven/mygroup/myartifact@1.0.0%20Final?mykey=my%20value", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid maven purl containing a space in the version and qualifier", + "test_group": "base", + "test_type": "build", + "input": { + "type": "maven", + "namespace": "mygroup", + "name": "myartifact", + "version": "1.0.0 Final", + "qualifiers": { + "mykey": "my value" + }, + "subpath": null + }, + "expected_output": "pkg:maven/mygroup/myartifact@1.0.0%20Final?mykey=my%20value", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "invalid encoded colon : between scheme and type", + "test_group": "base", + "test_type": "parse", + "input": "pkg%3Amaven/org.apache.commons/io", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid purl input" + }, + { + "description": "invalid encoded colon : between scheme and type", + "test_group": "base", + "test_type": "build", + "input": { + "type": "maven", + "namespace": "org.apache.commons", + "name": "io", + "version": null, + "qualifiers": null, + "subpath": null + }, + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to build a PURL from invalid input components" + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1", + "expected_output": { + "type": "maven", + "namespace": "org.apache.xmlgraphics", + "name": "batik-anim", + "version": "1.9.1", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1", + "expected_output": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "maven", + "namespace": "org.apache.xmlgraphics", + "name": "batik-anim", + "version": "1.9.1", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?type=pom", + "expected_output": { + "type": "maven", + "namespace": "org.apache.xmlgraphics", + "name": "batik-anim", + "version": "1.9.1", + "qualifiers": { + "type": "pom" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?type=pom", + "expected_output": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?type=pom", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "maven", + "namespace": "org.apache.xmlgraphics", + "name": "batik-anim", + "version": "1.9.1", + "qualifiers": { + "type": "pom" + }, + "subpath": null + }, + "expected_output": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?type=pom", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?classifier=sources", + "expected_output": { + "type": "maven", + "namespace": "org.apache.xmlgraphics", + "name": "batik-anim", + "version": "1.9.1", + "qualifiers": { + "classifier": "sources" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?classifier=sources", + "expected_output": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?classifier=sources", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "maven", + "namespace": "org.apache.xmlgraphics", + "name": "batik-anim", + "version": "1.9.1", + "qualifiers": { + "classifier": "sources" + }, + "subpath": null + }, + "expected_output": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?classifier=sources", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?type=zip&classifier=dist", + "expected_output": { + "type": "maven", + "namespace": "org.apache.xmlgraphics", + "name": "batik-anim", + "version": "1.9.1", + "qualifiers": { + "classifier": "dist", + "type": "zip" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?type=zip&classifier=dist", + "expected_output": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?type=zip&classifier=dist", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "maven", + "namespace": "org.apache.xmlgraphics", + "name": "batik-anim", + "version": "1.9.1", + "qualifiers": { + "classifier": "dist", + "type": "zip" + }, + "subpath": null + }, + "expected_output": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?type=zip&classifier=dist", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:maven/net.sf.jacob-projec/jacob@1.14.3?classifier=x86&type=dll", + "expected_output": { + "type": "maven", + "namespace": "net.sf.jacob-projec", + "name": "jacob", + "version": "1.14.3", + "qualifiers": { + "classifier": "x86", + "type": "dll" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:maven/net.sf.jacob-projec/jacob@1.14.3?classifier=x86&type=dll", + "expected_output": "pkg:maven/net.sf.jacob-projec/jacob@1.14.3?classifier=x86&type=dll", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "maven", + "namespace": "net.sf.jacob-projec", + "name": "jacob", + "version": "1.14.3", + "qualifiers": { + "classifier": "x86", + "type": "dll" + }, + "subpath": null + }, + "expected_output": "pkg:maven/net.sf.jacob-projec/jacob@1.14.3?classifier=x86&type=dll", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:maven/net.sf.jacob-projec/jacob@1.14.3?classifier=x64&type=dll", + "expected_output": { + "type": "maven", + "namespace": "net.sf.jacob-projec", + "name": "jacob", + "version": "1.14.3", + "qualifiers": { + "classifier": "x64", + "type": "dll" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:maven/net.sf.jacob-projec/jacob@1.14.3?classifier=x64&type=dll", + "expected_output": "pkg:maven/net.sf.jacob-projec/jacob@1.14.3?classifier=x64&type=dll", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "maven", + "namespace": "net.sf.jacob-projec", + "name": "jacob", + "version": "1.14.3", + "qualifiers": { + "classifier": "x64", + "type": "dll" + }, + "subpath": null + }, + "expected_output": "pkg:maven/net.sf.jacob-projec/jacob@1.14.3?classifier=x64&type=dll", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:maven/groovy/groovy@1.0?repository_url=https://maven.google.com", + "expected_output": { + "type": "maven", + "namespace": "groovy", + "name": "groovy", + "version": "1.0", + "qualifiers": { + "repository_url": "https://maven.google.com" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:maven/groovy/groovy@1.0?repository_url=https://maven.google.com", + "expected_output": "pkg:maven/groovy/groovy@1.0?repository_url=https://maven.google.com", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "maven", + "namespace": "groovy", + "name": "groovy", + "version": "1.0", + "qualifiers": { + "repository_url": "https://maven.google.com" + }, + "subpath": null + }, + "expected_output": "pkg:maven/groovy/groovy@1.0?repository_url=https://maven.google.com", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/mlflow-test.json b/tests/types/mlflow-test.json new file mode 100644 index 00000000..71f51708 --- /dev/null +++ b/tests/types/mlflow-test.json @@ -0,0 +1,265 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "MLflow model tracked in Azure Databricks (case insensitive). Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:mlflow/CreditFraud@3?repository_url=https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow", + "expected_output": "pkg:mlflow/creditfraud@3?repository_url=https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "MLflow model tracked in Azure Databricks (case insensitive)", + "test_group": "base", + "test_type": "parse", + "input": "pkg:mlflow/CreditFraud@3?repository_url=https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow", + "expected_output": { + "type": "mlflow", + "namespace": null, + "name": "creditfraud", + "version": "3", + "qualifiers": { + "repository_url": "https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "MLflow model tracked in Azure Databricks (case insensitive). Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:mlflow/creditfraud@3?repository_url=https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow", + "expected_output": "pkg:mlflow/creditfraud@3?repository_url=https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "MLflow model tracked in Azure Databricks (case insensitive)", + "test_group": "base", + "test_type": "build", + "input": { + "type": "mlflow", + "namespace": null, + "name": "creditfraud", + "version": "3", + "qualifiers": { + "repository_url": "https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow" + }, + "subpath": null + }, + "expected_output": "pkg:mlflow/creditfraud@3?repository_url=https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "MLflow model tracked in Azure ML (case sensitive). Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:mlflow/CreditFraud@3?repository_url=https://westus2.api.azureml.ms/mlflow/v1.0/subscriptions/a50f2011-fab8-4164-af23-c62881ef8c95/resourceGroups/TestResourceGroup/providers/Microsoft.MachineLearningServices/workspaces/TestWorkspace", + "expected_output": "pkg:mlflow/CreditFraud@3?repository_url=https://westus2.api.azureml.ms/mlflow/v1.0/subscriptions/a50f2011-fab8-4164-af23-c62881ef8c95/resourceGroups/TestResourceGroup/providers/Microsoft.MachineLearningServices/workspaces/TestWorkspace", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "MLflow model tracked in Azure ML (case sensitive)", + "test_group": "base", + "test_type": "parse", + "input": "pkg:mlflow/CreditFraud@3?repository_url=https://westus2.api.azureml.ms/mlflow/v1.0/subscriptions/a50f2011-fab8-4164-af23-c62881ef8c95/resourceGroups/TestResourceGroup/providers/Microsoft.MachineLearningServices/workspaces/TestWorkspace", + "expected_output": { + "type": "mlflow", + "namespace": null, + "name": "CreditFraud", + "version": "3", + "qualifiers": { + "repository_url": "https://westus2.api.azureml.ms/mlflow/v1.0/subscriptions/a50f2011-fab8-4164-af23-c62881ef8c95/resourceGroups/TestResourceGroup/providers/Microsoft.MachineLearningServices/workspaces/TestWorkspace" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "MLflow model tracked in Azure ML (case sensitive). Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:mlflow/CreditFraud@3?repository_url=https://westus2.api.azureml.ms/mlflow/v1.0/subscriptions/a50f2011-fab8-4164-af23-c62881ef8c95/resourceGroups/TestResourceGroup/providers/Microsoft.MachineLearningServices/workspaces/TestWorkspace", + "expected_output": "pkg:mlflow/CreditFraud@3?repository_url=https://westus2.api.azureml.ms/mlflow/v1.0/subscriptions/a50f2011-fab8-4164-af23-c62881ef8c95/resourceGroups/TestResourceGroup/providers/Microsoft.MachineLearningServices/workspaces/TestWorkspace", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "MLflow model tracked in Azure ML (case sensitive)", + "test_group": "base", + "test_type": "build", + "input": { + "type": "mlflow", + "namespace": null, + "name": "CreditFraud", + "version": "3", + "qualifiers": { + "repository_url": "https://westus2.api.azureml.ms/mlflow/v1.0/subscriptions/a50f2011-fab8-4164-af23-c62881ef8c95/resourceGroups/TestResourceGroup/providers/Microsoft.MachineLearningServices/workspaces/TestWorkspace" + }, + "subpath": null + }, + "expected_output": "pkg:mlflow/CreditFraud@3?repository_url=https://westus2.api.azureml.ms/mlflow/v1.0/subscriptions/a50f2011-fab8-4164-af23-c62881ef8c95/resourceGroups/TestResourceGroup/providers/Microsoft.MachineLearningServices/workspaces/TestWorkspace", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "MLflow model with unique identifiers. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:mlflow/trafficsigns@10?model_uuid=36233173b22f4c89b451f1228d700d49&run_id=410a3121-2709-4f88-98dd-dba0ef056b0a&repository_url=https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow", + "expected_output": "pkg:mlflow/trafficsigns@10?model_uuid=36233173b22f4c89b451f1228d700d49&repository_url=https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow&run_id=410a3121-2709-4f88-98dd-dba0ef056b0a", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "MLflow model with unique identifiers", + "test_group": "base", + "test_type": "parse", + "input": "pkg:mlflow/trafficsigns@10?model_uuid=36233173b22f4c89b451f1228d700d49&run_id=410a3121-2709-4f88-98dd-dba0ef056b0a&repository_url=https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow", + "expected_output": { + "type": "mlflow", + "namespace": null, + "name": "trafficsigns", + "version": "10", + "qualifiers": { + "model_uuid": "36233173b22f4c89b451f1228d700d49", + "run_id": "410a3121-2709-4f88-98dd-dba0ef056b0a", + "repository_url": "https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "MLflow model with unique identifiers. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:mlflow/trafficsigns@10?model_uuid=36233173b22f4c89b451f1228d700d49&repository_url=https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow&run_id=410a3121-2709-4f88-98dd-dba0ef056b0a", + "expected_output": "pkg:mlflow/trafficsigns@10?model_uuid=36233173b22f4c89b451f1228d700d49&repository_url=https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow&run_id=410a3121-2709-4f88-98dd-dba0ef056b0a", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "MLflow model with unique identifiers", + "test_group": "base", + "test_type": "build", + "input": { + "type": "mlflow", + "namespace": null, + "name": "trafficsigns", + "version": "10", + "qualifiers": { + "model_uuid": "36233173b22f4c89b451f1228d700d49", + "run_id": "410a3121-2709-4f88-98dd-dba0ef056b0a", + "repository_url": "https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow" + }, + "subpath": null + }, + "expected_output": "pkg:mlflow/trafficsigns@10?model_uuid=36233173b22f4c89b451f1228d700d49&repository_url=https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow&run_id=410a3121-2709-4f88-98dd-dba0ef056b0a", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:mlflow/creditfraud@3?repository_url=https://westus2.api.azureml.ms/mlflow/v1.0/subscriptions/a50f2011-fab8-4164-af23-c62881ef8c95/resourceGroups/TestResourceGroup/providers/Microsoft.MachineLearningServices/workspaces/TestWorkspace", + "expected_output": { + "type": "mlflow", + "namespace": null, + "name": "creditfraud", + "version": "3", + "qualifiers": { + "repository_url": "https://westus2.api.azureml.ms/mlflow/v1.0/subscriptions/a50f2011-fab8-4164-af23-c62881ef8c95/resourceGroups/TestResourceGroup/providers/Microsoft.MachineLearningServices/workspaces/TestWorkspace" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:mlflow/creditfraud@3?repository_url=https://westus2.api.azureml.ms/mlflow/v1.0/subscriptions/a50f2011-fab8-4164-af23-c62881ef8c95/resourceGroups/TestResourceGroup/providers/Microsoft.MachineLearningServices/workspaces/TestWorkspace", + "expected_output": "pkg:mlflow/creditfraud@3?repository_url=https://westus2.api.azureml.ms/mlflow/v1.0/subscriptions/a50f2011-fab8-4164-af23-c62881ef8c95/resourceGroups/TestResourceGroup/providers/Microsoft.MachineLearningServices/workspaces/TestWorkspace", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "mlflow", + "namespace": null, + "name": "creditfraud", + "version": "3", + "qualifiers": { + "repository_url": "https://westus2.api.azureml.ms/mlflow/v1.0/subscriptions/a50f2011-fab8-4164-af23-c62881ef8c95/resourceGroups/TestResourceGroup/providers/Microsoft.MachineLearningServices/workspaces/TestWorkspace" + }, + "subpath": null + }, + "expected_output": "pkg:mlflow/creditfraud@3?repository_url=https://westus2.api.azureml.ms/mlflow/v1.0/subscriptions/a50f2011-fab8-4164-af23-c62881ef8c95/resourceGroups/TestResourceGroup/providers/Microsoft.MachineLearningServices/workspaces/TestWorkspace", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:mlflow/trafficsigns@10?model_uuid=36233173b22f4c89b451f1228d700d49&run_id=410a3121-2709-4f88-98dd-dba0ef056b0a&repository_url=https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow", + "expected_output": { + "type": "mlflow", + "namespace": null, + "name": "trafficsigns", + "version": "10", + "qualifiers": { + "model_uuid": "36233173b22f4c89b451f1228d700d49", + "repository_url": "https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow", + "run_id": "410a3121-2709-4f88-98dd-dba0ef056b0a" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:mlflow/trafficsigns@10?model_uuid=36233173b22f4c89b451f1228d700d49&run_id=410a3121-2709-4f88-98dd-dba0ef056b0a&repository_url=https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow", + "expected_output": "pkg:mlflow/trafficsigns@10?model_uuid=36233173b22f4c89b451f1228d700d49&run_id=410a3121-2709-4f88-98dd-dba0ef056b0a&repository_url=https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "mlflow", + "namespace": null, + "name": "trafficsigns", + "version": "10", + "qualifiers": { + "model_uuid": "36233173b22f4c89b451f1228d700d49", + "repository_url": "https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow", + "run_id": "410a3121-2709-4f88-98dd-dba0ef056b0a" + }, + "subpath": null + }, + "expected_output": "pkg:mlflow/trafficsigns@10?model_uuid=36233173b22f4c89b451f1228d700d49&run_id=410a3121-2709-4f88-98dd-dba0ef056b0a&repository_url=https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/npm-test.json b/tests/types/npm-test.json new file mode 100644 index 00000000..7167f42d --- /dev/null +++ b/tests/types/npm-test.json @@ -0,0 +1,259 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "npm can be scoped. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:npm/%40angular/animation@12.3.1", + "expected_output": "pkg:npm/%40angular/animation@12.3.1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "npm can be scoped", + "test_group": "base", + "test_type": "parse", + "input": "pkg:npm/%40angular/animation@12.3.1", + "expected_output": { + "type": "npm", + "namespace": "@angular", + "name": "animation", + "version": "12.3.1", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "npm can be scoped. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:npm/%40angular/animation@12.3.1", + "expected_output": "pkg:npm/%40angular/animation@12.3.1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "npm can be scoped", + "test_group": "base", + "test_type": "build", + "input": { + "type": "npm", + "namespace": "@angular", + "name": "animation", + "version": "12.3.1", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:npm/%40angular/animation@12.3.1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "checks for invalid qualifier keys", + "test_group": "base", + "test_type": "parse", + "input": "pkg:npm/myartifact@1.0.0?in%20production=true", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid purl input" + }, + { + "description": "checks for invalid qualifier keys", + "test_group": "base", + "test_type": "build", + "input": { + "type": "npm", + "namespace": null, + "name": "myartifact", + "version": "1.0.0", + "qualifiers": { + "in production": "true" + }, + "subpath": null + }, + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to build a PURL from invalid input components" + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:npm/foobar@12.3.1", + "expected_output": { + "type": "npm", + "namespace": null, + "name": "foobar", + "version": "12.3.1", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:npm/foobar@12.3.1", + "expected_output": "pkg:npm/foobar@12.3.1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "npm", + "namespace": null, + "name": "foobar", + "version": "12.3.1", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:npm/foobar@12.3.1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:npm/%40angular/animation@12.3.1", + "expected_output": { + "type": "npm", + "namespace": "@angular", + "name": "animation", + "version": "12.3.1", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:npm/%40angular/animation@12.3.1", + "expected_output": "pkg:npm/%40angular/animation@12.3.1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "npm", + "namespace": "@angular", + "name": "animation", + "version": "12.3.1", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:npm/%40angular/animation@12.3.1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:npm/mypackage@12.4.5?vcs_url=git://host.com/path/to/repo.git%404345abcd34343", + "expected_output": { + "type": "npm", + "namespace": null, + "name": "mypackage", + "version": "12.4.5", + "qualifiers": { + "vcs_url": "git://host.com/path/to/repo.git@4345abcd34343" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:npm/mypackage@12.4.5?vcs_url=git://host.com/path/to/repo.git%404345abcd34343", + "expected_output": "pkg:npm/mypackage@12.4.5?vcs_url=git://host.com/path/to/repo.git%404345abcd34343", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "npm", + "namespace": null, + "name": "mypackage", + "version": "12.4.5", + "qualifiers": { + "vcs_url": "git://host.com/path/to/repo.git@4345abcd34343" + }, + "subpath": null + }, + "expected_output": "pkg:npm/mypackage@12.4.5?vcs_url=git://host.com/path/to/repo.git%404345abcd34343", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid npm purl without version and with subpath, scope unencoded", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:npm/@babel/core#/googleapis/api/annotations/", + "expected_output": "pkg:npm/%40babel/core#googleapis/api/annotations", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid npm purl without version and with subpath, scope unencoded", + "test_group": "advanced", + "test_type": "parse", + "input": "pkg:npm/@babel/core#/googleapis/api/annotations/", + "expected_output": { + "type": "npm", + "namespace": "@babel", + "name": "core", + "version": null, + "qualifiers": null, + "subpath": "googleapis/api/annotations" + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid npm purl without version and with subpath, scope unencoded", + "test_group": "base", + "test_type": "parse", + "input": "pkg:npm/%40babel/core#/googleapis/api/annotations/", + "expected_output": { + "type": "npm", + "namespace": "@babel", + "name": "core", + "version": null, + "qualifiers": null, + "subpath": "googleapis/api/annotations" + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid npm purl without namespace and with subpath", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:npm/core@2.0.1#/googleapis/api/annotations/", + "expected_output": "pkg:npm/core@2.0.1#googleapis/api/annotations", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/nuget-test.json b/tests/types/nuget-test.json new file mode 100644 index 00000000..67d97916 --- /dev/null +++ b/tests/types/nuget-test.json @@ -0,0 +1,96 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "nuget names are case sensitive. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:Nuget/EnterpriseLibrary.Common@6.0.1304", + "expected_output": "pkg:nuget/EnterpriseLibrary.Common@6.0.1304", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "nuget names are case sensitive", + "test_group": "base", + "test_type": "parse", + "input": "pkg:Nuget/EnterpriseLibrary.Common@6.0.1304", + "expected_output": { + "type": "nuget", + "namespace": null, + "name": "EnterpriseLibrary.Common", + "version": "6.0.1304", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "nuget names are case sensitive. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:nuget/EnterpriseLibrary.Common@6.0.1304", + "expected_output": "pkg:nuget/EnterpriseLibrary.Common@6.0.1304", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "nuget names are case sensitive", + "test_group": "base", + "test_type": "build", + "input": { + "type": "nuget", + "namespace": null, + "name": "EnterpriseLibrary.Common", + "version": "6.0.1304", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:nuget/EnterpriseLibrary.Common@6.0.1304", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:nuget/EnterpriseLibrary.Common@6.0.1304", + "expected_output": { + "type": "nuget", + "namespace": null, + "name": "EnterpriseLibrary.Common", + "version": "6.0.1304", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:nuget/EnterpriseLibrary.Common@6.0.1304", + "expected_output": "pkg:nuget/EnterpriseLibrary.Common@6.0.1304", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "nuget", + "namespace": null, + "name": "EnterpriseLibrary.Common", + "version": "6.0.1304", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:nuget/EnterpriseLibrary.Common@6.0.1304", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/oci-test.json b/tests/types/oci-test.json new file mode 100644 index 00000000..ccf8332c --- /dev/null +++ b/tests/types/oci-test.json @@ -0,0 +1,193 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:oci/debian@sha256%3A244fd47e07d10?repository_url=docker.io/library/debian&arch=amd64&tag=latest", + "expected_output": { + "type": "oci", + "namespace": null, + "name": "debian", + "version": "sha256:244fd47e07d10", + "qualifiers": { + "arch": "amd64", + "repository_url": "docker.io/library/debian", + "tag": "latest" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:oci/debian@sha256%3A244fd47e07d10?repository_url=docker.io/library/debian&arch=amd64&tag=latest", + "expected_output": "pkg:oci/debian@sha256%3A244fd47e07d10?repository_url=docker.io/library/debian&arch=amd64&tag=latest", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "oci", + "namespace": null, + "name": "debian", + "version": "sha256:244fd47e07d10", + "qualifiers": { + "arch": "amd64", + "repository_url": "docker.io/library/debian", + "tag": "latest" + }, + "subpath": null + }, + "expected_output": "pkg:oci/debian@sha256%3A244fd47e07d10?repository_url=docker.io/library/debian&arch=amd64&tag=latest", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:oci/debian@sha256%3A244fd47e07d10?repository_url=ghcr.io/debian&tag=bullseye", + "expected_output": { + "type": "oci", + "namespace": null, + "name": "debian", + "version": "sha256:244fd47e07d10", + "qualifiers": { + "repository_url": "ghcr.io/debian", + "tag": "bullseye" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:oci/debian@sha256%3A244fd47e07d10?repository_url=ghcr.io/debian&tag=bullseye", + "expected_output": "pkg:oci/debian@sha256%3A244fd47e07d10?repository_url=ghcr.io/debian&tag=bullseye", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "oci", + "namespace": null, + "name": "debian", + "version": "sha256:244fd47e07d10", + "qualifiers": { + "repository_url": "ghcr.io/debian", + "tag": "bullseye" + }, + "subpath": null + }, + "expected_output": "pkg:oci/debian@sha256%3A244fd47e07d10?repository_url=ghcr.io/debian&tag=bullseye", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:oci/static@sha256%3A244fd47e07d10?repository_url=gcr.io/distroless/static&tag=latest", + "expected_output": { + "type": "oci", + "namespace": null, + "name": "static", + "version": "sha256:244fd47e07d10", + "qualifiers": { + "repository_url": "gcr.io/distroless/static", + "tag": "latest" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:oci/static@sha256%3A244fd47e07d10?repository_url=gcr.io/distroless/static&tag=latest", + "expected_output": "pkg:oci/static@sha256%3A244fd47e07d10?repository_url=gcr.io/distroless/static&tag=latest", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "oci", + "namespace": null, + "name": "static", + "version": "sha256:244fd47e07d10", + "qualifiers": { + "repository_url": "gcr.io/distroless/static", + "tag": "latest" + }, + "subpath": null + }, + "expected_output": "pkg:oci/static@sha256%3A244fd47e07d10?repository_url=gcr.io/distroless/static&tag=latest", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:oci/hello-wasm@sha256%3A244fd47e07d10?tag=v1", + "expected_output": { + "type": "oci", + "namespace": null, + "name": "hello-wasm", + "version": "sha256:244fd47e07d10", + "qualifiers": { + "tag": "v1" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:oci/hello-wasm@sha256%3A244fd47e07d10?tag=v1", + "expected_output": "pkg:oci/hello-wasm@sha256%3A244fd47e07d10?tag=v1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "oci", + "namespace": null, + "name": "hello-wasm", + "version": "sha256:244fd47e07d10", + "qualifiers": { + "tag": "v1" + }, + "subpath": null + }, + "expected_output": "pkg:oci/hello-wasm@sha256%3A244fd47e07d10?tag=v1", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/pub-test.json b/tests/types/pub-test.json new file mode 100644 index 00000000..ef8daf24 --- /dev/null +++ b/tests/types/pub-test.json @@ -0,0 +1,87 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:pub/characters@1.2.0", + "expected_output": { + "type": "pub", + "namespace": null, + "name": "characters", + "version": "1.2.0", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:pub/characters@1.2.0", + "expected_output": "pkg:pub/characters@1.2.0", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "pub", + "namespace": null, + "name": "characters", + "version": "1.2.0", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:pub/characters@1.2.0", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:pub/flutter@0.0.0", + "expected_output": { + "type": "pub", + "namespace": null, + "name": "flutter", + "version": "0.0.0", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:pub/flutter@0.0.0", + "expected_output": "pkg:pub/flutter@0.0.0", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "pub", + "namespace": null, + "name": "flutter", + "version": "0.0.0", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:pub/flutter@0.0.0", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/pypi-test.json b/tests/types/pypi-test.json new file mode 100644 index 00000000..23eb979d --- /dev/null +++ b/tests/types/pypi-test.json @@ -0,0 +1,227 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "pypi names have special rules and not case sensitive. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:PYPI/Django_package@1.11.1.dev1", + "expected_output": "pkg:pypi/django-package@1.11.1.dev1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "pypi names have special rules and not case sensitive", + "test_group": "base", + "test_type": "parse", + "input": "pkg:PYPI/Django_package@1.11.1.dev1", + "expected_output": { + "type": "pypi", + "namespace": null, + "name": "django-package", + "version": "1.11.1.dev1", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "pypi names have special rules and not case sensitive. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:pypi/django-package@1.11.1.dev1", + "expected_output": "pkg:pypi/django-package@1.11.1.dev1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "pypi names have special rules and not case sensitive", + "test_group": "base", + "test_type": "build", + "input": { + "type": "pypi", + "namespace": null, + "name": "django-package", + "version": "1.11.1.dev1", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:pypi/django-package@1.11.1.dev1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:pypi/django@1.11.1", + "expected_output": { + "type": "pypi", + "namespace": null, + "name": "django", + "version": "1.11.1", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:pypi/django@1.11.1", + "expected_output": "pkg:pypi/django@1.11.1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "pypi", + "namespace": null, + "name": "django", + "version": "1.11.1", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:pypi/django@1.11.1", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:pypi/django@1.11.1?filename=Django-1.11.1.tar.gz", + "expected_output": { + "type": "pypi", + "namespace": null, + "name": "django", + "version": "1.11.1", + "qualifiers": { + "filename": "Django-1.11.1.tar.gz" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:pypi/django@1.11.1?filename=Django-1.11.1.tar.gz", + "expected_output": "pkg:pypi/django@1.11.1?filename=Django-1.11.1.tar.gz", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "pypi", + "namespace": null, + "name": "django", + "version": "1.11.1", + "qualifiers": { + "filename": "Django-1.11.1.tar.gz" + }, + "subpath": null + }, + "expected_output": "pkg:pypi/django@1.11.1?filename=Django-1.11.1.tar.gz", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:pypi/django@1.11.1?filename=Django-1.11.1-py2.py3-none-any.whl", + "expected_output": { + "type": "pypi", + "namespace": null, + "name": "django", + "version": "1.11.1", + "qualifiers": { + "filename": "Django-1.11.1-py2.py3-none-any.whl" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:pypi/django@1.11.1?filename=Django-1.11.1-py2.py3-none-any.whl", + "expected_output": "pkg:pypi/django@1.11.1?filename=Django-1.11.1-py2.py3-none-any.whl", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "pypi", + "namespace": null, + "name": "django", + "version": "1.11.1", + "qualifiers": { + "filename": "Django-1.11.1-py2.py3-none-any.whl" + }, + "subpath": null + }, + "expected_output": "pkg:pypi/django@1.11.1?filename=Django-1.11.1-py2.py3-none-any.whl", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:pypi/django-allauth@12.23", + "expected_output": { + "type": "pypi", + "namespace": null, + "name": "django-allauth", + "version": "12.23", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:pypi/django-allauth@12.23", + "expected_output": "pkg:pypi/django-allauth@12.23", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "pypi", + "namespace": null, + "name": "django-allauth", + "version": "12.23", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:pypi/django-allauth@12.23", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/qpkg-test.json b/tests/types/qpkg-test.json new file mode 100644 index 00000000..9450bf3d --- /dev/null +++ b/tests/types/qpkg-test.json @@ -0,0 +1,87 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:qpkg/blackberry/com.qnx.sdp@7.0.0.SGA201702151847", + "expected_output": { + "type": "qpkg", + "namespace": "blackberry", + "name": "com.qnx.sdp", + "version": "7.0.0.SGA201702151847", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:qpkg/blackberry/com.qnx.sdp@7.0.0.SGA201702151847", + "expected_output": "pkg:qpkg/blackberry/com.qnx.sdp@7.0.0.SGA201702151847", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "qpkg", + "namespace": "blackberry", + "name": "com.qnx.sdp", + "version": "7.0.0.SGA201702151847", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:qpkg/blackberry/com.qnx.sdp@7.0.0.SGA201702151847", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:qpkg/blackberry/com.qnx.qnx710.foo.bar.qux@0.0.4.01449T202205040833L", + "expected_output": { + "type": "qpkg", + "namespace": "blackberry", + "name": "com.qnx.qnx710.foo.bar.qux", + "version": "0.0.4.01449T202205040833L", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:qpkg/blackberry/com.qnx.qnx710.foo.bar.qux@0.0.4.01449T202205040833L", + "expected_output": "pkg:qpkg/blackberry/com.qnx.qnx710.foo.bar.qux@0.0.4.01449T202205040833L", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "qpkg", + "namespace": "blackberry", + "name": "com.qnx.qnx710.foo.bar.qux", + "version": "0.0.4.01449T202205040833L", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:qpkg/blackberry/com.qnx.qnx710.foo.bar.qux@0.0.4.01449T202205040833L", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/rpm-test.json b/tests/types/rpm-test.json new file mode 100644 index 00000000..8087b574 --- /dev/null +++ b/tests/types/rpm-test.json @@ -0,0 +1,157 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "rpm often use qualifiers. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:Rpm/fedora/curl@7.50.3-1.fc25?Arch=i386&Distro=fedora-25", + "expected_output": "pkg:rpm/fedora/curl@7.50.3-1.fc25?arch=i386&distro=fedora-25", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "rpm often use qualifiers", + "test_group": "base", + "test_type": "parse", + "input": "pkg:Rpm/fedora/curl@7.50.3-1.fc25?Arch=i386&Distro=fedora-25", + "expected_output": { + "type": "rpm", + "namespace": "fedora", + "name": "curl", + "version": "7.50.3-1.fc25", + "qualifiers": { + "arch": "i386", + "distro": "fedora-25" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "rpm often use qualifiers. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:rpm/fedora/curl@7.50.3-1.fc25?arch=i386&distro=fedora-25", + "expected_output": "pkg:rpm/fedora/curl@7.50.3-1.fc25?arch=i386&distro=fedora-25", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "rpm often use qualifiers", + "test_group": "base", + "test_type": "build", + "input": { + "type": "rpm", + "namespace": "fedora", + "name": "curl", + "version": "7.50.3-1.fc25", + "qualifiers": { + "arch": "i386", + "distro": "fedora-25" + }, + "subpath": null + }, + "expected_output": "pkg:rpm/fedora/curl@7.50.3-1.fc25?arch=i386&distro=fedora-25", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:rpm/fedora/curl@7.50.3-1.fc25?arch=i386&distro=fedora-25", + "expected_output": { + "type": "rpm", + "namespace": "fedora", + "name": "curl", + "version": "7.50.3-1.fc25", + "qualifiers": { + "arch": "i386", + "distro": "fedora-25" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:rpm/fedora/curl@7.50.3-1.fc25?arch=i386&distro=fedora-25", + "expected_output": "pkg:rpm/fedora/curl@7.50.3-1.fc25?arch=i386&distro=fedora-25", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "rpm", + "namespace": "fedora", + "name": "curl", + "version": "7.50.3-1.fc25", + "qualifiers": { + "arch": "i386", + "distro": "fedora-25" + }, + "subpath": null + }, + "expected_output": "pkg:rpm/fedora/curl@7.50.3-1.fc25?arch=i386&distro=fedora-25", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:rpm/centerim@4.22.10-1.el6?arch=i686&epoch=1&distro=fedora-25", + "expected_output": { + "type": "rpm", + "namespace": null, + "name": "centerim", + "version": "4.22.10-1.el6", + "qualifiers": { + "arch": "i686", + "distro": "fedora-25", + "epoch": "1" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:rpm/centerim@4.22.10-1.el6?arch=i686&epoch=1&distro=fedora-25", + "expected_output": "pkg:rpm/centerim@4.22.10-1.el6?arch=i686&epoch=1&distro=fedora-25", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "rpm", + "namespace": null, + "name": "centerim", + "version": "4.22.10-1.el6", + "qualifiers": { + "arch": "i686", + "distro": "fedora-25", + "epoch": "1" + }, + "subpath": null + }, + "expected_output": "pkg:rpm/centerim@4.22.10-1.el6?arch=i686&epoch=1&distro=fedora-25", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/swid-test.json b/tests/types/swid-test.json new file mode 100644 index 00000000..dd942d83 --- /dev/null +++ b/tests/types/swid-test.json @@ -0,0 +1,140 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:swid/Acme/example.com/Enterprise+Server@1.0.0?tag_id=75b8c285-fa7b-485b-b199-4745e3004d0d", + "expected_output": { + "type": "swid", + "namespace": "Acme/example.com", + "name": "Enterprise+Server", + "version": "1.0.0", + "qualifiers": { + "tag_id": "75b8c285-fa7b-485b-b199-4745e3004d0d" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:swid/Acme/example.com/Enterprise+Server@1.0.0?tag_id=75b8c285-fa7b-485b-b199-4745e3004d0d", + "expected_output": "pkg:swid/Acme/example.com/Enterprise+Server@1.0.0?tag_id=75b8c285-fa7b-485b-b199-4745e3004d0d", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "swid", + "namespace": "Acme/example.com", + "name": "Enterprise+Server", + "version": "1.0.0", + "qualifiers": { + "tag_id": "75b8c285-fa7b-485b-b199-4745e3004d0d" + }, + "subpath": null + }, + "expected_output": "pkg:swid/Acme/example.com/Enterprise+Server@1.0.0?tag_id=75b8c285-fa7b-485b-b199-4745e3004d0d", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:swid/Fedora@29?tag_id=org.fedoraproject.Fedora-29", + "expected_output": { + "type": "swid", + "namespace": null, + "name": "Fedora", + "version": "29", + "qualifiers": { + "tag_id": "org.fedoraproject.Fedora-29" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:swid/Fedora@29?tag_id=org.fedoraproject.Fedora-29", + "expected_output": "pkg:swid/Fedora@29?tag_id=org.fedoraproject.Fedora-29", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "swid", + "namespace": null, + "name": "Fedora", + "version": "29", + "qualifiers": { + "tag_id": "org.fedoraproject.Fedora-29" + }, + "subpath": null + }, + "expected_output": "pkg:swid/Fedora@29?tag_id=org.fedoraproject.Fedora-29", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:swid/Adobe+Systems+Incorporated/Adobe+InDesign@CC?tag_id=CreativeCloud-CS6-Win-GM-MUL", + "expected_output": { + "type": "swid", + "namespace": "Adobe+Systems+Incorporated", + "name": "Adobe+InDesign", + "version": "CC", + "qualifiers": { + "tag_id": "CreativeCloud-CS6-Win-GM-MUL" + }, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:swid/Adobe+Systems+Incorporated/Adobe+InDesign@CC?tag_id=CreativeCloud-CS6-Win-GM-MUL", + "expected_output": "pkg:swid/Adobe+Systems+Incorporated/Adobe+InDesign@CC?tag_id=CreativeCloud-CS6-Win-GM-MUL", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "swid", + "namespace": "Adobe+Systems+Incorporated", + "name": "Adobe+InDesign", + "version": "CC", + "qualifiers": { + "tag_id": "CreativeCloud-CS6-Win-GM-MUL" + }, + "subpath": null + }, + "expected_output": "pkg:swid/Adobe+Systems+Incorporated/Adobe+InDesign@CC?tag_id=CreativeCloud-CS6-Win-GM-MUL", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/tests/types/swift-test.json b/tests/types/swift-test.json new file mode 100644 index 00000000..ef3d1fb1 --- /dev/null +++ b/tests/types/swift-test.json @@ -0,0 +1,239 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-test.schema-1.0.json", + "tests": [ + { + "description": "valid swift purl. Rountrip an input purl to canonical.", + "test_group": "advanced", + "test_type": "roundtrip", + "input": "pkg:swift/github.com/Alamofire/Alamofire@5.4.3", + "expected_output": "pkg:swift/github.com/Alamofire/Alamofire@5.4.3", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid swift purl", + "test_group": "base", + "test_type": "parse", + "input": "pkg:swift/github.com/Alamofire/Alamofire@5.4.3", + "expected_output": { + "type": "swift", + "namespace": "github.com/Alamofire", + "name": "Alamofire", + "version": "5.4.3", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid swift purl. Rountrip a canonical input to canonical output.", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:swift/github.com/Alamofire/Alamofire@5.4.3", + "expected_output": "pkg:swift/github.com/Alamofire/Alamofire@5.4.3", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "valid swift purl", + "test_group": "base", + "test_type": "build", + "input": { + "type": "swift", + "namespace": "github.com/Alamofire", + "name": "Alamofire", + "version": "5.4.3", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:swift/github.com/Alamofire/Alamofire@5.4.3", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "invalid swift purl without namespace", + "test_group": "base", + "test_type": "parse", + "input": "pkg:swift/Alamofire@5.4.3", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid purl input" + }, + { + "description": "invalid swift purl without namespace", + "test_group": "base", + "test_type": "parse", + "input": "pkg:swift/Alamofire@5.4.3", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid canonical purl input" + }, + { + "description": "invalid swift purl without namespace", + "test_group": "base", + "test_type": "build", + "input": { + "type": "swift", + "namespace": null, + "name": "Alamofire", + "version": "5.4.3", + "qualifiers": null, + "subpath": null + }, + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to build a PURL from invalid input components" + }, + { + "description": "invalid swift purl without name", + "test_group": "base", + "test_type": "parse", + "input": "pkg:swift/github.com/Alamofire/@5.4.3", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid purl input" + }, + { + "description": "invalid swift purl without name", + "test_group": "base", + "test_type": "parse", + "input": "pkg:swift/github.com/Alamofire/@5.4.3", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid canonical purl input" + }, + { + "description": "invalid swift purl without name", + "test_group": "base", + "test_type": "build", + "input": { + "type": "swift", + "namespace": "github.com/Alamofire", + "name": null, + "version": "5.4.3", + "qualifiers": null, + "subpath": null + }, + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to build a PURL from invalid input components" + }, + { + "description": "invalid swift purl without version", + "test_group": "base", + "test_type": "parse", + "input": "pkg:swift/github.com/Alamofire/Alamofire", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid purl input" + }, + { + "description": "invalid swift purl without version", + "test_group": "base", + "test_type": "parse", + "input": "pkg:swift/github.com/Alamofire/Alamofire", + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to parse a PURL from invalid canonical purl input" + }, + { + "description": "invalid swift purl without version", + "test_group": "base", + "test_type": "build", + "input": { + "type": "swift", + "namespace": "github.com/Alamofire", + "name": "Alamofire", + "version": null, + "qualifiers": null, + "subpath": null + }, + "expected_output": null, + "expected_failure": true, + "expected_failure_reason": "Should fail to build a PURL from invalid input components" + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:swift/github.com/Alamofire/Alamofire@5.4.3", + "expected_output": { + "type": "swift", + "namespace": "github.com/Alamofire", + "name": "Alamofire", + "version": "5.4.3", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:swift/github.com/Alamofire/Alamofire@5.4.3", + "expected_output": "pkg:swift/github.com/Alamofire/Alamofire@5.4.3", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "swift", + "namespace": "github.com/Alamofire", + "name": "Alamofire", + "version": "5.4.3", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:swift/github.com/Alamofire/Alamofire@5.4.3", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Parse test for PURL", + "test_group": "base", + "test_type": "parse", + "input": "pkg:swift/github.com/RxSwiftCommunity/RxFlow@2.12.4", + "expected_output": { + "type": "swift", + "namespace": "github.com/RxSwiftCommunity", + "name": "RxFlow", + "version": "2.12.4", + "qualifiers": null, + "subpath": null + }, + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Rountrip test for PURL", + "test_group": "base", + "test_type": "roundtrip", + "input": "pkg:swift/github.com/RxSwiftCommunity/RxFlow@2.12.4", + "expected_output": "pkg:swift/github.com/RxSwiftCommunity/RxFlow@2.12.4", + "expected_failure": false, + "expected_failure_reason": null + }, + { + "description": "Build test for PURL", + "test_group": "base", + "test_type": "build", + "input": { + "type": "swift", + "namespace": "github.com/RxSwiftCommunity", + "name": "RxFlow", + "version": "2.12.4", + "qualifiers": null, + "subpath": null + }, + "expected_output": "pkg:swift/github.com/RxSwiftCommunity/RxFlow@2.12.4", + "expected_failure": false, + "expected_failure_reason": null + } + ] +} diff --git a/types-doc/README.md b/types-doc/README.md new file mode 100644 index 00000000..3b775394 --- /dev/null +++ b/types-doc/README.md @@ -0,0 +1,10 @@ +###Auto-Generated PURL Type Documentation + +This directory contains **human-readable documentation** generated from the **reference +machine-readable JSON PURL type definitions** found in `types/`. + +**Do not manually edit these files!** + +These documents are **automatically generated** and will be **overwritten** in future updates. + +All modifications should be made in the reference JSON files located in `types/`. diff --git a/types-doc/alpm-definition.md b/types-doc/alpm-definition.md new file mode 100644 index 00000000..16e22f50 --- /dev/null +++ b/types-doc/alpm-definition.md @@ -0,0 +1,52 @@ + + +# PURL Type Definition: alpm + +- **Type Name:** Arch Linux package +- **Description:** Arch Linux packages and other users of the libalpm/pacman package manager. +- **Schema ID:** `https://packageurl.org/types/github-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:alpm//@?# + +## Repository Information + +- **Use Repository:** Yes +- **Note:** There is no default package repository; this should be implied either from the distro qualifiers key or using a repository base url as repository_url qualifiers key. + +## Namespace definition + +- **Requirement:** Required +- **Normalization rules:** + - It is not case sensitive and must be lowercased. +- **Native Label:** vendor +- **Note:** `The namespace is the vendor such as arch, arch32, archarm, manjaro or msys.` + +## Name definition + +- **Native Label:** name +- **Note:** `The name is the package name. It is not case sensitive and must be lowercased.` + +## Version definition + +- **Case Sensitive:** Yes +- **Normalization rules:** + - normalize version as specified in vercmp(8) at https://man.archlinux.org/man/vercmp.8#DESCRIPTION as part of alpm. +- **Native Label:** version +- **Note:** `The version is the version of the package as specified in vercmp(8) at (https://man.archlinux.org/man/vercmp.8#DESCRIPTION as part of alpm.` + +## Qualifiers Definition + +| Key | Requirement | Native name | Default Value | Description | +|------|-------------|-------------|---------------|-------------| +| arch | Optional | arch | | The arch is the qualifiers key for a package architecture. | + +## Examples + +- `pkg:alpm/arch/pacman@6.0.1-1?arch=x86_64` +- `pkg:alpm/arch/python-pip@21.0-1?arch=any` +- `pkg:alpm/arch/containers-common@1:0.47.4-4?arch=x86_64` diff --git a/types-doc/apk-definition.md b/types-doc/apk-definition.md new file mode 100644 index 00000000..55e4076c --- /dev/null +++ b/types-doc/apk-definition.md @@ -0,0 +1,50 @@ + + +# PURL Type Definition: apk + +- **Type Name:** APK-based packages +- **Description:** Alpine Linux APK-based packages +- **Schema ID:** `https://packageurl.org/types/bitbucket-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:apk//@?# + +## Repository Information + +- **Use Repository:** Yes +- **Note:** There is no default package repository; this should be implied either from the distro qualifiers key or using a repository base url as repository_url qualifiers key. + +## Namespace definition + +- **Requirement:** Required +- **Native Label:** vendor +- **Note:** `The namespace is the vendor such as alpine or openwrt. It is not case sensitive and must be lowercased.` + +## Name definition + +- **Native Label:** name +- **Note:** `The name is the package name. It is not case sensitive and must be lowercased.` + +## Version definition + +- **Native Label:** version +- **Note:** `The version is a package version as expected by apk.` + +## Qualifiers Definition + +| Key | Requirement | Native name | Default Value | Description | +|------|-------------|-------------|---------------|-------------| +| arch | Optional | | | The arch is the qualifiers key for a package architecture. | + +## Examples + +- `pkg:apk/alpine/curl@7.83.0-r0?arch=x86` +- `pkg:apk/alpine/apk@2.12.9-r3?arch=x86` + +## Note + +not to be confused with Android packages with a .apk extension. diff --git a/types-doc/bitbucket-definition.md b/types-doc/bitbucket-definition.md new file mode 100644 index 00000000..78ff44dc --- /dev/null +++ b/types-doc/bitbucket-definition.md @@ -0,0 +1,39 @@ + + +# PURL Type Definition: bitbucket + +- **Type Name:** Bitbucket +- **Description:** Bitbucket-based packages +- **Schema ID:** `https://packageurl.org/types/bitbucket-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:bitbucket//@?# + +## Repository Information + +- **Use Repository:** Yes +- **Default Repository URL:** https://bitbucket.org + +## Namespace definition + +- **Requirement:** Required +- **Native Label:** user or organization +- **Note:** `The namespace is the user or organization. It is not case sensitive and must be lowercased.` + +## Name definition + +- **Native Label:** repository name +- **Note:** `The name is the repository name. It is not case sensitive and must be lowercased.` + +## Version definition + +- **Native Label:** commit or tag +- **Note:** `The version is a commit or tag.` + +## Examples + +- `pkg:bitbucket/birkenfeld/pygments-main@244fd47e07d1014f0aed9c` diff --git a/types-doc/bitnami-definition.md b/types-doc/bitnami-definition.md new file mode 100644 index 00000000..9d5e3eaf --- /dev/null +++ b/types-doc/bitnami-definition.md @@ -0,0 +1,48 @@ + + +# PURL Type Definition: bitnami + +- **Type Name:** Bitnami +- **Description:** Bitnami-based packages +- **Schema ID:** `https://packageurl.org/types/bitname-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:bitnami/@?# + +## Repository Information + +- **Use Repository:** Yes +- **Default Repository URL:** https://downloads.bitnami.com/files/stacksmith + +## Namespace definition + +- **Requirement:** Prohibited +- **Note:** `there is no namespace` + +## Name definition + +- **Native Label:** name +- **Note:** `The name is the component name. It must be lowercased.` + +## Version definition + +- **Native Label:** full package version, including version and revision +- **Note:** `The version is the full Bitnami package version, including version and revision.` + +## Qualifiers Definition + +| Key | Requirement | Native name | Default Value | Description | +|------|-------------|-------------|---------------|-------------| +| arch | Optional | | amd64 | The arch is the qualifiers key for a package architecture. Available values are amd64 (default) and arm64. | +| distro | Optional | | | The distro is the qualifiers key for the distribution associated to the package. | + +## Examples + +- `pkg:bitnami/wordpress?distro=debian-12` +- `pkg:bitnami/wordpress@6.2.0?distro=debian-12` +- `pkg:bitnami/wordpress@6.2.0?arch=arm64&distro=debian-12` +- `pkg:bitnami/wordpress@6.2.0?arch=arm64&distro=photon-4` diff --git a/types-doc/cargo-definition.md b/types-doc/cargo-definition.md new file mode 100644 index 00000000..4dfc926e --- /dev/null +++ b/types-doc/cargo-definition.md @@ -0,0 +1,40 @@ + + +# PURL Type Definition: cargo + +- **Type Name:** Cargo +- **Description:** Cargo packages for Rust +- **Schema ID:** `https://packageurl.org/types/cargo-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:cargo/@?# + +## Repository Information + +- **Use Repository:** Yes +- **Default Repository URL:** https://crates.io/ + +## Namespace definition + +- **Requirement:** Prohibited +- **Note:** `there is no namespace` + +## Name definition + +- **Native Label:** name +- **Note:** `The name is the repository name.` + +## Version definition + +- **Native Label:** version +- **Note:** `The version is the package version.` + +## Examples + +- `pkg:cargo/rand@0.7.2` +- `pkg:cargo/clap@2.33.0` +- `pkg:cargo/structopt@0.3.11` diff --git a/types-doc/cocoapods-definition.md b/types-doc/cocoapods-definition.md new file mode 100644 index 00000000..8b30c26e --- /dev/null +++ b/types-doc/cocoapods-definition.md @@ -0,0 +1,46 @@ + + +# PURL Type Definition: cocoapods + +- **Type Name:** CocoaPods +- **Description:** CocoaPods pods +- **Schema ID:** `https://packageurl.org/types/cocoapods-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:cocoapods/@?# + +## Repository Information + +- **Use Repository:** Yes +- **Default Repository URL:** https://cdn.cocoapods.org/ + +## Namespace definition + +- **Requirement:** Prohibited +- **Note:** `there is no namespace` + +## Name definition + +- **Case Sensitive:** Yes +- **Native Label:** pod name +- **Note:** `The name is the pod name and is case sensitive, cannot contain whitespace, a plus (+) character, or begin with a period (.).` + +## Version definition + +- **Native Label:** package version +- **Note:** `The version is the package version.` + +## Subpath definition + +- **Note:** `The purl subpath is used to represent a pods subspec (if present).` + +## Examples + +- `pkg:cocoapods/AFNetworking@4.0.1` +- `pkg:cocoapods/MapsIndoors@3.24.0` +- `pkg:cocoapods/ShareKit@2.0#Twitter` +- `pkg:cocoapods/GoogleUtilities@7.5.2#NSData+zlib` diff --git a/types-doc/composer-definition.md b/types-doc/composer-definition.md new file mode 100644 index 00000000..fa0c45a4 --- /dev/null +++ b/types-doc/composer-definition.md @@ -0,0 +1,38 @@ + + +# PURL Type Definition: composer + +- **Type Name:** Composer +- **Description:** Composer PHP packages +- **Schema ID:** `https://packageurl.org/types/composer-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:composer//@?# + +## Repository Information + +- **Use Repository:** Yes +- **Default Repository URL:** https://packagist.org + +## Namespace definition + +- **Requirement:** Required +- **Native Label:** vendor +- **Note:** `The namespace is the vendor. The namespace is not case sensitive and must be lowercased.` + +## Name definition + +- **Native Label:** name +- **Note:** `The name is not case sensitive and must be lowercased. Private, local packages may have no name. In this case you cannot create a purl for these.` + +## Version definition + +- **Native Label:** version + +## Examples + +- `pkg:composer/laravel/laravel@5.5.0` diff --git a/types-doc/conan-definition.md b/types-doc/conan-definition.md new file mode 100644 index 00000000..8db08918 --- /dev/null +++ b/types-doc/conan-definition.md @@ -0,0 +1,54 @@ + + +# PURL Type Definition: conan + +- **Type Name:** Conan C/C++ packages +- **Description:** Conan C/C++ packages. The purl is designed to closely resemble the Conan-native /@/ syntax for package references as specified in https://docs.conan.io/en/1.46/cheatsheet.html#package-terminology +- **Schema ID:** `https://packageurl.org/types/conan-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:conan//@?# + +## Repository Information + +- **Use Repository:** Yes +- **Default Repository URL:** https://center.conan.io + +## Namespace definition + +- **Requirement:** Optional +- **Native Label:** vendor +- **Note:** `The vendor of the package.` + +## Name definition + +- **Native Label:** package-name +- **Note:** `The Conan .` + +## Version definition + +- **Native Label:** package-version +- **Note:** `The Conan .` + +## Qualifiers Definition + +| Key | Requirement | Native name | Default Value | Description | +|------|-------------|-------------|---------------|-------------| +| user | Optional | user | | The Conan . Only required if the Conan package was published with . | +| channel | Optional | channel | | The Conan . Only required if the Conan package was published with Conan . | +| rrev | Optional | recipe revision | | The Conan recipe revision (optional). If omitted, the purl refers to the latest recipe revision available for the given version. | +| prev | Optional | package revision | | The Conan package revision (optional). If omitted, the purl refers to the latest package revision available for the given version and recipe revision. | + +## Examples + +- `pkg:conan/openssl@3.0.3` +- `pkg:conan/openssl.org/openssl@3.0.3?user=bincrafters&channel=stable` +- `pkg:conan/openssl.org/openssl@3.0.3?arch=x86_64&build_type=Debug&compiler=Visual%20Studio&compiler.runtime=MDd&compiler.version=16&os=Windows&shared=True&rrev=93a82349c31917d2d674d22065c7a9ef9f380c8e&prev=b429db8a0e324114c25ec387bfd8281f330d7c5c` + +## Note + +Additional qualifiers can be used to distinguish Conan packages with different settings or options, e.g. os=Linux, build_type=Debug or shared=True. If no additional qualifiers are used to distinguish Conan packages build with different settings or options, then the purl is ambiguous and it is up to the user to work out which package is being referred to (e.g. with context information). diff --git a/types-doc/conda-definition.md b/types-doc/conda-definition.md new file mode 100644 index 00000000..33716d2f --- /dev/null +++ b/types-doc/conda-definition.md @@ -0,0 +1,47 @@ + + +# PURL Type Definition: conda + +- **Type Name:** Conda +- **Description:** conda is for Conda packages +- **Schema ID:** `https://packageurl.org/types/conda-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:conda/@?# + +## Repository Information + +- **Use Repository:** Yes +- **Default Repository URL:** https://repo.anaconda.com + +## Namespace definition + +- **Requirement:** Prohibited +- **Note:** `there is no namspace` + +## Name definition + +- **Native Label:** name +- **Note:** `The name is the package name.` + +## Version definition + +- **Native Label:** version +- **Note:** `The version is the package version.` + +## Qualifiers Definition + +| Key | Requirement | Native name | Default Value | Description | +|------|-------------|-------------|---------------|-------------| +| build | Optional | | | the build string. | +| channel | Optional | | | the package stored location. | +| subdir | Optional | | | the associated platform. | +| type | Optional | | | package type. | + +## Examples + +- `pkg:conda/absl-py@0.4.1?build=py36h06a4308_0&channel=main&subdir=linux-64&type=tar.bz2` diff --git a/types-doc/cpan-definition.md b/types-doc/cpan-definition.md new file mode 100644 index 00000000..ae7dbd2f --- /dev/null +++ b/types-doc/cpan-definition.md @@ -0,0 +1,56 @@ + + +# PURL Type Definition: cpan + +- **Type Name:** CPAN +- **Description:** CPAN Perl packages +- **Schema ID:** `https://packageurl.org/types/cpan-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:cpan//@?# + +## Repository Information + +- **Use Repository:** Yes +- **Default Repository URL:** https://www.cpan.org/ + +## Namespace definition + +- **Requirement:** Optional +- **Note:** `- To refer to a CPAN distribution name, the namespace MUST be present. In this case, the namespace is the CPAN id of the author/publisher. It MUST be written uppercase, followed by the distribution name in the name component. A distribution name MUST NOT contain the string ::. +- To refer to a CPAN module, the namespace MUST be absent. The module name MAY contain zero or more :: strings, and the module name MUST NOT contain a - +` + +## Name definition + +- **Case Sensitive:** Yes +- **Native Label:** module or distribution name +- **Note:** `The name is the module or distribution name and is case sensitive.` + +## Version definition + +- **Native Label:** version +- **Note:** `The version is the module or distribution version.` + +## Qualifiers Definition + +| Key | Requirement | Native name | Default Value | Description | +|------|-------------|-------------|---------------|-------------| +| repository_url | Optional | | | CPAN/MetaCPAN/BackPAN/DarkPAN repository base URL | +| download_url | Optional | | | URL of package or distribution | +| vcs_url | Optional | | | extra URL for a package version control system | +| ext | Optional | | tar.gz | file extension | + +## Examples + +- `pkg:cpan/Perl::Version@1.013` +- `pkg:cpan/DROLSKY/DateTime@1.55` +- `pkg:cpan/DateTime@1.55` +- `pkg:cpan/GDT/URI-PackageURL` +- `pkg:cpan/LWP::UserAgent` +- `pkg:cpan/OALDERS/libwww-perl@6.76` +- `pkg:cpan/URI` diff --git a/types-doc/cran-definition.md b/types-doc/cran-definition.md new file mode 100644 index 00000000..32742cd1 --- /dev/null +++ b/types-doc/cran-definition.md @@ -0,0 +1,40 @@ + + +# PURL Type Definition: cran + +- **Type Name:** CRAN +- **Description:** CRAN R packages +- **Schema ID:** `https://packageurl.org/types/cran-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:cran/@?# + +## Repository Information + +- **Use Repository:** Yes +- **Default Repository URL:** https://cran.r-project.org + +## Namespace definition + +- **Requirement:** Prohibited +- **Note:** `there is no namespace` + +## Name definition + +- **Native Label:** name +- **Note:** `The name is the package name and is case sensitive, but there cannot be two packages on CRAN with the same name ignoring case.` + +## Version definition + +- **Native Label:** version +- **Note:** `The version is the package version.` + +## Examples + +- `pkg:cran/A3@1.0.0` +- `pkg:cran/rJava@1.0-4` +- `pkg:cran/caret@6.0-88` diff --git a/types-doc/deb-definition.md b/types-doc/deb-definition.md new file mode 100644 index 00000000..6955ce37 --- /dev/null +++ b/types-doc/deb-definition.md @@ -0,0 +1,49 @@ + + +# PURL Type Definition: deb + +- **Type Name:** Debian package +- **Description:** Debian packages, Debian derivatives, and Ubuntu packages +- **Schema ID:** `https://packageurl.org/types/deb-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:deb//@?# + +## Repository Information + +- **Use Repository:** Yes +- **Note:** There is no default package repository, this should be implied either from the distro qualifiers key or using a base url as a repository_url qualifiers key. + +## Namespace definition + +- **Requirement:** Required +- **Native Label:** vendor +- **Note:** `The namespace is the "vendor" name such as "debian" or "ubuntu". It is not case sensitive and must be lowercased.` + +## Name definition + +- **Native Label:** name +- **Note:** `The name is not case sensitive and must be lowercased.` + +## Version definition + +- **Native Label:** version +- **Note:** `The version is the version of the binary (or source) package.` + +## Qualifiers Definition + +| Key | Requirement | Native name | Default Value | Description | +|------|-------------|-------------|---------------|-------------| +| arch | Optional | | | arch is the qualifiers key for a package architecture. The special value arch=source identifies a Debian source package that usually consists of a Debian Source control file (.dsc) and corresponding upstream and Debian sources. The dpkg-query command can print the name and version of the corresponding source package of a binary package, e.g. dpkg-query -f ${source:Package} ${source:Version} -W | + +## Examples + +- `pkg:deb/debian/curl@7.50.3-1?arch=i386&distro=jessie` +- `pkg:deb/debian/dpkg@1.19.0.4?arch=amd64&distro=stretch` +- `pkg:deb/ubuntu/dpkg@1.19.0.4?arch=amd64` +- `pkg:deb/debian/attr@1:2.4.47-2?arch=source` +- `pkg:deb/debian/attr@1:2.4.47-2%2Bb1?arch=amd64` diff --git a/types-doc/docker-definition.md b/types-doc/docker-definition.md new file mode 100644 index 00000000..854651cf --- /dev/null +++ b/types-doc/docker-definition.md @@ -0,0 +1,38 @@ + + +# PURL Type Definition: docker + +- **Type Name:** Docker image +- **Description:** for Docker images +- **Schema ID:** `https://packageurl.org/types/docker-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:docker//@?# + +## Repository Information + +- **Use Repository:** Yes +- **Default Repository URL:** https://hub.docker.com + +## Namespace definition + +- **Requirement:** Optional +- **Note:** `The namespace is the registry/user/organization if present.` + +## Name definition + +- **Native Label:** name + +## Version definition + +- **Note:** `The version should be the image id sha256 or a tag. Since tags can be moved, a sha256 image id is preferred.` + +## Examples + +- `pkg:docker/cassandra@latest` +- `pkg:docker/smartentry/debian@dc437cc87d10` +- `pkg:docker/customer/dockerimage@sha256%3A244fd47e07d10?repository_url=gcr.io` diff --git a/types-doc/gem-definition.md b/types-doc/gem-definition.md new file mode 100644 index 00000000..7cf65bb7 --- /dev/null +++ b/types-doc/gem-definition.md @@ -0,0 +1,43 @@ + + +# PURL Type Definition: gem + +- **Type Name:** RubyGems +- **Description:** RubyGems +- **Schema ID:** `https://packageurl.org/types/generic-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:gem/@?# + +## Repository Information + +- **Use Repository:** Yes +- **Default Repository URL:** https://rubygems.org + +## Namespace definition + +- **Requirement:** Prohibited +- **Note:** `There is no namespace` + +## Name definition + +- **Native Label:** name + +## Version definition + +- **Native Label:** version + +## Qualifiers Definition + +| Key | Requirement | Native name | Default Value | Description | +|------|-------------|-------------|---------------|-------------| +| platform | Optional | platform | ruby | qualifiers key is used to specify an alternative platform. such as java for JRuby. The implied default is ruby for Ruby MRI. | + +## Examples + +- `pkg:gem/ruby-advisory-db-check@0.12.4` +- `pkg:gem/jruby-launcher@1.1.2?platform=java` diff --git a/types-doc/generic-definition.md b/types-doc/generic-definition.md new file mode 100644 index 00000000..861e285a --- /dev/null +++ b/types-doc/generic-definition.md @@ -0,0 +1,45 @@ + + +# PURL Type Definition: generic + +- **Type Name:** Generic Package +- **Description:** The generic type is for plain, generic packages that do not fit anywhere else such as for "upstream-from-distro" packages. In particular this is handy for a plain version control repository such as a bare git repo in combination with a vcs_url. +- **Schema ID:** `https://packageurl.org/types/generic-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:generic//@?# + +## Repository Information + +- **Use Repository:** No +- **Note:** There is no default repository. + +## Namespace definition + +- **Requirement:** Optional +- **Note:** `there is no generic namespace definition` + +## Name definition + +- **Note:** `as for other type, the name component is mandatory. In the worst case it can be a file or directory name.` + +## Qualifiers Definition + +| Key | Requirement | Native name | Default Value | Description | +|------|-------------|-------------|---------------|-------------| +| download_url | Optional | | | A download_url and checksum may be provided in qualifiers or as separate attributes outside of a purl for proper identification and location. | +| checksum | Optional | | | A checksum may be provided in qualifiers or as separate attributes outside of a purl for proper identification and location. | + +## Examples + +- `pkg:generic/openssl@1.1.10g` +- `pkg:generic/openssl@1.1.10g?download_url=https://openssl.org/source/openssl-1.1.0g.tar.gz&checksum=sha256:de4d501267da` +- `pkg:generic/bitwarderl?vcs_url=git%2Bhttps://git.fsfe.org/dxtr/bitwarderl%40cc55108da32` + +## Note + +When possible another or a new purl type should be used instead of using the generic type and eventually contributed back to this specification. Example have been truncated for brevity diff --git a/types-doc/github-definition.md b/types-doc/github-definition.md new file mode 100644 index 00000000..35a055bf --- /dev/null +++ b/types-doc/github-definition.md @@ -0,0 +1,40 @@ + + +# PURL Type Definition: github + +- **Type Name:** GitHub +- **Description:** GitHub-based packages +- **Schema ID:** `https://packageurl.org/types/github-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:github//@?# + +## Repository Information + +- **Use Repository:** Yes +- **Default Repository URL:** https://github.com + +## Namespace definition + +- **Requirement:** Required +- **Native Label:** user or organization +- **Note:** `The namespace is the user or organization. It is not case sensitive and must be lowercased.` + +## Name definition + +- **Native Label:** repository name +- **Note:** `The name is the repository name. It is not case sensitive and must be lowercased.` + +## Version definition + +- **Native Label:** commit or tag +- **Note:** `The version is a commit or tag.` + +## Examples + +- `pkg:github/package-url/purl-spec@244fd47e07d1004` +- `pkg:github/package-url/purl-spec@244fd47e07d1004#everybody/loves/dogs` diff --git a/types-doc/golang-definition.md b/types-doc/golang-definition.md new file mode 100644 index 00000000..612e9f96 --- /dev/null +++ b/types-doc/golang-definition.md @@ -0,0 +1,46 @@ + + +# PURL Type Definition: golang + +- **Type Name:** Go package +- **Description:** Go packages +- **Schema ID:** `https://packageurl.org/types/golang-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:golang//@?# + +## Repository Information + +- **Use Repository:** Yes +- **Note:** There is no default package repository, this is implied in the namespace using the go get command conventions. In practice the go module proxy acts as a public defulat repository. + +## Namespace definition + +- **Requirement:** Required +- **Note:** `The namespace must be lowercased.` + +## Name definition + +- **Note:** `The name must be lowercased.` + +## Version definition + +- **Note:** `The version is often empty when a commit is not specified and should be the commit in most cases when available.` + +## Subpath definition + +- **Note:** `The subpath is used to point to a subpath inside a package.` + +## Examples + +- `pkg:golang/github.com/gorilla/context@234fd47e07d1004f0aed9c` +- `pkg:golang/google.golang.org/genproto#googleapis/api/annotations` +- `pkg:golang/github.com/gorilla/context@234fd47e07d1004f0aed9c#api` + +## Note + +the current definition predates Go modules and has several practical problems, and in particular it is impossible to determine what is a module and what is a package short of having full access to the source code or making an API call to the Go module proxy. diff --git a/types-doc/hackage-definition.md b/types-doc/hackage-definition.md new file mode 100644 index 00000000..330000fc --- /dev/null +++ b/types-doc/hackage-definition.md @@ -0,0 +1,43 @@ + + +# PURL Type Definition: hackage + +- **Type Name:** Haskell package +- **Description:** Haskell packages +- **Schema ID:** `https://packageurl.org/types/hackage-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:hackage/@?# + +## Repository Information + +- **Use Repository:** Yes +- **Default Repository URL:** https://hackage.haskell.org + +## Namespace definition + +- **Requirement:** Prohibited +- **Note:** `there is no namespace` + +## Name definition + +- **Case Sensitive:** Yes +- **Normalization rules:** + - Apply kebab-case +- **Native Label:** name +- **Note:** `The name is case sensitive and use kebab-case.` + +## Version definition + +- **Native Label:** version +- **Note:** `The version is package version.` + +## Examples + +- `pkg:hackage/a50@0.5` +- `pkg:hackage/AC-HalfInteger@1.2.1` +- `pkg:hackage/3d-graphics-examples@0.0.0.2` diff --git a/types-doc/hex-definition.md b/types-doc/hex-definition.md new file mode 100644 index 00000000..54c8e316 --- /dev/null +++ b/types-doc/hex-definition.md @@ -0,0 +1,41 @@ + + +# PURL Type Definition: hex + +- **Type Name:** Hex +- **Description:** Hex packages +- **Schema ID:** `https://packageurl.org/types/hex-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:hex//@?# + +## Repository Information + +- **Use Repository:** Yes +- **Default Repository URL:** https://repo.hex.pm + +## Namespace definition + +- **Requirement:** Optional +- **Native Label:** organization for private packages +- **Note:** `The namespace is optional; it may be used to specify the organization for private packages on hex.pm. It is not case sensitive and must be lowercased.` + +## Name definition + +- **Native Label:** name +- **Note:** `The name is not case sensitive and must be lowercased.` + +## Version definition + +- **Native Label:** version + +## Examples + +- `pkg:hex/jason@1.1.2` +- `pkg:hex/acme/foo@2.3.` +- `pkg:hex/phoenix_html@2.13.3#priv/static/phoenix_html.js` +- `pkg:hex/bar@1.2.3?repository_url=https://myrepo.example.com` diff --git a/types-doc/huggingface-definition.md b/types-doc/huggingface-definition.md new file mode 100644 index 00000000..a0bb91da --- /dev/null +++ b/types-doc/huggingface-definition.md @@ -0,0 +1,42 @@ + + +# PURL Type Definition: huggingface + +- **Type Name:** HuggingFace models +- **Description:** Hugging Face ML models +- **Schema ID:** `https://packageurl.org/types/huggingfaces-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:huggingface//@?# + +## Repository Information + +- **Use Repository:** Yes +- **Note:** The default repository is https://huggingface.co. + +## Namespace definition + +- **Requirement:** Required +- **Case Sensitive:** Yes +- **Native Label:** model repository username or organization +- **Note:** `The namespace is the model repository username or organization, if present. It is case sensitive.` + +## Name definition + +- **Case Sensitive:** Yes +- **Native Label:** model repository name +- **Note:** `The name is the model repository name. It is case sensitive.` + +## Version definition + +- **Native Label:** model revision Git commit hash +- **Note:** `The version is the model revision Git commit hash. It is case insensitive and must be lowercased in the package URL.` + +## Examples + +- `pkg:huggingface/distilbert-base-uncased@043235d6088ecd3dd5fb5ca3592b6913fd516027` +- `pkg:huggingface/microsoft/deberta-v3-base@559062ad13d311b87b2c455e67dcd5f1c8f65111?repository_url=https://hub-ci.huggingface.co` diff --git a/types-doc/luarocks-definition.md b/types-doc/luarocks-definition.md new file mode 100644 index 00000000..b56662cf --- /dev/null +++ b/types-doc/luarocks-definition.md @@ -0,0 +1,47 @@ + + +# PURL Type Definition: luarocks + +- **Type Name:** LuaRocks +- **Description:** Lua packages installed with LuaRocks +- **Schema ID:** `https://packageurl.org/types/luarocks-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:luarocks//@?# + +## Repository Information + +- **Use Repository:** Yes + +## Namespace definition + +- **Requirement:** Optional +- **Native Label:** user manifest +- **Note:** `The user manifest under which the package is registered. If not given, the root manifest is assumed. It is case insensitive, but lowercase is encouraged since namespaces are normalized to ASCII lowercase.` + +## Name definition + +- **Native Label:** name +- **Note:** `The LuaRocks package name. It is case insensitive, but lowercase is encouraged since package names are normalized to ASCII lowercase.` + +## Version definition + +- **Case Sensitive:** Yes +- **Native Label:** full package version, including module version and rockspec revision +- **Note:** `The full LuaRocks package version, including module version and rockspec revision. It is case sensitive, and lowercase must be used to avoid compatibility issues with older LuaRocks versions. The full version number is required to uniquely identify a version.` + +## Qualifiers Definition + +| Key | Requirement | Native name | Default Value | Description | +|------|-------------|-------------|---------------|-------------| +| repository_url | Optional | | | The LuaRocks rocks server to be used; useful in case a private server is used (optional). If omitted, https://luarocks.org as default server is assumed. | + +## Examples + +- `pkg:luarocks/luasocket@3.1.0-1` +- `pkg:luarocks/hisham/luafilesystem@1.8.0-1` +- `pkg:luarocks/username/packagename@0.1.0-1?repository_url=https://example.com/private_rocks_server/` diff --git a/types-doc/maven-definition.md b/types-doc/maven-definition.md new file mode 100644 index 00000000..0f803af7 --- /dev/null +++ b/types-doc/maven-definition.md @@ -0,0 +1,55 @@ + + +# PURL Type Definition: maven + +- **Type Name:** Maven +- **Description:** PURL type for Maven JARs and related artifacts. +- **Schema ID:** `https://packageurl.org/types/maven-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:maven//@?# + +## Repository Information + +- **Use Repository:** Yes +- **Default Repository URL:** https://repo.maven.apache.org/maven2/ +- **Note:** The Maven Central repository is the public repository for Apache Maven packages. This repository is also mirrored at https://repo1.maven.org/maven2/. Use the standard repository_url qualifier to point to another repository + +## Namespace definition + +- **Requirement:** Required +- **Case Sensitive:** Yes +- **Native Label:** groupId +- **Note:** `The group id is the namespace.` + +## Name definition + +- **Case Sensitive:** Yes +- **Native Label:** artifactId +- **Note:** `The artifact id is the name.` + +## Version definition + +- **Case Sensitive:** Yes +- **Native Label:** version + +## Qualifiers Definition + +| Key | Requirement | Native name | Default Value | Description | +|------|-------------|-------------|---------------|-------------| +| classifier | Optional | classifier | | The maven classifier as defined in the POM documentation. | +| type | Optional | type | jar | The maven type as defined in the POM documentation. Note that Maven uses a concept / coordinate called packaging which does not map directly 1:1 to a file extension. In this use case, we need to construct a link to one of many possible artifacts. Maven itself uses type in a dependency declaration when needed to disambiguate between them. | + +## Examples + +- `pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1` +- `pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?type=pom` +- `pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?classifier=sources` +- `pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?type=zip&classifier=dist` +- `pkg:maven/net.sf.jacob-projec/jacob@1.14.3?classifier=x86&type=dll` +- `pkg:maven/net.sf.jacob-projec/jacob@1.14.3?classifier=x64&type=dll` +- `pkg:maven/groovy/groovy@1.0?repository_url=https://maven.google.com` diff --git a/types-doc/mlflow-definition.md b/types-doc/mlflow-definition.md new file mode 100644 index 00000000..0608b6a6 --- /dev/null +++ b/types-doc/mlflow-definition.md @@ -0,0 +1,45 @@ + + +# PURL Type Definition: mlflow + +- **Type Name:** +- **Description:** MLflow ML models (Azure ML, Databricks, etc.) +- **Schema ID:** `https://packageurl.org/types/mlflow-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:mlflow/@?# + +## Repository Information + +- **Use Repository:** Yes +- **Note:** The repository is the MLflow tracking URI. There is no default. Some examples include Azure ML https://.api.azureml.ms/mlflow/v1.0/subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/ and Azure Databricks https://adb-..azuredatabricks.net/api/2.0/mlflow and AWS Databricks https://dbc--.cloud.databricks.com/api/2.0/mlflow and GCP Databricks https://..gcp.databricks.com/api/2.0/mlflow + +## Namespace definition + +- **Requirement:** Prohibited +- **Note:** `there is no namespace` + +## Name definition + +- **Note:** `The name is the model name. Case sensitivity depends on the server implementation, such as for Azure ML, it is case sensitive and must be kept as-is in the package URL; and for Databricks, it is case insensitive and must be lowercased in the package URL.` + +## Version definition + +- **Native Label:** version +- **Note:** `The version is the model version.` + +## Qualifiers Definition + +| Key | Requirement | Native name | Default Value | Description | +|------|-------------|-------------|---------------|-------------| +| model_uuid | Optional | model_uuid | | model_uuid as defined in the MLflow documentation. | +| run_id | Optional | run_id | | run_id as defined in the MLflow documentation. | + +## Examples + +- `pkg:mlflow/creditfraud@3?repository_url=https://westus2.api.azureml.ms/mlflow/v1.0/subscriptions/a50f2011-fab8-4164-af23-c62881ef8c95/resourceGroups/TestResourceGroup/providers/Microsoft.MachineLearningServices/workspaces/TestWorkspace` +- `pkg:mlflow/trafficsigns@10?model_uuid=36233173b22f4c89b451f1228d700d49&run_id=410a3121-2709-4f88-98dd-dba0ef056b0a&repository_url=https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow` diff --git a/types-doc/npm-definition.md b/types-doc/npm-definition.md new file mode 100644 index 00000000..63c8b637 --- /dev/null +++ b/types-doc/npm-definition.md @@ -0,0 +1,42 @@ + + +# PURL Type Definition: npm + +- **Type Name:** Node NPM packages +- **Description:** PURL type for npm packages. +- **Schema ID:** `https://packageurl.org/types/npm-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:npm//@?# + +## Repository Information + +- **Use Repository:** Yes +- **Default Repository URL:** https://registry.npmjs.org/ +- **Note:** The default repository is the npm Registry at https://registry.npmjs.org + +## Namespace definition + +- **Requirement:** Optional +- **Native Label:** scope +- **Note:** `The namespace is used for the scope of a scoped NPM package. The npm scope @ sign prefix is always percent encoded, as it was in the early days of npm scope.` + +## Name definition + +- **Native Label:** name +- **Note:** `Per the package.json spec, new package 'must not have uppercase letters in the name', therefore the name must be lowercased. The npm name used to be case sensitive in the early days for some old packages.` + +## Version definition + +- **Case Sensitive:** Yes +- **Native Label:** version + +## Examples + +- `pkg:npm/foobar@12.3.1` +- `pkg:npm/%40angular/animation@12.3.1` +- `pkg:npm/mypackage@12.4.5?vcs_url=git://host.com/path/to/repo.git%404345abcd34343` diff --git a/types-doc/nuget-definition.md b/types-doc/nuget-definition.md new file mode 100644 index 00000000..3a5a9644 --- /dev/null +++ b/types-doc/nuget-definition.md @@ -0,0 +1,43 @@ + + +# PURL Type Definition: nuget + +- **Type Name:** NuGet +- **Description:** NuGet .NET packages +- **Schema ID:** `https://packageurl.org/types/nuget-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:nuget/@?# + +## Repository Information + +- **Use Repository:** Yes +- **Default Repository URL:** https://www.nuget.org + +## Namespace definition + +- **Requirement:** Prohibited +- **Note:** `there is no namespace` + +## Name definition + +- **Case Sensitive:** Yes +- **Native Label:** version +- **Note:** `Technically the name is case-perserving, but case-insensitive, and NuGet packages archives are case-perserving, while some NuGet API calls demand to lowercase the package name.` + +## Version definition + +- **Native Label:** version +- **Note:** `The NuGet version is semver-like but may contain more than three segments` + +## Examples + +- `pkg:nuget/EnterpriseLibrary.Common@6.0.1304` + +## Note + +There is no namespace per se even if the common convention is to use dot-separated package names where the first segment is namespace-like. diff --git a/types-doc/oci-definition.md b/types-doc/oci-definition.md new file mode 100644 index 00000000..47e8b75f --- /dev/null +++ b/types-doc/oci-definition.md @@ -0,0 +1,51 @@ + + +# PURL Type Definition: oci + +- **Type Name:** OCI image +- **Description:** For artifacts stored in registries that conform to the OCI Distribution Specification https://github.com/opencontainers/distribution-spec including container images built by Docker and others +- **Schema ID:** `https://packageurl.org/types/oci-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:oci/@?# + +## Repository Information + +- **Use Repository:** Yes +- **Note:** There is no canonical package repository for OCI artifacts. Therefore oci purls must be registry agnostic by default. To specify the repository, provide a repository_url value. + +## Namespace definition + +- **Requirement:** Prohibited +- **Note:** `OCI purls do not contain a namespace, although, repository_url may contain a namespace as part of the physical location of the package.` + +## Name definition + +- **Note:** `The name is not case sensitive and must be lowercased. The name is the last fragment of the repository name. For example if the repository name is library/debian then the name is debian.` + +## Version definition + +- **Note:** `The version is the sha256:hex_encoded_lowercase_digest of the artifact and is required to uniquely identify the artifact.` + +## Qualifiers Definition + +| Key | Requirement | Native name | Default Value | Description | +|------|-------------|-------------|---------------|-------------| +| arch | Optional | | | key for a package architecture, when relevant. | +| repository_url | Optional | | | A repository URL where the artifact may be found, but not intended as the only location. This value is encouraged to identify a location the content may be fetched. | +| tag | Optional | | | artifact tag that may have been associated with the digest at the time. | + +## Examples + +- `pkg:oci/debian@sha256%3A244fd47e07d10?repository_url=docker.io/library/debian&arch=amd64&tag=latest` +- `pkg:oci/debian@sha256%3A244fd47e07d10?repository_url=ghcr.io/debian&tag=bullseye` +- `pkg:oci/static@sha256%3A244fd47e07d10?repository_url=gcr.io/distroless/static&tag=latest` +- `pkg:oci/hello-wasm@sha256%3A244fd47e07d10?tag=v1` + +## Reference URLs + +- `https://github.com/opencontainers/distribution-spec` diff --git a/types-doc/pub-definition.md b/types-doc/pub-definition.md new file mode 100644 index 00000000..103d3626 --- /dev/null +++ b/types-doc/pub-definition.md @@ -0,0 +1,41 @@ + + +# PURL Type Definition: pub + +- **Type Name:** Pub +- **Description:** Dart and Flutter pub packages +- **Schema ID:** `https://packageurl.org/types/pub-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:pub/@?# + +## Repository Information + +- **Use Repository:** Yes +- **Default Repository URL:** https://pub.dartlang.org + +## Namespace definition + +- **Requirement:** Prohibited +- **Note:** `there is no namespace` + +## Name definition + +- **Permitted Characters:** `^[a-z0-9_]` +- **Normalization rules:** + - Replace non-[a-z] letters, non-[0-9] digits with underscore _ +- **Native Label:** name +- **Note:** `Pub normalizes all package names to be lowercase and using underscores. The only allowed characters are [a-z0-9_]. More information on pub naming and versioning is available in the pubspec documentation https://dart.dev/tools/pub/pubspec` + +## Version definition + +- **Native Label:** version + +## Examples + +- `pkg:pub/characters@1.2.0` +- `pkg:pub/flutter@0.0.0` diff --git a/types-doc/pypi-definition.md b/types-doc/pypi-definition.md new file mode 100644 index 00000000..1c1745d6 --- /dev/null +++ b/types-doc/pypi-definition.md @@ -0,0 +1,50 @@ + + +# PURL Type Definition: pypi + +- **Type Name:** PyPI +- **Description:** Python packages +- **Schema ID:** `https://packageurl.org/types/pypi-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:pypi/@?# + +## Repository Information + +- **Use Repository:** Yes +- **Default Repository URL:** https://pypi.org +- **Note:** Previously https://pypi.python.org + +## Namespace definition + +- **Requirement:** Prohibited +- **Note:** `there is no namespace` + +## Name definition + +- **Normalization rules:** + - Replace underscore _ with dash - + - Replace dot . with underscore _ when used in distribution (sdist, wheel) names +- **Native Label:** name +- **Note:** `PyPI treats - and _ as the same character and is not case sensitive. Therefore a PyPI package name must be lowercased and underscore _ replaced with a dash -. Note that PyPI itself is preserving the case of package names. When used in distribution and wheel names, the dot . is replaced with an underscore _` + +## Version definition + +- **Native Label:** version + +## Qualifiers Definition + +| Key | Requirement | Native name | Default Value | Description | +|------|-------------|-------------|---------------|-------------| +| file_name | Optional | | | The file_name qualifier selects a particular distribution file (case-sensitive). For naming convention, see the Python Packaging User Guide on source distributions https://packaging.python.org/en/latest/specifications/source-distribution-format/#source-distribution-file-name and on binary distributions https://packaging.python.org/en/latest/specifications/binary-distribution-format/#file-name-convention and the rules for platform compatibility tags https://packaging.python.org/en/latest/specifications/platform-compatibility-tags/ | + +## Examples + +- `pkg:pypi/django@1.11.1` +- `pkg:pypi/django@1.11.1?filename=Django-1.11.1.tar.gz` +- `pkg:pypi/django@1.11.1?filename=Django-1.11.1-py2.py3-none-any.whl` +- `pkg:pypi/django-allauth@12.23` diff --git a/types-doc/qpkg-definition.md b/types-doc/qpkg-definition.md new file mode 100644 index 00000000..69b678af --- /dev/null +++ b/types-doc/qpkg-definition.md @@ -0,0 +1,34 @@ + + +# PURL Type Definition: qpkg + +- **Type Name:** QNX package +- **Description:** QNX packages +- **Schema ID:** `https://packageurl.org/types/qpkg-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:qpkg//@?# + +## Repository Information + +- **Use Repository:** Yes +- **Note:** There is no default package repository, this should be implied either from the namespace or using a repository base URL as repository_url qualifiers key. + +## Namespace definition + +- **Requirement:** Required +- **Native Label:** vendor +- **Note:** `The namespace is the vendor of the package. It is not case sensitive and must be lowercased.` + +## Name definition + +- **Native Label:** name + +## Examples + +- `pkg:qpkg/blackberry/com.qnx.sdp@7.0.0.SGA201702151847` +- `pkg:qpkg/blackberry/com.qnx.qnx710.foo.bar.qux@0.0.4.01449T202205040833L` diff --git a/types-doc/rpm-definition.md b/types-doc/rpm-definition.md new file mode 100644 index 00000000..2192d431 --- /dev/null +++ b/types-doc/rpm-definition.md @@ -0,0 +1,48 @@ + + +# PURL Type Definition: rpm + +- **Type Name:** RPM +- **Description:** RPM packages +- **Schema ID:** `https://packageurl.org/types/rpm-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:rpm//@?# + +## Repository Information + +- **Use Repository:** Yes +- **Note:** There is no default package repository, this should be implied either from the distro qualifiers key or using a repository base URL as repository_url qualifiers key. + +## Namespace definition + +- **Requirement:** Required +- **Native Label:** vendor +- **Note:** `The namespace is the vendor such as Fedora or OpenSUSE. It is not case sensitive and must be lowercased.` + +## Name definition + +- **Case Sensitive:** Yes +- **Native Label:** name +- **Note:** `The name is the RPM name and is case sensitive.` + +## Version definition + +- **Native Label:** version-release +- **Note:** `The version is the combined version and release of an RPM.` + +## Qualifiers Definition + +| Key | Requirement | Native name | Default Value | Description | +|------|-------------|-------------|---------------|-------------| +| epoch | Optional | | | (optional for RPMs) is a qualifier as its not required for unique identification, but when the epoch exists we strongly encourage using it. | +| arch | Optional | | | the qualifiers key for a package architecture. | + +## Examples + +- `pkg:rpm/fedora/curl@7.50.3-1.fc25?arch=i386&distro=fedora-25` +- `pkg:rpm/centerim@4.22.10-1.el6?arch=i686&epoch=1&distro=fedora-25` diff --git a/types-doc/swid-definition.md b/types-doc/swid-definition.md new file mode 100644 index 00000000..59800db2 --- /dev/null +++ b/types-doc/swid-definition.md @@ -0,0 +1,60 @@ + + +# PURL Type Definition: swid + +- **Type Name:** Software Identification (SWID) Tag +- **Description:** PURL type for ISO-IEC 19770-2 Software Identification (SWID) tags. +- **Schema ID:** `https://packageurl.org/types/swid-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:swid//@?# + +## Repository Information + +- **Use Repository:** No +- **Note:** There is no default package repository. + +## Namespace definition + +- **Requirement:** Optional +- **Case Sensitive:** Yes +- **Native Label:** softwareCreator +- **Note:** `The namespace is the optional name and regid of the entity with a role of softwareCreator. If specified, name is required and is the first segment in the namespace. If regid is known, it must be specified as the second segment in the namespace. A maximum of two segments are supported.` + +## Name definition + +- **Requirement:** Required +- **Case Sensitive:** Yes +- **Native Label:** SoftwareIdentity/name +- **Note:** `The name is the name as defined in the SWID SoftwareIdentity element.` + +## Version definition + +- **Requirement:** Optional +- **Case Sensitive:** Yes +- **Native Label:** SoftwareIdentity/version +- **Note:** `The version is the version as defined in the SWID SoftwareIdentity element.` + +## Qualifiers Definition + +| Key | Requirement | Native name | Default Value | Description | +|------|-------------|-------------|---------------|-------------| +| tag_id | Required | | | The qualifier tag_id must not be empty and corresponds to the tagId as defined in the SWID SoftwareIdentity element. Per the SWID specification, GUIDs are recommended. If a GUID is used, it must be lowercase. If a GUID is not used, the tag_id qualifier is case aware but not case sensitive. | +| tag_version | Optional | | | The qualifier tag_version is an optional integer and corresponds to the tagVersion as defined in the SWID SoftwareIdentity element. If not specified, defaults to 0. | +| patch | Optional | | | The qualifier patch is optional and corresponds to the patch as defined in the SWID SoftwareIdentity element. If not specified, defaults to false. | +| tag_creator_name | Optional | | | The qualifier tag_creator_name is optional. If the tag creator is different from the software creator, the tag_creator_name qualifier should be specified. | +| tag_creator_regid | Optional | | | The qualifier tag_creator_regid is optional. If the tag creator is different from the software creator, the tag_creator_regid qualifier should be specified. | + +## Examples + +- `pkg:swid/Acme/example.com/Enterprise+Server@1.0.0?tag_id=75b8c285-fa7b-485b-b199-4745e3004d0d` +- `pkg:swid/Fedora@29?tag_id=org.fedoraproject.Fedora-29` +- `pkg:swid/Adobe+Systems+Incorporated/Adobe+InDesign@CC?tag_id=CreativeCloud-CS6-Win-GM-MUL` + +## Note + +Use of known qualifiers key/value pairs such as download_url can be used to specify where the package was retrieved from. diff --git a/types-doc/swift-definition.md b/types-doc/swift-definition.md new file mode 100644 index 00000000..4d67dbce --- /dev/null +++ b/types-doc/swift-definition.md @@ -0,0 +1,40 @@ + + +# PURL Type Definition: swift + +- **Type Name:** Swift packages +- **Description:** Swift packages +- **Schema ID:** `https://packageurl.org/types/swift-definition.json` + +## PURL Syntax + +The structure of a PURL for this package type is: + + pkg:swift//@?# + +## Repository Information + +- **Use Repository:** Yes +- **Note:** There is no default package repository, this should be implied from namespace. + +## Namespace definition + +- **Requirement:** Required +- **Case Sensitive:** Yes +- **Note:** `The namespace is source host and user/organization and is required.` + +## Name definition + +- **Case Sensitive:** Yes +- **Native Label:** repository name + +## Version definition + +- **Case Sensitive:** Yes +- **Native Label:** package version + +## Examples + +- `pkg:swift/github.com/Alamofire/Alamofire@5.4.3` +- `pkg:swift/github.com/RxSwiftCommunity/RxFlow@2.12.4` diff --git a/types/README.md b/types/README.md new file mode 100644 index 00000000..bfae95e0 --- /dev/null +++ b/types/README.md @@ -0,0 +1,42 @@ +###PURL Type Definitions + +This directory contains the machine-readable definitions of all registered Package-URL (PURL) types, +one JSON file for each type. These JSON files serve as the reference for PURL type specifications. + +##Contents + +- **index.json**: The index of all registered PURL types as a simple list of types. +- Definitions: **-definition.json**: The definition for a specific PURL type (e.g., + maven-definition.json, npm-definition.json). +- Tests: **-test.json**: The test suite for a specific PURL type. + +##Definitions + +Each JSON file named *-definition.json in this directory follows the standard PURL Type Definition +Schema, ensuring: + +- Consistency across all PURL types. +- Machine-readability for validation and automation. +- Standardized structure defining namespace, name, version, qualifiers, subpath, and repository behavior. + +##Tests + +Each JSON file named *-test.json in this directory follows the standard PURL Test Schema, ensuring: + +- Consistency across all PURL types tests +- Machine-readability for automation such that tools can all use the same tests. +- Two levels (aka. groups) of tests: one for the base conformance to the PURL spec and one for + advanced processing including flexible, recovering parsing of invalid PURL. + + + +##Usage + +- These JSON files are the the authoritative source for defining, validating and tesing PURL types. +- They should be referenced by tools, libraries, and documentation generators. + +##Contributions + +- Modifications must be made to these JSON files directly. +- The type definitions, tests and index and validated for consistency on commit. +- Documentation files are generated from these JSON files. diff --git a/types/alpm-definition.json b/types/alpm-definition.json new file mode 100644 index 00000000..97ac24b1 --- /dev/null +++ b/types/alpm-definition.json @@ -0,0 +1,46 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/github-definition.json", + "type": "alpm", + "type_name": "Arch Linux package", + "description": "Arch Linux packages and other users of the libalpm/pacman package manager.", + "repository": { + "use_repository": true, + "note": "There is no default package repository; this should be implied either from the distro qualifiers key or using a repository base url as repository_url qualifiers key." + }, + "namespace_definition": { + "requirement": "required", + "note": "The namespace is the vendor such as arch, arch32, archarm, manjaro or msys.", + "case_sensitive": false, + "native_name": "vendor", + "normalization_rules": [ + "It is not case sensitive and must be lowercased." + ] + }, + "name_definition": { + "note": "The name is the package name. It is not case sensitive and must be lowercased.", + "case_sensitive": false, + "native_name": "name" + }, + "version_definition": { + "native_name": "version", + "note": "The version is the version of the package as specified in vercmp(8) at (https://man.archlinux.org/man/vercmp.8#DESCRIPTION as part of alpm.", + "case_sensitive": true, + "normalization_rules": [ + "normalize version as specified in vercmp(8) at https://man.archlinux.org/man/vercmp.8#DESCRIPTION as part of alpm." + ] + }, + "qualifiers_definition": [ + { + "key": "arch", + "requirement": "optional", + "native_name": "arch", + "description": "The arch is the qualifiers key for a package architecture." + } + ], + "examples": [ + "pkg:alpm/arch/pacman@6.0.1-1?arch=x86_64", + "pkg:alpm/arch/python-pip@21.0-1?arch=any", + "pkg:alpm/arch/containers-common@1:0.47.4-4?arch=x86_64" + ] +} diff --git a/types/apk-definition.json b/types/apk-definition.json new file mode 100644 index 00000000..c05b3a3a --- /dev/null +++ b/types/apk-definition.json @@ -0,0 +1,37 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/bitbucket-definition.json", + "type": "apk", + "type_name": "APK-based packages", + "description": "Alpine Linux APK-based packages", + "repository": { + "use_repository": true, + "note": "There is no default package repository; this should be implied either from the distro qualifiers key or using a repository base url as repository_url qualifiers key." + }, + "namespace_definition": { + "requirement": "required", + "note": "The namespace is the vendor such as alpine or openwrt. It is not case sensitive and must be lowercased.", + "native_name": "vendor", + "case_sensitive": false + }, + "name_definition": { + "note": "The name is the package name. It is not case sensitive and must be lowercased.", + "native_name": "name", + "case_sensitive": false + }, + "version_definition": { + "note": "The version is a package version as expected by apk.", + "native_name": "version" + }, + "qualifiers_definition": [ + { + "key": "arch", + "description": "The arch is the qualifiers key for a package architecture." + } + ], + "examples": [ + "pkg:apk/alpine/curl@7.83.0-r0?arch=x86", + "pkg:apk/alpine/apk@2.12.9-r3?arch=x86" + ], + "note": "not to be confused with Android packages with a .apk extension." +} diff --git a/types/bitbucket-definition.json b/types/bitbucket-definition.json new file mode 100644 index 00000000..b3e9ad02 --- /dev/null +++ b/types/bitbucket-definition.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/bitbucket-definition.json", + "type": "bitbucket", + "type_name": "Bitbucket", + "description": "Bitbucket-based packages", + "repository": { + "use_repository": true, + "default_repository_url": "https://bitbucket.org" + }, + "namespace_definition": { + "requirement": "required", + "note": "The namespace is the user or organization. It is not case sensitive and must be lowercased.", + "native_name": "user or organization", + "is_case_sensitve": false + }, + "name_definition": { + "note": "The name is the repository name. It is not case sensitive and must be lowercased.", + "native_name": "repository name", + "is_case_sensitve": false + }, + "version_definition": { + "note": "The version is a commit or tag.", + "native_name": "commit or tag" + }, + "examples": [ + "pkg:bitbucket/birkenfeld/pygments-main@244fd47e07d1014f0aed9c" + ] +} diff --git a/types/bitnami-definition.json b/types/bitnami-definition.json new file mode 100644 index 00000000..54097061 --- /dev/null +++ b/types/bitnami-definition.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/bitname-definition.json", + "type": "bitnami", + "type_name": "Bitnami", + "description": "Bitnami-based packages", + "repository": { + "use_repository": true, + "default_repository_url": "https://downloads.bitnami.com/files/stacksmith" + }, + "namespace_definition": { + "requirement": "prohibited", + "note": "there is no namespace" + }, + "name_definition": { + "note": "The name is the component name. It must be lowercased.", + "case_sensitive": false, + "native_name": "name" + }, + "version_definition": { + "native_name": "full package version, including version and revision", + "note": "The version is the full Bitnami package version, including version and revision." + }, + "qualifiers_definition": [ + { + "key": "arch", + "description": "The arch is the qualifiers key for a package architecture. Available values are amd64 (default) and arm64.", + "default_value": "amd64" + }, + { + "key": "distro", + "description": "The distro is the qualifiers key for the distribution associated to the package." + } + ], + "examples": [ + "pkg:bitnami/wordpress?distro=debian-12", + "pkg:bitnami/wordpress@6.2.0?distro=debian-12", + "pkg:bitnami/wordpress@6.2.0?arch=arm64&distro=debian-12", + "pkg:bitnami/wordpress@6.2.0?arch=arm64&distro=photon-4" + ] +} diff --git a/types/cargo-definition.json b/types/cargo-definition.json new file mode 100644 index 00000000..a862b1fa --- /dev/null +++ b/types/cargo-definition.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/cargo-definition.json", + "type": "cargo", + "type_name": "Cargo", + "description": "Cargo packages for Rust", + "repository": { + "use_repository": true, + "default_repository_url": "https://crates.io/" + }, + "namespace_definition": { + "requirement": "prohibited", + "note": "there is no namespace" + }, + "name_definition": { + "native_name": "name", + "is_case_sensitve": true, + "note": "The name is the repository name." + }, + "version_definition": { + "native_name": "version", + "note": "The version is the package version." + }, + "examples": [ + "pkg:cargo/rand@0.7.2", + "pkg:cargo/clap@2.33.0", + "pkg:cargo/structopt@0.3.11" + ] +} diff --git a/types/cocoapods-definition.json b/types/cocoapods-definition.json new file mode 100644 index 00000000..99ddc22c --- /dev/null +++ b/types/cocoapods-definition.json @@ -0,0 +1,33 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/cocoapods-definition.json", + "type": "cocoapods", + "type_name": "CocoaPods", + "description": "CocoaPods pods", + "repository": { + "use_repository": true, + "default_repository_url": "https://cdn.cocoapods.org/" + }, + "namespace_definition": { + "requirement": "prohibited", + "note": "there is no namespace" + }, + "name_definition": { + "case_sensitive": true, + "native_name": "pod name", + "note": "The name is the pod name and is case sensitive, cannot contain whitespace, a plus (+) character, or begin with a period (.)." + }, + "version_definition": { + "native_name": "package version", + "note": "The version is the package version." + }, + "subpath_definition": { + "note": "The purl subpath is used to represent a pods subspec (if present)." + }, + "examples": [ + "pkg:cocoapods/AFNetworking@4.0.1", + "pkg:cocoapods/MapsIndoors@3.24.0", + "pkg:cocoapods/ShareKit@2.0#Twitter", + "pkg:cocoapods/GoogleUtilities@7.5.2#NSData+zlib" + ] +} diff --git a/types/composer-definition.json b/types/composer-definition.json new file mode 100644 index 00000000..7ea05b93 --- /dev/null +++ b/types/composer-definition.json @@ -0,0 +1,28 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/composer-definition.json", + "type": "composer", + "type_name": "Composer", + "description": "Composer PHP packages", + "repository": { + "use_repository": true, + "default_repository_url": "https://packagist.org" + }, + "namespace_definition": { + "requirement": "required", + "case_sensitive": false, + "native_name": "vendor", + "note": "The namespace is the vendor. The namespace is not case sensitive and must be lowercased." + }, + "name_definition": { + "case_sensitive": false, + "native_name": "name", + "note": "The name is not case sensitive and must be lowercased. Private, local packages may have no name. In this case you cannot create a purl for these." + }, + "version_definition": { + "native_name": "version" + }, + "examples": [ + "pkg:composer/laravel/laravel@5.5.0" + ] +} diff --git a/types/conan-definition.json b/types/conan-definition.json new file mode 100644 index 00000000..00604794 --- /dev/null +++ b/types/conan-definition.json @@ -0,0 +1,56 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/conan-definition.json", + "type": "conan", + "type_name": "Conan C/C++ packages", + "description": "Conan C/C++ packages. The purl is designed to closely resemble the Conan-native /@/ syntax for package references as specified in https://docs.conan.io/en/1.46/cheatsheet.html#package-terminology", + "repository": { + "use_repository": true, + "default_repository_url": "https://center.conan.io" + }, + "namespace_definition": { + "requirement": "optional", + "native_name": "vendor", + "note": "The vendor of the package." + }, + "name_definition": { + "native_name": "package-name", + "note": "The Conan ." + }, + "version_definition": { + "native_name": "package-version", + "note": "The Conan ." + }, + "qualifiers_definition": [ + { + "key": "user", + "native_name": "user", + "requirement": "optional", + "description": "The Conan . Only required if the Conan package was published with ." + }, + { + "key": "channel", + "native_name": "channel", + "requirement": "optional", + "description": "The Conan . Only required if the Conan package was published with Conan ." + }, + { + "key": "rrev", + "native_name": "recipe revision", + "requirement": "optional", + "description": "The Conan recipe revision (optional). If omitted, the purl refers to the latest recipe revision available for the given version." + }, + { + "key": "prev", + "native_name": "package revision", + "requirement": "optional", + "description": "The Conan package revision (optional). If omitted, the purl refers to the latest package revision available for the given version and recipe revision." + } + ], + "note": "Additional qualifiers can be used to distinguish Conan packages with different settings or options, e.g. os=Linux, build_type=Debug or shared=True. If no additional qualifiers are used to distinguish Conan packages build with different settings or options, then the purl is ambiguous and it is up to the user to work out which package is being referred to (e.g. with context information).", + "examples": [ + "pkg:conan/openssl@3.0.3", + "pkg:conan/openssl.org/openssl@3.0.3?user=bincrafters&channel=stable", + "pkg:conan/openssl.org/openssl@3.0.3?arch=x86_64&build_type=Debug&compiler=Visual%20Studio&compiler.runtime=MDd&compiler.version=16&os=Windows&shared=True&rrev=93a82349c31917d2d674d22065c7a9ef9f380c8e&prev=b429db8a0e324114c25ec387bfd8281f330d7c5c" + ] +} diff --git a/types/conda-definition.json b/types/conda-definition.json new file mode 100644 index 00000000..202da1d8 --- /dev/null +++ b/types/conda-definition.json @@ -0,0 +1,44 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/conda-definition.json", + "type": "conda", + "type_name": "Conda", + "description": "conda is for Conda packages", + "repository": { + "use_repository": true, + "default_repository_url": "https://repo.anaconda.com" + }, + "namespace_definition": { + "note": "there is no namspace", + "requirement": "prohibited" + }, + "name_definition": { + "native_name": "name", + "note": "The name is the package name." + }, + "version_definition": { + "native_name": "version", + "note": "The version is the package version." + }, + "qualifiers_definition": [ + { + "key": "build", + "description": "the build string." + }, + { + "key": "channel", + "description": "the package stored location." + }, + { + "key": "subdir", + "description": "the associated platform." + }, + { + "key": "type", + "description": "package type." + } + ], + "examples": [ + "pkg:conda/absl-py@0.4.1?build=py36h06a4308_0&channel=main&subdir=linux-64&type=tar.bz2" + ] +} diff --git a/types/cpan-definition.json b/types/cpan-definition.json new file mode 100644 index 00000000..d82113d2 --- /dev/null +++ b/types/cpan-definition.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/cpan-definition.json", + "type": "cpan", + "type_name": "CPAN", + "description": "CPAN Perl packages", + "repository": { + "use_repository": true, + "default_repository_url": "https://www.cpan.org/" + }, + "namespace_definition": { + "requirement": "optional", + "note": "- To refer to a CPAN distribution name, the namespace MUST be present. In this case, the namespace is the CPAN id of the author/publisher. It MUST be written uppercase, followed by the distribution name in the name component. A distribution name MUST NOT contain the string ::.\n- To refer to a CPAN module, the namespace MUST be absent. The module name MAY contain zero or more :: strings, and the module name MUST NOT contain a -\n" + }, + "name_definition": { + "case_sensitive": true, + "native_name": "module or distribution name", + "note": "The name is the module or distribution name and is case sensitive." + }, + "version_definition": { + "note": "The version is the module or distribution version.", + "native_name": "version" + }, + "qualifiers_definition": [ + { + "key": "repository_url", + "description": "CPAN/MetaCPAN/BackPAN/DarkPAN repository base URL" + }, + { + "key": "download_url", + "description": "URL of package or distribution" + }, + { + "key": "vcs_url", + "description": "extra URL for a package version control system" + }, + { + "key": "ext", + "description": "file extension", + "default_value": "tar.gz" + } + ], + "examples": [ + "pkg:cpan/Perl::Version@1.013", + "pkg:cpan/DROLSKY/DateTime@1.55", + "pkg:cpan/DateTime@1.55", + "pkg:cpan/GDT/URI-PackageURL", + "pkg:cpan/LWP::UserAgent", + "pkg:cpan/OALDERS/libwww-perl@6.76", + "pkg:cpan/URI" + ] +} diff --git a/types/cran-definition.json b/types/cran-definition.json new file mode 100644 index 00000000..828fcc1f --- /dev/null +++ b/types/cran-definition.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/cran-definition.json", + "type": "cran", + "type_name": "CRAN", + "description": "CRAN R packages", + "repository": { + "use_repository": true, + "default_repository_url": "https://cran.r-project.org" + }, + "namespace_definition": { + "requirement": "prohibited", + "note": "there is no namespace" + }, + "name_definition": { + "native_name": "name", + "is_case_sensitve": true, + "note": "The name is the package name and is case sensitive, but there cannot be two packages on CRAN with the same name ignoring case." + }, + "version_definition": { + "native_name": "version", + "note": "The version is the package version." + }, + "examples": [ + "pkg:cran/A3@1.0.0", + "pkg:cran/rJava@1.0-4", + "pkg:cran/caret@6.0-88" + ] +} diff --git a/types/deb-definition.json b/types/deb-definition.json new file mode 100644 index 00000000..75ee570b --- /dev/null +++ b/types/deb-definition.json @@ -0,0 +1,39 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/deb-definition.json", + "type": "deb", + "type_name": "Debian package", + "description": "Debian packages, Debian derivatives, and Ubuntu packages", + "repository": { + "use_repository": true, + "note": "There is no default package repository, this should be implied either from the distro qualifiers key or using a base url as a repository_url qualifiers key." + }, + "namespace_definition": { + "native_name": "vendor", + "is_case_sensitve": false, + "note": "The namespace is the \"vendor\" name such as \"debian\" or \"ubuntu\". It is not case sensitive and must be lowercased.", + "requirement": "required" + }, + "name_definition": { + "native_name": "name", + "is_case_sensitve": false, + "note": "The name is not case sensitive and must be lowercased." + }, + "version_definition": { + "native_name": "version", + "note": "The version is the version of the binary (or source) package." + }, + "qualifiers_definition": [ + { + "key": "arch", + "description": "arch is the qualifiers key for a package architecture. The special value arch=source identifies a Debian source package that usually consists of a Debian Source control file (.dsc) and corresponding upstream and Debian sources. The dpkg-query command can print the name and version of the corresponding source package of a binary package, e.g. dpkg-query -f ${source:Package} ${source:Version} -W " + } + ], + "examples": [ + "pkg:deb/debian/curl@7.50.3-1?arch=i386&distro=jessie", + "pkg:deb/debian/dpkg@1.19.0.4?arch=amd64&distro=stretch", + "pkg:deb/ubuntu/dpkg@1.19.0.4?arch=amd64", + "pkg:deb/debian/attr@1:2.4.47-2?arch=source", + "pkg:deb/debian/attr@1:2.4.47-2%2Bb1?arch=amd64" + ] +} diff --git a/types/docker-definition.json b/types/docker-definition.json new file mode 100644 index 00000000..0c19d594 --- /dev/null +++ b/types/docker-definition.json @@ -0,0 +1,26 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/docker-definition.json", + "type": "docker", + "type_name": "Docker image", + "description": "for Docker images", + "repository": { + "use_repository": true, + "default_repository_url": "https://hub.docker.com" + }, + "namespace_definition": { + "note": "The namespace is the registry/user/organization if present.", + "requirement": "optional" + }, + "name_definition": { + "native_name": "name" + }, + "version_definition": { + "note": "The version should be the image id sha256 or a tag. Since tags can be moved, a sha256 image id is preferred." + }, + "examples": [ + "pkg:docker/cassandra@latest", + "pkg:docker/smartentry/debian@dc437cc87d10", + "pkg:docker/customer/dockerimage@sha256%3A244fd47e07d10?repository_url=gcr.io" + ] +} diff --git a/types/gem-definition.json b/types/gem-definition.json new file mode 100644 index 00000000..23c6eb68 --- /dev/null +++ b/types/gem-definition.json @@ -0,0 +1,34 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/generic-definition.json", + "type": "gem", + "type_name": "RubyGems", + "description": "RubyGems", + "repository": { + "use_repository": true, + "default_repository_url": "https://rubygems.org" + }, + "namespace_definition": { + "requirement": "prohibited", + "note": "There is no namespace" + }, + "name_definition": { + "native_name": "name" + }, + "version_definition": { + "native_name": "version" + }, + "qualifiers_definition": [ + { + "key": "platform", + "native_name": "platform", + "requirement": "optional", + "default_value": "ruby", + "description": "qualifiers key is used to specify an alternative platform. such as java for JRuby. The implied default is ruby for Ruby MRI." + } + ], + "examples": [ + "pkg:gem/ruby-advisory-db-check@0.12.4", + "pkg:gem/jruby-launcher@1.1.2?platform=java" + ] +} diff --git a/types/generic-definition.json b/types/generic-definition.json new file mode 100644 index 00000000..6e0a5be3 --- /dev/null +++ b/types/generic-definition.json @@ -0,0 +1,34 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/generic-definition.json", + "type": "generic", + "type_name": "Generic Package", + "description": "The generic type is for plain, generic packages that do not fit anywhere else such as for \"upstream-from-distro\" packages. In particular this is handy for a plain version control repository such as a bare git repo in combination with a vcs_url.", + "repository": { + "use_repository": false, + "note": "There is no default repository." + }, + "namespace_definition": { + "requirement": "optional", + "note": "there is no generic namespace definition" + }, + "name_definition": { + "note": "as for other type, the name component is mandatory. In the worst case it can be a file or directory name." + }, + "qualifiers_definition": [ + { + "key": "download_url", + "description": "A download_url and checksum may be provided in qualifiers or as separate attributes outside of a purl for proper identification and location." + }, + { + "key": "checksum", + "description": "A checksum may be provided in qualifiers or as separate attributes outside of a purl for proper identification and location." + } + ], + "note": "When possible another or a new purl type should be used instead of using the generic type and eventually contributed back to this specification. Example have been truncated for brevity", + "examples": [ + "pkg:generic/openssl@1.1.10g", + "pkg:generic/openssl@1.1.10g?download_url=https://openssl.org/source/openssl-1.1.0g.tar.gz&checksum=sha256:de4d501267da", + "pkg:generic/bitwarderl?vcs_url=git%2Bhttps://git.fsfe.org/dxtr/bitwarderl%40cc55108da32" + ] +} diff --git a/types/github-definition.json b/types/github-definition.json new file mode 100644 index 00000000..1dd6a439 --- /dev/null +++ b/types/github-definition.json @@ -0,0 +1,30 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/github-definition.json", + "type": "github", + "type_name": "GitHub", + "description": "GitHub-based packages", + "repository": { + "use_repository": true, + "default_repository_url": "https://github.com" + }, + "namespace_definition": { + "requirement": "required", + "case_sensitive": false, + "native_name": "user or organization", + "note": "The namespace is the user or organization. It is not case sensitive and must be lowercased." + }, + "name_definition": { + "case_sensitive": false, + "native_name": "repository name", + "note": "The name is the repository name. It is not case sensitive and must be lowercased." + }, + "version_definition": { + "native_name": "commit or tag", + "note": "The version is a commit or tag." + }, + "examples": [ + "pkg:github/package-url/purl-spec@244fd47e07d1004", + "pkg:github/package-url/purl-spec@244fd47e07d1004#everybody/loves/dogs" + ] +} diff --git a/types/golang-definition.json b/types/golang-definition.json new file mode 100644 index 00000000..a5c4fd56 --- /dev/null +++ b/types/golang-definition.json @@ -0,0 +1,32 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/golang-definition.json", + "type": "golang", + "type_name": "Go package", + "description": "Go packages", + "repository": { + "use_repository": true, + "note": "There is no default package repository, this is implied in the namespace using the go get command conventions. In practice the go module proxy acts as a public defulat repository." + }, + "namespace_definition": { + "requirement": "required", + "case_sensitive": false, + "note": "The namespace must be lowercased." + }, + "name_definition": { + "case_sensitive": false, + "note": "The name must be lowercased." + }, + "subpath_definition": { + "note": "The subpath is used to point to a subpath inside a package." + }, + "note": "the current definition predates Go modules and has several practical problems, and in particular it is impossible to determine what is a module and what is a package short of having full access to the source code or making an API call to the Go module proxy.", + "version_definition": { + "note": "The version is often empty when a commit is not specified and should be the commit in most cases when available." + }, + "examples": [ + "pkg:golang/github.com/gorilla/context@234fd47e07d1004f0aed9c", + "pkg:golang/google.golang.org/genproto#googleapis/api/annotations", + "pkg:golang/github.com/gorilla/context@234fd47e07d1004f0aed9c#api" + ] +} diff --git a/types/hackage-definition.json b/types/hackage-definition.json new file mode 100644 index 00000000..1556b69b --- /dev/null +++ b/types/hackage-definition.json @@ -0,0 +1,32 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/hackage-definition.json", + "type": "hackage", + "type_name": "Haskell package", + "description": "Haskell packages", + "repository": { + "use_repository": true, + "default_repository_url": "https://hackage.haskell.org" + }, + "namespace_definition": { + "requirement": "prohibited", + "note": "there is no namespace" + }, + "name_definition": { + "case_sensitive": true, + "native_name": "name", + "normalization_rules": [ + "Apply kebab-case" + ], + "note": "The name is case sensitive and use kebab-case." + }, + "version_definition": { + "native_name": "version", + "note": "The version is package version." + }, + "examples": [ + "pkg:hackage/a50@0.5", + "pkg:hackage/AC-HalfInteger@1.2.1", + "pkg:hackage/3d-graphics-examples@0.0.0.2" + ] +} diff --git a/types/hex-definition.json b/types/hex-definition.json new file mode 100644 index 00000000..21b2f7cc --- /dev/null +++ b/types/hex-definition.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/hex-definition.json", + "type": "hex", + "type_name": "Hex", + "description": "Hex packages", + "repository": { + "use_repository": true, + "default_repository_url": "https://repo.hex.pm" + }, + "namespace_definition": { + "requirement": "optional", + "case_sensitive": false, + "native_name": "organization for private packages", + "note": "The namespace is optional; it may be used to specify the organization for private packages on hex.pm. It is not case sensitive and must be lowercased." + }, + "name_definition": { + "case_sensitive": false, + "native_name": "name", + "note": "The name is not case sensitive and must be lowercased." + }, + "version_definition": { + "native_name": "version" + }, + "examples": [ + "pkg:hex/jason@1.1.2", + "pkg:hex/acme/foo@2.3.", + "pkg:hex/phoenix_html@2.13.3#priv/static/phoenix_html.js", + "pkg:hex/bar@1.2.3?repository_url=https://myrepo.example.com" + ] +} diff --git a/types/huggingface-definition.json b/types/huggingface-definition.json new file mode 100644 index 00000000..256fd860 --- /dev/null +++ b/types/huggingface-definition.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/huggingfaces-definition.json", + "type": "huggingface", + "type_name": "HuggingFace models", + "description": "Hugging Face ML models", + "repository": { + "use_repository": true, + "note": "The default repository is https://huggingface.co." + }, + "namespace_definition": { + "requirement": "required", + "case_sensitive": true, + "native_name": "model repository username or organization", + "note": "The namespace is the model repository username or organization, if present. It is case sensitive." + }, + "name_definition": { + "case_sensitive": true, + "native_name": "model repository name", + "note": "The name is the model repository name. It is case sensitive." + }, + "version_definition": { + "case_sensitive": false, + "native_name": "model revision Git commit hash", + "note": "The version is the model revision Git commit hash. It is case insensitive and must be lowercased in the package URL." + }, + "examples": [ + "pkg:huggingface/distilbert-base-uncased@043235d6088ecd3dd5fb5ca3592b6913fd516027", + "pkg:huggingface/microsoft/deberta-v3-base@559062ad13d311b87b2c455e67dcd5f1c8f65111?repository_url=https://hub-ci.huggingface.co" + ] +} diff --git a/types/luarocks-definition.json b/types/luarocks-definition.json new file mode 100644 index 00000000..1132e33a --- /dev/null +++ b/types/luarocks-definition.json @@ -0,0 +1,37 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/luarocks-definition.json", + "type": "luarocks", + "type_name": "LuaRocks", + "description": "Lua packages installed with LuaRocks", + "repository": { + "use_repository": true + }, + "namespace_definition": { + "case_sensitive": false, + "native_name": "user manifest", + "note": "The user manifest under which the package is registered. If not given, the root manifest is assumed. It is case insensitive, but lowercase is encouraged since namespaces are normalized to ASCII lowercase.", + "requirement": "optional" + }, + "name_definition": { + "case_sensitive": false, + "native_name": "name", + "note": "The LuaRocks package name. It is case insensitive, but lowercase is encouraged since package names are normalized to ASCII lowercase." + }, + "version_definition": { + "case_sensitive": true, + "native_name": "full package version, including module version and rockspec revision", + "note": "The full LuaRocks package version, including module version and rockspec revision. It is case sensitive, and lowercase must be used to avoid compatibility issues with older LuaRocks versions. The full version number is required to uniquely identify a version." + }, + "qualifiers_definition": [ + { + "key": "repository_url", + "description": "The LuaRocks rocks server to be used; useful in case a private server is used (optional). If omitted, https://luarocks.org as default server is assumed." + } + ], + "examples": [ + "pkg:luarocks/luasocket@3.1.0-1", + "pkg:luarocks/hisham/luafilesystem@1.8.0-1", + "pkg:luarocks/username/packagename@0.1.0-1?repository_url=https://example.com/private_rocks_server/" + ] +} diff --git a/types/maven-definition.json b/types/maven-definition.json new file mode 100644 index 00000000..e4acbcf4 --- /dev/null +++ b/types/maven-definition.json @@ -0,0 +1,51 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/maven-definition.json", + "type": "maven", + "type_name": "Maven", + "description": "PURL type for Maven JARs and related artifacts.", + "repository": { + "use_repository": true, + "default_repository_url": "https://repo.maven.apache.org/maven2/", + "note": "The Maven Central repository is the public repository for Apache Maven packages. This repository is also mirrored at https://repo1.maven.org/maven2/. Use the standard repository_url qualifier to point to another repository" + }, + "namespace_definition": { + "requirement": "required", + "case_sensitive": true, + "native_name": "groupId", + "note": "The group id is the namespace." + }, + "name_definition": { + "case_sensitive": true, + "native_name": "artifactId", + "note": "The artifact id is the name." + }, + "version_definition": { + "case_sensitive": true, + "native_name": "version" + }, + "qualifiers_definition": [ + { + "key": "classifier", + "requirement": "optional", + "description": "The maven classifier as defined in the POM documentation.", + "native_name": "classifier" + }, + { + "key": "type", + "requirement": "optional", + "description": "The maven type as defined in the POM documentation. Note that Maven uses a concept / coordinate called packaging which does not map directly 1:1 to a file extension. In this use case, we need to construct a link to one of many possible artifacts. Maven itself uses type in a dependency declaration when needed to disambiguate between them.", + "native_name": "type", + "default_value": "jar" + } + ], + "examples": [ + "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1", + "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?type=pom", + "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?classifier=sources", + "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?type=zip&classifier=dist", + "pkg:maven/net.sf.jacob-projec/jacob@1.14.3?classifier=x86&type=dll", + "pkg:maven/net.sf.jacob-projec/jacob@1.14.3?classifier=x64&type=dll", + "pkg:maven/groovy/groovy@1.0?repository_url=https://maven.google.com" + ] +} diff --git a/types/mlflow-definition.json b/types/mlflow-definition.json new file mode 100644 index 00000000..7cd65487 --- /dev/null +++ b/types/mlflow-definition.json @@ -0,0 +1,38 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/mlflow-definition.json", + "type": "mlflow", + "type_name": "", + "description": "MLflow ML models (Azure ML, Databricks, etc.)", + "repository": { + "use_repository": true, + "note": "The repository is the MLflow tracking URI. There is no default. Some examples include Azure ML https://.api.azureml.ms/mlflow/v1.0/subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/ and Azure Databricks https://adb-..azuredatabricks.net/api/2.0/mlflow and AWS Databricks https://dbc--.cloud.databricks.com/api/2.0/mlflow and GCP Databricks https://..gcp.databricks.com/api/2.0/mlflow" + }, + "namespace_definition": { + "requirement": "prohibited", + "note": "there is no namespace" + }, + "name_definition": { + "note": "The name is the model name. Case sensitivity depends on the server implementation, such as for Azure ML, it is case sensitive and must be kept as-is in the package URL; and for Databricks, it is case insensitive and must be lowercased in the package URL." + }, + "version_definition": { + "native_name": "version", + "note": "The version is the model version." + }, + "qualifiers_definition": [ + { + "key": "model_uuid", + "native_name": "model_uuid", + "description": "model_uuid as defined in the MLflow documentation." + }, + { + "key": "run_id", + "native_name": "run_id", + "description": "run_id as defined in the MLflow documentation." + } + ], + "examples": [ + "pkg:mlflow/creditfraud@3?repository_url=https://westus2.api.azureml.ms/mlflow/v1.0/subscriptions/a50f2011-fab8-4164-af23-c62881ef8c95/resourceGroups/TestResourceGroup/providers/Microsoft.MachineLearningServices/workspaces/TestWorkspace", + "pkg:mlflow/trafficsigns@10?model_uuid=36233173b22f4c89b451f1228d700d49&run_id=410a3121-2709-4f88-98dd-dba0ef056b0a&repository_url=https://adb-5245952564735461.0.azuredatabricks.net/api/2.0/mlflow" + ] +} diff --git a/types/npm-definition.json b/types/npm-definition.json new file mode 100644 index 00000000..0bf4c9c4 --- /dev/null +++ b/types/npm-definition.json @@ -0,0 +1,32 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type.schema-1.0.json", + "$id": "https://packageurl.org/types/npm-definition.json", + "type": "npm", + "type_name": "Node NPM packages", + "description": "PURL type for npm packages.", + "repository": { + "use_repository": true, + "default_repository_url": "https://registry.npmjs.org/", + "note": "The default repository is the npm Registry at https://registry.npmjs.org" + }, + "namespace_definition": { + "requirement": "optional", + "case_sensitive": false, + "native_name": "scope", + "note": "The namespace is used for the scope of a scoped NPM package. The npm scope @ sign prefix is always percent encoded, as it was in the early days of npm scope." + }, + "name_definition": { + "case_sensitive": false, + "native_name": "name", + "note": "Per the package.json spec, new package 'must not have uppercase letters in the name', therefore the name must be lowercased. The npm name used to be case sensitive in the early days for some old packages." + }, + "version_definition": { + "case_sensitive": true, + "native_name": "version" + }, + "examples": [ + "pkg:npm/foobar@12.3.1", + "pkg:npm/%40angular/animation@12.3.1", + "pkg:npm/mypackage@12.4.5?vcs_url=git://host.com/path/to/repo.git%404345abcd34343" + ] +} diff --git a/types/nuget-definition.json b/types/nuget-definition.json new file mode 100644 index 00000000..80927f57 --- /dev/null +++ b/types/nuget-definition.json @@ -0,0 +1,28 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/nuget-definition.json", + "type": "nuget", + "type_name": "NuGet", + "description": "NuGet .NET packages", + "repository": { + "use_repository": true, + "default_repository_url": "https://www.nuget.org" + }, + "namespace_definition": { + "requirement": "prohibited", + "note": "there is no namespace" + }, + "name_definition": { + "native_name": "version", + "case_sensitive": true, + "note": "Technically the name is case-perserving, but case-insensitive, and NuGet packages archives are case-perserving, while some NuGet API calls demand to lowercase the package name." + }, + "version_definition": { + "native_name": "version", + "note": "The NuGet version is semver-like but may contain more than three segments" + }, + "note": "There is no namespace per se even if the common convention is to use dot-separated package names where the first segment is namespace-like.", + "examples": [ + "pkg:nuget/EnterpriseLibrary.Common@6.0.1304" + ] +} diff --git a/types/oci-definition.json b/types/oci-definition.json new file mode 100644 index 00000000..19777870 --- /dev/null +++ b/types/oci-definition.json @@ -0,0 +1,46 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/oci-definition.json", + "type": "oci", + "type_name": "OCI image", + "description": "For artifacts stored in registries that conform to the OCI Distribution Specification https://github.com/opencontainers/distribution-spec including container images built by Docker and others", + "repository": { + "use_repository": true, + "note": "There is no canonical package repository for OCI artifacts. Therefore oci purls must be registry agnostic by default. To specify the repository, provide a repository_url value." + }, + "namespace_definition": { + "requirement": "prohibited", + "note": "OCI purls do not contain a namespace, although, repository_url may contain a namespace as part of the physical location of the package." + }, + "name_definition": { + "case_sensitive": false, + "note": "The name is not case sensitive and must be lowercased. The name is the last fragment of the repository name. For example if the repository name is library/debian then the name is debian." + }, + "version_definition": { + "case_sensitive": false, + "note": "The version is the sha256:hex_encoded_lowercase_digest of the artifact and is required to uniquely identify the artifact." + }, + "qualifiers_definition": [ + { + "key": "arch", + "description": "key for a package architecture, when relevant." + }, + { + "key": "repository_url", + "description": "A repository URL where the artifact may be found, but not intended as the only location. This value is encouraged to identify a location the content may be fetched." + }, + { + "key": "tag", + "description": "artifact tag that may have been associated with the digest at the time." + } + ], + "reference_urls": [ + "https://github.com/opencontainers/distribution-spec" + ], + "examples": [ + "pkg:oci/debian@sha256%3A244fd47e07d10?repository_url=docker.io/library/debian&arch=amd64&tag=latest", + "pkg:oci/debian@sha256%3A244fd47e07d10?repository_url=ghcr.io/debian&tag=bullseye", + "pkg:oci/static@sha256%3A244fd47e07d10?repository_url=gcr.io/distroless/static&tag=latest", + "pkg:oci/hello-wasm@sha256%3A244fd47e07d10?tag=v1" + ] +} diff --git a/types/pub-definition.json b/types/pub-definition.json new file mode 100644 index 00000000..8e1694a1 --- /dev/null +++ b/types/pub-definition.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/pub-definition.json", + "type": "pub", + "type_name": "Pub", + "description": "Dart and Flutter pub packages", + "repository": { + "use_repository": true, + "default_repository_url": "https://pub.dartlang.org" + }, + "namespace_definition": { + "requirement": "prohibited", + "note": "there is no namespace" + }, + "name_definition": { + "native_name": "name", + "case_sensitive": false, + "permitted_characters": "^[a-z0-9_]", + "normalization_rules": [ + "Replace non-[a-z] letters, non-[0-9] digits with underscore _" + ], + "note": "Pub normalizes all package names to be lowercase and using underscores. The only allowed characters are [a-z0-9_]. More information on pub naming and versioning is available in the pubspec documentation https://dart.dev/tools/pub/pubspec" + }, + "version_definition": { + "native_name": "version" + }, + "examples": [ + "pkg:pub/characters@1.2.0", + "pkg:pub/flutter@0.0.0" + ] +} diff --git a/types/pypi-definition.json b/types/pypi-definition.json new file mode 100644 index 00000000..bec2625f --- /dev/null +++ b/types/pypi-definition.json @@ -0,0 +1,42 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/pypi-definition.json", + "type": "pypi", + "type_name": "PyPI", + "description": "Python packages", + "repository": { + "use_repository": true, + "default_repository_url": "https://pypi.org", + "note": "Previously https://pypi.python.org" + }, + "namespace_definition": { + "requirement": "prohibited", + "note": "there is no namespace" + }, + "name_definition": { + "native_name": "name", + "case_sensitive": false, + "normalization_rules": [ + "Replace underscore _ with dash -", + "Replace dot . with underscore _ when used in distribution (sdist, wheel) names" + ], + "note": "PyPI treats - and _ as the same character and is not case sensitive. Therefore a PyPI package name must be lowercased and underscore _ replaced with a dash -. Note that PyPI itself is preserving the case of package names. When used in distribution and wheel names, the dot . is replaced with an underscore _" + }, + "version_definition": { + "case_sensitive": false, + "native_name": "version" + }, + "qualifiers_definition": [ + { + "key": "file_name", + "requirement": "optional", + "description": "The file_name qualifier selects a particular distribution file (case-sensitive). For naming convention, see the Python Packaging User Guide on source distributions https://packaging.python.org/en/latest/specifications/source-distribution-format/#source-distribution-file-name and on binary distributions https://packaging.python.org/en/latest/specifications/binary-distribution-format/#file-name-convention and the rules for platform compatibility tags https://packaging.python.org/en/latest/specifications/platform-compatibility-tags/" + } + ], + "examples": [ + "pkg:pypi/django@1.11.1", + "pkg:pypi/django@1.11.1?filename=Django-1.11.1.tar.gz", + "pkg:pypi/django@1.11.1?filename=Django-1.11.1-py2.py3-none-any.whl", + "pkg:pypi/django-allauth@12.23" + ] +} diff --git a/types/qpkg-definition.json b/types/qpkg-definition.json new file mode 100644 index 00000000..16277bde --- /dev/null +++ b/types/qpkg-definition.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/qpkg-definition.json", + "type": "qpkg", + "type_name": "QNX package", + "description": "QNX packages", + "repository": { + "use_repository": true, + "note": "There is no default package repository, this should be implied either from the namespace or using a repository base URL as repository_url qualifiers key." + }, + "namespace_definition": { + "case_sensitive": false, + "native_name": "vendor", + "note": "The namespace is the vendor of the package. It is not case sensitive and must be lowercased.", + "requirement": "required" + }, + "name_definition": { + "native_name": "name" + }, + "examples": [ + "pkg:qpkg/blackberry/com.qnx.sdp@7.0.0.SGA201702151847", + "pkg:qpkg/blackberry/com.qnx.qnx710.foo.bar.qux@0.0.4.01449T202205040833L" + ] +} diff --git a/types/rpm-definition.json b/types/rpm-definition.json new file mode 100644 index 00000000..4e52acde --- /dev/null +++ b/types/rpm-definition.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/rpm-definition.json", + "type": "rpm", + "type_name": "RPM", + "description": "RPM packages", + "repository": { + "use_repository": true, + "note": "There is no default package repository, this should be implied either from the distro qualifiers key or using a repository base URL as repository_url qualifiers key." + }, + "namespace_definition": { + "case_sensitive": false, + "native_name": "vendor", + "note": "The namespace is the vendor such as Fedora or OpenSUSE. It is not case sensitive and must be lowercased.", + "requirement": "required" + }, + "name_definition": { + "case_sensitive": true, + "note": "The name is the RPM name and is case sensitive.", + "native_name": "name" + }, + "version_definition": { + "note": "The version is the combined version and release of an RPM.", + "native_name": "version-release" + }, + "qualifiers_definition": [ + { + "key": "epoch", + "requirement": "optional", + "description": "(optional for RPMs) is a qualifier as its not required for unique identification, but when the epoch exists we strongly encourage using it." + }, + { + "key": "arch", + "description": "the qualifiers key for a package architecture." + } + ], + "examples": [ + "pkg:rpm/fedora/curl@7.50.3-1.fc25?arch=i386&distro=fedora-25", + "pkg:rpm/centerim@4.22.10-1.el6?arch=i686&epoch=1&distro=fedora-25" + ] +} diff --git a/types/swid-definition.json b/types/swid-definition.json new file mode 100644 index 00000000..4d26ba98 --- /dev/null +++ b/types/swid-definition.json @@ -0,0 +1,62 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type.schema-1.0.json", + "$id": "https://packageurl.org/types/swid-definition.json", + "type": "swid", + "type_name": "Software Identification (SWID) Tag", + "description": "PURL type for ISO-IEC 19770-2 Software Identification (SWID) tags.", + "repository": { + "use_repository": false, + "note": "There is no default package repository." + }, + "namespace_definition": { + "requirement": "optional", + "case_sensitive": true, + "native_name": "softwareCreator", + "note": "The namespace is the optional name and regid of the entity with a role of softwareCreator. If specified, name is required and is the first segment in the namespace. If regid is known, it must be specified as the second segment in the namespace. A maximum of two segments are supported." + }, + "name_definition": { + "requirement": "required", + "case_sensitive": true, + "native_name": "SoftwareIdentity/name", + "note": "The name is the name as defined in the SWID SoftwareIdentity element." + }, + "version_definition": { + "requirement": "optional", + "case_sensitive": true, + "native_name": "SoftwareIdentity/version", + "note": "The version is the version as defined in the SWID SoftwareIdentity element." + }, + "qualifiers_definition": [ + { + "key": "tag_id", + "requirement": "required", + "description": "The qualifier tag_id must not be empty and corresponds to the tagId as defined in the SWID SoftwareIdentity element. Per the SWID specification, GUIDs are recommended. If a GUID is used, it must be lowercase. If a GUID is not used, the tag_id qualifier is case aware but not case sensitive." + }, + { + "key": "tag_version", + "requirement": "optional", + "description": "The qualifier tag_version is an optional integer and corresponds to the tagVersion as defined in the SWID SoftwareIdentity element. If not specified, defaults to 0." + }, + { + "key": "patch", + "requirement": "optional", + "description": "The qualifier patch is optional and corresponds to the patch as defined in the SWID SoftwareIdentity element. If not specified, defaults to false." + }, + { + "key": "tag_creator_name", + "requirement": "optional", + "description": "The qualifier tag_creator_name is optional. If the tag creator is different from the software creator, the tag_creator_name qualifier should be specified." + }, + { + "key": "tag_creator_regid", + "requirement": "optional", + "description": "The qualifier tag_creator_regid is optional. If the tag creator is different from the software creator, the tag_creator_regid qualifier should be specified." + } + ], + "note": "Use of known qualifiers key/value pairs such as download_url can be used to specify where the package was retrieved from.", + "examples": [ + "pkg:swid/Acme/example.com/Enterprise+Server@1.0.0?tag_id=75b8c285-fa7b-485b-b199-4745e3004d0d", + "pkg:swid/Fedora@29?tag_id=org.fedoraproject.Fedora-29", + "pkg:swid/Adobe+Systems+Incorporated/Adobe+InDesign@CC?tag_id=CreativeCloud-CS6-Win-GM-MUL" + ] +} diff --git a/types/swift-definition.json b/types/swift-definition.json new file mode 100644 index 00000000..55054b3c --- /dev/null +++ b/types/swift-definition.json @@ -0,0 +1,28 @@ +{ + "$schema": "https://packageurl.org/schemas/purl-type-definition.schema-1.0.json", + "$id": "https://packageurl.org/types/swift-definition.json", + "type": "swift", + "type_name": "Swift packages", + "description": "Swift packages", + "repository": { + "use_repository": true, + "note": "There is no default package repository, this should be implied from namespace." + }, + "namespace_definition": { + "requirement": "required", + "note": "The namespace is source host and user/organization and is required.", + "case_sensitive": true + }, + "name_definition": { + "case_sensitive": true, + "native_name": "repository name" + }, + "version_definition": { + "case_sensitive": true, + "native_name": "package version" + }, + "examples": [ + "pkg:swift/github.com/Alamofire/Alamofire@5.4.3", + "pkg:swift/github.com/RxSwiftCommunity/RxFlow@2.12.4" + ] +}