andrew/purl

GitHub: andrew/purl

一个符合 PURL 规范的 Ruby 库与 CLI 工具,用于跨 37 种包生态系统解析、验证、生成 Package URL 并进行 registry URL 转换与包信息查询。

Stars: 12 | Forks: 1

# Purl - Ruby 的 Package URL 解析器 一个 Ruby 库,用于解析、验证和生成由 [PURL 规范](https://github.com/package-url/purl-spec) 定义的 Package URL (PURL)。 该库具有命名空间错误类型的全面错误处理、双向 registry URL 转换以及基于 JSON 的配置以实现跨语言兼容性。 [![Ruby](https://img.shields.io/badge/ruby-%3E%3D%203.1-red.svg)](https://www.ruby-lang.org/) [![Gem Version](https://badge.fury.io/rb/purl.svg)](https://rubygems.org/gems/purl) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) **[在 RubyGems 上获取](https://rubygems.org/gems/purl)** | **[API 文档](https://rdoc.info/github/andrew/purl)** ## 相关库 - **[Vers](https://github.com/andrew/vers)** - 一个 Ruby 库,用于处理支持 VERS 规范的版本范围 ## 功能 - **命令行界面** 包含 parse、validate、convert、download、generate、info、lookup 和 advisories 命令,并支持 JSON 输出 - **全面的 PURL 解析和验证** 支持 37 种包类型(32 种官方类型 + 5 种额外的生态系统) - **更好的错误处理** 包含命名空间错误类和上下文信息 - **双向 registry URL 转换** - 从 PURL 生成 registry URL 并从 registry URL 解析 PURL - **下载 URL 生成** 支持 18 种包生态系统(gem、npm、cargo、maven 等) - **安全公告查询** - 从 advisories.ecosyste.ms 查询安全公告 - **包信息查询** - 从 ecosyste.ms 查询包元数据 - **针对特定类型的验证** 支持 conan、cran 和 swift 包 - **Registry URL 生成** 支持 20 种包生态系统(npm、gem、maven、pypi 等) - **Rails 风格的路由模式** 用于 registry URL 模板 - **100% 兼容** 官方 PURL 规范测试套件(59/59 项测试通过) - **跨语言兼容性** 采用基于 JSON 的配置 - **全面的文档** 和示例 ## 安装说明 将以下行添加到您的应用程序的 Gemfile 中: ``` gem 'purl' ``` 然后执行: ``` bundle install ``` 或者自行安装: ``` gem install purl ``` ## 命令行界面 purl gem 包含一个命令行界面,可方便地访问所有解析、验证、转换和生成功能。 ### 安装说明 安装 gem 后即可自动使用 CLI: ``` gem install purl purl --help ``` ### 可用命令 ``` purl parse # Parse and display PURL components purl validate # Validate a PURL (exit code indicates success) purl convert # Convert registry URL to PURL purl url # Convert PURL to registry URL purl download # Get download URL for package version purl generate [options] # Generate PURL from components purl info [type] # Show information about PURL types purl lookup # Look up package information from ecosyste.ms purl advisories # Look up security advisories from advisories.ecosyste.ms ``` ### JSON 输出 所有命令均支持带有 `--json` 标志的 JSON 输出: ``` purl --json parse "pkg:gem/rails@7.0.0" purl --json info gem purl --json lookup "pkg:cargo/rand" purl --json advisories "pkg:npm/lodash@4.17.19" ``` ### 命令示例 #### 解析 PURL ``` $ purl parse "pkg:gem/rails@7.0.0" Valid PURL: pkg:gem/rails@7.0.0 Components: Type: gem Namespace: (none) Name: rails Version: 7.0.0 Qualifiers: (none) Subpath: (none) $ purl --json parse "pkg:npm/@babel/core@7.0.0" { "success": true, "purl": "pkg:npm/%40babel/core@7.0.0", "components": { "type": "npm", "namespace": "@babel", "name": "core", "version": "7.0.0", "qualifiers": {}, "subpath": null } } ``` #### 验证 PURL ``` $ purl validate "pkg:gem/rails@7.0.0" Valid PURL $ purl validate "invalid-purl" Invalid PURL: PURL must start with 'pkg:' ``` #### 将 Registry URL 转换为 PURL ``` $ purl convert "https://rubygems.org/gems/rails" pkg:gem/rails $ purl convert "https://www.npmjs.com/package/@babel/core" pkg:npm/@babel/core ``` #### 将 PURL 转换为 Registry URL ``` $ purl url "pkg:gem/rails@7.0.0" https://rubygems.org/gems/rails $ purl url "pkg:npm/@babel/core@7.0.0" https://www.npmjs.com/package/@babel/core $ purl --json url "pkg:gem/rails@7.0.0" { "success": true, "purl": "pkg:gem/rails@7.0.0", "registry_url": "https://rubygems.org/gems/rails", "type": "gem" } ``` #### 获取下载 URL ``` $ purl download "pkg:gem/rails@7.0.0" https://rubygems.org/downloads/rails-7.0.0.gem $ purl download "pkg:npm/@babel/core@7.20.0" https://registry.npmjs.org/@babel/core/-/core-7.20.0.tgz $ purl download "pkg:cargo/serde@1.0.152" https://static.crates.io/crates/serde/serde-1.0.152.crate $ purl --json download "pkg:maven/org.apache.commons/commons-lang3@3.12.0" { "success": true, "purl": "pkg:maven/org.apache.commons/commons-lang3@3.12.0", "download_url": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-lang3/3.12.0/commons-lang3-3.12.0.jar", "type": "maven" } ``` #### 生成 PURL ``` $ purl generate --type gem --name rails --version 7.0.0 pkg:gem/rails@7.0.0 $ purl generate --type npm --namespace @babel --name core --version 7.0.0 --qualifiers "arch=x64,os=linux" pkg:npm/%40babel/core@7.0.0?arch=x64&os=linux ``` #### 显示类型信息 ``` $ purl info gem Type: gem Known: Yes Description: RubyGems Default registry: https://rubygems.org Registry URL generation: Yes Reverse parsing: Yes Examples: pkg:gem/ruby-advisory-db-check@0.12.4 pkg:gem/rails@7.0.4 pkg:gem/bundler@2.3.26 Registry URL patterns: https://rubygems.org/gems/:name https://rubygems.org/gems/:name/versions/:version $ purl info # Shows all types Known PURL types: alpm Description: Arch Linux packages Registry support: No Reverse parsing: No ... Total types: 37 Registry supported: 20 ``` #### 查询包信息 ``` $ purl lookup "pkg:cargo/rand" Package: rand (cargo) Description: Random number generators and other randomness functionality. Homepage: https://rust-random.github.io/book Repository: https://github.com/rust-random/rand License: MIT OR Apache-2.0 Downloads: 145,678,901 Latest Version: 0.8.5 Published: 2023-01-13T17:47:01.870Z $ purl --json lookup "pkg:cargo/rand@0.8.5" { "success": true, "purl": "pkg:cargo/rand@0.8.5", "package": { "name": "rand", "ecosystem": "cargo", "description": "Random number generators and other randomness functionality.", "homepage": "https://rust-random.github.io/book", "repository_url": "https://github.com/rust-random/rand", "registry_url": "https://crates.io/crates/rand", "licenses": "MIT OR Apache-2.0", "latest_version": "0.8.5", "latest_version_published_at": "2023-01-13T17:47:01.870Z", "versions_count": 89, "maintainers": [ { "login": "dhardy", "name": "Diggory Hardy" } ] }, "version": { "number": "0.8.5", "published_at": "2023-01-13T17:47:01.870Z", "registry_url": "https://crates.io/crates/rand/0.8.5", "downloads": 5678901, "size": 102400 } } ``` #### 查询安全公告 ``` $ purl advisories "pkg:npm/lodash@4.17.19" Security Advisories for pkg:npm/lodash@4.17.19 ================================================================================ Advisory #1: Regular Expression Denial of Service (ReDoS) in lodash Identifiers: GHSA-x5rq-j2xg-h7qm, CVE-2019-1010266 Severity: MODERATE Description: lodash prior to 4.7.11 is affected by: CWE-400: Uncontrolled Resource Consumption. The impact is: Denial of service. The component is: Date handler. The attack vector is: Attacker provides very long strings, which the library attempts to match using a regular expression. The fixed version is: 4.7.11. Affected Packages: Package: npm/lodash Vulnerable: >= 4.7.0, < 4.17.11 Patched: 4.17.11 Source: github | Origin: UNSPECIFIED | Published: 2019-07-19T16:13:07.000Z Advisory URL: https://github.com/advisories/GHSA-x5rq-j2xg-h7qm Total advisories found: 3 $ purl --json advisories "pkg:npm/lodash@4.17.19" { "success": true, "purl": "pkg:npm/lodash@4.17.19", "advisories": [ { "id": "MDE2OlNlY3VyaXR5QWR2aXNvcnlHSFNBLXg1cnEtajJ4Zy1oN3Ft", "title": "Regular Expression Denial of Service (ReDoS) in lodash", "description": "lodash prior to 4.7.11 is affected by...", "severity": "MODERATE", "url": "https://github.com/advisories/GHSA-x5rq-j2xg-h7qm", "published_at": "2019-07-19T16:13:07.000Z", "affected_packages": [ { "ecosystem": "npm", "name": "lodash", "vulnerable_version_range": ">= 4.7.0, < 4.17.11", "first_patched_version": "4.17.11" } ], "identifiers": ["GHSA-x5rq-j2xg-h7qm", "CVE-2019-1010266"] } ], "count": 3 } ``` ### 生成选项 `generate` 命令支持所有 PURL 组件: ``` purl generate --help Usage: purl generate [options] --type TYPE Package type (required) --name NAME Package name (required) --namespace NAMESPACE Package namespace --version VERSION Package version --qualifiers QUALIFIERS Qualifiers as key=value,key2=value2 --subpath SUBPATH Package subpath -h, --help Show this help ``` ### 退出代码 CLI 使用标准退出代码: - `0` - 成功 - `1` - 错误(无效的 PURL、不支持的操作等) 这使得 CLI 适合在脚本和 CI/CD pipeline 中使用: ``` if purl validate "pkg:gem/rails@7.0.0"; then echo "Valid PURL" else echo "Invalid PURL" exit 1 fi ``` ## 库的用法 ### 基础 PURL 解析 ``` require 'purl' # 解析 PURL 字符串 purl = Purl.parse("pkg:gem/rails@7.0.0") puts purl.type # => "gem" puts purl.name # => "rails" puts purl.version # => "7.0.0" puts purl.namespace # => nil # 使用 namespace 和 qualifiers 进行解析 purl = Purl.parse("pkg:npm/@babel/core@7.0.0?arch=x86_64") puts purl.type # => "npm" puts purl.namespace # => "@babel" puts purl.name # => "core" puts purl.version # => "7.0.0" puts purl.qualifiers # => {"arch" => "x86_64"} ``` ### 创建 PURL ``` # 创建 PURL 对象 purl = Purl::PackageURL.new( type: "maven", namespace: "org.apache.commons", name: "commons-lang3", version: "3.12.0" ) puts purl.to_s # => "pkg:maven/org.apache.commons/commons-lang3@3.12.0" ``` ### 修改 PURL 对象 PURL 对象在设计上是不变的,但您可以使用 `with` 方法创建带有修改属性的新对象: ``` # 创建原始 PURL original = Purl::PackageURL.new( type: "npm", namespace: "@babel", name: "core", version: "7.20.0", qualifiers: { "arch" => "x64" } ) # 创建更新了 version 的新 PURL updated = original.with(version: "7.21.0") puts updated.to_s # => "pkg:npm/@babel/core@7.21.0?arch=x64" # 更新 qualifiers with_new_qualifiers = original.with( qualifiers: { "arch" => "arm64", "os" => "linux" } ) puts with_new_qualifiers.to_s # => "pkg:npm/@babel/core@7.20.0?arch=arm64&os=linux" # 一次更新多个属性 fully_updated = original.with( version: "8.0.0", qualifiers: { "dev" => "true" }, subpath: "lib/index.js" ) puts fully_updated.to_s # => "pkg:npm/@babel/core@8.0.0#lib/index.js?dev=true" # 原始对象保持不变 puts original.to_s # => "pkg:npm/@babel/core@7.20.0?arch=x64" ``` ### Registry URL 生成 ``` # 从 PURLs 生成 registry URLs purl = Purl.parse("pkg:gem/rails@7.0.0") puts purl.registry_url # => "https://rubygems.org/gems/rails" puts purl.registry_url_with_version # => "https://rubygems.org/gems/rails/versions/7.0.0" # 检查是否支持 registry URL 生成 puts purl.supports_registry_url? # => true # 带 scoped packages 的 NPM purl = Purl.parse("pkg:npm/@babel/core@7.0.0") puts purl.registry_url # => "https://www.npmjs.com/package/@babel/core" ``` ### 下载 URL 生成 为包构件生成直接下载 URL: ``` # 从 PURLs 生成 download URLs purl = Purl.parse("pkg:gem/rails@7.0.0") puts purl.download_url # => "https://rubygems.org/downloads/rails-7.0.0.gem" # 检查是否支持 download URL 生成 puts purl.supports_download_url? # => true # 带 scoped packages 的 NPM purl = Purl.parse("pkg:npm/@babel/core@7.20.0") puts purl.download_url # => "https://registry.npmjs.org/@babel/core/-/core-7.20.0.tgz" # Maven packages purl = Purl.parse("pkg:maven/org.apache.commons/commons-lang3@3.12.0") puts purl.download_url # => "https://repo.maven.apache.org/maven2/org/apache/commons/commons-lang3/3.12.0/commons-lang3-3.12.0.jar" # 通过 repository_url qualifier 的自定义 registry purl = Purl.parse("pkg:npm/lodash@4.17.21?repository_url=https://npm.mycompany.com") puts purl.download_url # => "https://npm.mycompany.com/lodash/-/lodash-4.17.21.tgz" # 通过参数指定自定义 registry purl = Purl.parse("pkg:gem/rails@7.0.0") puts purl.download_url(base_url: "https://gems.internal.com/downloads") # => "https://gems.internal.com/downloads/rails-7.0.0.gem" # 获取支持的类型列表 puts Purl.download_supported_types # => ["bioconductor", "bitbucket", "cargo", "clojars", "cran", "elm", "gem", # "github", "gitlab", "golang", "hackage", "hex", "luarocks", "maven", # "npm", "nuget", "pub", "swift"] ``` ### ecosyste.ms API URL 为 packages.ecosyste.ms 服务生成 API URL: ``` # 获取 package type 的 ecosyste.ms registry 名称 purl = Purl.parse("pkg:gem/rake@13.3.1") purl.ecosystems_registry # => "rubygems.org" # 生成 API URLs purl.ecosystems_api_url # => "https://packages.ecosyste.ms/api/v1/registries/rubygems.org/packages/rake/versions/13.3.1" purl.ecosystems_package_api_url # => "https://packages.ecosyste.ms/api/v1/registries/rubygems.org/packages/rake" purl.ecosystems_version_api_url # => "https://packages.ecosyste.ms/api/v1/registries/rubygems.org/packages/rake/versions/13.3.1" # 适用于带 namespace 的 packages purl = Purl.parse("pkg:npm/@babel/core@7.20.0") purl.ecosystems_registry # => "npmjs.org" purl.ecosystems_api_url # => "https://packages.ecosyste.ms/api/v1/registries/npmjs.org/packages/%40babel%2Fcore/versions/7.20.0" # 没有 version 时,返回 package URL purl = Purl.parse("pkg:cargo/serde") purl.ecosystems_api_url # => "https://packages.ecosyste.ms/api/v1/registries/crates.io/packages/serde" ``` ### 反向解析:Registry URL 到 PURL ``` # 将 registry URLs 解析回 PURLs purl = Purl.from_registry_url("https://rubygems.org/gems/rails/versions/7.0.0") puts purl.to_s # => "pkg:gem/rails@7.0.0" # 适用于各种 registries purl = Purl.from_registry_url("https://www.npmjs.com/package/@babel/core") puts purl.to_s # => "pkg:npm/@babel/core" purl = Purl.from_registry_url("https://pypi.org/project/django/4.0.0/") puts purl.to_s # => "pkg:pypi/django@4.0.0" ``` ### 自定义 Registry 域名 您可以解析来自自定义域名的 registry URL,或为私有 registry 生成 URL: ``` # 从自定义域名解析(指定 type 以辅助解析) purl = Purl.from_registry_url("https://npm.company.com/package/@babel/core", type: "npm") puts purl.to_s # => "pkg:npm/@babel/core" # 为自定义 registries 生成 URLs purl = Purl.parse("pkg:gem/rails@7.0.0") custom_url = purl.registry_url(base_url: "https://gems.internal.com/gems") puts custom_url # => "https://gems.internal.com/gems/rails" # 带有特定版本的 URLs with_version = purl.registry_url_with_version(base_url: "https://gems.internal.com/gems") puts with_version # => "https://gems.internal.com/gems/rails/versions/7.0.0" # 适用于所有支持的 package 类型 composer_purl = Purl.parse("pkg:composer/symfony/console@5.4.0") private_composer = composer_purl.registry_url(base_url: "https://packagist.company.com/packages") puts private_composer # => "https://packagist.company.com/packages/symfony/console" ``` ### 路由模式 ``` # 获取 package type 的 route patterns(Rails 风格) patterns = Purl::RegistryURL.route_patterns_for("gem") # => ["https://rubygems.org/gems/:name", "https://rubygems.org/gems/:name/versions/:version"] # 获取所有 route patterns all_patterns = Purl::RegistryURL.all_route_patterns puts all_patterns["npm"] # => ["https://www.npmjs.com/package/:namespace/:name", "https://www.npmjs.com/package/:name", ...] ``` ### 使用 Qualifiers Qualifiers 是键值对,用于提供有关包的额外元数据: ``` # 创建带 qualifiers 的 PURL purl = Purl::PackageURL.new( type: "apk", name: "curl", version: "7.83.0-r0", qualifiers: { "distro" => "alpine-3.16", "arch" => "x86_64", "repository_url" => "https://dl-cdn.alpinelinux.org" } ) puts purl.to_s # => "pkg:apk/curl@7.83.0-r0?arch=x86_64&distro=alpine-3.16&repository_url=https://dl-cdn.alpinelinux.org" # 访问 qualifiers puts purl.qualifiers["distro"] # => "alpine-3.16" puts purl.qualifiers["arch"] # => "x86_64" # 解析带 qualifiers 的 PURL parsed = Purl.parse("pkg:rpm/httpd@2.4.53?distro=fedora-36&arch=x86_64") puts parsed.qualifiers # => {"distro" => "fedora-36", "arch" => "x86_64"} # 向现有 PURL 添加 qualifiers with_qualifiers = purl.with(qualifiers: purl.qualifiers.merge("signed" => "true")) ``` ### 包类型信息 ``` # 获取所有已知的 PURL 类型 puts Purl.known_types.length # => 37 puts Purl.known_types.include?("gem") # => true # 检查类型支持 puts Purl.known_type?("gem") # => true puts Purl.registry_supported_types # => ["cargo", "gem", "maven", "npm", ...] puts Purl.reverse_parsing_supported_types # => ["bioconductor", "cargo", "clojars", ...] puts Purl.download_supported_types # => ["cargo", "gem", "maven", "npm", ...] # 获取某种类型的默认 registry puts Purl.default_registry("gem") # => "https://rubygems.org" puts Purl.default_registry("npm") # => "https://registry.npmjs.org" puts Purl.default_registry("golang") # => nil (no default) # 获取某种类型的官方示例 puts Purl.type_examples("gem") # => ["pkg:gem/rails@7.0.4", "pkg:gem/bundler@2.3.26", ...] puts Purl.type_examples("npm") # => ["pkg:npm/lodash@4.17.21", "pkg:npm/@babel/core@7.20.0", ...] puts Purl.type_examples("unknown") # => [] # 获取详细的类型信息 info = Purl.type_info("gem") puts info[:known] # => true puts info[:description] # => "RubyGems" puts info[:default_registry] # => "https://rubygems.org" puts info[:examples] # => ["pkg:gem/rails@7.0.4", ...] puts info[:registry_url_generation] # => true puts info[:reverse_parsing] # => true puts info[:download_url_generation] # => true puts info[:route_patterns] # => ["https://rubygems.org/gems/:name", ...] ``` ### 安全公告查询 使用 advisories.ecosyste.ms API 查询包的安全公告: ``` # 查找 package 的 advisories purl = Purl.parse("pkg:npm/lodash@4.17.19") advisories = purl.advisories # 显示 advisory 信息 advisories.each do |advisory| puts "Title: #{advisory[:title]}" puts "Severity: #{advisory[:severity]}" puts "Description: #{advisory[:description]}" puts "URL: #{advisory[:url]}" # Show affected packages advisory[:affected_packages].each do |pkg| puts " Package: #{pkg[:ecosystem]}/#{pkg[:name]}" puts " Vulnerable: #{pkg[:vulnerable_version_range]}" puts " Patched: #{pkg[:first_patched_version]}" if pkg[:first_patched_version] end # Show identifiers (CVE, GHSA, etc.) puts "Identifiers: #{advisory[:identifiers].join(', ')}" puts end # 查找 package 任意版本的 advisories purl = Purl.parse("pkg:npm/lodash") all_advisories = purl.advisories # 使用自定义 user agent 和 timeout advisories = purl.advisories(user_agent: "my-app/1.0", timeout: 5) ``` ### 错误处理 ``` # 带有 context 的详细错误类型 begin Purl.parse("invalid-purl") rescue Purl::InvalidSchemeError => e puts "Scheme error: #{e.message}" rescue Purl::ParseError => e puts "Parse error: #{e.message}" puts "Component: #{e.component}" puts "Value: #{e.value}" end # 特定类型的 validation 错误 begin Purl::PackageURL.new(type: "swift", name: "Alamofire") # Swift requires namespace rescue Purl::ValidationError => e puts e.message # => "Swift PURLs require a namespace to be unambiguous" end ``` ### 支持的包类型 该库支持 37 种包类型(32 种官方类型 + 5 种额外的生态系统): **Registry URL 生成(20 种):** - `bioconductor` (R/Bioconductor) - bioconductor.org - `cargo` (Rust) - crates.io - `clojars` (Clojure) - clojars.org - `cocoapods` (iOS) - cocoapods.org - `composer` (PHP) - packagist.org - `conda` (Python) - anaconda.org - `cpan` (Perl) - metacpan.org - `deno` (Deno) - deno.land/x - `elm` (Elm) - package.elm-lang.org - `gem` (Ruby) - rubygems.org - `golang` (Go) - pkg.go.dev - `hackage` (Haskell) - hackage.haskell.org - `hex` (Elixir) - hex.pm - `homebrew` (macOS) - formulae.brew.sh - `maven` (Java) - mvnrepository.com - `npm` (Node.js) - npmjs.com - `nuget` (.NET) - nuget.org - `pub` (Dart) - pub.dev - `pypi` (Python) - pypi.org - `swift` (Swift) - swiftpackageindex.com **反向解析(20 种):** - `bioconductor`, `cargo`, `clojars`, `cocoapods`, `composer`, `conda`, `cpan`, `deno`, `elm`, `gem`, `golang`, `hackage`, `hex`, `homebrew`, `maven`, `npm`, `nuget`, `pub`, `pypi`, `swift` **下载 URL 生成(18 种):** - `bioconductor` - bioconductor.org/packages/release/bioc/src/contrib - `bitbucket` - bitbucket.org 归档下载 - `cargo` - static.crates.io/crates - `clojars` - repo.clojars.org(Maven 风格) - `cran` - cran.r-project.org/src/contrib - `elm` - GitHub 归档下载 - `gem` - rubygems.org/downloads - `github` - GitHub 归档下载 - `gitlab` - GitLab 归档下载 - `golang` - proxy.golang.org - `hackage` - hackage.haskell.org/package - `hex` - repo.hex.pm/tarballs - `luarocks` - luarocks.org/manifests - `maven` - repo.maven.apache.org/maven2 - `npm` - registry.npmjs.org - `nuget` - api.nuget.org/v3-flatcontainer - `pub` - pub.dev/packages - `swift` - GitHub/GitLab/Bitbucket(派生自 namespace) **所有 37 种支持的类型:** `alpm`, `apk`, `bioconductor`, `bitbucket`, `bitnami`, `cargo`, `clojars`, `cocoapods`, `composer`, `conan`, `conda`, `cpan`, `cran`, `deb`, `deno`, `docker`, `elm`, `gem`, `generic`, `github`, `golang`, `hackage`, `hex`, `homebrew`, `huggingface`, `luarocks`, `maven`, `mlflow`, `npm`, `nuget`, `oci`, `pub`, `pypi`, `qpkg`, `rpm`, `swid`, `swift` ## 规范合规性 - **100% 兼容** 官方 PURL 规范测试套件(59/59 项测试通过) - **支持所有 32 种官方包类型** 以及 5 种额外的生态系统类型 - **针对特定类型的验证** 支持 conan、cran、swift、cpan 和 mlflow 包 - **妥善的错误处理** 用于处理应被拒绝的无效 PURL ## JSON 配置 包类型和 registry 模式存储在 `purl-types.json` 中,以便于贡献和实现跨语言兼容性: ``` { "version": "1.0.0", "description": "PURL types and registry URL patterns for package ecosystems", "source": "https://github.com/package-url/purl-spec/blob/main/PURL-TYPES.rst", "last_updated": "2025-07-24", "types": { "gem": { "description": "RubyGems", "default_registry": "https://rubygems.org", "registry_config": { "path_template": "/gems/:name", "version_path_template": "/gems/:name/versions/:version", "reverse_regex": "/gems/([^/?#]+)(?:/versions/([^/?#]+))?", "components": { "namespace": false, "version_in_url": true, "version_path": "/versions/" } } } } } ``` **关键配置改进:** - **与域名无关的模式**:不带硬编码域名的 `path_template` 支持自定义 registry - **灵活的 URL 生成**:将 `default_registry` + `path_template` 组合适用于任何域名 - **更整洁的 JSON**:减少重复并简化维护 - **跨 registry 兼容性**:相同的 URL 结构适用于公共和私有 registry ## JSON Schema 验证 该库包含用于验证和文档的 JSON schema: - **`schemas/purl-types.schema.json`** - PURL 类型配置文件的 schema - **`schemas/test-suite-data.schema.json`** - 官方测试套件数据的 schema 这些 schema 提供: - **结构验证** - 确保 JSON 文件符合预期格式 - **文档** - 带有描述的自我记录配置 - **IDE 支持** - 在编辑器中启用自动补全和验证 - **CI/CD 集成** - 在自动化 pipeline 中验证配置 根据对应的 schema 验证 JSON 文件: ``` rake spec:validate_schemas ``` ## 开发 检出仓库后,运行 `bin/setup` 安装依赖项。然后: ``` # 运行测试 rake test # 运行 specification compliance 测试 rake spec:compliance # 从官方 PURL spec 更新测试用例 rake spec:update # 显示类型信息 rake spec:types # 根据官方 specification 验证类型 rake spec:verify_types ``` ### 针对官方规范进行测试 该库包含官方 [purl-spec](https://github.com/package-url/purl-spec) 仓库作为 git submodule 用于测试和验证: ``` # 初始化 submodule(仅首次) git submodule update --init --recursive # 将 submodule 更新到最新的 spec git submodule update --remote purl-spec ``` 测试使用 submodule 中的文件来: - **Schema 验证**:根据 `purl-spec/schemas/` 中的官方 schema 验证我们的 `purl-types.json` - **类型合规性**:确保我们支持的类型与 `purl-spec/types/` 中的官方类型相匹配 - **测试数据**:从 `purl-spec/tests/` 访问官方测试用例和示例 该 submodule 会通过 Dependabot 每周自动更新,确保测试与最新的规范更改保持同步。当 submodule 更新时,您可以审查并合并 PR 以采用新的规范要求。 ### Rake 任务 - `rake spec:update` - 从官方 PURL 规范仓库获取最新测试用例 - `rake spec:compliance` - 针对官方测试套件运行合规性测试 - `rake spec:types` - 显示所有 PURL 类型及其支持情况的信息 - `rake spec:verify_types` - 根据官方规范验证我们的类型列表 - `rake spec:validate_schemas` - 根据 schema 验证 JSON 文件 - `rake spec:debug` - 显示失败测试用例的详细信息 ## 资金支持 如果您觉得这个项目有用,请考虑支持它的开发: - [GitHub Sponsors](https://github.com/sponsors/andrew) - [Ko-fi](https://ko-fi.com/andrewnez) - [Buy Me a Coffee](https://www.buymeacoffee.com/andrewnez) 您的支持有助于为整个 Ruby 社区维护和改进此库。 ## 贡献 欢迎在 GitHub 上提交 Bug 报告和 Pull Request。本项目旨在成为一个安全、欢迎的协作空间,并期望贡献者遵守[贡献者公约](http://contributor-covenant.org)的行为准则。 1. Fork 它 2. 创建您的功能分支 (`git checkout -b my-new-feature`) 3. 进行更改 4. 为您的更改添加测试 5. 确保所有测试通过 (`rake test`) 6. 提交您的更改 (`git commit -am 'Add some feature'`) 7. 推送到分支 (`git push origin my-new-feature`) 8. 创建新的 Pull Request ### 添加新的包类型 要添加对新包类型的支持: 1. 使用新的类型配置更新 `purl-types.json` 2. 如果适用,添加 registry URL 模式 3. 如果需要,在 `lib/purl/package_url.rb` 中添加特定于类型的验证规则 4. 为新功能添加测试 ## 许可证 该 gem 作为开源软件提供,基于 [MIT 许可证](https://opensource.org/licenses/MIT) 的条款发布。 ## 更新日志 请查看 [CHANGELOG.md](CHANGELOG.md) 获取详细的更改和发布历史。 ## 行为准则 期望所有在 Purl 项目代码库、问题跟踪系统、聊天室和邮件列表中进行互动的人员都能遵守[贡献者公约行为准则CODE_OF_CONDUCT.md)。
标签:Homebrew安装, PURL规范, Ruby, 依赖解析, 动态分析, 包管理, 库, 应急响应, 文档结构分析, 知识库