{"id":50975313,"url":"https://github.com/prefix-dev/purl-associator","last_synced_at":"2026-06-19T07:02:04.200Z","repository":{"id":354113214,"uuid":"1221912002","full_name":"prefix-dev/purl-associator","owner":"prefix-dev","description":"PURL ↔ conda-forge mapping with auto-inference + edit-via-PR workflow","archived":false,"fork":false,"pushed_at":"2026-06-18T04:56:10.000Z","size":128500,"stargazers_count":10,"open_issues_count":5,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-06-19T04:00:10.000Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://prefix-dev.github.io/purl-associator/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/prefix-dev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-26T20:49:27.000Z","updated_at":"2026-06-18T04:56:18.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/prefix-dev/purl-associator","commit_stats":null,"previous_names":["prefix-dev/purl-associator"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/prefix-dev/purl-associator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prefix-dev%2Fpurl-associator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prefix-dev%2Fpurl-associator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prefix-dev%2Fpurl-associator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prefix-dev%2Fpurl-associator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/prefix-dev","download_url":"https://codeload.github.com/prefix-dev/purl-associator/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prefix-dev%2Fpurl-associator/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34520433,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-19T02:00:06.005Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-19T07:02:03.108Z","updated_at":"2026-06-19T07:02:04.194Z","avatar_url":"https://github.com/prefix-dev.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PURL Associator\n\nThis repository maintains canonical **conda-forge package identity mappings**.\nEach mapping record is keyed by conda-forge package name and carries identifiers\nthat downstream security tooling can use:\n\n- a primary Package URL (**PURL**) and optional alternative PURLs\n- optional CPE 2.3 vendor/product prefixes for NVD matching\n- package context such as latest observed version, recipe/source URLs, summary,\n  and download counts\n\nCVE assignment, OpenVEX review state, AI CVE drafts, and SBOM-derived findings\nare intentionally out of scope. A downstream CVE project should consume the\nidentity mapping payload produced here, enumerate conda-forge versions there,\nand join those versions with OSV/NVD affected-version data there.\n\n## Data model\n\nThe core object is a conda-forge package identity record:\n\n```json\n{\n  \"name\": \"ncurses\",\n  \"version\": \"6.5\",\n  \"purl\": \"pkg:github/ThomasDickey/ncurses-snapshots\",\n  \"type\": \"github\",\n  \"namespace\": \"ThomasDickey\",\n  \"pkg_name\": \"ncurses-snapshots\",\n  \"alternative_purls\": [],\n  \"cpes\": [\n    \"cpe:2.3:a:gnu:ncurses\",\n    \"cpe:2.3:a:invisible-island:ncurses\"\n  ],\n  \"status\": \"verified\"\n}\n```\n\nPURLs identify source/package ecosystem coordinates. CPEs identify NVD\nvendor/product coordinates. CPE strings stored here are identity-level prefixes;\nthis repository does not store CVE affected ranges or per-CVE version decisions.\n\n## Sources and outputs\n\n| Path | Purpose |\n|---|---|\n| `mappings/auto.json` | automatically inferred PURL mappings |\n| `mappings/manual.json` | legacy/manual reviewed overrides |\n| `mappings/contributions/*.json` | PR-submitted mapping contributions, including CPE pipeline output |\n| `mappings/cpe_candidates/*.json` | audit output from CPE discovery |\n| `mappings/cpe_vet/*.json` | optional AI tiebreaker output for ambiguous CPE candidates |\n| `web/public/mappings.json` | generated full mapping bundle |\n| `web/public/mappings-index.json` | generated compact index for the web app |\n| `web/public/mapping_packages/*.json` | generated sharded package detail payloads |\n\n## PURL flow\n\n```mermaid\nflowchart TD\n  A[conda-forge metadata] --\u003e B[scripts.automap]\n  B --\u003e C[mappings/auto.json]\n  C --\u003e D[scripts.merge_mappings]\n  E[mappings/manual.json] --\u003e D\n  F[mappings/contributions/*.json] --\u003e D\n  D --\u003e G[web/public/mappings*.json]\n  G --\u003e H[PURL editing UI]\n  H --\u003e I[Worker POST /api/submit]\n  I --\u003e F\n```\n\nUseful commands:\n\n```sh\npixi run purl:automap --only numpy,ripgrep,pandas\npixi run -e lite mappings:merge\npixi run -e lite mappings:validate\npixi run purl:test\n```\n\n## CPE flow\n\nCPE discovery is part of identity mapping, not CVE assignment. The retained CPE\npipeline proposes NVD vendor/product prefixes and promotes accepted mappings as\nnormal contribution files. Those CPEs then flow through `scripts.merge_mappings`\ninto the public mapping payload.\n\n```mermaid\nflowchart TD\n  A[mappings/auto.json + reviewed mappings] --\u003e B[scripts.cpe_discover]\n  B --\u003e C[mappings/cpe_candidates/*.json]\n  C --\u003e D[scripts.cpe_vet optional]\n  D --\u003e E[mappings/cpe_vet/*.json]\n  C --\u003e F[scripts.cpe_promote]\n  E --\u003e F\n  F --\u003e G[mappings/contributions/*--cpe-pipeline--*.json]\n  G --\u003e H[scripts.merge_mappings]\n```\n\nUseful commands:\n\n```sh\npixi run cpe:discover --top 50\npixi run cpe:vet --dry-run\npixi run cpe:promote --dry-run\npixi run -e lite mappings:merge\npixi run -e lite mappings:validate\n```\n\n## Frontend behavior\n\nThe GitHub Pages app is a PURL editing UI:\n\n- users can review, edit, approve, or mark PURL mappings as unmapped\n- staged PURL edits are saved locally until submitted\n- submitted edits open PRs containing one new file under `mappings/contributions/`\n- CPEs are displayed read-only as package identity metadata\n- no CVE dashboard, OpenVEX review, AI CVE queue, or deep-inspection routes are\n  served from this repository\n\nThe Worker exposes only:\n\n- `POST /exchange` for GitHub OAuth code exchange\n- `POST /api/submit` for PURL mapping contribution PRs\n\n## Downstream CVE consumption\n\nA downstream CVE project should consume `web/public/mappings.json` or the split\n`mappings-index.json` + `mapping_packages/*.json` payload. It should then:\n\n1. enumerate conda-forge package versions independently,\n2. use PURLs for OSV/package-ecosystem matching,\n3. use CPE prefixes for NVD matching,\n4. apply OSV/NVD affected-version logic in that downstream project, and\n5. store CVE assignment/review state outside this repository.\n\n## Verification\n\nRun these checks before opening a PR:\n\n```sh\npixi run -e lite mappings:merge\npixi run -e lite mappings:validate\npixi run app:check\n```\n\nFor frontend/Worker-only checks:\n\n```sh\ncd web \u0026\u0026 npm run build\ncd worker \u0026\u0026 npm run typecheck\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprefix-dev%2Fpurl-associator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprefix-dev%2Fpurl-associator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprefix-dev%2Fpurl-associator/lists"}