Skip to content

Development Setup

Prerequisites

  • Python 3.11 or later
  • git
  • uv

Clone the repository

git clone https://github.com/emiliano-go/trustsight.git
cd trustsight

Install development dependencies

uv sync --locked --extra dev

This installs the package in editable mode along with pytest, ruff, and other dev tooling.

Run the test suite

uv run --with pytest python -m pytest

Run uv run --with pytest python -m pytest for the current test count; it changes as coverage is added.

Run a single test

uv run --with pytest python -m pytest tests/test_rules.py::test_r001_curl_bash -v

The suite does not reach the network

Every test runs with TRUSTSIGHT_OFFLINE=1 set and with outbound sockets blocked. A test that tries to open a connection to anything but loopback fails immediately with NetworkAccessDenied, naming the address and the frame that reached for it.

This is not a policy about tidiness. A test that reaches the real AUR does not fail; it waits. The metadata dump is tens of megabytes behind a 300-second timeout, so a mock that silently stops applying turns a one-second unit test into a stalled CI job with no failing assertion to point at. The guard converts that stall into a named failure.

If you hit it, the fix is almost always to patch the function that fetches rather than to allow the call:

Reaching for Patch
The release channel (seed, IOC baselines, corpus) Nothing - TRUSTSIGHT_OFFLINE already covers it
The AUR metadata snapshot trustsight.full_aur.metadata.fetch_metadata
A package's PKGBUILD trustsight.full_aur.fetch.fetch_pkgbuild_with_tree
Dependency resolution Already stubbed suite-wide; override it with your own data

A test whose subject is the online path opts back in with monkeypatch.delenv("TRUSTSIGHT_OFFLINE", raising=False) and mocks its own transport; tests/test_release_fetch.py does this at file level. The socket guard still holds the line underneath, so opting out of offline mode does not let a real request through.

Do not leave sys.modules rewritten

A test that deletes trustsight* modules to re-import them must put them back, in a finally. Otherwise a later test's monkeypatch.setattr("trustsight.db.DATA_DIR", tmp_path) patches one module object while its own from trustsight.db import init_db refers to another: init_db() creates tables in a tmpdir and get_connection() opens your real database. This cost the suite 27 failures across three files, none of which named the test that caused them.

Lint the codebase

uv run ruff check src/ tests/

Run evaluation locally

Evaluation recomputes the baseline against the pinned corpus:

uv run python scripts/rebaseline.py

The corpus is gitignored, so rebuild it from the lock first:

uv run python scripts/build_corpus.py --from-manifest \
  --manifest tests/fixtures/corpus.lock \
  --out tests/fixtures/benign-corpus

See Re-baselining for details.

Debug a single package

uv run python -m trustsight inspect <package-name>

This runs the full analysis pipeline on one AUR package and prints the per-rule breakdown, evidence, and final score.

Build the documentation

uv run --extra docs zensical serve          # build and serve with live reload
uv run --extra docs zensical build          # renders docs/ into site/
uv run --extra docs python scripts/build_llms_txt.py

zensical build renders every page listed in zensical.toml's nav. The second command writes site/llms.txt and site/llms-full.txt, the plain-text companions every page advertises through <link rel="alternate">: an indexed map of the site, and the whole corpus concatenated. It reads the same nav, so a page reachable in the sidebar is a page reachable in both files.

Run it after zensical build, which clears site/. --check verifies the two files match the current docs without writing anything, which is the form to use in a deployment that should fail rather than publish a stale index:

uv run --extra docs python scripts/build_llms_txt.py --check

site/ is gitignored; neither the rendered site nor these two files are committed.