Development Guide¶
Prerequisites¶
- Python 3.11–3.13
- Git
- No external services required (SQLite, in-memory cache by default)
Setup¶
git clone https://github.com/code-with-zeeshan/universal-dependency-resolver
cd universal-dependency-resolver
python3 -m venv venv
source venv/bin/activate
pip install -e ".[dev,z3,system,postgres]"
Pre-commit Hooks¶
The pre-commit hook runs:
ruff check backend/— lint (no violations allowed)ruff format --check backend/— format checkmypy backend/— type checking (strict mode)- Architecture import rules — no violations allowed
- Check for large files, private keys, merge conflicts, debug statements
Development Server¶
Auto-reloads on Python file changes (dev only).
Tests¶
# Run all tests
python -m pytest
# By category
python -m pytest tests/unit # 3811 tests
python -m pytest tests/integration # 96 tests
python -m pytest tests/e2e # 392 tests
python -m pytest tests/e2e/test_golden_matrix.py # golden regression matrix (real registries)
# With coverage
python -m pytest --cov=backend --cov-report=term-missing --cov-fail-under=57
# Specific test file
python -m pytest tests/unit/test_cli.py -v
# Fast fail
python -m pytest -x
# Parallel (needs pytest-xdist)
python -m pytest -n auto
Current totals: 4382 tests (3811 unit + 96 integration + 392 e2e + others)
Code Quality¶
# Lint (ruff)
ruff check backend/
# Auto-fix
ruff check backend/ --fix
# Format check
ruff format --check backend/
# Format
ruff format backend/
# Type check (mypy)
mypy backend/
Project Structure¶
universal-dependency-resolver/
├── backend/
│ ├── __init__.py
│ ├── py.typed # PEP 561 marker
│ ├── api/ # FastAPI application
│ │ ├── main.py # App factory, middleware, exception handlers
│ │ ├── dependencies.py # FastAPI dependency injection
│ │ ├── middleware.py # Auth, CSRF, rate limiting, logging
│ │ └── routes/ # 9 route modules (59 endpoints)
│ │ ├── auth.py # Registration, login, API keys, signing keys
│ │ ├── check.py # CVE, license, deprecated, policy
│ │ ├── completion.py # Shell completion scripts
│ │ ├── index.py # Offline SQLite index management
│ │ ├── lock.py # Lock generation, verification, signing, etc.
│ │ ├── packages.py # Search, details, versions, resolve, export
│ │ ├── sbom.py # SPDX / CycloneDX generation
│ │ ├── scan.py # GitHub, local, upload scanning
│ │ └── system.py # System info, compatibility check
│ ├── cli/ # Command-line interface
│ │ ├── main.py # Argparse entry point (26 subparsers)
│ │ ├── shared.py # Shared helpers (lock path, manifest updaters)
│ │ ├── completion.py # Shell completion (bash/zsh/fish)
│ │ └── commands/ # 26 command modules
│ │ ├── auth.py install.py lock.py scan.py serve.py ...
│ ├── core/ # Core business logic
│ │ ├── conflict_resolver.py # Z3 SAT solver
│ │ ├── pubgrub_solver.py # PubGrub solver (Rust/pure Python)
│ │ ├── data_aggregator.py # Registry data fetching + caching
│ │ ├── system_scanner.py # OS/CPU/GPU/CUDA/Runtime detection
│ │ ├── license_checker.py # SPDX license compliance
│ │ ├── export_generator.py # requirements.txt / Dockerfile export
│ │ ├── markers.py # PEP 508 platform marker evaluation
│ │ ├── vers.py # Cross-ecosystem version parsing
│ │ ├── content_cache.py # SHA256-verified blob cache
│ │ ├── cache.py # DictCache (in-memory JSON)
│ │ ├── utils.py # Shared utilities
│ │ └── fetchers.py # Async HTTP fetching
│ ├── data_sources/ # 25 ecosystem plugins
│ │ ├── base_client.py # Base HTTP client with caching, retry, auth
│ │ ├── pypi_client.py npm_client.py crates_client.py ...
│ │ └── hex_plugin.py haskell_plugin.py nix_plugin.py ...
│ ├── database/ # Persistence layer
│ │ ├── models.py # 9 SQLAlchemy ORM models
│ │ ├── connection.py # Engine + session management
│ │ └── queries.py # Query helpers
│ ├── orchestrator/ # Resolution orchestration
│ │ ├── resolve.py # BFS dep discovery, solver factory
│ │ └── __init__.py
│ └── settings/ # Configuration
│ └── __init__.py # Env var loading (PEP 562 lazy eval)
├── frontend/ # Web SPA (vanilla JS, no build step)
│ ├── index.html # 255 lines — SPA shell
│ ├── css/style.css # 632 lines — Dark theme
│ ├── js/
│ │ ├── app.js # 836 lines — Router + state + pages
│ │ ├── api.js # 175 lines — BackendAPI fetch wrapper
│ │ └── utils.js # 480 lines — Formatting, OSV, policy, SBOM
│ ├── tests/
│ │ ├── api.test.js # 315 lines — 21+ BackendAPI tests
│ │ └── utils.test.js # 722 lines — Utility/SBOM/policy tests
│ └── package.json # Jest dev dependency only
├── desktop/ # Electron app
│ ├── main.js # Electron main process
│ ├── app.js # Renderer logic (17 tabs)
│ ├── index.html # GUI shell
│ └── package.json
├── vscode-extension/ # VS Code extension (TypeScript, 13 commands)
│ ├── package.json # 169 lines — extension manifest
│ ├── src/
│ │ ├── extension.ts # 61 lines — activate/deactivate
│ │ ├── cliRunner.ts # 58 lines — spawnSync udr CLI
│ │ ├── cveDiagnostics.ts # 75 lines — CVE problem markers
│ │ ├── lockFileProvider.ts # 86 lines — UDR Lock tree view
│ │ └── manifestEditor.ts # 124 lines — dep editing (req.txt, pyproject, pkg.json)
│ └── test/
│ └── extension.test.ts # 23 lines — 3 smoke tests
├── tests/
│ ├── unit/ # 3811 unit tests
│ ├── integration/ # 96 integration tests
│ └── e2e/ # 392 end-to-end tests
├── docs/ # Documentation
├── alembic/ # Database migrations
├── pyproject.toml
└── AGENTS.md
VS Code Extension Development¶
The VS Code extension shells out to the udr CLI — no Python API calls.
cd vscode-extension
npm install # installs TypeScript + @vscode/test-electron
npm run compile # tsc -p ./
npm test # @vscode/test-electron (3 smoke tests)
Test files: test/extension.test.ts (23 lines, 3 tests — extension presence, command count, tree view).
Extension structure¶
vscode-extension/
package.json (169 lines) — 13 commands, 4 settings, 7 activation events
src/
extension.ts ( 61 lines) — activate/deactivate, registers all commands
cliRunner.ts ( 58 lines) — spawnSync wrapper for `udr` CLI
cveDiagnostics.ts ( 75 lines) — CVE problem markers in lock file
lockFileProvider.ts ( 86 lines) — "UDR Lock" tree view (sidebar)
manifestEditor.ts (124 lines) — Add/update/remove deps in manifest files
Total: 13 files, 719 lines (including config/docs).
Key design notes¶
- CLI-only communication: No REST API calls — everything runs
udrviachild_process.spawnSync() - Lock file tree view: Parses
udr.lockdirectly for grouped-by-ecosystem display - CVE diagnostics: Inline squiggly underlines on vulnerable package names in the lock file
- Manifest editing: Supports
requirements.txt,pyproject.toml, andpackage.json(18+ manifest types show informational message to edit manually) - 13 commands from Command Palette: check, update, SBOM, verify, policies, fix CVEs, lock, lock check, graph, refresh, add/update/remove dependency
- 4 settings:
udr.cliPath,udr.lockFileName,udr.autoCheckOnSave,udr.cveSeverityThreshold - 7 activation events: workspace contains
udr.lock,requirements.txt,package.json, etc.
Frontend Development¶
The web frontend is a vanilla JS SPA (no framework, no build step).
# Serve frontend separately (backend must be running)
cd frontend
python -m http.server 3000
# Run frontend tests
cd frontend
npm install # installs Jest (dev only)
npm test # 21+ tests (api.test.js + utils.test.js)
# Alternatively with backend auto-served:
udr serve # serves both API + frontend at http://localhost:8000
Test files: frontend/tests/api.test.js (315 lines, BackendAPI tests) + frontend/tests/utils.test.js (722 lines, utility/SBOM/policy/OSV tests).
Desktop Development¶
cd desktop
npm install
npm run build # Compile backend via PyInstaller
npm run start # Launch Electron with built backend
npm run dev # Dev mode (separate backend + Electron)
Adding a New Ecosystem¶
- Create a data source plugin in
backend/data_sources/(inheritBaseDataSourceClient) - Register the plugin in
backend/core/data_aggregator.py(_register_builtin()) - Add manifest patterns in
backend/manifest_detector.py(MANIFEST_PATTERNS) - Add a manifest parser in
backend/manifest_detector.py(if needed) - Add settings in
backend/settings/__init__.py(rate limits, URL templates) - Add ecosystem entry in
backend/core/utils.py(sanitize_ecosystem_name, aliases) - Write tests in
tests/unit/(contract tests intest_plugin_contract.py) - Update the manifest updater in
backend/cli/shared.py(_get_manifest_updater)
Adding a New Export Format¶
- Add a Jinja2 template in
backend/core/templates/export/ - Register the format in
backend/core/export_generator.py(__init__orregister_format) - Write tests for the new format
Commit Messages¶
Types: feat, fix, docs, test, refactor, perf, chore, ci