lazaret 0.0.1__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.
- lazaret-0.0.1/LICENSE +13 -0
- lazaret-0.0.1/PKG-INFO +44 -0
- lazaret-0.0.1/README.md +23 -0
- lazaret-0.0.1/_build/lazaret_build.py +238 -0
- lazaret-0.0.1/pyproject.toml +9 -0
- lazaret-0.0.1/src/lazaret/__init__.py +11 -0
- lazaret-0.0.1/src/lazaret/__main__.py +3 -0
- lazaret-0.0.1/src/lazaret/mcp/__init__.py +1 -0
- lazaret-0.0.1/src/lazaret/mcp/__main__.py +3 -0
- lazaret-0.0.1/src/lazaret/mcp/server.py +536 -0
- lazaret-0.0.1/src/lazaret/pg/__init__.py +40 -0
- lazaret-0.0.1/src/lazaret/pg/_dsn.py +277 -0
- lazaret-0.0.1/src/lazaret/pg/_scram.py +202 -0
- lazaret-0.0.1/src/lazaret/pg/_types.py +374 -0
- lazaret-0.0.1/src/lazaret/pg/connection.py +858 -0
- lazaret-0.0.1/src/lazaret/pg/errors.py +115 -0
- lazaret-0.0.1/src/lazaret/registry/__init__.py +1 -0
- lazaret-0.0.1/src/lazaret/registry/__main__.py +3 -0
- lazaret-0.0.1/src/lazaret/registry/repo.py +1199 -0
- lazaret-0.0.1/src/lazaret/registry/schema.sql +53 -0
- lazaret-0.0.1/src/lazaret/safexml/ElementTree.py +244 -0
- lazaret-0.0.1/src/lazaret/safexml/__init__.py +46 -0
- lazaret-0.0.1/src/lazaret/safexml/_common.py +150 -0
- lazaret-0.0.1/src/lazaret/safexml/minidom.py +86 -0
- lazaret-0.0.1/src/lazaret/safexml/pulldom.py +26 -0
- lazaret-0.0.1/src/lazaret/safexml/sax.py +95 -0
- lazaret-0.0.1/src/lazaret/safexml/xmlrpc.py +140 -0
- lazaret-0.0.1/src/lazaret/scanner/__init__.py +2 -0
- lazaret-0.0.1/src/lazaret/scanner/core.py +2558 -0
- lazaret-0.0.1/src/lazaret/scanner/flow.py +995 -0
- lazaret-0.0.1/src/lazaret/scanner/reports.py +384 -0
- lazaret-0.0.1/src/lazaret/scanner/sca.py +859 -0
- lazaret-0.0.1/src/lazaret/web/lazaret.html +1293 -0
lazaret-0.0.1/LICENSE
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Copyright 2026 The Lazaret authors
|
|
2
|
+
|
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License.
|
|
5
|
+
You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
See the License for the specific language governing permissions and
|
|
13
|
+
limitations under the License.
|
lazaret-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: lazaret
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Static security, supply-chain and quality analysis for Python, JavaScript and SQL
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Keywords: security,supply-chain,sast,taint-analysis,sca,pypi,npm
|
|
8
|
+
Project-URL: Homepage, https://lazaret.dev
|
|
9
|
+
Project-URL: Source, https://github.com/lazaret-dev/lazaret
|
|
10
|
+
Project-URL: Issues, https://github.com/lazaret-dev/lazaret/issues
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Topic :: Security
|
|
19
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# Lazaret
|
|
23
|
+
|
|
24
|
+
Static security, supply-chain and quality analysis for Python, JavaScript and SQL, with **no dependencies**: Lazaret runs on the Python standard library alone, and even building it downloads nothing.
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install lazaret
|
|
28
|
+
lazaret path/to/project # scan; writes lazaret-report.{html,json}
|
|
29
|
+
lazaret . --ci --sarif out.sarif # quality gate for CI, SARIF for code scanning
|
|
30
|
+
lazaret-registry scan npm:left-pad # audit a published npm / PyPI package
|
|
31
|
+
lazaret-sca . --bundle cve-bundle.json # match installed dependencies against CVEs
|
|
32
|
+
lazaret-mcp # MCP server, so an AI assistant can scan code
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
What it finds:
|
|
36
|
+
|
|
37
|
+
- **Security:** SQL/command/code injection, SSTI, XXE, unsafe deserialization, XSS sinks, weak crypto, disabled TLS verification, hardcoded secrets (provider signatures and entropy), and more, across about 58 rules.
|
|
38
|
+
- **Taint analysis:** follows untrusted input through assignments, function calls, and across files into sinks, with category-aware sanitizers and a configurable source/sink/sanitizer spec.
|
|
39
|
+
- **Supply chain:** decode-then-execute patterns, packed and obfuscated JavaScript, suspicious install hooks, smuggled binaries and nested archives, both in your tree and in published npm/PyPI packages.
|
|
40
|
+
- **Quality:** bugs, code smells, complexity, duplication, with a quality gate and ratings.
|
|
41
|
+
|
|
42
|
+
Two of its building blocks are usable on their own (provisional APIs until 1.0): `lazaret.pg`, a PostgreSQL client in pure Python with SCRAM-SHA-256, channel binding and TLS; and `lazaret.safexml`, a layer that makes the stdlib XML parsers safe for untrusted input.
|
|
43
|
+
|
|
44
|
+
Licensed under Apache-2.0. Documentation, source and issue tracker: https://github.com/lazaret-dev/lazaret · https://lazaret.dev
|
lazaret-0.0.1/README.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Lazaret
|
|
2
|
+
|
|
3
|
+
Static security, supply-chain and quality analysis for Python, JavaScript and SQL, with **no dependencies**: Lazaret runs on the Python standard library alone, and even building it downloads nothing.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pip install lazaret
|
|
7
|
+
lazaret path/to/project # scan; writes lazaret-report.{html,json}
|
|
8
|
+
lazaret . --ci --sarif out.sarif # quality gate for CI, SARIF for code scanning
|
|
9
|
+
lazaret-registry scan npm:left-pad # audit a published npm / PyPI package
|
|
10
|
+
lazaret-sca . --bundle cve-bundle.json # match installed dependencies against CVEs
|
|
11
|
+
lazaret-mcp # MCP server, so an AI assistant can scan code
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
What it finds:
|
|
15
|
+
|
|
16
|
+
- **Security:** SQL/command/code injection, SSTI, XXE, unsafe deserialization, XSS sinks, weak crypto, disabled TLS verification, hardcoded secrets (provider signatures and entropy), and more, across about 58 rules.
|
|
17
|
+
- **Taint analysis:** follows untrusted input through assignments, function calls, and across files into sinks, with category-aware sanitizers and a configurable source/sink/sanitizer spec.
|
|
18
|
+
- **Supply chain:** decode-then-execute patterns, packed and obfuscated JavaScript, suspicious install hooks, smuggled binaries and nested archives, both in your tree and in published npm/PyPI packages.
|
|
19
|
+
- **Quality:** bugs, code smells, complexity, duplication, with a quality gate and ratings.
|
|
20
|
+
|
|
21
|
+
Two of its building blocks are usable on their own (provisional APIs until 1.0): `lazaret.pg`, a PostgreSQL client in pure Python with SCRAM-SHA-256, channel binding and TLS; and `lazaret.safexml`, a layer that makes the stdlib XML parsers safe for untrusted input.
|
|
22
|
+
|
|
23
|
+
Licensed under Apache-2.0. Documentation, source and issue tracker: https://github.com/lazaret-dev/lazaret · https://lazaret.dev
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
"""Lazaret's build backend (PEP 517 / PEP 660), standard library only.
|
|
2
|
+
|
|
3
|
+
Building Lazaret downloads nothing: pyproject.toml declares no build
|
|
4
|
+
requirements and points here via backend-path. pip uses these hooks for
|
|
5
|
+
`pip install .` and `pip install -e .`; release CI calls them directly:
|
|
6
|
+
|
|
7
|
+
python _build/lazaret_build.py [output-dir] # writes the wheel and sdist
|
|
8
|
+
|
|
9
|
+
Package metadata lives in this module (METADATA below) rather than in a
|
|
10
|
+
[project] table: a backend must honor [project] if it exists, and reading TOML
|
|
11
|
+
on Python 3.10 would need a third-party parser. The version has one source of
|
|
12
|
+
truth: __version__ in src/lazaret/__init__.py.
|
|
13
|
+
|
|
14
|
+
Outputs are reproducible: file order, timestamps, and permissions are fixed,
|
|
15
|
+
so building the same tree twice gives byte-identical artifacts (set
|
|
16
|
+
SOURCE_DATE_EPOCH to stamp a specific time instead of 1980-01-01).
|
|
17
|
+
|
|
18
|
+
The wheel contains only the package. Tests and fixtures never ship, in the
|
|
19
|
+
wheel or the sdist (see STRUCTURE.md, "What ships to the registries").
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import base64
|
|
25
|
+
import hashlib
|
|
26
|
+
import io
|
|
27
|
+
import os
|
|
28
|
+
import pathlib
|
|
29
|
+
import re
|
|
30
|
+
import sys
|
|
31
|
+
import tarfile
|
|
32
|
+
import zipfile
|
|
33
|
+
|
|
34
|
+
ROOT = pathlib.Path(__file__).resolve().parent.parent # python/
|
|
35
|
+
SRC = ROOT / "src"
|
|
36
|
+
PKG = SRC / "lazaret"
|
|
37
|
+
|
|
38
|
+
NAME = "lazaret"
|
|
39
|
+
METADATA = {
|
|
40
|
+
"Summary": "Static security, supply-chain and quality analysis for Python, JavaScript and SQL",
|
|
41
|
+
"Requires-Python": ">=3.10",
|
|
42
|
+
"License": "Apache-2.0",
|
|
43
|
+
"Keywords": "security,supply-chain,sast,taint-analysis,sca,pypi,npm",
|
|
44
|
+
"Project-URL": [
|
|
45
|
+
"Homepage, https://lazaret.dev",
|
|
46
|
+
"Source, https://github.com/lazaret-dev/lazaret",
|
|
47
|
+
"Issues, https://github.com/lazaret-dev/lazaret/issues",
|
|
48
|
+
],
|
|
49
|
+
"Classifier": [
|
|
50
|
+
"Development Status :: 4 - Beta",
|
|
51
|
+
"Environment :: Console",
|
|
52
|
+
"Intended Audience :: Developers",
|
|
53
|
+
"License :: OSI Approved :: Apache Software License",
|
|
54
|
+
"Operating System :: OS Independent",
|
|
55
|
+
"Programming Language :: Python :: 3",
|
|
56
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
57
|
+
"Topic :: Security",
|
|
58
|
+
"Topic :: Software Development :: Quality Assurance",
|
|
59
|
+
],
|
|
60
|
+
}
|
|
61
|
+
# Deliberately empty: Lazaret has no runtime dependencies. Tested.
|
|
62
|
+
REQUIRES_DIST: list[str] = []
|
|
63
|
+
|
|
64
|
+
CONSOLE_SCRIPTS = {
|
|
65
|
+
"lazaret": "lazaret.scanner.core:main",
|
|
66
|
+
"lazaret-registry": "lazaret.registry.repo:main",
|
|
67
|
+
"lazaret-mcp": "lazaret.mcp.server:main",
|
|
68
|
+
"lazaret-sca": "lazaret.scanner.sca:main",
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
SDIST_TOP_FILES = ["pyproject.toml", "README.md", "LICENSE"]
|
|
72
|
+
_SKIP_DIRS = {"__pycache__"}
|
|
73
|
+
_SKIP_SUFFIXES = (".pyc", ".pyo")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
# --- helpers -------------------------------------------------------------------
|
|
77
|
+
|
|
78
|
+
def version() -> str:
|
|
79
|
+
text = (PKG / "__init__.py").read_text(encoding="utf-8")
|
|
80
|
+
match = re.search(r'^__version__\s*=\s*["\']([^"\']+)["\']', text, re.M)
|
|
81
|
+
if not match:
|
|
82
|
+
raise RuntimeError("__version__ not found in src/lazaret/__init__.py")
|
|
83
|
+
return match.group(1)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _epoch_date_time() -> tuple[int, int, int, int, int, int]:
|
|
87
|
+
import time
|
|
88
|
+
epoch = os.environ.get("SOURCE_DATE_EPOCH")
|
|
89
|
+
if not epoch:
|
|
90
|
+
return (1980, 1, 1, 0, 0, 0)
|
|
91
|
+
t = time.gmtime(max(int(epoch), 315532800)) # zip can't go before 1980
|
|
92
|
+
return (t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _package_files() -> list[pathlib.Path]:
|
|
96
|
+
out = []
|
|
97
|
+
for path in sorted(PKG.rglob("*")):
|
|
98
|
+
if not path.is_file():
|
|
99
|
+
continue
|
|
100
|
+
if _SKIP_DIRS & set(path.relative_to(PKG).parts) or path.suffix in _SKIP_SUFFIXES:
|
|
101
|
+
continue
|
|
102
|
+
out.append(path)
|
|
103
|
+
return out
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def metadata_text() -> str:
|
|
107
|
+
lines = ["Metadata-Version: 2.1", f"Name: {NAME}", f"Version: {version()}"]
|
|
108
|
+
for key, value in METADATA.items():
|
|
109
|
+
for item in (value if isinstance(value, list) else [value]):
|
|
110
|
+
lines.append(f"{key}: {item}")
|
|
111
|
+
lines += [f"Requires-Dist: {req}" for req in REQUIRES_DIST]
|
|
112
|
+
readme = ROOT / "README.md"
|
|
113
|
+
if readme.exists():
|
|
114
|
+
lines.append("Description-Content-Type: text/markdown")
|
|
115
|
+
return "\n".join(lines) + "\n\n" + readme.read_text(encoding="utf-8")
|
|
116
|
+
return "\n".join(lines) + "\n"
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _entry_points_text() -> str:
|
|
120
|
+
body = "".join(f"{name} = {target}\n" for name, target in CONSOLE_SCRIPTS.items())
|
|
121
|
+
return "[console_scripts]\n" + body
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _record_hash(data: bytes) -> str:
|
|
125
|
+
digest = base64.urlsafe_b64encode(hashlib.sha256(data).digest()).rstrip(b"=").decode("ascii")
|
|
126
|
+
return f"sha256={digest}"
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class _WheelWriter:
|
|
130
|
+
def __init__(self, path: pathlib.Path):
|
|
131
|
+
self._zip = zipfile.ZipFile(path, "w", compression=zipfile.ZIP_DEFLATED)
|
|
132
|
+
self._records: list[str] = []
|
|
133
|
+
self._date_time = _epoch_date_time()
|
|
134
|
+
|
|
135
|
+
def add(self, arcname: str, data: bytes) -> None:
|
|
136
|
+
info = zipfile.ZipInfo(arcname, date_time=self._date_time)
|
|
137
|
+
info.external_attr = 0o644 << 16
|
|
138
|
+
info.compress_type = zipfile.ZIP_DEFLATED
|
|
139
|
+
self._zip.writestr(info, data)
|
|
140
|
+
self._records.append(f"{arcname},{_record_hash(data)},{len(data)}")
|
|
141
|
+
|
|
142
|
+
def close(self, dist_info: str) -> None:
|
|
143
|
+
record = f"{dist_info}/RECORD"
|
|
144
|
+
body = "\n".join(self._records + [f"{record},,"]) + "\n"
|
|
145
|
+
info = zipfile.ZipInfo(record, date_time=self._date_time)
|
|
146
|
+
info.external_attr = 0o644 << 16
|
|
147
|
+
self._zip.writestr(info, body.encode("utf-8"))
|
|
148
|
+
self._zip.close()
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _write_wheel(directory: str, payload: dict[str, bytes]) -> str:
|
|
152
|
+
ver = version()
|
|
153
|
+
dist_info = f"{NAME}-{ver}.dist-info"
|
|
154
|
+
filename = f"{NAME}-{ver}-py3-none-any.whl"
|
|
155
|
+
writer = _WheelWriter(pathlib.Path(directory) / filename)
|
|
156
|
+
for arcname in sorted(payload):
|
|
157
|
+
writer.add(arcname, payload[arcname])
|
|
158
|
+
writer.add(f"{dist_info}/METADATA", metadata_text().encode("utf-8"))
|
|
159
|
+
writer.add(f"{dist_info}/WHEEL", (
|
|
160
|
+
"Wheel-Version: 1.0\nGenerator: lazaret_build\nRoot-Is-Purelib: true\nTag: py3-none-any\n"
|
|
161
|
+
).encode("utf-8"))
|
|
162
|
+
writer.add(f"{dist_info}/entry_points.txt", _entry_points_text().encode("utf-8"))
|
|
163
|
+
license_file = ROOT / "LICENSE"
|
|
164
|
+
if license_file.exists():
|
|
165
|
+
writer.add(f"{dist_info}/licenses/LICENSE", license_file.read_bytes())
|
|
166
|
+
writer.close(dist_info)
|
|
167
|
+
return filename
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
# --- PEP 517 hooks ---------------------------------------------------------------
|
|
171
|
+
|
|
172
|
+
def get_requires_for_build_wheel(config_settings=None):
|
|
173
|
+
return []
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def get_requires_for_build_sdist(config_settings=None):
|
|
177
|
+
return []
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def get_requires_for_build_editable(config_settings=None):
|
|
181
|
+
return []
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def build_wheel(wheel_directory, config_settings=None, metadata_directory=None):
|
|
185
|
+
payload = {path.relative_to(SRC).as_posix(): path.read_bytes() for path in _package_files()}
|
|
186
|
+
return _write_wheel(wheel_directory, payload)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def build_editable(wheel_directory, config_settings=None, metadata_directory=None):
|
|
190
|
+
"""PEP 660: a wheel whose only payload is a .pth file pointing at src/."""
|
|
191
|
+
pth = f"__editable__.{NAME}-{version()}.pth"
|
|
192
|
+
return _write_wheel(wheel_directory, {pth: (str(SRC) + "\n").encode("utf-8")})
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def build_sdist(sdist_directory, config_settings=None):
|
|
196
|
+
ver = version()
|
|
197
|
+
base = f"{NAME}-{ver}"
|
|
198
|
+
filename = f"{base}.tar.gz"
|
|
199
|
+
mtime = int(os.environ.get("SOURCE_DATE_EPOCH", "315532800"))
|
|
200
|
+
|
|
201
|
+
members: list[tuple[str, bytes]] = []
|
|
202
|
+
for name in SDIST_TOP_FILES:
|
|
203
|
+
path = ROOT / name
|
|
204
|
+
if path.exists():
|
|
205
|
+
members.append((name, path.read_bytes()))
|
|
206
|
+
members.append(("_build/lazaret_build.py", pathlib.Path(__file__).read_bytes()))
|
|
207
|
+
for path in _package_files():
|
|
208
|
+
members.append((path.relative_to(ROOT).as_posix(), path.read_bytes()))
|
|
209
|
+
members.append(("PKG-INFO", metadata_text().encode("utf-8")))
|
|
210
|
+
|
|
211
|
+
# gzip header carries a timestamp too; pin it for reproducible output
|
|
212
|
+
raw = io.BytesIO()
|
|
213
|
+
import gzip
|
|
214
|
+
with gzip.GzipFile(fileobj=raw, mode="wb", mtime=mtime) as gz:
|
|
215
|
+
with tarfile.open(fileobj=gz, mode="w", format=tarfile.PAX_FORMAT) as tar:
|
|
216
|
+
for arcname, data in sorted(members):
|
|
217
|
+
info = tarfile.TarInfo(f"{base}/{arcname}")
|
|
218
|
+
info.size = len(data)
|
|
219
|
+
info.mtime = mtime
|
|
220
|
+
info.mode = 0o644
|
|
221
|
+
info.uid = info.gid = 0
|
|
222
|
+
info.uname = info.gname = ""
|
|
223
|
+
tar.addfile(info, io.BytesIO(data))
|
|
224
|
+
(pathlib.Path(sdist_directory) / filename).write_bytes(raw.getvalue())
|
|
225
|
+
return filename
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def main(argv=None) -> int:
|
|
229
|
+
argv = sys.argv[1:] if argv is None else argv
|
|
230
|
+
out = pathlib.Path(argv[0] if argv else ROOT / "dist")
|
|
231
|
+
out.mkdir(parents=True, exist_ok=True)
|
|
232
|
+
for build in (build_sdist, build_wheel):
|
|
233
|
+
print(out / build(str(out)))
|
|
234
|
+
return 0
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
if __name__ == "__main__":
|
|
238
|
+
sys.exit(main())
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Lazaret builds with its own standard-library backend (_build/lazaret_build.py):
|
|
2
|
+
# no build requirements, nothing downloaded. Package metadata and console
|
|
3
|
+
# scripts are defined in that module; the version is __version__ in
|
|
4
|
+
# src/lazaret/__init__.py. Lazaret has no runtime dependencies.
|
|
5
|
+
|
|
6
|
+
[build-system]
|
|
7
|
+
requires = []
|
|
8
|
+
build-backend = "lazaret_build"
|
|
9
|
+
backend-path = ["_build"]
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""Lazaret: static security, supply-chain and quality analysis for Python,
|
|
2
|
+
JavaScript and SQL. Standard library only.
|
|
3
|
+
|
|
4
|
+
lazaret.scanner rule engine, taint analysis, CLI (`lazaret`)
|
|
5
|
+
lazaret.registry npm / PyPI package auditing (`lazaret-registry`)
|
|
6
|
+
lazaret.mcp MCP server (`lazaret-mcp`)
|
|
7
|
+
lazaret.pg PostgreSQL client (provisional API until 1.0)
|
|
8
|
+
lazaret.safexml safe XML parsing (provisional API until 1.0)
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
__version__ = "0.0.1"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""MCP server exposing the Lazaret scanner as tools (stdio transport)."""
|