mayhem-cli 0.5.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.
Files changed (191) hide show
  1. mayhem_cli-0.5.1/.github/workflows/release.yml +58 -0
  2. mayhem_cli-0.5.1/.gitignore +17 -0
  3. mayhem_cli-0.5.1/Justfile +204 -0
  4. mayhem_cli-0.5.1/PKG-INFO +555 -0
  5. mayhem_cli-0.5.1/README.md +541 -0
  6. mayhem_cli-0.5.1/docs/compensation.md +119 -0
  7. mayhem_cli-0.5.1/docs/drill-spec.md +574 -0
  8. mayhem_cli-0.5.1/examples/k8s/README.md +32 -0
  9. mayhem_cli-0.5.1/examples/k8s/kubernetes.yaml +74 -0
  10. mayhem_cli-0.5.1/examples/k8s/mayhem.yaml +76 -0
  11. mayhem_cli-0.5.1/examples/testCase/data/hello.txt +1 -0
  12. mayhem_cli-0.5.1/examples/testCase/data/index.html +9 -0
  13. mayhem_cli-0.5.1/examples/testCase/docker-compose.mayhem.yml +145 -0
  14. mayhem_cli-0.5.1/examples/testCase/docker-compose.yml +99 -0
  15. mayhem_cli-0.5.1/examples/testCase/mayhem.yaml +210 -0
  16. mayhem_cli-0.5.1/examples/testCase/nginx.conf +31 -0
  17. mayhem_cli-0.5.1/pyproject.toml +157 -0
  18. mayhem_cli-0.5.1/src/mayhem/agent/__init__.py +1 -0
  19. mayhem_cli-0.5.1/src/mayhem/agent/cli.py +36 -0
  20. mayhem_cli-0.5.1/src/mayhem/agents/__init__.py +1 -0
  21. mayhem_cli-0.5.1/src/mayhem/agents/capabilities.py +106 -0
  22. mayhem_cli-0.5.1/src/mayhem/agents/executors.py +430 -0
  23. mayhem_cli-0.5.1/src/mayhem/agents/impact.py +729 -0
  24. mayhem_cli-0.5.1/src/mayhem/agents/lease_client.py +141 -0
  25. mayhem_cli-0.5.1/src/mayhem/agents/probes.py +284 -0
  26. mayhem_cli-0.5.1/src/mayhem/agents/protocol.py +134 -0
  27. mayhem_cli-0.5.1/src/mayhem/agents/server.py +281 -0
  28. mayhem_cli-0.5.1/src/mayhem/agents/sinks.py +60 -0
  29. mayhem_cli-0.5.1/src/mayhem/agents/transports.py +134 -0
  30. mayhem_cli-0.5.1/src/mayhem/agents/watchdog.py +140 -0
  31. mayhem_cli-0.5.1/src/mayhem/cli/__init__.py +11 -0
  32. mayhem_cli-0.5.1/src/mayhem/cli/app.py +154 -0
  33. mayhem_cli-0.5.1/src/mayhem/cli/campaign.py +496 -0
  34. mayhem_cli-0.5.1/src/mayhem/cli/config_cmd.py +47 -0
  35. mayhem_cli-0.5.1/src/mayhem/cli/context.py +23 -0
  36. mayhem_cli-0.5.1/src/mayhem/cli/dependency.py +429 -0
  37. mayhem_cli-0.5.1/src/mayhem/cli/exit_codes.py +24 -0
  38. mayhem_cli-0.5.1/src/mayhem/cli/experiment.py +24 -0
  39. mayhem_cli-0.5.1/src/mayhem/cli/lifecycle.py +805 -0
  40. mayhem_cli-0.5.1/src/mayhem/cli/resolver.py +72 -0
  41. mayhem_cli-0.5.1/src/mayhem/cli/services.py +459 -0
  42. mayhem_cli-0.5.1/src/mayhem/cli/style.py +101 -0
  43. mayhem_cli-0.5.1/src/mayhem/cli/toolkit.py +41 -0
  44. mayhem_cli-0.5.1/src/mayhem/cli/topology.py +127 -0
  45. mayhem_cli-0.5.1/src/mayhem/config.py +208 -0
  46. mayhem_cli-0.5.1/src/mayhem/controller/__init__.py +1 -0
  47. mayhem_cli-0.5.1/src/mayhem/controller/compensation.py +2156 -0
  48. mayhem_cli-0.5.1/src/mayhem/controller/executor.py +1719 -0
  49. mayhem_cli-0.5.1/src/mayhem/controller/janitor.py +196 -0
  50. mayhem_cli-0.5.1/src/mayhem/controller/observability_collector.py +382 -0
  51. mayhem_cli-0.5.1/src/mayhem/controller/observations.py +102 -0
  52. mayhem_cli-0.5.1/src/mayhem/controller/planner.py +715 -0
  53. mayhem_cli-0.5.1/src/mayhem/controller/recovery.py +245 -0
  54. mayhem_cli-0.5.1/src/mayhem/controller/resilience_report.py +585 -0
  55. mayhem_cli-0.5.1/src/mayhem/controller/resource_manager.py +457 -0
  56. mayhem_cli-0.5.1/src/mayhem/controller/safety.py +392 -0
  57. mayhem_cli-0.5.1/src/mayhem/domain/__init__.py +6 -0
  58. mayhem_cli-0.5.1/src/mayhem/domain/campaigns.py +118 -0
  59. mayhem_cli-0.5.1/src/mayhem/domain/cancellation.py +110 -0
  60. mayhem_cli-0.5.1/src/mayhem/domain/candidates.py +101 -0
  61. mayhem_cli-0.5.1/src/mayhem/domain/capabilities.py +86 -0
  62. mayhem_cli-0.5.1/src/mayhem/domain/catalog.py +727 -0
  63. mayhem_cli-0.5.1/src/mayhem/domain/checks.py +173 -0
  64. mayhem_cli-0.5.1/src/mayhem/domain/common.py +104 -0
  65. mayhem_cli-0.5.1/src/mayhem/domain/coverage.py +106 -0
  66. mayhem_cli-0.5.1/src/mayhem/domain/decisions.py +57 -0
  67. mayhem_cli-0.5.1/src/mayhem/domain/errors.py +87 -0
  68. mayhem_cli-0.5.1/src/mayhem/domain/events.py +61 -0
  69. mayhem_cli-0.5.1/src/mayhem/domain/execution_context.py +120 -0
  70. mayhem_cli-0.5.1/src/mayhem/domain/execution_loci.py +94 -0
  71. mayhem_cli-0.5.1/src/mayhem/domain/experiments.py +370 -0
  72. mayhem_cli-0.5.1/src/mayhem/domain/faults.py +239 -0
  73. mayhem_cli-0.5.1/src/mayhem/domain/identity.py +200 -0
  74. mayhem_cli-0.5.1/src/mayhem/domain/k8s_adapter.py +132 -0
  75. mayhem_cli-0.5.1/src/mayhem/domain/leases.py +186 -0
  76. mayhem_cli-0.5.1/src/mayhem/domain/load_strategy.py +98 -0
  77. mayhem_cli-0.5.1/src/mayhem/domain/m5_campaign.py +120 -0
  78. mayhem_cli-0.5.1/src/mayhem/domain/maniac.py +93 -0
  79. mayhem_cli-0.5.1/src/mayhem/domain/observability.py +146 -0
  80. mayhem_cli-0.5.1/src/mayhem/domain/outcomes.py +92 -0
  81. mayhem_cli-0.5.1/src/mayhem/domain/remote_agent_interface.py +70 -0
  82. mayhem_cli-0.5.1/src/mayhem/domain/resources.py +245 -0
  83. mayhem_cli-0.5.1/src/mayhem/domain/risks.py +61 -0
  84. mayhem_cli-0.5.1/src/mayhem/domain/run_outcome.py +146 -0
  85. mayhem_cli-0.5.1/src/mayhem/domain/runtime_adapter.py +256 -0
  86. mayhem_cli-0.5.1/src/mayhem/domain/success.py +329 -0
  87. mayhem_cli-0.5.1/src/mayhem/domain/topology.py +452 -0
  88. mayhem_cli-0.5.1/src/mayhem/infra/__init__.py +1 -0
  89. mayhem_cli-0.5.1/src/mayhem/infra/campaign_engine.py +205 -0
  90. mayhem_cli-0.5.1/src/mayhem/infra/candidate_gates.py +124 -0
  91. mayhem_cli-0.5.1/src/mayhem/infra/candidate_generator.py +110 -0
  92. mayhem_cli-0.5.1/src/mayhem/infra/coverage_repository.py +101 -0
  93. mayhem_cli-0.5.1/src/mayhem/infra/lease_repository.py +129 -0
  94. mayhem_cli-0.5.1/src/mayhem/infra/maniac.py +103 -0
  95. mayhem_cli-0.5.1/src/mayhem/infra/migrations.py +596 -0
  96. mayhem_cli-0.5.1/src/mayhem/infra/migrator.py +149 -0
  97. mayhem_cli-0.5.1/src/mayhem/infra/report.py +227 -0
  98. mayhem_cli-0.5.1/src/mayhem/infra/store.py +200 -0
  99. mayhem_cli-0.5.1/src/mayhem/py.typed +0 -0
  100. mayhem_cli-0.5.1/src/mayhem/spec.py +52 -0
  101. mayhem_cli-0.5.1/src/mayhem/toolkit/__init__.py +1 -0
  102. mayhem_cli-0.5.1/src/mayhem/toolkit/fingerprint.py +69 -0
  103. mayhem_cli-0.5.1/src/mayhem/toolkit/hashing.py +32 -0
  104. mayhem_cli-0.5.1/src/mayhem/toolkit/manifests/docker.yaml +11 -0
  105. mayhem_cli-0.5.1/src/mayhem/toolkit/manifests/podman.yaml +11 -0
  106. mayhem_cli-0.5.1/src/mayhem/toolkit/manifests/stress-ng.yaml +11 -0
  107. mayhem_cli-0.5.1/src/mayhem/toolkit/manifests/tc-netem.yaml +11 -0
  108. mayhem_cli-0.5.1/src/mayhem/toolkit/manifests/toxiproxy.yaml +10 -0
  109. mayhem_cli-0.5.1/src/mayhem/toolkit/registry.py +185 -0
  110. mayhem_cli-0.5.1/src/mayhem/toolkit/tool_runner.py +129 -0
  111. mayhem_cli-0.5.1/src/mayhem/topology/__init__.py +10 -0
  112. mayhem_cli-0.5.1/src/mayhem/topology/providers/__init__.py +0 -0
  113. mayhem_cli-0.5.1/src/mayhem/topology/providers/adapter_registry.py +60 -0
  114. mayhem_cli-0.5.1/src/mayhem/topology/providers/base.py +31 -0
  115. mayhem_cli-0.5.1/src/mayhem/topology/providers/compose.py +207 -0
  116. mayhem_cli-0.5.1/src/mayhem/topology/providers/docker_adapter.py +277 -0
  117. mayhem_cli-0.5.1/src/mayhem/topology/providers/docker_runtime.py +461 -0
  118. mayhem_cli-0.5.1/src/mayhem/topology/providers/podman_adapter.py +328 -0
  119. mayhem_cli-0.5.1/src/mayhem/topology/resolve.py +196 -0
  120. mayhem_cli-0.5.1/src/mayhem/topology/service.py +158 -0
  121. mayhem_cli-0.5.1/tests/conftest.py +66 -0
  122. mayhem_cli-0.5.1/tests/e2e/__init__.py +0 -0
  123. mayhem_cli-0.5.1/tests/e2e/test_cli_e2e.py +1162 -0
  124. mayhem_cli-0.5.1/tests/integration/test_agent_serve.py +89 -0
  125. mayhem_cli-0.5.1/tests/integration/test_agent_watchdog_e2e.py +100 -0
  126. mayhem_cli-0.5.1/tests/integration/test_m5_e2e.py +205 -0
  127. mayhem_cli-0.5.1/tests/integration/test_store.py +142 -0
  128. mayhem_cli-0.5.1/tests/unit/test_agent_capabilities.py +140 -0
  129. mayhem_cli-0.5.1/tests/unit/test_agent_protocol.py +157 -0
  130. mayhem_cli-0.5.1/tests/unit/test_agents.py +447 -0
  131. mayhem_cli-0.5.1/tests/unit/test_campaign_run.py +232 -0
  132. mayhem_cli-0.5.1/tests/unit/test_campaigns.py +480 -0
  133. mayhem_cli-0.5.1/tests/unit/test_cancellation.py +170 -0
  134. mayhem_cli-0.5.1/tests/unit/test_candidates.py +235 -0
  135. mayhem_cli-0.5.1/tests/unit/test_capability_matrix.py +97 -0
  136. mayhem_cli-0.5.1/tests/unit/test_capability_registry.py +154 -0
  137. mayhem_cli-0.5.1/tests/unit/test_capability_safety.py +231 -0
  138. mayhem_cli-0.5.1/tests/unit/test_check_spec.py +162 -0
  139. mayhem_cli-0.5.1/tests/unit/test_cli.py +627 -0
  140. mayhem_cli-0.5.1/tests/unit/test_cli_campaign.py +219 -0
  141. mayhem_cli-0.5.1/tests/unit/test_cli_exit_codes.py +124 -0
  142. mayhem_cli-0.5.1/tests/unit/test_cli_resolver.py +43 -0
  143. mayhem_cli-0.5.1/tests/unit/test_compensation.py +584 -0
  144. mayhem_cli-0.5.1/tests/unit/test_config.py +109 -0
  145. mayhem_cli-0.5.1/tests/unit/test_container_fault_matrix.py +217 -0
  146. mayhem_cli-0.5.1/tests/unit/test_coverage.py +156 -0
  147. mayhem_cli-0.5.1/tests/unit/test_domain_properties.py +243 -0
  148. mayhem_cli-0.5.1/tests/unit/test_drill_spec.py +459 -0
  149. mayhem_cli-0.5.1/tests/unit/test_example_specs_yaml.py +221 -0
  150. mayhem_cli-0.5.1/tests/unit/test_execution_context.py +107 -0
  151. mayhem_cli-0.5.1/tests/unit/test_executor.py +704 -0
  152. mayhem_cli-0.5.1/tests/unit/test_executor_drill.py +352 -0
  153. mayhem_cli-0.5.1/tests/unit/test_fault_catalog_all.py +287 -0
  154. mayhem_cli-0.5.1/tests/unit/test_faults.py +112 -0
  155. mayhem_cli-0.5.1/tests/unit/test_fingerprint.py +47 -0
  156. mayhem_cli-0.5.1/tests/unit/test_fork_atomicity.py +105 -0
  157. mayhem_cli-0.5.1/tests/unit/test_impact_gate.py +645 -0
  158. mayhem_cli-0.5.1/tests/unit/test_janitor.py +195 -0
  159. mayhem_cli-0.5.1/tests/unit/test_lease_repository.py +85 -0
  160. mayhem_cli-0.5.1/tests/unit/test_leases.py +116 -0
  161. mayhem_cli-0.5.1/tests/unit/test_lifecycle_run_liveness.py +133 -0
  162. mayhem_cli-0.5.1/tests/unit/test_load_strategy.py +92 -0
  163. mayhem_cli-0.5.1/tests/unit/test_m12_step1_catalog.py +78 -0
  164. mayhem_cli-0.5.1/tests/unit/test_m7_k8s.py +531 -0
  165. mayhem_cli-0.5.1/tests/unit/test_m8_operations.py +146 -0
  166. mayhem_cli-0.5.1/tests/unit/test_m9_catalog.py +135 -0
  167. mayhem_cli-0.5.1/tests/unit/test_maniac.py +153 -0
  168. mayhem_cli-0.5.1/tests/unit/test_migrations.py +211 -0
  169. mayhem_cli-0.5.1/tests/unit/test_network_path_model.py +90 -0
  170. mayhem_cli-0.5.1/tests/unit/test_observability.py +458 -0
  171. mayhem_cli-0.5.1/tests/unit/test_observations.py +85 -0
  172. mayhem_cli-0.5.1/tests/unit/test_planner.py +782 -0
  173. mayhem_cli-0.5.1/tests/unit/test_recovery.py +153 -0
  174. mayhem_cli-0.5.1/tests/unit/test_report.py +146 -0
  175. mayhem_cli-0.5.1/tests/unit/test_resilience_report.py +359 -0
  176. mayhem_cli-0.5.1/tests/unit/test_resolve.py +262 -0
  177. mayhem_cli-0.5.1/tests/unit/test_resource_conflict_exec.py +114 -0
  178. mayhem_cli-0.5.1/tests/unit/test_resource_manager.py +331 -0
  179. mayhem_cli-0.5.1/tests/unit/test_resources.py +189 -0
  180. mayhem_cli-0.5.1/tests/unit/test_risks.py +43 -0
  181. mayhem_cli-0.5.1/tests/unit/test_run_outcome.py +351 -0
  182. mayhem_cli-0.5.1/tests/unit/test_runtime_adapter.py +181 -0
  183. mayhem_cli-0.5.1/tests/unit/test_safety.py +205 -0
  184. mayhem_cli-0.5.1/tests/unit/test_success.py +496 -0
  185. mayhem_cli-0.5.1/tests/unit/test_three_locus.py +88 -0
  186. mayhem_cli-0.5.1/tests/unit/test_tool_runner.py +82 -0
  187. mayhem_cli-0.5.1/tests/unit/test_topology.py +196 -0
  188. mayhem_cli-0.5.1/tests/unit/test_topology_ctr.py +113 -0
  189. mayhem_cli-0.5.1/tests/unit/test_topology_providers.py +709 -0
  190. mayhem_cli-0.5.1/tests/unit/test_watchdog.py +109 -0
  191. mayhem_cli-0.5.1/uv.lock +819 -0
@@ -0,0 +1,58 @@
1
+ name: Release to PyPI
2
+ on:
3
+ push:
4
+ tags:
5
+ # Both conventions fire the release: `v0.5.0` and the repo's
6
+ # existing numeric tags (`0.5.0`, `0.5.0dev`). hatch-vcs strips a
7
+ # leading `v`, so either produces a clean PEP 440 version.
8
+ - "v*"
9
+ - "[0-9]*"
10
+
11
+ permissions:
12
+ contents: read
13
+ id-token: write # trusted publishing (OIDC) — no PyPI token secret required
14
+
15
+ jobs:
16
+ test:
17
+ name: Test (unit + integration)
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - uses: actions/setup-python@v5
22
+ with:
23
+ python-version: "3.12"
24
+ - name: Install uv
25
+ run: python -m pip install --quiet uv
26
+ - name: Sync dev dependencies
27
+ run: uv sync --group dev
28
+ - name: Run tests
29
+ run: uv run pytest tests/unit tests/integration
30
+ # NOTE: `ruff check src/` is NOT gated here — the repository's committed
31
+ # ruff config currently reports 30-49 pre-existing violations under every
32
+ # ruff generation (0.8-0.16); the project has no lint-green baseline in
33
+ # its history. Land a lint-cleanup first, then re-add `ruff check src/`.
34
+ - name: Architectural contracts
35
+ run: uv run lint-imports
36
+
37
+ build-and-publish:
38
+ name: Build and publish to PyPI
39
+ needs: test
40
+ runs-on: ubuntu-latest
41
+ steps:
42
+ # Full history so hatch-vcs can resolve the invoking tag.
43
+ - uses: actions/checkout@v4
44
+ with:
45
+ fetch-depth: 0
46
+ - uses: actions/setup-python@v5
47
+ with:
48
+ python-version: "3.12"
49
+ - name: Build wheel + sdist
50
+ run: |
51
+ python -m pip install --upgrade build
52
+ python -m build
53
+ # Trusted Publishing: authenticates via OIDC against the Trusted
54
+ # Publisher configured on pypi.org for this repository (owner
55
+ # magichrist, repo Mayhem, workflow release.yml). Do NOT add a
56
+ # username/password here — the action would try token auth.
57
+ - name: Publish to PyPI
58
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,17 @@
1
+ # Byte-compiled / cache
2
+ __pycache__/
3
+ *.py[cod]
4
+
5
+ # Test / tooling caches
6
+ .pytest_cache/
7
+ .ruff_cache/
8
+ tests/unit/__pycache__
9
+
10
+ # Virtual environments
11
+ .venv/
12
+ venv/
13
+
14
+ # Local artifacts
15
+ *.db
16
+ *.sqlite
17
+ *.sqlite3
@@ -0,0 +1,204 @@
1
+ # ─────────────────────────────────────────────────────────────────────────────
2
+ # Mayhem justfile — test every capability against examples/testCase
3
+ # ─────────────────────────────────────────────────────────────────────────────
4
+ # Usage: just --list (show all recipes)
5
+ # just e2e (full automated run)
6
+ # just smoke (quick sanity check)
7
+
8
+ set shell := ["bash", "-euo", "pipefail", "-c"]
9
+
10
+ _testcase := "examples/testCase"
11
+ _compose := _testcase / "docker-compose.yml"
12
+ _config := _testcase / "mayhem.yml"
13
+ _spec := _testcase / "mayhem.yaml"
14
+ _db := ".mayhem/e2e.db"
15
+
16
+ # ── setup ────────────────────────────────────────────────────────────────────
17
+
18
+ [private]
19
+ setup:
20
+ rm -f {{ _db }}
21
+ mkdir -p .mayhem
22
+ @echo "✓ setup"
23
+
24
+ # ── topology ─────────────────────────────────────────────────────────────────
25
+
26
+ # Discover topology from compose + live runtime (containers, processes, services)
27
+ topology:
28
+ @echo "=== topology discover ==="
29
+ mayhem topology discover --compose {{ _compose }} | python3 -m json.tool > /dev/null
30
+ @echo "✓ topology discover"
31
+
32
+ # Topology with prefix shorthand
33
+ topology-prefix:
34
+ @echo "=== topology prefix ==="
35
+ mayhem top d --compose {{ _compose }} | python3 -m json.tool > /dev/null
36
+ @echo "✓ topology prefix"
37
+
38
+ # ── toolkit ──────────────────────────────────────────────────────────────────
39
+
40
+ # List available faults and capabilities
41
+ toolkit:
42
+ @echo "=== toolkit ==="
43
+ mayhem toolkit faults
44
+ mayhem toolkit list --json | python3 -m json.tool > /dev/null
45
+ @echo "✓ toolkit"
46
+
47
+ # ── config ───────────────────────────────────────────────────────────────────
48
+
49
+ # Show and validate effective config (default + testCase)
50
+ config:
51
+ @echo "=== config ==="
52
+ mayhem config show --json | python3 -m json.tool > /dev/null
53
+ mayhem --config {{ _config }} config show --json | python3 -m json.tool > /dev/null
54
+ mayhem config validate
55
+ mayhem --config {{ _config }} config validate
56
+ @echo "✓ config"
57
+
58
+ # ── experiment ───────────────────────────────────────────────────────────────
59
+
60
+ # Show and validate experiment spec
61
+ # Validate the drill spec through the experiment group alias
62
+ experiment:
63
+ @echo "=== experiment ==="
64
+ mayhem experiment validate {{ _spec }} --compose {{ _compose }}
65
+ @echo "✓ experiment"
66
+
67
+ # ── lifecycle: validate → plan → run → status → history → recover ────────────
68
+
69
+ # Validate spec against live topology
70
+ validate: setup
71
+ @echo "=== validate ==="
72
+ mayhem --db {{ _db }} validate {{ _spec }} --compose {{ _compose }}
73
+ @echo "✓ validate"
74
+
75
+ # Validate with explicit process topology (no compose auto-detect)
76
+ validate-process:
77
+ @echo "=== validate --process ==="
78
+ mayhem validate {{ _spec }} \
79
+ --process "download-1=10001" --process "download-2=10002"
80
+ @echo "✓ validate --process"
81
+
82
+ # Plan the experiment
83
+ plan:
84
+ @echo "=== plan ==="
85
+ mayhem plan {{ _spec }} --compose {{ _compose }}
86
+ @echo "✓ plan"
87
+
88
+ # Full run: inject faults, record events, compensate
89
+ run: setup
90
+ @echo "=== run ==="
91
+ mayhem --db {{ _db }} run {{ _spec }} --compose {{ _compose }}
92
+ @echo "✓ run"
93
+
94
+ # Show run status (JSON + text)
95
+ status: setup
96
+ @echo "=== status ==="
97
+ mayhem --db {{ _db }} status
98
+ @echo "✓ status"
99
+
100
+ # Show detailed run history (JSON + text)
101
+ history:
102
+ @echo "=== history ==="
103
+ @run_id=$$(sqlite3 {{ _db }} "SELECT id FROM runs ORDER BY rowid DESC LIMIT 1" 2>/dev/null || echo ""); \
104
+ if [ -z "$$run_id" ]; then \
105
+ echo "⚠ no runs in DB — skipping history"; \
106
+ else \
107
+ mayhem --db {{ _db }} history "$$run_id"; \
108
+ echo "✓ history"; \
109
+ fi
110
+
111
+ # Recovery sweep (orphaned fault leases)
112
+ recover: setup
113
+ @echo "=== recover ==="
114
+ mayhem --db {{ _db }} recover
115
+ @echo "✓ recover"
116
+
117
+ # Janitor sweep (stale runs / resources)
118
+ janitor: setup
119
+ @echo "=== janitor ==="
120
+ mayhem --db {{ _db }} janitor sweep
121
+ @echo "✓ janitor"
122
+
123
+ # ── campaign CRUD ────────────────────────────────────────────────────────────
124
+
125
+ # Create, list, show, start, abort, delete a campaign
126
+ campaign: setup
127
+ @echo "=== campaign ==="
128
+ mayhem --db {{ _db }} campaign create --name "e2e-campaign" --hypothesis "stack survives chaos"
129
+ mayhem --db {{ _db }} campaign list
130
+ @cid=$$(sqlite3 {{ _db }} "SELECT id FROM campaigns ORDER BY rowid DESC LIMIT 1"); \
131
+ mayhem --db {{ _db }} campaign show "$$cid"; \
132
+ mayhem --db {{ _db }} campaign status "$$cid"; \
133
+ mayhem --db {{ _db }} campaign start "$$cid" || true; \
134
+ mayhem --db {{ _db }} campaign abort "$$cid" || true; \
135
+ mayhem --db {{ _db }} campaign delete "$$cid"
136
+ @echo "✓ campaign"
137
+
138
+ # ── full round-trip ─────────────────────────────────────────────────────────
139
+
140
+ # Full lifecycle: validate → plan → run → status → history → recover
141
+ full: setup
142
+ @echo "=== full round-trip ==="
143
+ mayhem --db {{ _db }} validate {{ _spec }} --compose {{ _compose }}
144
+ mayhem --db {{ _db }} plan {{ _spec }} --compose {{ _compose }}
145
+ mayhem --db {{ _db }} run {{ _spec }} --compose {{ _compose }}
146
+ mayhem --db {{ _db }} status
147
+ @run_id=$$(sqlite3 {{ _db }} "SELECT id FROM runs ORDER BY rowid DESC LIMIT 1"); \
148
+ mayhem --db {{ _db }} history "$$run_id"
149
+ mayhem --db {{ _db }} recover
150
+ @echo "✓ full round-trip"
151
+
152
+ # ── stack management ─────────────────────────────────────────────────────────
153
+
154
+ # Start the testCase compose stack
155
+ stack-up:
156
+ @echo "=== stack up ==="
157
+ cd {{ _testcase }} && podman compose up -d 2>/dev/null || docker compose up -d
158
+ @sleep 3
159
+ @echo "✓ stack up"
160
+
161
+ # Stop the testCase compose stack
162
+ stack-down:
163
+ @echo "=== stack down ==="
164
+ cd {{ _testcase }} && podman compose down -v 2>/dev/null || docker compose down -v
165
+ @echo "✓ stack down"
166
+
167
+ # ── tests ────────────────────────────────────────────────────────────────────
168
+
169
+ # Run unit tests
170
+ test-unit:
171
+ @echo "=== unit tests ==="
172
+ python3 -m pytest tests/unit/ -v --tb=short
173
+ @echo "✓ unit tests"
174
+
175
+ # Run e2e tests (in-process, no containers needed)
176
+ test-e2e:
177
+ @echo "=== e2e tests ==="
178
+ python3 -m pytest tests/e2e/ -v --tb=short
179
+ @echo "✓ e2e tests"
180
+
181
+ # Run all tests
182
+ test:
183
+ @echo "=== all tests ==="
184
+ python3 -m pytest tests/ -v --tb=short
185
+ @echo "✓ all tests"
186
+
187
+ # Run linter
188
+ lint:
189
+ @echo "=== lint ==="
190
+ ruff check src/ tests/
191
+ @echo "✓ lint"
192
+
193
+ # ── aggregate targets ────────────────────────────────────────────────────────
194
+
195
+ # Quick smoke: topology + toolkit + config + experiment + validate + plan
196
+ smoke: topology toolkit config experiment validate plan
197
+ @echo "✓ smoke"
198
+
199
+ # Full automated run: stack → topology → config → experiment → full lifecycle → campaign → tests
200
+ e2e: stack-up topology toolkit config experiment full campaign test
201
+ @echo ""
202
+ @echo "╔══════════════════════════════════════════════╗"
203
+ @echo "║ ALL E2E RECIPES PASSED ║"
204
+ @echo "╚══════════════════════════════════════════════╝"