API Reference¶
Docstrings on this page are pulled directly from the source under src/ by mkdocstrings. Edit the docstring, rebuild, and the rendered page updates.
lex_align_client¶
The thin client used by developers and AI agents. Provides the lex-align-client CLI as well as the Claude Code and git pre-commit hooks.
lex_align_client ¶
api ¶
HTTP client for the lex-align server.
Synchronous; the CLI is one-shot, so the simplicity of httpx.Client is worth more than the throughput of an async client. Failure semantics:
- connection error and
fail_open=true→ return a synthetic ALLOWED verdict withtransport_error=Trueso the caller can warn. - connection error and
fail_open=false→ raise ServerUnreachable. - server 4xx/5xx → raise ServerError(detail).
claude_hooks ¶
Claude Code session hooks (Advisor surface).
SessionStart and PreToolUse proxy through to the server's /evaluate so the agent sees blocked / provisionally-allowed verdicts during planning, before the pre-commit gate fires.
handle_pre_tool_use ¶
handle_pre_tool_use(event: dict, project_root: Path, config: ClientConfig) -> Optional[tuple[str, str | None]]
Return (decision, message) for pyproject.toml edits, else None.
Source code in src/lex_align_client/claude_hooks.py
claudemd ¶
CLAUDE.md integration: write lex-align usage instructions into the project's CLAUDE.md.
install_claude_md ¶
Create CLAUDE.md or append the lex-align section if not already present.
Returns (path, created_or_updated). Returns False for the second element when the section was already present and no write was performed.
Source code in src/lex_align_client/claudemd.py
cli ¶
lex-align-client CLI: init, check, request-approval, hook, precommit.
main ¶
init ¶
init(yes: bool, server_url: str | None, project_name: str | None, mode: str | None, no_claude_hooks: bool, no_precommit: bool, no_claude_md: bool) -> None
One-time setup: write .lexalign.toml and install hooks.
Source code in src/lex_align_client/cli.py
check ¶
check(package: str, version: str | None, as_json: bool, agent_model: str | None, agent_version: str | None) -> None
Check a package against the server policy.
Source code in src/lex_align_client/cli.py
request_approval ¶
request_approval(package: str, rationale: str, agent_model: str | None, agent_version: str | None) -> None
Submit a non-blocking request to add package to the registry.
Source code in src/lex_align_client/cli.py
precommit ¶
uninstall ¶
Remove .claude hooks and the git pre-commit shim. Leaves .lexalign.toml.
Source code in src/lex_align_client/cli.py
config ¶
.lexalign.toml reader/writer.
Schema:
project = "lex-align" server_url = "http://127.0.0.1:8765" mode = "single-user" # or "org" fail_open = true # ignored unless server is unreachable api_key_env_var = "LEXALIGN_API_KEY" # only used when mode = "org"
find_project_root ¶
Walk up looking for .lexalign.toml. Falls back to cwd.
Source code in src/lex_align_client/config.py
precommit ¶
Git pre-commit hook entry point.
Behavior
- Read the staged contents of
pyproject.toml(if it's in the index). - Re-evaluate every runtime dependency against the server. Reading existing deps catches new CVEs published since the last commit.
- If any verdict is DENIED, exit non-zero with a structured stderr message that an AI agent can parse to self-correct.
pyproject_utils ¶
Helpers for parsing and diffing pyproject.toml dependencies.
These are the only pieces of the v1.x reconciler that survive the rewrite — the client uses them to drive the pre-commit hook and the Claude Code edit hook.
get_runtime_deps ¶
Return {normalized_name: raw_spec} from [project].dependencies.
Source code in src/lex_align_client/pyproject_utils.py
diff_deps ¶
Return ({added_name: raw_spec}, {removed_names}).
Source code in src/lex_align_client/pyproject_utils.py
extract_pinned_version ¶
Pull a concrete version out of a spec like 'redis>=5.0' or 'httpx==0.28.1'.
Source code in src/lex_align_client/pyproject_utils.py
apply_edit ¶
Simulate how a Claude Code Edit/Write/MultiEdit affects file content.
Source code in src/lex_align_client/pyproject_utils.py
detect_project_name ¶
Best-effort autodetect for lex-align-client init.
Prefer [project].name from pyproject.toml; fall back to the directory name.
Source code in src/lex_align_client/pyproject_utils.py
settings ¶
Idempotent installers for the Claude Code hooks and the git pre-commit hook.
install_precommit ¶
Install or augment .git/hooks/pre-commit. Returns the path if written.
Source code in src/lex_align_client/settings.py
CLI¶
cli ¶
lex-align-client CLI: init, check, request-approval, hook, precommit.
main ¶
init ¶
init(yes: bool, server_url: str | None, project_name: str | None, mode: str | None, no_claude_hooks: bool, no_precommit: bool, no_claude_md: bool) -> None
One-time setup: write .lexalign.toml and install hooks.
Source code in src/lex_align_client/cli.py
check ¶
check(package: str, version: str | None, as_json: bool, agent_model: str | None, agent_version: str | None) -> None
Check a package against the server policy.
Source code in src/lex_align_client/cli.py
request_approval ¶
request_approval(package: str, rationale: str, agent_model: str | None, agent_version: str | None) -> None
Submit a non-blocking request to add package to the registry.
Source code in src/lex_align_client/cli.py
precommit ¶
uninstall ¶
Remove .claude hooks and the git pre-commit shim. Leaves .lexalign.toml.
Source code in src/lex_align_client/cli.py
Server API client¶
api ¶
HTTP client for the lex-align server.
Synchronous; the CLI is one-shot, so the simplicity of httpx.Client is worth more than the throughput of an async client. Failure semantics:
- connection error and
fail_open=true→ return a synthetic ALLOWED verdict withtransport_error=Trueso the caller can warn. - connection error and
fail_open=false→ raise ServerUnreachable. - server 4xx/5xx → raise ServerError(detail).
Configuration¶
config ¶
.lexalign.toml reader/writer.
Schema:
project = "lex-align" server_url = "http://127.0.0.1:8765" mode = "single-user" # or "org" fail_open = true # ignored unless server is unreachable api_key_env_var = "LEXALIGN_API_KEY" # only used when mode = "org"
find_project_root ¶
Walk up looking for .lexalign.toml. Falls back to cwd.
Source code in src/lex_align_client/config.py
Settings¶
settings ¶
Idempotent installers for the Claude Code hooks and the git pre-commit hook.
install_precommit ¶
Install or augment .git/hooks/pre-commit. Returns the path if written.
Source code in src/lex_align_client/settings.py
pyproject.toml utilities¶
pyproject_utils ¶
Helpers for parsing and diffing pyproject.toml dependencies.
These are the only pieces of the v1.x reconciler that survive the rewrite — the client uses them to drive the pre-commit hook and the Claude Code edit hook.
get_runtime_deps ¶
Return {normalized_name: raw_spec} from [project].dependencies.
Source code in src/lex_align_client/pyproject_utils.py
diff_deps ¶
Return ({added_name: raw_spec}, {removed_names}).
Source code in src/lex_align_client/pyproject_utils.py
extract_pinned_version ¶
Pull a concrete version out of a spec like 'redis>=5.0' or 'httpx==0.28.1'.
Source code in src/lex_align_client/pyproject_utils.py
apply_edit ¶
Simulate how a Claude Code Edit/Write/MultiEdit affects file content.
Source code in src/lex_align_client/pyproject_utils.py
detect_project_name ¶
Best-effort autodetect for lex-align-client init.
Prefer [project].name from pyproject.toml; fall back to the directory name.
Source code in src/lex_align_client/pyproject_utils.py
Pre-commit hook¶
precommit ¶
Git pre-commit hook entry point.
Behavior
- Read the staged contents of
pyproject.toml(if it's in the index). - Re-evaluate every runtime dependency against the server. Reading existing deps catches new CVEs published since the last commit.
- If any verdict is DENIED, exit non-zero with a structured stderr message that an AI agent can parse to self-correct.
Claude Code hooks¶
claude_hooks ¶
Claude Code session hooks (Advisor surface).
SessionStart and PreToolUse proxy through to the server's /evaluate so the agent sees blocked / provisionally-allowed verdicts during planning, before the pre-commit gate fires.
handle_pre_tool_use ¶
handle_pre_tool_use(event: dict, project_root: Path, config: ClientConfig) -> Optional[tuple[str, str | None]]
Return (decision, message) for pyproject.toml edits, else None.
Source code in src/lex_align_client/claude_hooks.py
CLAUDE.md rendering¶
claudemd ¶
CLAUDE.md integration: write lex-align usage instructions into the project's CLAUDE.md.
install_claude_md ¶
Create CLAUDE.md or append the lex-align section if not already present.
Returns (path, created_or_updated). Returns False for the second element when the section was already present and no write was performed.
Source code in src/lex_align_client/claudemd.py
lex_align_server¶
The FastAPI service that owns the registry, runs license + CVE checks, persists the audit log, and surfaces report endpoints.
lex_align_server ¶
api ¶
v1 ¶
approval_requests ¶
POST /api/v1/approval-requests — the Good Citizen.
Persists a request and returns 202 immediately. Phase 4 will swap in real PR creation against the registry's git repo.
evaluate ¶
GET /api/v1/evaluate — the Advisor.
health ¶
GET /api/v1/health — basic liveness/readiness.
registry ¶
Registry endpoints used by the dashboard workshop.
- GET /registry returns the live registry as JSON.
- GET /registry/pending returns PENDING_REVIEW approval requests for packages not in the loaded registry.
- POST /registry/packages classifies a package and adds it to the in-memory registry. Pending approval requests for that package flip to APPROVED. The change is not persisted to the registry file — the operator must export the updated YAML and redeploy the server to make it stick.
- POST /registry/parse-yaml validates user-supplied YAML against the schema the CLI compiler uses and returns it as JSON.
The classify endpoint is the only one that mutates server state.
pending_requests async ¶
Pending approval requests for packages not yet in the live registry.
Once a package is classified via POST /registry/packages, its pending approval requests are flipped to APPROVED in the audit store and stop appearing here. Without a loaded registry, every PENDING_REVIEW row is surfaced.
Source code in src/lex_align_server/api/v1/registry.py
classify_package async ¶
Classify a package and upsert it into the in-memory registry.
This is what the dashboard calls when an operator approves a pending request: the package + its assigned status is written into the live Registry so subsequent /evaluate calls see it immediately, and every PENDING_REVIEW approval request for the same normalized name flips to APPROVED.
The change lives only in memory. To persist it across restarts, the operator must export the YAML from the dashboard and rebuild the server image (or re-run lex-align-server registry compile against the updated YAML and restart the process).
Source code in src/lex_align_server/api/v1/registry.py
reports ¶
Read-only report endpoints.
Phase 4 dashboards consume these; Phase 3 also exposes them directly so operators can query them with curl.
agents_report async ¶
Aggregate audit rows by (agent_model, agent_version).
Operators use this to answer "which Claude version is doing what" — the headers X-LexAlign-Agent-Model and X-LexAlign-Agent-Version reported by the client propagate into every audit row.
Source code in src/lex_align_server/api/v1/reports.py
audit ¶
SQLite audit log + approval-request store.
Two tables:
audit_log— one row per/evaluatecall. Backs the legal report (license-driven denials) and security report (CVE-driven denials).approval_requests— one row per/approval-requestsPOST. Phase 3 will attach a PR-creation workflow; for now we just persist them.
We use plain aiosqlite rather than an ORM. The schema is small and the report queries are easier to read as straight SQL.
AuditStore ¶
Source code in src/lex_align_server/audit.py
mark_approved_by_package async ¶
Move every PENDING_REVIEW request for normalized_name to APPROVED.
Called when an operator classifies a pending package via the dashboard and adds it to the in-memory registry. Returns the number of rows flipped, which the dashboard can display in its toast.
Source code in src/lex_align_server/audit.py
list_pending_by_package async ¶
All PENDING_REVIEW approval requests grouped by package.
The dashboard uses this to surface "things developers asked for" as a triage queue. Multiple requests for the same package (across projects/requesters) collapse into a single row carrying the count, the most recent rationale, and the most recent timestamp. Callers are expected to further filter against the live registry.
Source code in src/lex_align_server/audit.py
agents_report async ¶
Aggregate evaluations by (agent_model, agent_version).
Powers the "agents" dashboard, so operators can see exactly which Claude (or other agent) version is making which kinds of requests. Rows where the agent is unknown collapse into one bucket.
Source code in src/lex_align_server/audit.py
auth ¶
Auth dependencies.
When AUTH_ENABLED=false (default) every request is treated as anonymous. When AUTH_ENABLED=true the bearer token is required but the validation/key storage is intentionally a Phase-3 stub. Wire-up exists so callers don't need to change when org-mode lands.
AgentInfo dataclass ¶
Agent identity reported by the client.
Both fields are optional; when the client doesn't send the headers, both are None and reports group those rows under an "(unknown agent)" bucket.
cache ¶
Redis-backed JSON cache.
Used by the license and CVE adapters to avoid hammering PyPI/OSV. We intentionally swallow connection errors and degrade to "no cache" so the server keeps serving when Redis is unreachable — the audit log still records every decision.
cli ¶
lex-align-server CLI.
Exposes
serve— run uvicorn against the FastAPI app.init— materialize the operator bundle (compose stack, Dockerfile, registry, .env) into a target dir.registry compile— compile a YAML registry to the JSON form the server consumes.selftest— hit/api/v1/healthto confirm a stack is up.admin keys ...— placeholders for the org-mode admin tooling.
main ¶
serve ¶
Start the lex-align FastAPI server via uvicorn.
Source code in src/lex_align_server/cli.py
init ¶
Materialize the docker-compose stack, Dockerfile, registry, and .env template into TARGET so the server can be built and run with a single docker compose up -d.
Source code in src/lex_align_server/cli.py
registry ¶
registry_compile ¶
Compile a YAML registry SOURCE to the JSON form at DESTINATION.
Source code in src/lex_align_server/cli.py
selftest ¶
Probe /api/v1/health and report whether the stack is alive.
Source code in src/lex_align_server/cli.py
admin ¶
config ¶
Server configuration.
All settings are sourced from environment variables. Defaults bias towards the single-user/local-evaluation experience: no auth, bind to localhost, point at a co-located Redis.
get_settings ¶
Build a fresh Settings object. Avoids module-level caching so tests can override via env vars on a per-test basis.
cve ¶
CVE lookup via OSV (osv.dev).
OSV is the Google-sponsored aggregator that ingests GHSA, NVD, PyPA Advisory DB, and others. The free POST /v1/query endpoint takes a package coordinate and returns the list of vulnerabilities with severity scores. We parse out the highest CVSS base score and let GlobalPolicies.cve_blocks decide.
query_osv async ¶
query_osv(package: str, version: Optional[str], osv_url: str, http_client: AsyncClient) -> Optional[list[dict]]
Return raw vulns list from OSV, or None on error/timeout.
Source code in src/lex_align_server/cve.py
resolve_cves async ¶
resolve_cves(package: str, version: Optional[str], cache: JsonCache, cache_ttl: int, osv_url: str, http_client: AsyncClient) -> CveInfo
Cache-or-fetch CVE data for a package@version.
A None version is cached separately from versioned queries — OSV's behaviour with no version is documented as "all versions" so we treat it as a distinct cache entry.
Source code in src/lex_align_server/cve.py
dashboards ¶
router ¶
Dashboard pages.
Four pages render server-side and fetch their data from the JSON API: - /dashboard/security, /dashboard/legal and /dashboard/agents show read-only reports. - /dashboard/registry is an interactive workshop: it loads the live registry, lets the operator triage pending approval requests, and exports the result as YAML. Classifying a pending request also updates the in-memory registry so live /evaluate calls see the rule immediately, but persistence still requires exporting the YAML and rebuilding the server image.
evaluate ¶
Evaluation orchestrator.
Combines registry lookup, CVE check, and license check into a single verdict. Emits one audit-log row per call. The order matters:
- registry hard-blocks (banned, deprecated, version-violated)
- CVE check — applies even to registry-allowed packages so a newly published critical CVE on a
preferredpackage still blocks - license check — only when the package is unknown to the registry
evaluate async ¶
evaluate(*, package: str, version: Optional[str], project: str, requester: str, registry: Optional[Registry], cache: JsonCache, audit: AuditStore, settings: Settings, http_client: AsyncClient, agent: Optional[AgentInfo] = None) -> EvaluationResult
Single evaluation. Always writes one audit row before returning.
Source code in src/lex_align_server/evaluate.py
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | |
init ¶
lex-align-server init — materialize the operator bundle into a directory.
Mirrors the design of lex-align-client init: copies the docker-compose stack, Dockerfile, example registry, and .env.example from the wheel's bundled assets into a target directory, then compiles the registry to JSON so docker compose up works on the first try.
asset_names ¶
All asset basenames as they appear in the wheel. Useful for tests.
init_target ¶
Materialize the operator bundle into target.
Idempotent by default: if the marker file exists, raises FileExistsError unless force is set.
Source code in src/lex_align_server/init.py
licenses ¶
License lookup, normalization, and policy evaluation.
For packages not listed in the registry, the server fetches the license from PyPI, normalizes it to an SPDX-ish token, and checks it against global_policies. Results are cached in Redis keyed by package name.
fetch_license_from_pypi async ¶
fetch_license_from_pypi(package: str, version: Optional[str], pypi_base: str, client: AsyncClient) -> tuple[Optional[str], Optional[str]]
Return (raw_license_string, latest_version) from PyPI, or (None, None) on error.
Source code in src/lex_align_server/licenses.py
resolve_license async ¶
resolve_license(package: str, version: Optional[str], cache: JsonCache, cache_ttl: int, pypi_base: str, http_client: AsyncClient) -> tuple[LicenseInfo, Optional[str]]
Resolve (cache-or-fetch) a package's license. Returns (info, latest_version).
Source code in src/lex_align_server/licenses.py
main ¶
FastAPI application factory.
Wires up the routers, builds the per-app state (cache, audit store, HTTP client, registry), and exposes a lifespan so resources are torn down cleanly.
registry ¶
Enterprise registry: package policies, license rules, CVE threshold.
The registry is loaded from a local JSON file (compiled from the human-authored YAML by lex-align-server registry compile). The server consults it on every /evaluate call.
registry_schema ¶
Registry-YAML schema validation, shared by the CLI compiler and the dashboard's import endpoint.
This module is intentionally pure: no I/O, no CLI argparse, no FastAPI dependencies. The two entry points that consume it (the lex-align-server registry compile CLI and lex_align_server.api.v1.registry) both depend on the same validator so a registry YAML accepted by the dashboard is guaranteed to compile in CI, and vice versa.
validate_package_rule ¶
Public single-package validator. Raises ValidationError on failure.
Used by the dashboard's classify endpoint so the in-memory mutation has the same guarantees as a YAML round-trip.
Source code in src/lex_align_server/registry_schema.py
state ¶
Application state container.
Carried on app.state so the per-request dependencies don't have to know how the cache, audit log, or registry got built.
Application entrypoint¶
main ¶
FastAPI application factory.
Wires up the routers, builds the per-app state (cache, audit store, HTTP client, registry), and exposes a lifespan so resources are torn down cleanly.
CLI¶
cli ¶
lex-align-server CLI.
Exposes
serve— run uvicorn against the FastAPI app.init— materialize the operator bundle (compose stack, Dockerfile, registry, .env) into a target dir.registry compile— compile a YAML registry to the JSON form the server consumes.selftest— hit/api/v1/healthto confirm a stack is up.admin keys ...— placeholders for the org-mode admin tooling.
main ¶
serve ¶
Start the lex-align FastAPI server via uvicorn.
Source code in src/lex_align_server/cli.py
init ¶
Materialize the docker-compose stack, Dockerfile, registry, and .env template into TARGET so the server can be built and run with a single docker compose up -d.
Source code in src/lex_align_server/cli.py
registry ¶
registry_compile ¶
Compile a YAML registry SOURCE to the JSON form at DESTINATION.
Source code in src/lex_align_server/cli.py
selftest ¶
Probe /api/v1/health and report whether the stack is alive.
Source code in src/lex_align_server/cli.py
admin ¶
Configuration¶
config ¶
Server configuration.
All settings are sourced from environment variables. Defaults bias towards the single-user/local-evaluation experience: no auth, bind to localhost, point at a co-located Redis.
get_settings ¶
Build a fresh Settings object. Avoids module-level caching so tests can override via env vars on a per-test basis.
State management¶
state ¶
Application state container.
Carried on app.state so the per-request dependencies don't have to know how the cache, audit log, or registry got built.
Evaluation pipeline¶
evaluate ¶
Evaluation orchestrator.
Combines registry lookup, CVE check, and license check into a single verdict. Emits one audit-log row per call. The order matters:
- registry hard-blocks (banned, deprecated, version-violated)
- CVE check — applies even to registry-allowed packages so a newly published critical CVE on a
preferredpackage still blocks - license check — only when the package is unknown to the registry
evaluate async ¶
evaluate(*, package: str, version: Optional[str], project: str, requester: str, registry: Optional[Registry], cache: JsonCache, audit: AuditStore, settings: Settings, http_client: AsyncClient, agent: Optional[AgentInfo] = None) -> EvaluationResult
Single evaluation. Always writes one audit row before returning.
Source code in src/lex_align_server/evaluate.py
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | |
Registry¶
registry ¶
Enterprise registry: package policies, license rules, CVE threshold.
The registry is loaded from a local JSON file (compiled from the human-authored YAML by lex-align-server registry compile). The server consults it on every /evaluate call.
registry_schema ¶
Registry-YAML schema validation, shared by the CLI compiler and the dashboard's import endpoint.
This module is intentionally pure: no I/O, no CLI argparse, no FastAPI dependencies. The two entry points that consume it (the lex-align-server registry compile CLI and lex_align_server.api.v1.registry) both depend on the same validator so a registry YAML accepted by the dashboard is guaranteed to compile in CI, and vice versa.
validate_package_rule ¶
Public single-package validator. Raises ValidationError on failure.
Used by the dashboard's classify endpoint so the in-memory mutation has the same guarantees as a YAML round-trip.
Source code in src/lex_align_server/registry_schema.py
License checks¶
licenses ¶
License lookup, normalization, and policy evaluation.
For packages not listed in the registry, the server fetches the license from PyPI, normalizes it to an SPDX-ish token, and checks it against global_policies. Results are cached in Redis keyed by package name.
fetch_license_from_pypi async ¶
fetch_license_from_pypi(package: str, version: Optional[str], pypi_base: str, client: AsyncClient) -> tuple[Optional[str], Optional[str]]
Return (raw_license_string, latest_version) from PyPI, or (None, None) on error.
Source code in src/lex_align_server/licenses.py
resolve_license async ¶
resolve_license(package: str, version: Optional[str], cache: JsonCache, cache_ttl: int, pypi_base: str, http_client: AsyncClient) -> tuple[LicenseInfo, Optional[str]]
Resolve (cache-or-fetch) a package's license. Returns (info, latest_version).
Source code in src/lex_align_server/licenses.py
CVE checks (OSV)¶
cve ¶
CVE lookup via OSV (osv.dev).
OSV is the Google-sponsored aggregator that ingests GHSA, NVD, PyPA Advisory DB, and others. The free POST /v1/query endpoint takes a package coordinate and returns the list of vulnerabilities with severity scores. We parse out the highest CVSS base score and let GlobalPolicies.cve_blocks decide.
query_osv async ¶
query_osv(package: str, version: Optional[str], osv_url: str, http_client: AsyncClient) -> Optional[list[dict]]
Return raw vulns list from OSV, or None on error/timeout.
Source code in src/lex_align_server/cve.py
resolve_cves async ¶
resolve_cves(package: str, version: Optional[str], cache: JsonCache, cache_ttl: int, osv_url: str, http_client: AsyncClient) -> CveInfo
Cache-or-fetch CVE data for a package@version.
A None version is cached separately from versioned queries — OSV's behaviour with no version is documented as "all versions" so we treat it as a distinct cache entry.
Source code in src/lex_align_server/cve.py
Audit log¶
audit ¶
SQLite audit log + approval-request store.
Two tables:
audit_log— one row per/evaluatecall. Backs the legal report (license-driven denials) and security report (CVE-driven denials).approval_requests— one row per/approval-requestsPOST. Phase 3 will attach a PR-creation workflow; for now we just persist them.
We use plain aiosqlite rather than an ORM. The schema is small and the report queries are easier to read as straight SQL.
AuditStore ¶
Source code in src/lex_align_server/audit.py
mark_approved_by_package async ¶
Move every PENDING_REVIEW request for normalized_name to APPROVED.
Called when an operator classifies a pending package via the dashboard and adds it to the in-memory registry. Returns the number of rows flipped, which the dashboard can display in its toast.
Source code in src/lex_align_server/audit.py
list_pending_by_package async ¶
All PENDING_REVIEW approval requests grouped by package.
The dashboard uses this to surface "things developers asked for" as a triage queue. Multiple requests for the same package (across projects/requesters) collapse into a single row carrying the count, the most recent rationale, and the most recent timestamp. Callers are expected to further filter against the live registry.
Source code in src/lex_align_server/audit.py
agents_report async ¶
Aggregate evaluations by (agent_model, agent_version).
Powers the "agents" dashboard, so operators can see exactly which Claude (or other agent) version is making which kinds of requests. Rows where the agent is unknown collapse into one bucket.
Source code in src/lex_align_server/audit.py
Caching¶
cache ¶
Redis-backed JSON cache.
Used by the license and CVE adapters to avoid hammering PyPI/OSV. We intentionally swallow connection errors and degrade to "no cache" so the server keeps serving when Redis is unreachable — the audit log still records every decision.
Authentication¶
auth ¶
Auth dependencies.
When AUTH_ENABLED=false (default) every request is treated as anonymous. When AUTH_ENABLED=true the bearer token is required but the validation/key storage is intentionally a Phase-3 stub. Wire-up exists so callers don't need to change when org-mode lands.
AgentInfo dataclass ¶
Agent identity reported by the client.
Both fields are optional; when the client doesn't send the headers, both are None and reports group those rows under an "(unknown agent)" bucket.