Repository navigation
Expand file tree
/
Copy pathpyproject.toml
More file actions
203 lines (184 loc) · 8.94 KB
/
Copy pathpyproject.toml
File metadata and controls
203 lines (184 loc) · 8.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
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
[project]
# PyPI distribution name. The bare `modelith` is taken on PyPI by an unrelated
# project, so the install name is `modelith-dbt` (install: uv tool install
# modelith-dbt). The command stays `mdl`; the import modules stay mdl_*.
name = "modelith-dbt"
version = "0.7.2"
description = "Ontology-anchored, git-native data modeling tool for dbt-core teams"
readme = "README.md"
requires-python = ">=3.11"
license = { text = "Apache-2.0" }
# Single distributable wheel: all mdl_* module trees ship inside one
# `modelith` distribution. These are the UNION of the workspace members'
# third-party dependencies; the inter-member `modelith-*` deps are gone because
# everything now lives here. The [tool.uv.workspace] block below keeps the
# split-package layout for local development.
# Version floors that carry a CVE fix are called out inline; the rest are ordinary
# minimums. Transitive-dependency CVE floors live in [tool.uv] constraint-dependencies
# below (they are held, not made first-class deps). All floors are already satisfied by
# the committed uv.lock — they codify a safe minimum so the resolver can never drift down
# into a known-vulnerable version, which is what an enterprise SCA/firewall scan checks.
dependencies = [
"pydantic>=2.6", # >2.4.0, clears CVE-2024-3772 (ReDoS)
"ruamel.yaml>=0.18", # >0.16.8, clears CVE-2019-20478
"typer>=0.12",
"dbt-artifacts-parser>=0.5",
"jinja2>=3.1.6", # CVE-2025-27516 (sandbox breakout); also 2024 SSTI fixes
"fastapi>=0.115", # pulls starlette>=0.40 for CVE-2024-47874 (multipart DoS)
"uvicorn>=0.29",
"python-multipart>=0.0.18", # CVE-2024-53981 (boundary DoS)
"pygls>=2.0",
"sqlglot>=25",
"mcp>=1.28.1,<2", # CVE-2026-59950 (WebSocket Host/Origin); >1.23 DNS-rebind
"httpx>=0.27", # ontology remote resolvers + the telemetry emitter
]
# Optional OpenTelemetry export for the audit log (spec §20). `pip install
# modelith-dbt[audit]` / `uv sync --extra audit` adds it; without it, the audit log
# still writes its local JSONL file, just no OTLP.
[project.optional-dependencies]
audit = [
"opentelemetry-sdk>=1.20",
"opentelemetry-exporter-otlp-proto-http>=1.20",
]
# Optional ontology / knowledge-graph stack: RDF/OWL/SHACL/R2RML export, vocabulary
# alignment, and remote SPARQL. Kept OUT of the core deps so `modelith-dbt` installs
# cleanly where an enterprise package firewall quarantines an RDF coordinate. The
# backend is pyoxigraph (Rust wheel, zero Python transitive deps, CVE-clean, a coordinate
# a name-matching scanner does not flag — unlike rdflib). Without this extra the CLI still
# runs; ontology / `export rdf|shacl|r2rml` commands exit with a one-line install hint.
# uv tool install 'modelith-dbt[ontology]' (or: pip install 'modelith-dbt[ontology]')
ontology = [
"pyoxigraph>=0.5.9",
]
# Single `mdl` command. Not exposing a `modelith` script avoids colliding with
# the unrelated `modelith` package that already exists on PyPI.
[project.scripts]
mdl = "mdl_cli.main:main"
# Plugin seam for `mdl reverse-config import`: a package can register a resolver for a new
# source scheme (e.g. an enterprise `mdl://` Global-Standards registry) by exposing it here.
# Each entry point loads to a ConfigResolver (see mdl_reverse.remote_config); installing the
# package makes that scheme importable with no change to the open CLI. Modelith ships none —
# the built-in file/https/github/gitlab resolvers are registered in-process.
[project.entry-points."modelith.config_resolvers"]
# example (in a separate enterprise package's pyproject, NOT here):
# mdl = "modelith_enterprise.registry:MdlResolver"
# Plugin seam for new `mdl` subcommands: a package can add top-level commands (e.g. the
# paid `mdl ci` drift gate) by exposing a `register(app)` callable here. The loader
# (mdl_cli.plugins.load_command_plugins) runs it against the root Typer app at startup, so
# the command appears in `mdl --help` with no change to the open CLI. Failures are
# swallowed — a broken plugin never bricks the free CLI. Modelith ships none.
[project.entry-points."modelith.commands"]
# example (in a separate enterprise package's pyproject, NOT here):
# ci = "modelith_enterprise.ci:register"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
# Scratch dirs that live in the working tree but must never ship. The sdist is
# built from the working tree, so an untracked .claude/worktrees/ got swept into
# the 0.3.2 tarball and doubled it to 10MB.
[tool.hatch.build.targets.sdist]
exclude = [
".claude",
".venv",
"node_modules",
"dist",
"sandbox",
]
# The single-wheel mapping lives in hatch_build.py, NOT here: a static
# force-include also applies to the EDITABLE build, which copied all fourteen
# trees into site-packages where they shadowed the real sources (edits under
# packages/*/src silently did nothing, and the test suite could pass green
# against stale code). The hook applies it to the real wheel only.
[tool.hatch.build.targets.wheel]
# Editable installs get each member's src/ on sys.path via a .pth file, so
# imports resolve to the working tree. Keep in step with hatch_build.py.
dev-mode-dirs = [
"packages/core/src",
"packages/cli/src",
"packages/emit-dbt/src",
"packages/emit-contract/src",
"packages/emit-pydantic/src",
"packages/emit-graph/src",
"packages/emit-erd/src",
"packages/reverse/src",
"packages/docs/src",
"packages/ontology/src",
"packages/emit-semantic/src",
"packages/governance/src",
"packages/catalog/src",
"packages/server/src",
"packages/lsp/src",
"packages/mcp/src",
"packages/adapters/collibra/src",
]
[tool.hatch.build.targets.wheel.hooks.custom]
path = "hatch_build.py"
# CVE-clean floors for TRANSITIVE dependencies. These are not direct deps of Modelith —
# they arrive through fastapi/httpx/mcp/etc. — so rather than pin them as first-class deps
# (brittle as the tree evolves) they are held above their fix version here. `uv lock`
# respects these; each is already satisfied by the committed lock, so this is a guard
# against downward drift, not an upgrade. Each line cites the CVE fixed at that floor.
[tool.uv]
constraint-dependencies = [
"requests>=2.32.4", # CVE-2024-47081 (.netrc credential leak)
"urllib3>=2.5.0", # CVE-2025-50181 / CVE-2025-50182 (redirect handling)
"certifi>=2024.7.4", # CVE-2024-39689 (removed GLOBALTRUST CA bundle)
"cryptography>=50.0.0", # CVE-2026-69247 (PKCS#7 Bleichenbacher)
"h11>=0.16.0", # CVE-2025-43859 (chunked-encoding request smuggling)
"idna>=3.7", # CVE-2024-3651 (quadratic-complexity DoS)
"anyio>=4.14.2", # CVE-2026-63374 (TLS spoof via IDNA 2003)
"click>=8.3.3", # CVE-2026-7246 (command injection in click.edit())
"pygments>=2.15.0", # CVE-2022-40896 (ReDoS in SmithyLexer)
"pydantic-settings>=2.14.2", # CVE-2026-58203 (symlink attack in secrets source)
"python-dotenv>=1.2.2", # CVE-2026-28684 (symlink path traversal in set_key)
"zipp>=3.19.1", # CVE-2024-5569 (infinite-loop DoS)
"protobuf>=6.33.5", # CVE-2025-4565 / CVE-2026-0994 (recursion DoS)
"pyjwt>=2.10.1", # CVE-2022-29217 / CVE-2024-53861 (alg confusion, iss match)
]
[tool.uv.workspace]
members = ["packages/*", "packages/adapters/*"]
exclude = ["packages/adapters"]
[tool.uv.sources]
modelith-core = { workspace = true }
modelith-emit-dbt = { workspace = true }
modelith-emit-contract = { workspace = true }
modelith-emit-pydantic = { workspace = true }
modelith-emit-graph = { workspace = true }
modelith-emit-erd = { workspace = true }
modelith-reverse = { workspace = true }
modelith-ontology = { workspace = true }
modelith-emit-semantic = { workspace = true }
modelith-governance = { workspace = true }
modelith-catalog = { workspace = true }
modelith-adapter-collibra = { workspace = true }
modelith-server = { workspace = true }
modelith-lsp = { workspace = true }
modelith-cli = { workspace = true }
[dependency-groups]
dev = [
"pytest>=8.0",
"hypothesis>=6.100",
"pytest-cov>=5.0",
"ruff>=0.6",
"httpx>=0.27", # FastAPI TestClient
]
[tool.ruff]
line-length = 100
target-version = "py311"
[tool.ruff.lint]
select = ["E", "F", "I", "UP", "B"]
# B008: typer uses call-in-default as its documented API idiom.
# UP042: str+Enum is intentional (JSON/YAML-serialisable string enums).
ignore = ["B008", "UP042"]
[tool.ruff.lint.per-file-ignores]
# Jinja macro signatures are strings we can't line-wrap.
"packages/emit-dbt/src/mdl_emit_dbt/macros.py" = ["E501"]
# Test fixtures embed 26-char ULID literals that push lines past the limit.
"packages/*/tests/*.py" = ["E501"]
[tool.ruff.lint.isort]
# Test-local helper modules imported by bare name (added to sys.path in conftest).
known-first-party = ["mdl_core", "mdl_emit_dbt", "mdl_reverse", "mdl_cli"]
known-local-folder = ["model_builders", "manifest_fixtures", "conftest"]
[tool.pytest.ini_options]
testpaths = ["packages"]
addopts = "-q"