Skip to content

ActiveState/CuratedCatalogUI

Repository files navigation

CuratedCatalog UI

A demo interface for the ActiveState Curated Catalog — a curated, vetted package index covering multiple languages. Built for customer POVs and sales demos.

Live: https://activestate.github.io/CuratedCatalogUI/


What this is

The ActiveState Curated Catalog provides private, security-vetted package indexes. This UI gives customers a visual overview of catalog contents and security posture across languages — things that are otherwise invisible when consuming the index via a package manager.

The UI is multi-customer. Each customer gets their own package + CVE data at public/data/<customer>/<lang>/. The active customer is shown as a pill in the navbar; to enable a full customer switcher, set CUSTOMER_SWITCHER_ACTIVE = true in src/components/Navbar.tsx.

Currently live: LDPoV — Python (1726 packages), JavaScript (4387 packages), Java/Maven (5357 packages).

Catalog browser (/#/:lang)

Full package table with inline information:

  • Package name — monospace, truncates gracefully on long names
  • Versions — all version pills, latest highlighted; consistent column width across languages
  • Vulnerabilities Summary — CVE alias or vuln ID pill per vulnerability, or a green Clean badge. Sortable.
  • View ↗ (Python only) — link to the package's page in the private PyPI index

Live search + sortable columns (name, CVE status).

CVE scan report (/#/:lang/cve-report)

Opens on the Vulnerable filter by default.

  • Stat cards — packages scanned / vulnerable / total CVEs / clean / scanner tool; Severity breakdown card (Critical / High / Moderate / Low counts) when CVEs are present
  • Filter — All / Vulnerable / Clean
  • Sortable columns — Package (A–Z / Z–A) and Severity (worst-first / best-first); severity sort also orders vulns within each package worst-first
  • Per-row — version pill, severity pill (Critical/High/Moderate/Low), vuln ID, CVE aliases, fix version, truncated description
  • Description modal — click for the full description with formatted text, headers, bold, code, links. Modal header shows severity pill + CVE aliases. Multi-CVE packages let you switch vulnerabilities inside the modal.
  • Unaudited notice (ASPoV internal only) — packages with no published registry versions are excluded from scan; a banner shows the count with a toggle to browse the list. Hidden for customer-facing views.

Python — scanned with pip-audit + OSV inside Docker (--disable-pip --no-deps).
JavaScript — scanned with osv-scanner via Docker against a generated package-lock.json.
Java — scanned with osv-scanner scan source --no-resolve via Docker against a generated pom.xml.


Tech stack

  • React 18 + TypeScript + Vite
  • React Router v6 (HashRouter — works on GitHub Pages without server config)
  • CSS variables — light and dark themes matching the ActiveState design system
  • GitHub Actionsvite build → deploys to gh-pages branch on every push to main

Repo structure

├── public/data/
│   ├── ldpov/                    ← active customer
│   │   ├── python/
│   │   │   ├── catalog.json      package list + versions
│   │   │   └── audit.json        pip-audit CVE results (normalized)
│   │   ├── javascript/
│   │   │   ├── catalog.json      npm package list + versions
│   │   │   └── audit.json        osv-scanner CVE results (normalized)
│   │   └── java/
│   │       ├── catalog.json      Maven artifact list + versions
│   │       └── audit.json        osv-scanner CVE results (normalized)
│   └── aspov/                    ← disabled (legacy ASPoV data)
│       ├── python/
│       └── javascript/
├── src/
│   ├── customers.ts              customer registry (id, label, languages[], disabled?)
│   ├── languages.ts              language registry (id, label, icon, scanTool, disabled?)
│   ├── context/
│   │   └── CustomerContext.tsx   selected-customer React context (defaults to ldpov)
│   ├── hooks/
│   │   └── useLanguageData.ts    per-customer/lang data fetch + cache
│   ├── components/               Navbar, VersionPill, CvePill, StatCard, DescriptionCell
│   ├── pages/                    CatalogPage, ScanReportPage, PackageDetailPage
│   └── styles/                   CSS variables (tokens.css) + global base styles
├── scripts/                      data pipelines (see below)
└── .github/workflows/            CI deploy to GitHub Pages

Environment setup

Copy .env.example to .env and fill in your values:

# LDPoV credentials
LDPOV_USER=<user>
LDPOV_CATALOG_TOKEN=<token>
LDPOV_ORG_ID=<org UUID>

# LDPoV registry URLs
PYPI_URL=<private PyPI index URL>
NPM_URL=<private npm registry URL>
MAVEN_URL=<private Maven repo URL>

.env is gitignored — never commit real credentials.


Refreshing data

Requires: .env loaded in your shell, AWS CLI logged in (aws sso login), Docker running.

Note: Docker on this machine requires --network host. The scan scripts set this automatically.

Rules — read before running anything

  1. Always run the fetch script before the scan script. Never reuse a stale catalog.json from a previous session. The scan uses whatever packages are in catalog.json at the time it runs — if that file is old, the scan results are wrong.

  2. All fetch scripts use S3 redirect_map only. Package names and versions are parsed directly from tarball/wheel/sdist filenames in the redirect_map keys. No registry API calls are made. Do not add registry calls — they cause rate-limiting (silent HTTP 403/404) that makes packages disappear without any error.

    • npm key format: {name}/-/{short_name}-{version}.tgz
    • PyPI key format: {sha256}/{filename} where filename is .whl or .tar.gz
    • Maven key format: group:artifact:version triples
  3. Switching to a different org or customer: change LDPOV_ORG_ID (or the equivalent *_ORG_ID) in .env, then re-run all three fetch scripts and all three scan scripts. Old data files for a different org must never be committed alongside new ones.

LDPoV Python

cd scripts
python3 fetch_ldpov_pypi.py      # → ../public/data/ldpov/python/catalog.json
bash run_ldpov_pypi_scan.sh      # → ../public/data/ldpov/python/audit.json

LDPoV JavaScript

cd scripts
python3 fetch_ldpov_npm.py       # → ../public/data/ldpov/javascript/catalog.json
bash run_ldpov_npm_scan.sh       # → ../public/data/ldpov/javascript/audit.json

LDPoV Java (Maven)

cd scripts
python3 fetch_ldpov_maven.py     # → ../public/data/ldpov/java/catalog.json
bash run_ldpov_maven_scan.sh     # → ../public/data/ldpov/java/audit.json

Commit + push

cd ..
git add public/data/ldpov/
git commit -m "chore: refresh LDPoV catalog + CVE data"
git push

Local development

npm install
npm run dev       # http://localhost:5173/CuratedCatalogUI/

Navigate to /#/python, /#/javascript, or /#/java. The root redirects to /#/python.


Scripts (scripts/)

File Language Purpose
fetch_ldpov_pypi.py Python S3 redirect_map → parse whl/sdist filenames → ldpov/python/catalog.json
run_ldpov_pypi_scan.sh Python pip-audit in Docker → ldpov/python/audit.json
fetch_ldpov_npm.py JavaScript S3 redirect_map → parse tarball keys → ldpov/javascript/catalog.json
run_ldpov_npm_scan.sh JavaScript osv-scanner in Docker → ldpov/javascript/audit.json
normalize_npm_audit.py JavaScript Normalize osv-scanner JSON → shared audit.json schema; extracts severity from database_specific.severity
fetch_ldpov_maven.py Java S3 repo-type=maven2 redirect_map (group:artifact:version keys) → ldpov/java/catalog.json
run_ldpov_maven_scan.sh Java Build pom.xml → osv-scanner scan source --no-resolve in Docker → raw JSON
normalize_maven_audit.py Java Normalize osv-scanner v2 JSON → shared audit.json schema; includes all catalog packages; extracts severity
Dockerfile Python python:3.12-slim + pip-audit for Python scanning

Adding a new customer

  1. Add an entry to src/customers.ts with id, label, languages[], and disabled: true initially.
  2. Add credentials to .env.
  3. Write scripts/fetch_<customer>_pypi.py, npm, maven as needed (copy from ldpov equivalents).
  4. Run fetches and scans → public/data/<customer>/.
  5. Remove disabled: true from the customer entry to make it visible.
  6. Set CUSTOMER_SWITCHER_ACTIVE = true in src/components/Navbar.tsx to enable the dropdown.

Customer switcher

The customer pill in the navbar is currently non-interactive. To enable the full dropdown:

// src/components/Navbar.tsx
const CUSTOMER_SWITCHER_ACTIVE = true   // ← change this

All dropdown logic (state, refs, click-outside detection, language fallback) is already wired up and gated by this constant.

About

No description, website, or topics provided.

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors