ladex 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ladex-0.1.0/.gitattributes +7 -0
- ladex-0.1.0/.gitignore +45 -0
- ladex-0.1.0/.pre-commit-config.yaml +26 -0
- ladex-0.1.0/.python-version +1 -0
- ladex-0.1.0/LICENSE +21 -0
- ladex-0.1.0/PKG-INFO +164 -0
- ladex-0.1.0/README.md +138 -0
- ladex-0.1.0/assets/ladex-lockup-dark.png +0 -0
- ladex-0.1.0/assets/ladex-lockup-light.png +0 -0
- ladex-0.1.0/extensions/vscode/.gitignore +3 -0
- ladex-0.1.0/extensions/vscode/.vscode/launch.json +23 -0
- ladex-0.1.0/extensions/vscode/.vscode/tasks.json +12 -0
- ladex-0.1.0/extensions/vscode/.vscodeignore +8 -0
- ladex-0.1.0/extensions/vscode/LICENSE +21 -0
- ladex-0.1.0/extensions/vscode/README.md +53 -0
- ladex-0.1.0/extensions/vscode/demo/example.py +20 -0
- ladex-0.1.0/extensions/vscode/icon.png +0 -0
- ladex-0.1.0/extensions/vscode/ladex-0.1.0.vsix +0 -0
- ladex-0.1.0/extensions/vscode/out/extension.js +73 -0
- ladex-0.1.0/extensions/vscode/out/extension.js.map +1 -0
- ladex-0.1.0/extensions/vscode/package-lock.json +3972 -0
- ladex-0.1.0/extensions/vscode/package.json +73 -0
- ladex-0.1.0/extensions/vscode/src/extension.ts +56 -0
- ladex-0.1.0/extensions/vscode/tsconfig.json +15 -0
- ladex-0.1.0/packaging/entry.py +12 -0
- ladex-0.1.0/packaging/ladex.spec +64 -0
- ladex-0.1.0/pyproject.toml +98 -0
- ladex-0.1.0/src/ladex/__init__.py +8 -0
- ladex-0.1.0/src/ladex/cli/__init__.py +394 -0
- ladex-0.1.0/src/ladex/cli/report.py +306 -0
- ladex-0.1.0/src/ladex/engine/__init__.py +1 -0
- ladex-0.1.0/src/ladex/engine/attest/__init__.py +31 -0
- ladex-0.1.0/src/ladex/engine/attest/service.py +69 -0
- ladex-0.1.0/src/ladex/engine/attest/signer.py +107 -0
- ladex-0.1.0/src/ladex/engine/attest/statement.py +61 -0
- ladex-0.1.0/src/ladex/engine/attest/store.py +100 -0
- ladex-0.1.0/src/ladex/engine/bom/__init__.py +7 -0
- ladex-0.1.0/src/ladex/engine/bom/cyclonedx.py +215 -0
- ladex-0.1.0/src/ladex/engine/detect/__init__.py +8 -0
- ladex-0.1.0/src/ladex/engine/detect/ast_walker.py +263 -0
- ladex-0.1.0/src/ladex/engine/detect/iac.py +346 -0
- ladex-0.1.0/src/ladex/engine/detect/records.py +47 -0
- ladex-0.1.0/src/ladex/engine/enrich/__init__.py +34 -0
- ladex-0.1.0/src/ladex/engine/enrich/cache.py +98 -0
- ladex-0.1.0/src/ladex/engine/enrich/hfhub.py +74 -0
- ladex-0.1.0/src/ladex/engine/enrich/http.py +84 -0
- ladex-0.1.0/src/ladex/engine/enrich/models.py +104 -0
- ladex-0.1.0/src/ladex/engine/enrich/osv.py +53 -0
- ladex-0.1.0/src/ladex/engine/enrich/pypi.py +59 -0
- ladex-0.1.0/src/ladex/engine/enrich/service.py +73 -0
- ladex-0.1.0/src/ladex/engine/policy/__init__.py +41 -0
- ladex-0.1.0/src/ladex/engine/policy/context.py +71 -0
- ladex-0.1.0/src/ladex/engine/policy/evaluate.py +93 -0
- ladex-0.1.0/src/ladex/engine/policy/loader.py +91 -0
- ladex-0.1.0/src/ladex/engine/policy/models.py +108 -0
- ladex-0.1.0/src/ladex/engine/policy/report.py +62 -0
- ladex-0.1.0/src/ladex/engine/policy/service.py +16 -0
- ladex-0.1.0/src/ladex/engine/scan.py +116 -0
- ladex-0.1.0/src/ladex/engine/server/__init__.py +8 -0
- ladex-0.1.0/src/ladex/engine/server/diagnostics.py +55 -0
- ladex-0.1.0/src/ladex/engine/server/server.py +51 -0
- ladex-0.1.0/src/ladex/engine/taxonomy/__init__.py +41 -0
- ladex-0.1.0/src/ladex/engine/taxonomy/loader.py +128 -0
- ladex-0.1.0/src/ladex/engine/taxonomy/models.py +146 -0
- ladex-0.1.0/src/ladex/packs/__init__.py +1 -0
- ladex-0.1.0/src/ladex/packs/iac/iac.yaml +59 -0
- ladex-0.1.0/src/ladex/packs/policy/eu_ai_act/art50.yaml +42 -0
- ladex-0.1.0/src/ladex/packs/taxonomy/frameworks.yaml +46 -0
- ladex-0.1.0/src/ladex/packs/taxonomy/inference_apis.yaml +73 -0
- ladex-0.1.0/src/ladex/packs/taxonomy/model_loaders.yaml +66 -0
- ladex-0.1.0/src/ladex/packs/taxonomy/vector_stores.yaml +37 -0
- ladex-0.1.0/src/ladex/py.typed +0 -0
- ladex-0.1.0/tests/__init__.py +0 -0
- ladex-0.1.0/tests/attest/__init__.py +0 -0
- ladex-0.1.0/tests/attest/test_attest.py +104 -0
- ladex-0.1.0/tests/attest/test_attest_bom.py +55 -0
- ladex-0.1.0/tests/attest/test_attest_cli.py +87 -0
- ladex-0.1.0/tests/bom/__init__.py +0 -0
- ladex-0.1.0/tests/bom/test_bom_cli.py +31 -0
- ladex-0.1.0/tests/bom/test_cyclonedx.py +134 -0
- ladex-0.1.0/tests/detect/__init__.py +0 -0
- ladex-0.1.0/tests/detect/test_detector.py +116 -0
- ladex-0.1.0/tests/detect/test_fixture_repo.py +67 -0
- ladex-0.1.0/tests/detect/test_iac.py +127 -0
- ladex-0.1.0/tests/detect/test_scan.py +58 -0
- ladex-0.1.0/tests/detect/test_scan_cli.py +42 -0
- ladex-0.1.0/tests/enrich/__init__.py +0 -0
- ladex-0.1.0/tests/enrich/conftest.py +43 -0
- ladex-0.1.0/tests/enrich/test_cache.py +82 -0
- ladex-0.1.0/tests/enrich/test_providers.py +142 -0
- ladex-0.1.0/tests/enrich/test_service.py +76 -0
- ladex-0.1.0/tests/fixtures/iac/main.tf +41 -0
- ladex-0.1.0/tests/fixtures/iac/workloads.yaml +41 -0
- ladex-0.1.0/tests/fixtures/sample_repo/agents.py +12 -0
- ladex-0.1.0/tests/fixtures/sample_repo/broken.py +7 -0
- ladex-0.1.0/tests/fixtures/sample_repo/models.py +9 -0
- ladex-0.1.0/tests/fixtures/sample_repo/noise.py +12 -0
- ladex-0.1.0/tests/fixtures/sample_repo/store.py +7 -0
- ladex-0.1.0/tests/policy/__init__.py +0 -0
- ladex-0.1.0/tests/policy/test_bundles.py +86 -0
- ladex-0.1.0/tests/policy/test_evaluate.py +122 -0
- ladex-0.1.0/tests/policy/test_policy_cli.py +53 -0
- ladex-0.1.0/tests/server/__init__.py +0 -0
- ladex-0.1.0/tests/server/test_diagnostics.py +56 -0
- ladex-0.1.0/tests/taxonomy/__init__.py +0 -0
- ladex-0.1.0/tests/taxonomy/test_builtin_packs.py +73 -0
- ladex-0.1.0/tests/taxonomy/test_schema_validation.py +135 -0
- ladex-0.1.0/tests/test_smoke.py +25 -0
- ladex-0.1.0/uv.lock +1890 -0
ladex-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.eggs/
|
|
6
|
+
build/
|
|
7
|
+
dist/
|
|
8
|
+
*.so
|
|
9
|
+
|
|
10
|
+
# PyInstaller single-binary build outputs (artifacts go to GitHub Releases)
|
|
11
|
+
dist-bin/
|
|
12
|
+
build-bin/
|
|
13
|
+
|
|
14
|
+
# Virtualenv / uv
|
|
15
|
+
.venv/
|
|
16
|
+
venv/
|
|
17
|
+
|
|
18
|
+
# Tooling caches
|
|
19
|
+
.mypy_cache/
|
|
20
|
+
.ruff_cache/
|
|
21
|
+
.pytest_cache/
|
|
22
|
+
.cache/
|
|
23
|
+
htmlcov/
|
|
24
|
+
.coverage
|
|
25
|
+
.coverage.*
|
|
26
|
+
|
|
27
|
+
# IDE / OS
|
|
28
|
+
.idea/
|
|
29
|
+
.vscode/*
|
|
30
|
+
!.vscode/extensions.json
|
|
31
|
+
.DS_Store
|
|
32
|
+
Thumbs.db
|
|
33
|
+
|
|
34
|
+
# Node (VS Code extension, Step 8)
|
|
35
|
+
node_modules/
|
|
36
|
+
|
|
37
|
+
# Local secrets / env
|
|
38
|
+
.env
|
|
39
|
+
.env.*
|
|
40
|
+
|
|
41
|
+
# Personal learning notes (never committed)
|
|
42
|
+
notes/
|
|
43
|
+
|
|
44
|
+
# Project context / constitution — kept local, not committed
|
|
45
|
+
CLAUDE.md
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
3
|
+
rev: v0.6.9
|
|
4
|
+
hooks:
|
|
5
|
+
- id: ruff
|
|
6
|
+
args: [--fix]
|
|
7
|
+
exclude: ^tests/fixtures/
|
|
8
|
+
- id: ruff-format
|
|
9
|
+
exclude: ^tests/fixtures/
|
|
10
|
+
|
|
11
|
+
- repo: https://github.com/pre-commit/mirrors-mypy
|
|
12
|
+
rev: v1.11.2
|
|
13
|
+
hooks:
|
|
14
|
+
- id: mypy
|
|
15
|
+
additional_dependencies:
|
|
16
|
+
[
|
|
17
|
+
pytest>=8.3,
|
|
18
|
+
pydantic>=2.7,
|
|
19
|
+
types-PyYAML>=6.0,
|
|
20
|
+
rich>=13.7,
|
|
21
|
+
cyclonedx-python-lib>=8.0,
|
|
22
|
+
pygls>=1.3,
|
|
23
|
+
]
|
|
24
|
+
args: [--strict]
|
|
25
|
+
files: ^(src|tests)/
|
|
26
|
+
exclude: ^tests/fixtures/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
ladex-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 duskyvesper
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
ladex-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: ladex
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A bill of lading for AI — shift-left AI governance and ML-BOM generation for developers.
|
|
5
|
+
Project-URL: Homepage, https://ladex.dev
|
|
6
|
+
Project-URL: Repository, https://github.com/aibhuyan/ladex
|
|
7
|
+
Author-email: aibhuyan <bhuyanalimrans@gmail.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: ai-governance,aibom,cyclonedx,eu-ai-act,ml-bom,sbom
|
|
11
|
+
Requires-Python: >=3.12
|
|
12
|
+
Requires-Dist: cryptography>=42.0
|
|
13
|
+
Requires-Dist: cyclonedx-python-lib>=8.0
|
|
14
|
+
Requires-Dist: httpx>=0.27
|
|
15
|
+
Requires-Dist: platformdirs>=4.0
|
|
16
|
+
Requires-Dist: pydantic>=2.7
|
|
17
|
+
Requires-Dist: pygls>=1.3
|
|
18
|
+
Requires-Dist: python-hcl2>=4.3
|
|
19
|
+
Requires-Dist: pyyaml>=6.0
|
|
20
|
+
Requires-Dist: rich>=13.7
|
|
21
|
+
Requires-Dist: tree-sitter-python>=0.23
|
|
22
|
+
Requires-Dist: tree-sitter>=0.23
|
|
23
|
+
Provides-Extra: sigstore
|
|
24
|
+
Requires-Dist: sigstore>=3.0; extra == 'sigstore'
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
<p align="center">
|
|
28
|
+
<picture>
|
|
29
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/ladex-lockup-dark.png">
|
|
30
|
+
<img src="assets/ladex-lockup-light.png" alt="Ladex" width="360">
|
|
31
|
+
</picture>
|
|
32
|
+
</p>
|
|
33
|
+
|
|
34
|
+
<p align="center"><strong>A bill of lading for AI.</strong></p>
|
|
35
|
+
|
|
36
|
+
<p align="center">
|
|
37
|
+
<img src="https://img.shields.io/badge/version-0.1.0-3b82f6?style=flat" alt="version 0.1.0">
|
|
38
|
+
<img src="https://img.shields.io/github/stars/aibhuyan/ladex?style=flat&color=3b82f6" alt="GitHub stars">
|
|
39
|
+
<img src="https://img.shields.io/badge/license-MIT-3b82f6?style=flat" alt="license MIT">
|
|
40
|
+
<img src="https://img.shields.io/badge/python-3.12+-3b82f6?style=flat" alt="python 3.12+">
|
|
41
|
+
<img src="https://img.shields.io/badge/tests-139%20passing-22c55e?style=flat" alt="tests 139 passing">
|
|
42
|
+
<img src="https://img.shields.io/badge/output-CycloneDX%20ML--BOM-3b82f6?style=flat" alt="CycloneDX ML-BOM">
|
|
43
|
+
<img src="https://img.shields.io/badge/EU%20AI%20Act-Art.%2050-3b82f6?style=flat" alt="EU AI Act Art. 50">
|
|
44
|
+
</p>
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
You already require a **bill of lading** for physical cargo and an **SBOM** for software.
|
|
49
|
+
Ladex is the one for **AI** — it records what AI is aboard your codebase, from whom, and under
|
|
50
|
+
what terms, captured at the moment the code is written rather than discovered after the fact.
|
|
51
|
+
|
|
52
|
+
Ladex is a shift-left AI governance tool for developers. When you write an AI-relevant line of
|
|
53
|
+
code — importing an agent framework, loading a Hugging Face model, calling an inference API,
|
|
54
|
+
provisioning a GPU node pool in Terraform — Ladex detects it and answers three questions:
|
|
55
|
+
|
|
56
|
+
1. **What is this?** model / dataset / agent framework / vector store / inference API
|
|
57
|
+
2. **What does it obligate?** EU AI Act Art. 50 disclosure, Annex III high-risk triggers
|
|
58
|
+
3. **What's auto-verifiable vs. what needs a human?** CVEs and licenses resolve
|
|
59
|
+
automatically. Training-data provenance and consent basis can't be derived by any scanner —
|
|
60
|
+
they're flagged `UNDOCUMENTED` and require a **signed human attestation**, never a fake green
|
|
61
|
+
checkmark.
|
|
62
|
+
|
|
63
|
+
The output is a **CycloneDX ML-BOM** committed to your repo, diffable in PRs, with signed
|
|
64
|
+
attestations for the fields no tool can derive.
|
|
65
|
+
|
|
66
|
+
> Ladex records what's aboard; it does not block attacks.
|
|
67
|
+
|
|
68
|
+
## What it does
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
detect (Python + Terraform + Kubernetes)
|
|
72
|
+
→ enrich PyPI licenses · OSV CVEs · Hugging Face model cards (cached, offline-capable)
|
|
73
|
+
→ obligate EU AI Act Art. 50 — applies / may-apply / silent; derivable vs. attestation
|
|
74
|
+
→ BOM deterministic CycloneDX ML-BOM that diffs cleanly in PRs
|
|
75
|
+
→ attest in-toto/DSSE signature fills an UNDOCUMENTED gap with a verifiable declaration
|
|
76
|
+
|
|
77
|
+
surfaces: CLI + VS Code (LSP, inline diagnostics as you type) — one shared engine
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Install
|
|
81
|
+
|
|
82
|
+
Requires [uv](https://docs.astral.sh/uv/) and Python 3.12.
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
git clone https://github.com/aibhuyan/ladex
|
|
86
|
+
cd ladex
|
|
87
|
+
uv sync
|
|
88
|
+
uv run ladex --version
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Quickstart
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# See every AI component in a repo (silent on non-AI code)
|
|
95
|
+
uv run ladex scan path/to/repo
|
|
96
|
+
|
|
97
|
+
# Add real facts: licenses, CVEs, model cards (cached; --offline works from cache)
|
|
98
|
+
uv run ladex scan path/to/repo --enrich
|
|
99
|
+
|
|
100
|
+
# What does it obligate under the EU AI Act? (declare project facts to resolve "may apply")
|
|
101
|
+
uv run ladex policy check path/to/repo --user-facing
|
|
102
|
+
|
|
103
|
+
# Produce the committable, deterministic ML-BOM
|
|
104
|
+
uv run ladex scan path/to/repo --write-bom aibom.cdx.json
|
|
105
|
+
|
|
106
|
+
# Sign a human answer for a gap no scanner can fill, then verify it
|
|
107
|
+
uv run ladex attest "sentence-transformers/all-MiniLM-L6-v2" \
|
|
108
|
+
--claim provenance --value "Curated public corpora, reviewed 2026-08"
|
|
109
|
+
uv run ladex verify
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Example
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
app.py
|
|
116
|
+
7:10 inference_api openai.client openai.OpenAI (OpenAI)
|
|
117
|
+
12:9 model openai.model-id gpt-4o (OpenAI)
|
|
118
|
+
|
|
119
|
+
infra/main.tf
|
|
120
|
+
20:1 vector_store iac.tf.vector-store-unencrypted HIGH aws_opensearch_domain.vectors
|
|
121
|
+
- Vector store is not encrypted at rest
|
|
122
|
+
|
|
123
|
+
Summary: 3 detection(s) across 2 of 2 file(s) scanned.
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## In your editor
|
|
127
|
+
|
|
128
|
+
The VS Code extension is a thin client over the same engine — inline diagnostics as you type,
|
|
129
|
+
nothing on non-AI code. Install it, no repo checkout needed:
|
|
130
|
+
|
|
131
|
+
1. Install the engine so the extension can call it: `pip install ladex` (or `uv tool install ladex`).
|
|
132
|
+
2. Grab `ladex-<version>.vsix` from the [Releases page](https://github.com/aibhuyan/ladex/releases)
|
|
133
|
+
→ Extensions panel → **Install from VSIX…** (Marketplace listing coming soon).
|
|
134
|
+
|
|
135
|
+
Then open any Python file that uses an AI library. See
|
|
136
|
+
[`extensions/vscode/README.md`](extensions/vscode/README.md) for configuration and development.
|
|
137
|
+
|
|
138
|
+
## Design principles
|
|
139
|
+
|
|
140
|
+
- **One engine, three surfaces.** The IDE, CLI, and (v2) PR check all call the same Python
|
|
141
|
+
engine — the editor can never disagree with the gate.
|
|
142
|
+
- **Ruthless silence.** If a line isn't AI-relevant, Ladex says nothing.
|
|
143
|
+
- **Honest gaps.** `UNDOCUMENTED` is a valid, valuable output. A green checkmark only appears
|
|
144
|
+
when something was actually verified — or signed by a named human.
|
|
145
|
+
- **Policy as versioned data.** Taxonomy and EU AI Act rules are updatable bundles, not code.
|
|
146
|
+
|
|
147
|
+
## Scope (v1)
|
|
148
|
+
|
|
149
|
+
**Python + Terraform + Kubernetes detection. EU AI Act. Two surfaces (CLI + VS Code).**
|
|
150
|
+
The GitHub PR check and evidence graph are v2.
|
|
151
|
+
|
|
152
|
+
## Development
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
uv run ruff check .
|
|
156
|
+
uv run mypy
|
|
157
|
+
uv run pytest
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Pre-commit (`ruff` + `mypy`) runs on every commit; run `uv run pre-commit install` once.
|
|
161
|
+
|
|
162
|
+
## License
|
|
163
|
+
|
|
164
|
+
MIT — see [`LICENSE`](LICENSE).
|
ladex-0.1.0/README.md
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/ladex-lockup-dark.png">
|
|
4
|
+
<img src="assets/ladex-lockup-light.png" alt="Ladex" width="360">
|
|
5
|
+
</picture>
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
<p align="center"><strong>A bill of lading for AI.</strong></p>
|
|
9
|
+
|
|
10
|
+
<p align="center">
|
|
11
|
+
<img src="https://img.shields.io/badge/version-0.1.0-3b82f6?style=flat" alt="version 0.1.0">
|
|
12
|
+
<img src="https://img.shields.io/github/stars/aibhuyan/ladex?style=flat&color=3b82f6" alt="GitHub stars">
|
|
13
|
+
<img src="https://img.shields.io/badge/license-MIT-3b82f6?style=flat" alt="license MIT">
|
|
14
|
+
<img src="https://img.shields.io/badge/python-3.12+-3b82f6?style=flat" alt="python 3.12+">
|
|
15
|
+
<img src="https://img.shields.io/badge/tests-139%20passing-22c55e?style=flat" alt="tests 139 passing">
|
|
16
|
+
<img src="https://img.shields.io/badge/output-CycloneDX%20ML--BOM-3b82f6?style=flat" alt="CycloneDX ML-BOM">
|
|
17
|
+
<img src="https://img.shields.io/badge/EU%20AI%20Act-Art.%2050-3b82f6?style=flat" alt="EU AI Act Art. 50">
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
You already require a **bill of lading** for physical cargo and an **SBOM** for software.
|
|
23
|
+
Ladex is the one for **AI** — it records what AI is aboard your codebase, from whom, and under
|
|
24
|
+
what terms, captured at the moment the code is written rather than discovered after the fact.
|
|
25
|
+
|
|
26
|
+
Ladex is a shift-left AI governance tool for developers. When you write an AI-relevant line of
|
|
27
|
+
code — importing an agent framework, loading a Hugging Face model, calling an inference API,
|
|
28
|
+
provisioning a GPU node pool in Terraform — Ladex detects it and answers three questions:
|
|
29
|
+
|
|
30
|
+
1. **What is this?** model / dataset / agent framework / vector store / inference API
|
|
31
|
+
2. **What does it obligate?** EU AI Act Art. 50 disclosure, Annex III high-risk triggers
|
|
32
|
+
3. **What's auto-verifiable vs. what needs a human?** CVEs and licenses resolve
|
|
33
|
+
automatically. Training-data provenance and consent basis can't be derived by any scanner —
|
|
34
|
+
they're flagged `UNDOCUMENTED` and require a **signed human attestation**, never a fake green
|
|
35
|
+
checkmark.
|
|
36
|
+
|
|
37
|
+
The output is a **CycloneDX ML-BOM** committed to your repo, diffable in PRs, with signed
|
|
38
|
+
attestations for the fields no tool can derive.
|
|
39
|
+
|
|
40
|
+
> Ladex records what's aboard; it does not block attacks.
|
|
41
|
+
|
|
42
|
+
## What it does
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
detect (Python + Terraform + Kubernetes)
|
|
46
|
+
→ enrich PyPI licenses · OSV CVEs · Hugging Face model cards (cached, offline-capable)
|
|
47
|
+
→ obligate EU AI Act Art. 50 — applies / may-apply / silent; derivable vs. attestation
|
|
48
|
+
→ BOM deterministic CycloneDX ML-BOM that diffs cleanly in PRs
|
|
49
|
+
→ attest in-toto/DSSE signature fills an UNDOCUMENTED gap with a verifiable declaration
|
|
50
|
+
|
|
51
|
+
surfaces: CLI + VS Code (LSP, inline diagnostics as you type) — one shared engine
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Install
|
|
55
|
+
|
|
56
|
+
Requires [uv](https://docs.astral.sh/uv/) and Python 3.12.
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
git clone https://github.com/aibhuyan/ladex
|
|
60
|
+
cd ladex
|
|
61
|
+
uv sync
|
|
62
|
+
uv run ladex --version
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Quickstart
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
# See every AI component in a repo (silent on non-AI code)
|
|
69
|
+
uv run ladex scan path/to/repo
|
|
70
|
+
|
|
71
|
+
# Add real facts: licenses, CVEs, model cards (cached; --offline works from cache)
|
|
72
|
+
uv run ladex scan path/to/repo --enrich
|
|
73
|
+
|
|
74
|
+
# What does it obligate under the EU AI Act? (declare project facts to resolve "may apply")
|
|
75
|
+
uv run ladex policy check path/to/repo --user-facing
|
|
76
|
+
|
|
77
|
+
# Produce the committable, deterministic ML-BOM
|
|
78
|
+
uv run ladex scan path/to/repo --write-bom aibom.cdx.json
|
|
79
|
+
|
|
80
|
+
# Sign a human answer for a gap no scanner can fill, then verify it
|
|
81
|
+
uv run ladex attest "sentence-transformers/all-MiniLM-L6-v2" \
|
|
82
|
+
--claim provenance --value "Curated public corpora, reviewed 2026-08"
|
|
83
|
+
uv run ladex verify
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Example
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
app.py
|
|
90
|
+
7:10 inference_api openai.client openai.OpenAI (OpenAI)
|
|
91
|
+
12:9 model openai.model-id gpt-4o (OpenAI)
|
|
92
|
+
|
|
93
|
+
infra/main.tf
|
|
94
|
+
20:1 vector_store iac.tf.vector-store-unencrypted HIGH aws_opensearch_domain.vectors
|
|
95
|
+
- Vector store is not encrypted at rest
|
|
96
|
+
|
|
97
|
+
Summary: 3 detection(s) across 2 of 2 file(s) scanned.
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## In your editor
|
|
101
|
+
|
|
102
|
+
The VS Code extension is a thin client over the same engine — inline diagnostics as you type,
|
|
103
|
+
nothing on non-AI code. Install it, no repo checkout needed:
|
|
104
|
+
|
|
105
|
+
1. Install the engine so the extension can call it: `pip install ladex` (or `uv tool install ladex`).
|
|
106
|
+
2. Grab `ladex-<version>.vsix` from the [Releases page](https://github.com/aibhuyan/ladex/releases)
|
|
107
|
+
→ Extensions panel → **Install from VSIX…** (Marketplace listing coming soon).
|
|
108
|
+
|
|
109
|
+
Then open any Python file that uses an AI library. See
|
|
110
|
+
[`extensions/vscode/README.md`](extensions/vscode/README.md) for configuration and development.
|
|
111
|
+
|
|
112
|
+
## Design principles
|
|
113
|
+
|
|
114
|
+
- **One engine, three surfaces.** The IDE, CLI, and (v2) PR check all call the same Python
|
|
115
|
+
engine — the editor can never disagree with the gate.
|
|
116
|
+
- **Ruthless silence.** If a line isn't AI-relevant, Ladex says nothing.
|
|
117
|
+
- **Honest gaps.** `UNDOCUMENTED` is a valid, valuable output. A green checkmark only appears
|
|
118
|
+
when something was actually verified — or signed by a named human.
|
|
119
|
+
- **Policy as versioned data.** Taxonomy and EU AI Act rules are updatable bundles, not code.
|
|
120
|
+
|
|
121
|
+
## Scope (v1)
|
|
122
|
+
|
|
123
|
+
**Python + Terraform + Kubernetes detection. EU AI Act. Two surfaces (CLI + VS Code).**
|
|
124
|
+
The GitHub PR check and evidence graph are v2.
|
|
125
|
+
|
|
126
|
+
## Development
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
uv run ruff check .
|
|
130
|
+
uv run mypy
|
|
131
|
+
uv run pytest
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Pre-commit (`ruff` + `mypy`) runs on every commit; run `uv run pre-commit install` once.
|
|
135
|
+
|
|
136
|
+
## License
|
|
137
|
+
|
|
138
|
+
MIT — see [`LICENSE`](LICENSE).
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "0.2.0",
|
|
3
|
+
"configurations": [
|
|
4
|
+
{
|
|
5
|
+
"name": "Run Ladex Extension",
|
|
6
|
+
"type": "extensionHost",
|
|
7
|
+
"request": "launch",
|
|
8
|
+
// Load THIS extension and open the demo/ folder in the dev host window.
|
|
9
|
+
"args": [
|
|
10
|
+
"--extensionDevelopmentPath=${workspaceFolder}",
|
|
11
|
+
"${workspaceFolder}/demo"
|
|
12
|
+
],
|
|
13
|
+
"outFiles": ["${workspaceFolder}/out/**/*.js"],
|
|
14
|
+
"preLaunchTask": "npm: compile",
|
|
15
|
+
// Put the project's virtualenv on PATH so the extension's default `ladex serve`
|
|
16
|
+
// resolves without a global install. Windows layout: <repo>/.venv/Scripts.
|
|
17
|
+
// (On macOS/Linux use ".venv/bin" and ":" as the separator.)
|
|
18
|
+
"env": {
|
|
19
|
+
"PATH": "${workspaceFolder}/../../.venv/Scripts;${env:PATH}"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 duskyvesper
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Ladex for VS Code
|
|
2
|
+
|
|
3
|
+
Flags AI components inline as you edit Python — inference APIs, models, agent frameworks,
|
|
4
|
+
vector stores — and nudges what each obligates under the EU AI Act. Nothing shows on non-AI
|
|
5
|
+
code (ruthless silence).
|
|
6
|
+
|
|
7
|
+
All detection runs in the Ladex Python engine, the *same* engine the CLI and PR check use —
|
|
8
|
+
the editor can never disagree with the gate.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
**1. Install the Ladex engine** (the extension talks to it):
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pip install ladex # or: uv tool install ladex / pipx install ladex
|
|
16
|
+
ladex --version # verify it's on your PATH
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**2. Install the extension** — either:
|
|
20
|
+
|
|
21
|
+
- **From a `.vsix`:** download `ladex-<version>.vsix` from the
|
|
22
|
+
[Releases page](https://github.com/aibhuyan/ladex/releases), then in VS Code open the
|
|
23
|
+
Extensions panel → `⋯` menu → **Install from VSIX…** (or run
|
|
24
|
+
`code --install-extension ladex-<version>.vsix`).
|
|
25
|
+
- **From the Marketplace:** search **“Ladex”** in the Extensions panel *(once published)*.
|
|
26
|
+
|
|
27
|
+
Open any Python file that uses an AI library — diagnostics appear as you type.
|
|
28
|
+
|
|
29
|
+
## Configuration
|
|
30
|
+
|
|
31
|
+
| Setting | Default | Meaning |
|
|
32
|
+
| --- | --- | --- |
|
|
33
|
+
| `ladex.serverCommand` | `ladex` | Command that starts the engine. Set to a full path if `ladex` isn't on PATH. |
|
|
34
|
+
| `ladex.serverArgs` | `["serve"]` | Arguments passed to it. |
|
|
35
|
+
|
|
36
|
+
If you see *“could not start 'ladex serve'”*, the engine isn't on your PATH — install it
|
|
37
|
+
(step 1) or point `ladex.serverCommand` at the executable
|
|
38
|
+
(e.g. `.../.venv/Scripts/ladex.exe`).
|
|
39
|
+
|
|
40
|
+
## Development (contributing to the extension)
|
|
41
|
+
|
|
42
|
+
You only need this if you're hacking on the extension itself:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
cd extensions/vscode
|
|
46
|
+
npm install
|
|
47
|
+
npm run compile # or: npm run watch
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Then press **F5** — the bundled launch config compiles, puts the repo's `.venv` on PATH, and
|
|
51
|
+
opens `demo/` in an Extension Development Host so you can see live diagnostics.
|
|
52
|
+
|
|
53
|
+
Build a distributable package with `npm run package` → `ladex-<version>.vsix`.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""Ladex extension demo.
|
|
2
|
+
|
|
3
|
+
Open this file in the Extension Development Host (F5) and you should see inline Ladex
|
|
4
|
+
diagnostics on the AI-relevant lines below — and nothing on the ordinary Python.
|
|
5
|
+
Try editing: add `import transformers` and watch a new diagnostic appear as you type.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import openai
|
|
9
|
+
from anthropic import Anthropic
|
|
10
|
+
|
|
11
|
+
client = openai.OpenAI()
|
|
12
|
+
ac = Anthropic()
|
|
13
|
+
|
|
14
|
+
MODEL = "gpt-4o"
|
|
15
|
+
reply = ac.messages.create(model="claude-3-5-sonnet-latest", max_tokens=10, messages=[])
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# Ordinary Python below — Ladex stays silent here (ruthless silence).
|
|
19
|
+
def add(a: int, b: int) -> int:
|
|
20
|
+
return a + b
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Ladex VS Code extension — a thin client that launches the Python engine over stdio.
|
|
3
|
+
//
|
|
4
|
+
// It deliberately contains no detection logic: it starts `ladex serve` (the same engine the
|
|
5
|
+
// CLI and PR check use) and lets the language server publish diagnostics. "One engine, three
|
|
6
|
+
// surfaces" — the editor can never disagree with the gate.
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.activate = activate;
|
|
42
|
+
exports.deactivate = deactivate;
|
|
43
|
+
const vscode = __importStar(require("vscode"));
|
|
44
|
+
const node_1 = require("vscode-languageclient/node");
|
|
45
|
+
let client;
|
|
46
|
+
function activate(context) {
|
|
47
|
+
const config = vscode.workspace.getConfiguration("ladex");
|
|
48
|
+
const command = config.get("serverCommand", "ladex");
|
|
49
|
+
const args = config.get("serverArgs", ["serve"]);
|
|
50
|
+
const serverOptions = {
|
|
51
|
+
run: { command, args, transport: node_1.TransportKind.stdio },
|
|
52
|
+
debug: { command, args, transport: node_1.TransportKind.stdio },
|
|
53
|
+
};
|
|
54
|
+
const clientOptions = {
|
|
55
|
+
documentSelector: [{ scheme: "file", language: "python" }],
|
|
56
|
+
diagnosticCollectionName: "ladex",
|
|
57
|
+
};
|
|
58
|
+
client = new node_1.LanguageClient("ladex", "Ladex", serverOptions, clientOptions);
|
|
59
|
+
// Surface a clear error if the engine isn't on PATH, rather than failing silently.
|
|
60
|
+
client.start().catch((err) => {
|
|
61
|
+
void vscode.window.showErrorMessage(`Ladex: could not start '${command} ${args.join(" ")}'. ` +
|
|
62
|
+
`Install the ladex CLI and ensure it is on PATH. (${String(err)})`);
|
|
63
|
+
});
|
|
64
|
+
context.subscriptions.push({
|
|
65
|
+
dispose: () => {
|
|
66
|
+
void client?.stop();
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function deactivate() {
|
|
71
|
+
return client?.stop();
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=extension.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":";AAAA,sFAAsF;AACtF,EAAE;AACF,4FAA4F;AAC5F,6FAA6F;AAC7F,2DAA2D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAY3D,4BAmCC;AAED,gCAEC;AAjDD,+CAAiC;AACjC,qDAKoC;AAEpC,IAAI,MAAkC,CAAC;AAEvC,SAAgB,QAAQ,CAAC,OAAgC;IACvD,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC1D,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAS,eAAe,EAAE,OAAO,CAAC,CAAC;IAC7D,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAW,YAAY,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAE3D,MAAM,aAAa,GAAkB;QACnC,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,oBAAa,CAAC,KAAK,EAAE;QACtD,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,oBAAa,CAAC,KAAK,EAAE;KACzD,CAAC;IAEF,MAAM,aAAa,GAA0B;QAC3C,gBAAgB,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;QAC1D,wBAAwB,EAAE,OAAO;KAClC,CAAC;IAEF,MAAM,GAAG,IAAI,qBAAc,CACzB,OAAO,EACP,OAAO,EACP,aAAa,EACb,aAAa,CACd,CAAC;IAEF,mFAAmF;IACnF,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;QACpC,KAAK,MAAM,CAAC,MAAM,CAAC,gBAAgB,CACjC,2BAA2B,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK;YACvD,oDAAoD,MAAM,CAAC,GAAG,CAAC,GAAG,CACrE,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC;QACzB,OAAO,EAAE,GAAG,EAAE;YACZ,KAAK,MAAM,EAAE,IAAI,EAAE,CAAC;QACtB,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,SAAgB,UAAU;IACxB,OAAO,MAAM,EAAE,IAAI,EAAE,CAAC;AACxB,CAAC"}
|