-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathpyproject.toml
More file actions
217 lines (194 loc) · 8.31 KB
/
Copy pathpyproject.toml
File metadata and controls
217 lines (194 loc) · 8.31 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
204
205
206
207
208
209
210
211
212
213
214
215
216
217
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "aptl-labs"
version = "6.0.0"
description = "Advanced Purple Team Lab CLI"
readme = "README.md"
requires-python = ">=3.11"
license = { text = "MIT" }
authors = [{ name = "Brad Edwards" }]
keywords = ["purple-team", "security", "cyber-range", "wazuh", "kali", "mcp", "raes"]
classifiers = [
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Security",
"Intended Audience :: Developers",
]
# Version is managed by release-please, which rewrites this string on release.
dependencies = [
"typer>=0.12.0",
"pydantic>=2.0.0",
"rich>=13.0.0",
"PyYAML>=6.0",
"icontract>=2.6.0,<3.0",
"opentelemetry-api>=1.33.0",
"opentelemetry-sdk>=1.33.0",
"opentelemetry-exporter-otlp-proto-http>=1.33.0",
"opentelemetry-semantic-conventions>=0.54b0",
"cryptography>=50.0.0",
"raes==5.0.0",
"raes-env-packs==6.1.0",
"mcp>=2,<3",
"rfc8785>=0.1.4,<0.2.0",
"packaging>=24.2",
# Imported directly by aptl.core.experiment.resolver; previously satisfied
# only transitively through the upstream SDL distribution.
"blake3>=1.0.8,<2",
]
[project.urls]
Homepage = "https://github.com/Brad-Edwards/aptl"
Repository = "https://github.com/Brad-Edwards/aptl"
Issues = "https://github.com/Brad-Edwards/aptl/issues"
[project.scripts]
aptl = "aptl.cli.main:app"
aptl-misp-suricata-sync = "aptl.services.misp_suricata_sync.main:main"
[project.optional-dependencies]
s3 = [
"boto3>=1.28.0",
]
# Optional Parquet projection for the EXP-008 evidence bundle (in-process,
# loss-accounted). Kept out of the runtime install: without it, the bundle
# records a `projection-unavailable` limitation instead of failing.
parquet = [
"pyarrow>=17.0.0",
]
web = [
"httpx>=0.28.1",
"fastapi>=0.115.0",
"uvicorn[standard]>=0.34.0",
"sse-starlette>=2.0.0",
"asyncssh>=2.17.0",
]
dev = [
"pytest>=8.0.0",
"pytest-mock>=3.12.0",
"pytest-xdist>=3.6.0",
"coverage>=7.0.0",
"httpx>=0.27.0",
"hypothesis>=6.0.0",
"ruff>=0.15.0",
# EXP-008 Parquet-projection tests exercise pyarrow in-process; CI installs
# requirements/dev.txt, so the projection's mapping/schema-evolution tests
# run there rather than silently skipping.
"pyarrow>=17.0.0",
]
docs = [
"mkdocs-material>=9.5.0",
"mkdocs-git-revision-date-localized-plugin>=1.2.0",
]
# CI-only tooling. These are not part of any install a user performs, so they are
# a dependency group rather than an optional-dependency extra. They live here so
# `uv.lock` stays the single source of truth for every Python artifact CI
# installs — which is what lets `requirements/ci.txt` be generated with hashes
# instead of CI running an unpinned `pip install pre-commit` (issue #847).
[dependency-groups]
ci = [
"pre-commit>=4.0.0",
"pip-audit>=2.7.0",
"build>=1.2.0",
"cyclonedx-bom>=6.0.0",
]
# The PEP 517 build backend, locked like everything else. `--require-hashes`
# only covers what pip *resolves*; a source install (`pip install -e .`) or
# `python -m build` otherwise spins up an isolated build environment and fetches
# `[build-system].requires` from PyPI with no hash checking at all — an unpinned
# hole straight through the middle of the hashed-install contract. Exporting
# this group into every requirements file lets those commands run with
# `--no-build-isolation` / `--no-isolation` against a hash-verified backend.
build = [
"hatchling>=1.27.0",
# Ubuntu cloud images provide Python without pip or ensurepip. The signed
# offline payload uses this locked wheel as its bootstrap installer.
"pip>=26.2.1",
# hatchling imports `editables` to build an editable wheel. Under build
# isolation it would fetch this itself; with isolation off it has to be
# present (and hashed) up front, or every `pip install -e .` fails at
# metadata generation.
"editables>=0.5",
]
# Per-scenario runtime, startup and verification adapters. The generic
# materializer under `src/aptl` does not branch on scenario identities. Native
# evidence declarations and behavior live in the selected adapter package;
# core owns only the generic request-scoped contracts and execution machinery.
[project.entry-points."aptl.pack_backend_interactions"]
"techvault.aptl" = "aptl_techvault.serving:provider"
[project.entry-points."aptl.scenario_capture"]
"techvault.aptl" = "aptl_techvault.capture:provider"
[project.entry-points."aptl.scenario_planning_compatibility"]
"techvault.aptl" = "aptl_techvault.planning_compatibility:provider"
[project.entry-points."aptl.scenario_runtime_parameters"]
"techvault" = "aptl_techvault.runtime_parameters:provider"
[project.entry-points."aptl.scenario_startup"]
"techvault" = "aptl_techvault.startup:provider"
[project.entry-points."aptl.scenario_verifiers"]
"techvault.aptl" = "aptl_techvault.verification:verifier"
[project.entry-points."aptl.participant_mcp_smoke_plans"]
"techvault-full.techvault" = "aptl_techvault.participant_smoke:FULL_TECHVAULT_SMOKE_OPERATIONS"
"guided-purple.techvault-attacker-target" = "aptl_techvault.participant_smoke:PARTICIPANT_SMOKE_OPERATIONS"
[tool.hatch.build.targets.wheel]
packages = ["src/aptl", "src/aptl_techvault"]
# Bundle the git-tracked lab-asset tree (docker-compose.yml, config/,
# containers/, web/, scripts/, and the source that container images
# build from) into the wheel under aptl/_labdata/ so `pipx install aptl-labs`
# + `aptl lab init` runs a lab without a git clone (issue #659 / DEP-008).
# The hook ships only git-tracked files, which keeps generated secrets and
# local state out of the distribution. See hatch_build.py.
[tool.hatch.build.targets.wheel.hooks.custom]
path = "hatch_build.py"
[tool.ruff]
# Lint only the Python control-plane source. Tests, generated files, and
# the (TypeScript) MCP / web trees are out of scope for this check.
src = ["src"]
[tool.ruff.lint]
# Intentionally narrow: this is a *complexity* gate, not a style linter —
# `C901` (McCabe cyclomatic complexity) is the only rule enabled, so the
# check fails a god-method without churning the codebase on style. Widen
# the rule set deliberately if/when the team wants more from ruff.
select = ["C901"]
[tool.ruff.lint.mccabe]
# A function over this many independent paths is the "god method" this
# gate exists to stop. Matches SonarCloud's default cognitive-complexity
# threshold (15); ratchet down over time as the backlog shrinks.
max-complexity = 15
# [tool.ruff.lint.per-file-ignores] intentionally absent: the complexity
# backlog is empty. Every function under `src/` is now gated at
# max-complexity 15 with no carve-outs (issue #286). If a future change must
# temporarily exempt a file, add the table back and record the offender in
# ADR-010's backlog with its measured score.
[tool.pytest.ini_options]
testpaths = ["tests"]
pythonpath = ["src"]
markers = [
"fuzz: property-based fuzz tests (run with: pytest -m fuzz)",
"integration: tests that spawn subprocesses or read/write the filesystem; runnable by default but selectable via `pytest -m integration` or `pytest -m 'not integration'`",
]
addopts = "-m 'not fuzz'"
[tool.coverage.run]
# Both top-level packages the wheel ships. `aptl_techvault` is a scenario
# adapter reached only through entry points, but it is production code in this
# distribution: leaving it out of the source set reported its every line as
# uncovered while its tests were in fact exercising it.
source = ["aptl", "aptl_techvault"]
[tool.coverage.report]
show_missing = true
# Non-POSIX branches (file modes are advisory off POSIX) cannot be exercised
# on the Linux CI runner, and ``if TYPE_CHECKING:`` blocks never run at all.
# Excluding these guard clauses here keeps such paths out of coverage without
# inline trailing ``# pragma: no cover`` comments (SonarCloud S139).
# ``exclude_also`` extends — not replaces — coverage's defaults, so
# ``# pragma: no cover`` still works.
exclude_also = [
"if os.name != \"posix\":",
"if os.name == \"nt\":",
"except metadata.PackageNotFoundError:",
"if TYPE_CHECKING:",
# Low-level Windows handle bindings are exercised by Windows CI only;
# Linux CI covers the platform-neutral orchestration around them.
"def _windows_",
]
[tool.coverage.xml]
output = "coverage.xml"