autoops-sre 0.1.3__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.
- autoops_sre-0.1.3/.gitignore +38 -0
- autoops_sre-0.1.3/LICENSE +21 -0
- autoops_sre-0.1.3/PKG-INFO +199 -0
- autoops_sre-0.1.3/README.md +169 -0
- autoops_sre-0.1.3/pyproject.toml +221 -0
- autoops_sre-0.1.3/src/autoops/__init__.py +35 -0
- autoops_sre-0.1.3/src/autoops/actions/__init__.py +7 -0
- autoops_sre-0.1.3/src/autoops/actions/scale.py +140 -0
- autoops_sre-0.1.3/src/autoops/adapters/__init__.py +1 -0
- autoops_sre-0.1.3/src/autoops/adapters/aiopslab.py +287 -0
- autoops_sre-0.1.3/src/autoops/adapters/anthropic_client.py +82 -0
- autoops_sre-0.1.3/src/autoops/adapters/llm.py +110 -0
- autoops_sre-0.1.3/src/autoops/adapters/openrouter_client.py +139 -0
- autoops_sre-0.1.3/src/autoops/autoctl.py +453 -0
- autoops_sre-0.1.3/src/autoops/cli.py +2728 -0
- autoops_sre-0.1.3/src/autoops/cli_options.py +42 -0
- autoops_sre-0.1.3/src/autoops/config.py +278 -0
- autoops_sre-0.1.3/src/autoops/controller/__init__.py +21 -0
- autoops_sre-0.1.3/src/autoops/controller/artifacts.py +1597 -0
- autoops_sre-0.1.3/src/autoops/controller/budget.py +132 -0
- autoops_sre-0.1.3/src/autoops/controller/composition.py +3038 -0
- autoops_sre-0.1.3/src/autoops/controller/context_budget.py +207 -0
- autoops_sre-0.1.3/src/autoops/controller/engine.py +4000 -0
- autoops_sre-0.1.3/src/autoops/controller/judge.py +78 -0
- autoops_sre-0.1.3/src/autoops/controller/localization.py +82 -0
- autoops_sre-0.1.3/src/autoops/controller/loop.py +131 -0
- autoops_sre-0.1.3/src/autoops/controller/mutation.py +312 -0
- autoops_sre-0.1.3/src/autoops/controller/owner_join.py +114 -0
- autoops_sre-0.1.3/src/autoops/controller/panel.py +141 -0
- autoops_sre-0.1.3/src/autoops/controller/rca.py +187 -0
- autoops_sre-0.1.3/src/autoops/controller/rca_loop.py +877 -0
- autoops_sre-0.1.3/src/autoops/controller/responses.py +200 -0
- autoops_sre-0.1.3/src/autoops/controller/senses.py +2110 -0
- autoops_sre-0.1.3/src/autoops/controller/stages.py +291 -0
- autoops_sre-0.1.3/src/autoops/controller/watch.py +411 -0
- autoops_sre-0.1.3/src/autoops/controller/workload_resolution.py +245 -0
- autoops_sre-0.1.3/src/autoops/core/__init__.py +3 -0
- autoops_sre-0.1.3/src/autoops/core/cell.py +221 -0
- autoops_sre-0.1.3/src/autoops/core/events.py +53 -0
- autoops_sre-0.1.3/src/autoops/core/evidence_bundle.py +174 -0
- autoops_sre-0.1.3/src/autoops/core/guard_error.py +29 -0
- autoops_sre-0.1.3/src/autoops/core/messages.py +50 -0
- autoops_sre-0.1.3/src/autoops/core/middleware.py +125 -0
- autoops_sre-0.1.3/src/autoops/core/registry.py +38 -0
- autoops_sre-0.1.3/src/autoops/delivery.py +307 -0
- autoops_sre-0.1.3/src/autoops/eval/__init__.py +14 -0
- autoops_sre-0.1.3/src/autoops/eval/admission.py +177 -0
- autoops_sre-0.1.3/src/autoops/eval/agent.py +657 -0
- autoops_sre-0.1.3/src/autoops/eval/axis_gap.py +400 -0
- autoops_sre-0.1.3/src/autoops/eval/briefing.py +174 -0
- autoops_sre-0.1.3/src/autoops/eval/campaign_declaration.py +324 -0
- autoops_sre-0.1.3/src/autoops/eval/campaign_report.py +1508 -0
- autoops_sre-0.1.3/src/autoops/eval/decision.py +141 -0
- autoops_sre-0.1.3/src/autoops/eval/fault_verifier.py +647 -0
- autoops_sre-0.1.3/src/autoops/eval/live_orchestrator.py +1093 -0
- autoops_sre-0.1.3/src/autoops/eval/measure.py +207 -0
- autoops_sre-0.1.3/src/autoops/eval/miss_record.py +619 -0
- autoops_sre-0.1.3/src/autoops/eval/miss_scenario.py +439 -0
- autoops_sre-0.1.3/src/autoops/eval/offline_door.py +565 -0
- autoops_sre-0.1.3/src/autoops/eval/offline_orchestrator.py +535 -0
- autoops_sre-0.1.3/src/autoops/eval/offline_series.py +136 -0
- autoops_sre-0.1.3/src/autoops/eval/panel.py +91 -0
- autoops_sre-0.1.3/src/autoops/eval/process_metrics.py +211 -0
- autoops_sre-0.1.3/src/autoops/eval/reachability_probe.py +127 -0
- autoops_sre-0.1.3/src/autoops/eval/runner.py +1269 -0
- autoops_sre-0.1.3/src/autoops/eval/scoring.py +378 -0
- autoops_sre-0.1.3/src/autoops/eval/strata.py +385 -0
- autoops_sre-0.1.3/src/autoops/eval/trajectory.py +207 -0
- autoops_sre-0.1.3/src/autoops/eval/verify_channels.py +93 -0
- autoops_sre-0.1.3/src/autoops/eval/verify_event_join.py +309 -0
- autoops_sre-0.1.3/src/autoops/memory/__init__.py +6 -0
- autoops_sre-0.1.3/src/autoops/memory/estate_store.py +346 -0
- autoops_sre-0.1.3/src/autoops/memory/versioning.py +163 -0
- autoops_sre-0.1.3/src/autoops/observability/__init__.py +19 -0
- autoops_sre-0.1.3/src/autoops/observability/abstraction.py +128 -0
- autoops_sre-0.1.3/src/autoops/observability/alert_rules.py +762 -0
- autoops_sre-0.1.3/src/autoops/observability/answer_bound.py +179 -0
- autoops_sre-0.1.3/src/autoops/observability/autoscaler_reach.py +249 -0
- autoops_sre-0.1.3/src/autoops/observability/aws_credentials.py +160 -0
- autoops_sre-0.1.3/src/autoops/observability/aws_sigv4.py +166 -0
- autoops_sre-0.1.3/src/autoops/observability/backend_fingerprint.py +105 -0
- autoops_sre-0.1.3/src/autoops/observability/baselines.py +304 -0
- autoops_sre-0.1.3/src/autoops/observability/budget_dwell.py +355 -0
- autoops_sre-0.1.3/src/autoops/observability/capability_probes.py +473 -0
- autoops_sre-0.1.3/src/autoops/observability/carrier_relation.py +221 -0
- autoops_sre-0.1.3/src/autoops/observability/causal_localizer.py +452 -0
- autoops_sre-0.1.3/src/autoops/observability/causal_rca.py +4644 -0
- autoops_sre-0.1.3/src/autoops/observability/channels.py +117 -0
- autoops_sre-0.1.3/src/autoops/observability/citation_grounding.py +258 -0
- autoops_sre-0.1.3/src/autoops/observability/claim_binding.py +282 -0
- autoops_sre-0.1.3/src/autoops/observability/cloudwatch.py +638 -0
- autoops_sre-0.1.3/src/autoops/observability/concurrency_wedge.py +275 -0
- autoops_sre-0.1.3/src/autoops/observability/connectors.py +144 -0
- autoops_sre-0.1.3/src/autoops/observability/control_plane_oracle.py +204 -0
- autoops_sre-0.1.3/src/autoops/observability/control_plane_posture.py +91 -0
- autoops_sre-0.1.3/src/autoops/observability/control_plane_rbac.py +407 -0
- autoops_sre-0.1.3/src/autoops/observability/control_plane_reader.py +3263 -0
- autoops_sre-0.1.3/src/autoops/observability/daemon_scheduling.py +158 -0
- autoops_sre-0.1.3/src/autoops/observability/datasources.py +129 -0
- autoops_sre-0.1.3/src/autoops/observability/declared_topology.py +2256 -0
- autoops_sre-0.1.3/src/autoops/observability/dependencies.py +1122 -0
- autoops_sre-0.1.3/src/autoops/observability/deploy_digest.py +110 -0
- autoops_sre-0.1.3/src/autoops/observability/discovery.py +894 -0
- autoops_sre-0.1.3/src/autoops/observability/disruption_budget.py +589 -0
- autoops_sre-0.1.3/src/autoops/observability/entities.py +213 -0
- autoops_sre-0.1.3/src/autoops/observability/entity_existence.py +249 -0
- autoops_sre-0.1.3/src/autoops/observability/estate_map.py +571 -0
- autoops_sre-0.1.3/src/autoops/observability/estate_model.py +723 -0
- autoops_sre-0.1.3/src/autoops/observability/event_digest.py +279 -0
- autoops_sre-0.1.3/src/autoops/observability/event_identity.py +62 -0
- autoops_sre-0.1.3/src/autoops/observability/event_provenance.py +169 -0
- autoops_sre-0.1.3/src/autoops/observability/evidence_gate.py +329 -0
- autoops_sre-0.1.3/src/autoops/observability/evidence_graph.py +457 -0
- autoops_sre-0.1.3/src/autoops/observability/gateway_reach.py +346 -0
- autoops_sre-0.1.3/src/autoops/observability/golden_signals.py +59 -0
- autoops_sre-0.1.3/src/autoops/observability/golden_sweep.py +240 -0
- autoops_sre-0.1.3/src/autoops/observability/governing_service.py +219 -0
- autoops_sre-0.1.3/src/autoops/observability/governor.py +1012 -0
- autoops_sre-0.1.3/src/autoops/observability/graph_reasoning.py +552 -0
- autoops_sre-0.1.3/src/autoops/observability/httpget.py +80 -0
- autoops_sre-0.1.3/src/autoops/observability/ingress_reach.py +387 -0
- autoops_sre-0.1.3/src/autoops/observability/investigation.py +247 -0
- autoops_sre-0.1.3/src/autoops/observability/jaeger.py +525 -0
- autoops_sre-0.1.3/src/autoops/observability/job_failure.py +272 -0
- autoops_sre-0.1.3/src/autoops/observability/keyword_denylists.py +116 -0
- autoops_sre-0.1.3/src/autoops/observability/kind_inventory.py +250 -0
- autoops_sre-0.1.3/src/autoops/observability/label_sets.py +44 -0
- autoops_sre-0.1.3/src/autoops/observability/live_candidate_logs.py +150 -0
- autoops_sre-0.1.3/src/autoops/observability/live_deployments.py +52 -0
- autoops_sre-0.1.3/src/autoops/observability/live_logs.py +70 -0
- autoops_sre-0.1.3/src/autoops/observability/live_pods.py +100 -0
- autoops_sre-0.1.3/src/autoops/observability/live_service_ports.py +64 -0
- autoops_sre-0.1.3/src/autoops/observability/live_service_red.py +112 -0
- autoops_sre-0.1.3/src/autoops/observability/log_digest.py +200 -0
- autoops_sre-0.1.3/src/autoops/observability/loki.py +664 -0
- autoops_sre-0.1.3/src/autoops/observability/metrics_digest.py +137 -0
- autoops_sre-0.1.3/src/autoops/observability/network_policy_reach.py +374 -0
- autoops_sre-0.1.3/src/autoops/observability/node_condition.py +324 -0
- autoops_sre-0.1.3/src/autoops/observability/node_placement.py +163 -0
- autoops_sre-0.1.3/src/autoops/observability/observation_composition.py +260 -0
- autoops_sre-0.1.3/src/autoops/observability/pipeline_health.py +281 -0
- autoops_sre-0.1.3/src/autoops/observability/placement_refusal.py +220 -0
- autoops_sre-0.1.3/src/autoops/observability/pod_binding_digest.py +465 -0
- autoops_sre-0.1.3/src/autoops/observability/pod_ownership.py +111 -0
- autoops_sre-0.1.3/src/autoops/observability/pod_placement.py +265 -0
- autoops_sre-0.1.3/src/autoops/observability/pod_status.py +754 -0
- autoops_sre-0.1.3/src/autoops/observability/probe_outcome.py +47 -0
- autoops_sre-0.1.3/src/autoops/observability/prometheus.py +950 -0
- autoops_sre-0.1.3/src/autoops/observability/promql_series.py +268 -0
- autoops_sre-0.1.3/src/autoops/observability/provenance_digest.py +173 -0
- autoops_sre-0.1.3/src/autoops/observability/reachability.py +101 -0
- autoops_sre-0.1.3/src/autoops/observability/read_audit.py +331 -0
- autoops_sre-0.1.3/src/autoops/observability/replica_failure.py +305 -0
- autoops_sre-0.1.3/src/autoops/observability/request_path_digest.py +206 -0
- autoops_sre-0.1.3/src/autoops/observability/resource_key.py +633 -0
- autoops_sre-0.1.3/src/autoops/observability/route_reach.py +579 -0
- autoops_sre-0.1.3/src/autoops/observability/schedule_reach.py +366 -0
- autoops_sre-0.1.3/src/autoops/observability/scheduling_failure.py +443 -0
- autoops_sre-0.1.3/src/autoops/observability/scope_selection.py +187 -0
- autoops_sre-0.1.3/src/autoops/observability/sense_evidence.py +1309 -0
- autoops_sre-0.1.3/src/autoops/observability/service_port_digest.py +366 -0
- autoops_sre-0.1.3/src/autoops/observability/service_proxy.py +87 -0
- autoops_sre-0.1.3/src/autoops/observability/service_red.py +133 -0
- autoops_sre-0.1.3/src/autoops/observability/service_red_digest.py +153 -0
- autoops_sre-0.1.3/src/autoops/observability/severity.py +251 -0
- autoops_sre-0.1.3/src/autoops/observability/storage_class_inventory.py +285 -0
- autoops_sre-0.1.3/src/autoops/observability/structural_finding.py +672 -0
- autoops_sre-0.1.3/src/autoops/observability/taint.py +54 -0
- autoops_sre-0.1.3/src/autoops/observability/telemetry_families.py +150 -0
- autoops_sre-0.1.3/src/autoops/observability/telemetry_stack.py +449 -0
- autoops_sre-0.1.3/src/autoops/observability/tenancy.py +609 -0
- autoops_sre-0.1.3/src/autoops/observability/timestamps.py +28 -0
- autoops_sre-0.1.3/src/autoops/observability/topology.py +1084 -0
- autoops_sre-0.1.3/src/autoops/observability/traces_digest.py +228 -0
- autoops_sre-0.1.3/src/autoops/observability/verifier.py +109 -0
- autoops_sre-0.1.3/src/autoops/observability/volume_reclaim.py +202 -0
- autoops_sre-0.1.3/src/autoops/observability/workload_history.py +359 -0
- autoops_sre-0.1.3/src/autoops/onboarding/__init__.py +11 -0
- autoops_sre-0.1.3/src/autoops/onboarding/allowlist.py +309 -0
- autoops_sre-0.1.3/src/autoops/onboarding/commands.py +254 -0
- autoops_sre-0.1.3/src/autoops/onboarding/endpoints.py +183 -0
- autoops_sre-0.1.3/src/autoops/onboarding/identity.py +80 -0
- autoops_sre-0.1.3/src/autoops/onboarding/runconfig.py +43 -0
- autoops_sre-0.1.3/src/autoops/policy/__init__.py +12 -0
- autoops_sre-0.1.3/src/autoops/policy/cedar/ops.cedar +179 -0
- autoops_sre-0.1.3/src/autoops/policy/cedar/ops.cedarschema +109 -0
- autoops_sre-0.1.3/src/autoops/policy/cedar_diagnostics.py +57 -0
- autoops_sre-0.1.3/src/autoops/policy/cedar_guard.py +202 -0
- autoops_sre-0.1.3/src/autoops/policy/cloudwatch_read_guard.py +74 -0
- autoops_sre-0.1.3/src/autoops/policy/control_plane_read_guard.py +125 -0
- autoops_sre-0.1.3/src/autoops/policy/destructive.py +128 -0
- autoops_sre-0.1.3/src/autoops/policy/envelope.py +50 -0
- autoops_sre-0.1.3/src/autoops/policy/mutation_approval.py +315 -0
- autoops_sre-0.1.3/src/autoops/policy/oracle_guard.py +236 -0
- autoops_sre-0.1.3/src/autoops/policy/reachability_guard.py +108 -0
- autoops_sre-0.1.3/src/autoops/policy/readonly_guard.py +58 -0
- autoops_sre-0.1.3/src/autoops/policy/scale_guard.py +207 -0
- autoops_sre-0.1.3/src/autoops/policy/shell_gate.py +955 -0
- autoops_sre-0.1.3/src/autoops/sandbox/__init__.py +55 -0
- autoops_sre-0.1.3/src/autoops/sandbox/cluster_guard.py +170 -0
- autoops_sre-0.1.3/src/autoops/sandbox/crossing.py +1122 -0
- autoops_sre-0.1.3/src/autoops/sandbox/egress.py +541 -0
- autoops_sre-0.1.3/src/autoops/sandbox/executor.py +318 -0
- autoops_sre-0.1.3/src/autoops/sandbox/identity.py +499 -0
- autoops_sre-0.1.3/src/autoops/sandbox/k8s_read_request.py +578 -0
- autoops_sre-0.1.3/src/autoops/sandbox/k8s_read_transport.py +130 -0
- autoops_sre-0.1.3/src/autoops/sandbox/pinned_http.py +216 -0
- autoops_sre-0.1.3/src/autoops/sandbox/preflight.py +89 -0
- autoops_sre-0.1.3/src/autoops/sandbox/probe_executor.py +153 -0
- autoops_sre-0.1.3/src/autoops/sandbox/probe_target.py +113 -0
- autoops_sre-0.1.3/src/autoops/sandbox/scale_executor.py +178 -0
- autoops_sre-0.1.3/src/autoops/sandbox/token_minter.py +298 -0
- autoops_sre-0.1.3/src/autoops/selftest.py +71 -0
- autoops_sre-0.1.3/src/autoops/serve/__init__.py +23 -0
- autoops_sre-0.1.3/src/autoops/serve/api.py +386 -0
- autoops_sre-0.1.3/src/autoops/serve/auth.py +149 -0
- autoops_sre-0.1.3/src/autoops/serve/authority.py +153 -0
- autoops_sre-0.1.3/src/autoops/serve/commands.py +285 -0
- autoops_sre-0.1.3/src/autoops/serve/mcp_server.py +109 -0
- autoops_sre-0.1.3/src/autoops/serve/models.py +306 -0
- autoops_sre-0.1.3/src/autoops/serve/runs.py +265 -0
- autoops_sre-0.1.3/src/autoops/serve/stream.py +75 -0
- autoops_sre-0.1.3/src/autoops/serve/tools.py +247 -0
- autoops_sre-0.1.3/src/autoops/telemetry/__init__.py +3 -0
- autoops_sre-0.1.3/src/autoops/telemetry/comparability.py +231 -0
- autoops_sre-0.1.3/src/autoops/telemetry/ledger.py +306 -0
- autoops_sre-0.1.3/src/autoops/telemetry/manifest.py +733 -0
- autoops_sre-0.1.3/src/autoops/telemetry/otel.py +25 -0
- autoops_sre-0.1.3/src/autoops/telemetry/stratum.py +40 -0
- autoops_sre-0.1.3/uv.lock +2332 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.eggs/
|
|
6
|
+
build/
|
|
7
|
+
dist/
|
|
8
|
+
|
|
9
|
+
# uv / venv
|
|
10
|
+
.venv/
|
|
11
|
+
.python-version
|
|
12
|
+
|
|
13
|
+
# Tooling caches
|
|
14
|
+
.ruff_cache/
|
|
15
|
+
.mypy_cache/
|
|
16
|
+
.pytest_cache/
|
|
17
|
+
.coverage
|
|
18
|
+
.coverage.*
|
|
19
|
+
htmlcov/
|
|
20
|
+
coverage.xml
|
|
21
|
+
|
|
22
|
+
# Artifacts, evidence, traces and SBOM are committed as a backup
|
|
23
|
+
# (large >3MB dumps go through Git LFS, see .gitattributes).
|
|
24
|
+
# Only transient root-level logs stay ignored; logs inside the dirs are kept.
|
|
25
|
+
/*.log
|
|
26
|
+
|
|
27
|
+
# Editor / OS
|
|
28
|
+
.vscode/
|
|
29
|
+
.idea/
|
|
30
|
+
.DS_Store
|
|
31
|
+
|
|
32
|
+
# Secrets (never commit credentials)
|
|
33
|
+
.env
|
|
34
|
+
.env.*
|
|
35
|
+
!.env.example
|
|
36
|
+
|
|
37
|
+
# Claude Code personal project settings
|
|
38
|
+
.claude/settings.local.json
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Evangelos Pappas
|
|
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,199 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: autoops-sre
|
|
3
|
+
Version: 0.1.3
|
|
4
|
+
Summary: An agentic ops harness for AIOps — SRE, cloud, Kubernetes, observability, and security automation.
|
|
5
|
+
Project-URL: Repository, https://github.com/epappas/autoops
|
|
6
|
+
Author-email: Evangelos Pappas <epappas@evalonlabs.com>
|
|
7
|
+
License: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Keywords: agent,aiops,harness,kubernetes,observability,sre
|
|
10
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Topic :: System :: Systems Administration
|
|
15
|
+
Requires-Python: >=3.12
|
|
16
|
+
Requires-Dist: anthropic>=0.121.0
|
|
17
|
+
Requires-Dist: cedarpy<5,>=4.8.7
|
|
18
|
+
Requires-Dist: cryptography>=50
|
|
19
|
+
Requires-Dist: mcp>=2.1.1
|
|
20
|
+
Requires-Dist: openai>=2.53.0
|
|
21
|
+
Requires-Dist: opentelemetry-api>=1.43.0
|
|
22
|
+
Requires-Dist: opentelemetry-sdk>=1.44.0
|
|
23
|
+
Requires-Dist: pydantic>=2.7
|
|
24
|
+
Requires-Dist: pyyaml>=6.0
|
|
25
|
+
Requires-Dist: starlette>=1.6.0
|
|
26
|
+
Requires-Dist: typer>=0.27.1
|
|
27
|
+
Requires-Dist: uvicorn>=0.52.4
|
|
28
|
+
Requires-Dist: websockets>=17.1
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# autoOps
|
|
32
|
+
|
|
33
|
+
An autonomous SRE agent. Point it at a Kubernetes namespace and it models the estate,
|
|
34
|
+
names the service that is broken, shows the evidence it used, and re-reads the cluster to
|
|
35
|
+
check its own answer — or hands a human a briefing saying why it could not.
|
|
36
|
+
|
|
37
|
+
**Prime objective:** an agent that operates real estates unaided through one core runtime
|
|
38
|
+
loop. The measure of done is **transfer** — the loop working on an estate it was not built
|
|
39
|
+
for (ADR-0038 D6) — never a benchmark score.
|
|
40
|
+
|
|
41
|
+
> **What works today.** The nine-stage loop is built and has run against real clusters
|
|
42
|
+
> read-only. Perception is deterministic and comes first: 35 senses read the cluster's own
|
|
43
|
+
> declared state and nominate what looks broken, while metrics, traces and logs supply the
|
|
44
|
+
> evidence that either confirms a candidate or refuses it. A sense never votes on its own
|
|
45
|
+
> nomination. Diagnosis then reaches a confident answer or escalates, and says which.
|
|
46
|
+
>
|
|
47
|
+
> **What it deliberately will not do.** It does not act. Stage 8 emits an incident note or
|
|
48
|
+
> a remediation proposal, never a change. The one typed mutation verb that exists,
|
|
49
|
+
> `k8s_scale_workload`, has an executor that raises unconditionally and is reachable from no
|
|
50
|
+
> live path — the boundary is code, not policy. It stays locked until the reasoning is
|
|
51
|
+
> trustworthy enough to earn it.
|
|
52
|
+
|
|
53
|
+
## Install
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
uv tool install autoops-sre # or: pip install autoops-sre
|
|
57
|
+
docker pull ghcr.io/epappas/autoops:latest # entrypoint is `autoops`
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The distribution is **`autoops-sre`**; the command it installs is **`autoops`**. The bare name
|
|
61
|
+
`autoops` on PyPI belongs to an unrelated project — do not install it.
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
autoops version && autoops --help
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Three paths — a Python tool, a container image, or a source checkout — with the exact commands,
|
|
68
|
+
what the image does and does not contain, and how to verify its provenance:
|
|
69
|
+
**[`docs/operations/install.md`](docs/operations/install.md)**.
|
|
70
|
+
|
|
71
|
+
## The Loop
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
recall -> understand -> [detect -> map topology -> map services -> localize] -> rca -> mitigate -> remember
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The bracket is the investigation. `rca` matches over everything inside it plus what was
|
|
78
|
+
recalled; `remember` closes the loop so the next run starts from a model rather than from
|
|
79
|
+
nothing. Perception is deterministic and precedes action — the estate model generates the
|
|
80
|
+
agent's moves, not the other way round (ADR-0038, ADR-0039).
|
|
81
|
+
|
|
82
|
+
## Try It Without A Cluster
|
|
83
|
+
|
|
84
|
+
A real model drives the real agent stack over committed recordings — no cluster, and no
|
|
85
|
+
credentials beyond an LLM key. The run is graded against the fixture's known answer, so you
|
|
86
|
+
see both what it concluded and whether it was right.
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
uv sync
|
|
90
|
+
export OPENROUTER_API_KEY=... # or put both in .env (never committed)
|
|
91
|
+
export OPENROUTER_MODEL=anthropic/claude-opus-4.8
|
|
92
|
+
|
|
93
|
+
uv run autoops offline --fixtures tests/fixtures/observability --results-dir ./out
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
It writes the trajectory, `results.tsv` and — only if it was wrong — a miss record, all under
|
|
97
|
+
`./out`. Four problems are available: `--problem localization` (default), `detection`, `rca`,
|
|
98
|
+
`cascade-localization`.
|
|
99
|
+
|
|
100
|
+
## Running It Against A Cluster
|
|
101
|
+
|
|
102
|
+
Read **[`docs/operations/operator-runbook.md`](docs/operations/operator-runbook.md)** — the
|
|
103
|
+
operator's document: prerequisites, exit codes and what to do about each, the exact shape of
|
|
104
|
+
a confident answer and of an escalation, troubleshooting, and the safety rails.
|
|
105
|
+
|
|
106
|
+
The short version, on a loopback (kind/k3s) cluster:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
uv run autoops diagnose --namespace <ns> --results-dir ./out
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
It runs a three-vote panel and decides fail-closed: **exit 0** is a confident answer,
|
|
113
|
+
**exit 3** is an escalation briefing for a human, **exit 4** means every sense came back
|
|
114
|
+
without a read and no answer above it can be trusted.
|
|
115
|
+
|
|
116
|
+
Once an estate is written into a config file — `./autoops.yaml`, or `--config <path>`, or
|
|
117
|
+
`$AUTOOPS_CONFIG` — a routine diagnosis is `autoops diagnose --namespace <ns>` and nothing
|
|
118
|
+
else. Every flag overrides the config, the config overrides the environment, and with no
|
|
119
|
+
config file every command resolves exactly as it did before (ADR-0206).
|
|
120
|
+
|
|
121
|
+
`autoops watch` is the continuous mode — scheduled panels with a cadence floor, a rolling
|
|
122
|
+
token budget, and escalations delivered to a directory or a webhook.
|
|
123
|
+
|
|
124
|
+
Any cluster that is not loopback is refused before a single read until it is named in an
|
|
125
|
+
allowlist the owner has signed out of band. That refusal is the authorization boundary and
|
|
126
|
+
it lives in the loader, not in the model.
|
|
127
|
+
|
|
128
|
+
## The Command Surface
|
|
129
|
+
|
|
130
|
+
Seven verbs, plus `version` (ADR-0206, ADR-0208):
|
|
131
|
+
|
|
132
|
+
| Verb | What it is for |
|
|
133
|
+
|---|---|
|
|
134
|
+
| `init` | Onboard an estate and check the setup: `init verify` (the crossing kill-switch), `init validate`, `init print-config`, `init selftest` |
|
|
135
|
+
| `diagnose` | Diagnose a live namespace read-only — the product path |
|
|
136
|
+
| `watch` | Continuous mode: scheduled panels, cadence floor, budget, delivered escalations |
|
|
137
|
+
| `offline` | One committed fixture problem, no cluster, recorded telemetry only |
|
|
138
|
+
| `export` | `export evidence` bundles a finished run for a ticket; `export misses` turns recorded misses into replayable scenarios |
|
|
139
|
+
| `serve` | Serve over the network: `serve http` (REST + websockets + MCP), `serve mcp-stdio` (MCP for a local agent) |
|
|
140
|
+
| `eval` | Evaluation and campaign instrumentation — `declare-campaign`, `campaign-report`, `miss-replay`, `axis-gap` |
|
|
141
|
+
| `version` | Print the version |
|
|
142
|
+
|
|
143
|
+
Every pre-ADR-0206 command name still dispatches, hidden and with a deprecation notice
|
|
144
|
+
naming its replacement, because committed evidence manifests and estate crossing scripts
|
|
145
|
+
record those invocations verbatim.
|
|
146
|
+
|
|
147
|
+
## Safety
|
|
148
|
+
|
|
149
|
+
autoOps is built to run against real infrastructure, so the constraints come first:
|
|
150
|
+
|
|
151
|
+
- **The model is never the authorization boundary.** Every tool call passes a
|
|
152
|
+
deny-by-default policy gate before execution, and gets a structured reason it can replan
|
|
153
|
+
on rather than a bare refusal.
|
|
154
|
+
- **Read-only by construction on the shipped path.** The Cedar read-only profile plus a
|
|
155
|
+
destructive re-check; a diagnosis cannot mutate.
|
|
156
|
+
- **Approvals are short-lived, target-scoped and re-checked** before every target contact —
|
|
157
|
+
deleting an allowlist entry aborts a run already in flight.
|
|
158
|
+
- **Secrets never enter the model context or the logs.**
|
|
159
|
+
|
|
160
|
+
## Documentation
|
|
161
|
+
|
|
162
|
+
**[`docs/`](docs/index.md)** is the map — every document, what it answers, and who it is for.
|
|
163
|
+
The four an operator needs:
|
|
164
|
+
|
|
165
|
+
| Task | Document |
|
|
166
|
+
|---|---|
|
|
167
|
+
| Install it | [`operations/install.md`](docs/operations/install.md) |
|
|
168
|
+
| Point it at a cluster | [`operations/onboarding-a-cluster.md`](docs/operations/onboarding-a-cluster.md) |
|
|
169
|
+
| Run a diagnosis and read the answer | [`operations/operator-runbook.md`](docs/operations/operator-runbook.md) |
|
|
170
|
+
| Run it unattended, or over the network | [`operations/continuous.md`](docs/operations/continuous.md) · [`operations/api.md`](docs/operations/api.md) |
|
|
171
|
+
|
|
172
|
+
## Design
|
|
173
|
+
|
|
174
|
+
- Decisions: [`docs/architecture/adr/`](docs/architecture/adr/) — ADR-0038 and ADR-0039
|
|
175
|
+
define the loop; ADR-0113 records why a sense is a node in the estate graph rather than a
|
|
176
|
+
vote for a culprit.
|
|
177
|
+
- Architecture: [`system-architecture.md`](docs/architecture/system-architecture.md)
|
|
178
|
+
(structure) · [`incident-loop.md`](docs/architecture/incident-loop.md) (behaviour) ·
|
|
179
|
+
[`data-plane.md`](docs/architecture/data-plane.md)
|
|
180
|
+
- Estates: [`deploy/estates/`](deploy/estates/) — eighteen deployable fault estates, each
|
|
181
|
+
with its own contract and offline validators.
|
|
182
|
+
- Research: [`docs/research/`](docs/research/) · beliefs that constrain the design live in
|
|
183
|
+
[`_meta/beliefs.md`](docs/research/_meta/beliefs.md).
|
|
184
|
+
|
|
185
|
+
## Contributing
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
make help # every target
|
|
189
|
+
make check # the merge gate: lint, imports, types, dead code, tests + coverage, security, estates
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
See [`CLAUDE.md`](CLAUDE.md) (= `AGENTS.md`) and [`CONTRIBUTING.md`](CONTRIBUTING.md). The
|
|
193
|
+
hard rule: no detection, localization, RCA or mitigation capability is "done" without an
|
|
194
|
+
end-to-end run that closes the telemetry loop — re-reading real cluster state to verify the
|
|
195
|
+
outcome, not the agent's self-report.
|
|
196
|
+
|
|
197
|
+
## License
|
|
198
|
+
|
|
199
|
+
MIT — see [`LICENSE`](LICENSE).
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# autoOps
|
|
2
|
+
|
|
3
|
+
An autonomous SRE agent. Point it at a Kubernetes namespace and it models the estate,
|
|
4
|
+
names the service that is broken, shows the evidence it used, and re-reads the cluster to
|
|
5
|
+
check its own answer — or hands a human a briefing saying why it could not.
|
|
6
|
+
|
|
7
|
+
**Prime objective:** an agent that operates real estates unaided through one core runtime
|
|
8
|
+
loop. The measure of done is **transfer** — the loop working on an estate it was not built
|
|
9
|
+
for (ADR-0038 D6) — never a benchmark score.
|
|
10
|
+
|
|
11
|
+
> **What works today.** The nine-stage loop is built and has run against real clusters
|
|
12
|
+
> read-only. Perception is deterministic and comes first: 35 senses read the cluster's own
|
|
13
|
+
> declared state and nominate what looks broken, while metrics, traces and logs supply the
|
|
14
|
+
> evidence that either confirms a candidate or refuses it. A sense never votes on its own
|
|
15
|
+
> nomination. Diagnosis then reaches a confident answer or escalates, and says which.
|
|
16
|
+
>
|
|
17
|
+
> **What it deliberately will not do.** It does not act. Stage 8 emits an incident note or
|
|
18
|
+
> a remediation proposal, never a change. The one typed mutation verb that exists,
|
|
19
|
+
> `k8s_scale_workload`, has an executor that raises unconditionally and is reachable from no
|
|
20
|
+
> live path — the boundary is code, not policy. It stays locked until the reasoning is
|
|
21
|
+
> trustworthy enough to earn it.
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
uv tool install autoops-sre # or: pip install autoops-sre
|
|
27
|
+
docker pull ghcr.io/epappas/autoops:latest # entrypoint is `autoops`
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The distribution is **`autoops-sre`**; the command it installs is **`autoops`**. The bare name
|
|
31
|
+
`autoops` on PyPI belongs to an unrelated project — do not install it.
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
autoops version && autoops --help
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Three paths — a Python tool, a container image, or a source checkout — with the exact commands,
|
|
38
|
+
what the image does and does not contain, and how to verify its provenance:
|
|
39
|
+
**[`docs/operations/install.md`](docs/operations/install.md)**.
|
|
40
|
+
|
|
41
|
+
## The Loop
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
recall -> understand -> [detect -> map topology -> map services -> localize] -> rca -> mitigate -> remember
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The bracket is the investigation. `rca` matches over everything inside it plus what was
|
|
48
|
+
recalled; `remember` closes the loop so the next run starts from a model rather than from
|
|
49
|
+
nothing. Perception is deterministic and precedes action — the estate model generates the
|
|
50
|
+
agent's moves, not the other way round (ADR-0038, ADR-0039).
|
|
51
|
+
|
|
52
|
+
## Try It Without A Cluster
|
|
53
|
+
|
|
54
|
+
A real model drives the real agent stack over committed recordings — no cluster, and no
|
|
55
|
+
credentials beyond an LLM key. The run is graded against the fixture's known answer, so you
|
|
56
|
+
see both what it concluded and whether it was right.
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
uv sync
|
|
60
|
+
export OPENROUTER_API_KEY=... # or put both in .env (never committed)
|
|
61
|
+
export OPENROUTER_MODEL=anthropic/claude-opus-4.8
|
|
62
|
+
|
|
63
|
+
uv run autoops offline --fixtures tests/fixtures/observability --results-dir ./out
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
It writes the trajectory, `results.tsv` and — only if it was wrong — a miss record, all under
|
|
67
|
+
`./out`. Four problems are available: `--problem localization` (default), `detection`, `rca`,
|
|
68
|
+
`cascade-localization`.
|
|
69
|
+
|
|
70
|
+
## Running It Against A Cluster
|
|
71
|
+
|
|
72
|
+
Read **[`docs/operations/operator-runbook.md`](docs/operations/operator-runbook.md)** — the
|
|
73
|
+
operator's document: prerequisites, exit codes and what to do about each, the exact shape of
|
|
74
|
+
a confident answer and of an escalation, troubleshooting, and the safety rails.
|
|
75
|
+
|
|
76
|
+
The short version, on a loopback (kind/k3s) cluster:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
uv run autoops diagnose --namespace <ns> --results-dir ./out
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
It runs a three-vote panel and decides fail-closed: **exit 0** is a confident answer,
|
|
83
|
+
**exit 3** is an escalation briefing for a human, **exit 4** means every sense came back
|
|
84
|
+
without a read and no answer above it can be trusted.
|
|
85
|
+
|
|
86
|
+
Once an estate is written into a config file — `./autoops.yaml`, or `--config <path>`, or
|
|
87
|
+
`$AUTOOPS_CONFIG` — a routine diagnosis is `autoops diagnose --namespace <ns>` and nothing
|
|
88
|
+
else. Every flag overrides the config, the config overrides the environment, and with no
|
|
89
|
+
config file every command resolves exactly as it did before (ADR-0206).
|
|
90
|
+
|
|
91
|
+
`autoops watch` is the continuous mode — scheduled panels with a cadence floor, a rolling
|
|
92
|
+
token budget, and escalations delivered to a directory or a webhook.
|
|
93
|
+
|
|
94
|
+
Any cluster that is not loopback is refused before a single read until it is named in an
|
|
95
|
+
allowlist the owner has signed out of band. That refusal is the authorization boundary and
|
|
96
|
+
it lives in the loader, not in the model.
|
|
97
|
+
|
|
98
|
+
## The Command Surface
|
|
99
|
+
|
|
100
|
+
Seven verbs, plus `version` (ADR-0206, ADR-0208):
|
|
101
|
+
|
|
102
|
+
| Verb | What it is for |
|
|
103
|
+
|---|---|
|
|
104
|
+
| `init` | Onboard an estate and check the setup: `init verify` (the crossing kill-switch), `init validate`, `init print-config`, `init selftest` |
|
|
105
|
+
| `diagnose` | Diagnose a live namespace read-only — the product path |
|
|
106
|
+
| `watch` | Continuous mode: scheduled panels, cadence floor, budget, delivered escalations |
|
|
107
|
+
| `offline` | One committed fixture problem, no cluster, recorded telemetry only |
|
|
108
|
+
| `export` | `export evidence` bundles a finished run for a ticket; `export misses` turns recorded misses into replayable scenarios |
|
|
109
|
+
| `serve` | Serve over the network: `serve http` (REST + websockets + MCP), `serve mcp-stdio` (MCP for a local agent) |
|
|
110
|
+
| `eval` | Evaluation and campaign instrumentation — `declare-campaign`, `campaign-report`, `miss-replay`, `axis-gap` |
|
|
111
|
+
| `version` | Print the version |
|
|
112
|
+
|
|
113
|
+
Every pre-ADR-0206 command name still dispatches, hidden and with a deprecation notice
|
|
114
|
+
naming its replacement, because committed evidence manifests and estate crossing scripts
|
|
115
|
+
record those invocations verbatim.
|
|
116
|
+
|
|
117
|
+
## Safety
|
|
118
|
+
|
|
119
|
+
autoOps is built to run against real infrastructure, so the constraints come first:
|
|
120
|
+
|
|
121
|
+
- **The model is never the authorization boundary.** Every tool call passes a
|
|
122
|
+
deny-by-default policy gate before execution, and gets a structured reason it can replan
|
|
123
|
+
on rather than a bare refusal.
|
|
124
|
+
- **Read-only by construction on the shipped path.** The Cedar read-only profile plus a
|
|
125
|
+
destructive re-check; a diagnosis cannot mutate.
|
|
126
|
+
- **Approvals are short-lived, target-scoped and re-checked** before every target contact —
|
|
127
|
+
deleting an allowlist entry aborts a run already in flight.
|
|
128
|
+
- **Secrets never enter the model context or the logs.**
|
|
129
|
+
|
|
130
|
+
## Documentation
|
|
131
|
+
|
|
132
|
+
**[`docs/`](docs/index.md)** is the map — every document, what it answers, and who it is for.
|
|
133
|
+
The four an operator needs:
|
|
134
|
+
|
|
135
|
+
| Task | Document |
|
|
136
|
+
|---|---|
|
|
137
|
+
| Install it | [`operations/install.md`](docs/operations/install.md) |
|
|
138
|
+
| Point it at a cluster | [`operations/onboarding-a-cluster.md`](docs/operations/onboarding-a-cluster.md) |
|
|
139
|
+
| Run a diagnosis and read the answer | [`operations/operator-runbook.md`](docs/operations/operator-runbook.md) |
|
|
140
|
+
| Run it unattended, or over the network | [`operations/continuous.md`](docs/operations/continuous.md) · [`operations/api.md`](docs/operations/api.md) |
|
|
141
|
+
|
|
142
|
+
## Design
|
|
143
|
+
|
|
144
|
+
- Decisions: [`docs/architecture/adr/`](docs/architecture/adr/) — ADR-0038 and ADR-0039
|
|
145
|
+
define the loop; ADR-0113 records why a sense is a node in the estate graph rather than a
|
|
146
|
+
vote for a culprit.
|
|
147
|
+
- Architecture: [`system-architecture.md`](docs/architecture/system-architecture.md)
|
|
148
|
+
(structure) · [`incident-loop.md`](docs/architecture/incident-loop.md) (behaviour) ·
|
|
149
|
+
[`data-plane.md`](docs/architecture/data-plane.md)
|
|
150
|
+
- Estates: [`deploy/estates/`](deploy/estates/) — eighteen deployable fault estates, each
|
|
151
|
+
with its own contract and offline validators.
|
|
152
|
+
- Research: [`docs/research/`](docs/research/) · beliefs that constrain the design live in
|
|
153
|
+
[`_meta/beliefs.md`](docs/research/_meta/beliefs.md).
|
|
154
|
+
|
|
155
|
+
## Contributing
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
make help # every target
|
|
159
|
+
make check # the merge gate: lint, imports, types, dead code, tests + coverage, security, estates
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
See [`CLAUDE.md`](CLAUDE.md) (= `AGENTS.md`) and [`CONTRIBUTING.md`](CONTRIBUTING.md). The
|
|
163
|
+
hard rule: no detection, localization, RCA or mitigation capability is "done" without an
|
|
164
|
+
end-to-end run that closes the telemetry loop — re-reading real cluster state to verify the
|
|
165
|
+
outcome, not the agent's self-report.
|
|
166
|
+
|
|
167
|
+
## License
|
|
168
|
+
|
|
169
|
+
MIT — see [`LICENSE`](LICENSE).
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
# hatch-vcs (ADR-0205 D3): the version IS the git tag, never a hand-edited constant. A released
|
|
3
|
+
# artifact reporting 0.0.0 is a falsehood the release workflow would publish under a real tag.
|
|
4
|
+
# ⚑ hatchling is BOUNDED, and the upper bound is load-bearing. `[build-system].requires` is the one
|
|
5
|
+
# input to a release that `uv.lock` does not lock, so an unpinned backend means the published
|
|
6
|
+
# artefact can change with zero commits to this repository -- which is exactly what happened.
|
|
7
|
+
# hatchling 1.32.0 (2026-08-11) began emitting `Metadata-Version: 2.5`, and the SHA-pinned
|
|
8
|
+
# `pypa/gh-action-pypi-publish` bundles a twine that rejects it, so `v0.1.2` built, version-checked
|
|
9
|
+
# and cut a GitHub Release, then died on upload with:
|
|
10
|
+
#
|
|
11
|
+
# InvalidDistribution: Invalid distribution metadata: '2.5' is not a valid metadata version
|
|
12
|
+
#
|
|
13
|
+
# MEASURED by building this project against each: 1.32.0 -> 2.5, 1.31.0 -> 2.4, 1.27.0 -> 2.4.
|
|
14
|
+
# Lift the cap when the publish action ships a twine that accepts 2.5 -- its newest release
|
|
15
|
+
# (v1.14.2, 2026-07-29) PREDATES hatchling 1.32.0, so bumping the action today fixes nothing.
|
|
16
|
+
# The cap is the honest fix; disabling the action's `verify_metadata` would be passing by declining.
|
|
17
|
+
requires = ["hatchling>=1.27,<1.32", "hatch-vcs>=0.5"]
|
|
18
|
+
build-backend = "hatchling.build"
|
|
19
|
+
|
|
20
|
+
[project]
|
|
21
|
+
name = "autoops-sre"
|
|
22
|
+
dynamic = ["version"]
|
|
23
|
+
description = "An agentic ops harness for AIOps — SRE, cloud, Kubernetes, observability, and security automation."
|
|
24
|
+
readme = "README.md"
|
|
25
|
+
requires-python = ">=3.12"
|
|
26
|
+
license = { text = "MIT" }
|
|
27
|
+
authors = [{ name = "Evangelos Pappas", email = "epappas@evalonlabs.com" }]
|
|
28
|
+
keywords = ["aiops", "sre", "agent", "kubernetes", "observability", "harness"]
|
|
29
|
+
classifiers = [
|
|
30
|
+
"Development Status :: 2 - Pre-Alpha",
|
|
31
|
+
"Intended Audience :: Developers",
|
|
32
|
+
"License :: OSI Approved :: MIT License",
|
|
33
|
+
"Programming Language :: Python :: 3.12",
|
|
34
|
+
"Topic :: System :: Systems Administration",
|
|
35
|
+
]
|
|
36
|
+
dependencies = [
|
|
37
|
+
"typer>=0.27.1",
|
|
38
|
+
"pydantic>=2.7",
|
|
39
|
+
"pyyaml>=6.0",
|
|
40
|
+
"opentelemetry-api>=1.43.0",
|
|
41
|
+
"opentelemetry-sdk>=1.44.0",
|
|
42
|
+
"anthropic>=0.121.0",
|
|
43
|
+
"openai>=2.53.0",
|
|
44
|
+
"cedarpy>=4.8.7,<5",
|
|
45
|
+
# ADR-0042: the SPKI telemetry pin (sandbox/pinned_http.py) parses the negotiated DER leaf and
|
|
46
|
+
# extracts its SubjectPublicKeyInfo -- X.509 parsing the stdlib does not provide. Promoted from
|
|
47
|
+
# the dev group (#109); a real, disclosed runtime cost, not "free".
|
|
48
|
+
# >=50 pins out CVE-2026-69247 (fixed in 50.0.0); the SPKI pin (ADR-0042) needs this at runtime.
|
|
49
|
+
"cryptography>=50",
|
|
50
|
+
# ADR-0208, `autoops serve`. ONE new dependency SUBTREE, declared as the four names this code
|
|
51
|
+
# actually imports: `mcp` already depends on starlette and uvicorn, so naming them costs nothing
|
|
52
|
+
# in the resolved graph and buys honesty -- `serve/api.py` imports starlette, `serve/commands.py`
|
|
53
|
+
# imports uvicorn, and a module that imports a package it does not declare is one upstream drop
|
|
54
|
+
# away from breaking.
|
|
55
|
+
# `mcp` is the protocol's REFERENCE implementation. Hand-rolling the MCP wire protocol for an
|
|
56
|
+
# agent-facing boundary is the higher risk, not the lower one: session ids, protocol-version
|
|
57
|
+
# negotiation and the Streamable-HTTP handshake are exactly where a hand-rolled server silently
|
|
58
|
+
# stops interoperating. Measured before adding: `pip-audit --strict` and `osv-scanner` are both
|
|
59
|
+
# green on the resulting lock, and the tree overlaps what autoOps already ships (pydantic,
|
|
60
|
+
# opentelemetry-api, cryptography, anyio, httpx).
|
|
61
|
+
# `websockets` is NOT optional and that was MEASURED, not assumed: without it,
|
|
62
|
+
# `uvicorn.config.Config(ws="auto").load()` resolves `ws_protocol_class = None` and the shipped
|
|
63
|
+
# `autoops serve http` refuses every websocket upgrade -- the stage stream would not exist. With
|
|
64
|
+
# it, the same call resolves `WebSocketsSansIOProtocol`.
|
|
65
|
+
"mcp>=2.1.1",
|
|
66
|
+
"starlette>=1.6.0",
|
|
67
|
+
"uvicorn>=0.52.4",
|
|
68
|
+
"websockets>=17.1",
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
[project.scripts]
|
|
72
|
+
autoops = "autoops.cli:main"
|
|
73
|
+
autoctl = "autoops.autoctl:main"
|
|
74
|
+
|
|
75
|
+
[project.urls]
|
|
76
|
+
Repository = "https://github.com/epappas/autoops"
|
|
77
|
+
|
|
78
|
+
[dependency-groups]
|
|
79
|
+
dev = [
|
|
80
|
+
# ⚑ DECLARED, not inherited. `httpx` reached the tests transitively through `openai` 2.x and the
|
|
81
|
+
# 3.x bump dropped it, breaking collection in `test_openrouter_client.py`, `test_serve_api.py` and
|
|
82
|
+
# `test_serve_mcp.py` with `ModuleNotFoundError`. Every one of the nine dependency PRs was green
|
|
83
|
+
# on its own; the UNION was red. This is exactly the hazard the main dependency block's own
|
|
84
|
+
# comment names -- "a module that imports a package it does not declare is one upstream drop away
|
|
85
|
+
# from breaking" -- so the fix is to declare it rather than re-pin `openai`.
|
|
86
|
+
"httpx>=0.28",
|
|
87
|
+
"ruff>=0.16.2",
|
|
88
|
+
"mypy>=2.3.0",
|
|
89
|
+
"pytest>=9.1.1",
|
|
90
|
+
"pytest-cov>=5.0",
|
|
91
|
+
"bandit>=1.7",
|
|
92
|
+
"pip-audit>=2.7",
|
|
93
|
+
# ADR-0099: the import-layering gate (`.importlinter`, run by `make lint-imports`). Unlike
|
|
94
|
+
# semgrep below, this one BELONGS in the group: `lint-imports` resolves its root package
|
|
95
|
+
# through `sys.path`, so an isolated `uvx` environment would analyse whatever `autoops` it
|
|
96
|
+
# could find rather than this working tree. Membership makes it resolve the editable install.
|
|
97
|
+
# Measured before adding, against the precedent below: it pulls `click` and `grimp` into the
|
|
98
|
+
# graph -- `click` being the exact package semgrep held at a vulnerable pin -- and resolves
|
|
99
|
+
# click 8.4.2, not the 8.1.8 that carries PYSEC-2026-2132. `make security` is green with it.
|
|
100
|
+
# Pinned exactly because this tool is a GATE: layer parsing, `exhaustive` and
|
|
101
|
+
# `exclude_type_checking_imports` are version-dependent, so a silent minor bump would change
|
|
102
|
+
# what the contract means, not just how it runs.
|
|
103
|
+
"import-linter==2.14",
|
|
104
|
+
"pre-commit>=4.6.1",
|
|
105
|
+
"cyclonedx-bom>=7.3.1",
|
|
106
|
+
"types-pyyaml>=6.0.12.20260724",
|
|
107
|
+
# semgrep is NOT a project dependency -- it is a TOOL, and it is pinned and run in isolation by
|
|
108
|
+
# the Makefile (`uvx semgrep==...`), exactly as osv-scanner is (`go run ...@v2.3.8`). It was a dev
|
|
109
|
+
# dependency until #126: it pins `click~=8.1.8`, and click 8.1.8 carries PYSEC-2026-2132, so a
|
|
110
|
+
# non-shipping scanner was holding a CVE inside the project's own dependency graph and failing the
|
|
111
|
+
# gate it exists to serve. Even semgrep's latest release (1.169.0) still carries that pin, so no
|
|
112
|
+
# bump fixes it -- the tool simply does not belong in the graph.
|
|
113
|
+
# cryptography moved to [project].dependencies for ADR-0042 (the SPKI pin needs it at
|
|
114
|
+
# runtime); tests/test_token_minter.py and the pinned-transport tests keep using it from there.
|
|
115
|
+
]
|
|
116
|
+
|
|
117
|
+
[tool.hatch.version]
|
|
118
|
+
# ADR-0205 D3. The version comes from the nearest `v*` tag; `autoops.__version__` reads it back out
|
|
119
|
+
# of the installed distribution's metadata at runtime.
|
|
120
|
+
source = "vcs"
|
|
121
|
+
# BOTH the describe glob AND the regex are constrained to `v*`, and BOTH are load-bearing. This
|
|
122
|
+
# tree carries 15 non-release tags -- `gate-combined-8dc7c554`, `archive/estate-gate-6ee92ef`,
|
|
123
|
+
# `rescue/worktree-prune-2026-08-25/...` -- and setuptools-scm's DEFAULT_DESCRIBE glob is
|
|
124
|
+
# `*[0-9]*`, which matches them.
|
|
125
|
+
#
|
|
126
|
+
# ⚑ MEASURED end to end on 2026-08-31, in a scratch repository holding `v0.1.0` and then
|
|
127
|
+
# `gate-combined-8dc7c554` one commit later, exactly the shape a merge would produce here:
|
|
128
|
+
#
|
|
129
|
+
# git describe --tags --long --match '*[0-9]*' -> gate-combined-8dc7c554-0-g528b1e0
|
|
130
|
+
# git describe --tags --long --match 'v[0-9]*' -> v0.1.0-1-g528b1e0
|
|
131
|
+
# uv build, WITH these two lines -> autoops-0.1.1.dev1+g528b1e09-py3-none-any.whl
|
|
132
|
+
# uv build, with the defaults -> ValueError: Error getting the version from source
|
|
133
|
+
# `vcs`: Can't parse version from tag
|
|
134
|
+
# 'gate-combined-8dc7c554'
|
|
135
|
+
#
|
|
136
|
+
# So the default configuration REFUSES rather than lying, which is the better of the two failures
|
|
137
|
+
# -- but it refuses at release time, on a tag push, with the release half-made. `tag-pattern`
|
|
138
|
+
# alone cannot prevent it: `git describe` has already chosen the wrong tag by the time the regex
|
|
139
|
+
# sees the result, and a tag the regex rejects is an error, not a fallback.
|
|
140
|
+
#
|
|
141
|
+
# A LATENT trap today, not an active one: `git tag --merged HEAD` is empty, so none of the 15 is
|
|
142
|
+
# reachable from this branch yet. It is closed now because the merge that makes one reachable will
|
|
143
|
+
# not announce itself.
|
|
144
|
+
tag-pattern = '^v(?P<version>[0-9]+\.[0-9]+\.[0-9]+.*)$'
|
|
145
|
+
raw-options = { git_describe_command = [
|
|
146
|
+
"git", "describe", "--dirty", "--tags", "--long", "--match", "v[0-9]*", "--abbrev=8",
|
|
147
|
+
] }
|
|
148
|
+
# Used ONLY where there is neither VCS metadata nor sdist PKG-INFO -- the container build, whose
|
|
149
|
+
# context excludes `.git` (`.dockerignore`). Declared here so the fallback has exactly one home
|
|
150
|
+
# rather than being duplicated into the Dockerfile. `.github/workflows/release.yml` ASSERTS the
|
|
151
|
+
# built wheel carries the pushed tag, so this string can never silently reach PyPI.
|
|
152
|
+
fallback-version = "0.1.0.dev0"
|
|
153
|
+
|
|
154
|
+
[tool.hatch.build.targets.wheel]
|
|
155
|
+
packages = ["src/autoops"]
|
|
156
|
+
|
|
157
|
+
[tool.hatch.build.targets.sdist]
|
|
158
|
+
# ⚑ DENY BY DEFAULT, exactly as `.dockerignore` does for the image (ADR-0205 D2), and for the same
|
|
159
|
+
# reason. The wheel target above bounds the wheel; nothing bounded the sdist, and hatchling's
|
|
160
|
+
# default sdist is the whole project directory. Measured before this section existed:
|
|
161
|
+
#
|
|
162
|
+
# autoops_sre-*.tar.gz 120,019,386 bytes vs the wheel's 1,590,905
|
|
163
|
+
# evidence/ 1,934 entries · artifacts/ 1,677 · docs/ 1,321 · deploy/ 562 · tests/ 416 · src/ 222
|
|
164
|
+
# 393 files inside it carrying the production control-plane IP
|
|
165
|
+
#
|
|
166
|
+
# `uv build` builds the sdist and then builds the WHEEL FROM IT, so an over-narrow list here fails
|
|
167
|
+
# the build loudly rather than shipping something short. These are the same five paths the image
|
|
168
|
+
# ships, which keeps one answer to "what leaves this repository" instead of two.
|
|
169
|
+
include = ["/src", "/README.md", "/LICENSE", "/uv.lock"]
|
|
170
|
+
|
|
171
|
+
[tool.ruff]
|
|
172
|
+
line-length = 100
|
|
173
|
+
target-version = "py312"
|
|
174
|
+
# `operators/` is out-of-tree live-crossing code (NOT shipped in the wheel), held to the same lint
|
|
175
|
+
# bar as `src`/`tests` — see operators/__init__.py for why it lives outside `src/`.
|
|
176
|
+
src = ["src", "tests", "operators"]
|
|
177
|
+
|
|
178
|
+
[tool.ruff.lint]
|
|
179
|
+
select = ["E", "F", "W", "I", "N", "UP", "B", "S", "C4", "C90", "SIM", "RUF"]
|
|
180
|
+
# S101 (assert) is expected in tests; S603/S607 reviewed case-by-case when subprocess lands.
|
|
181
|
+
|
|
182
|
+
[tool.ruff.lint.per-file-ignores]
|
|
183
|
+
"tests/**" = ["S101"]
|
|
184
|
+
|
|
185
|
+
[tool.ruff.lint.mccabe]
|
|
186
|
+
max-complexity = 10
|
|
187
|
+
|
|
188
|
+
[tool.mypy]
|
|
189
|
+
python_version = "3.12"
|
|
190
|
+
strict = true
|
|
191
|
+
warn_unreachable = true
|
|
192
|
+
warn_redundant_casts = true
|
|
193
|
+
plugins = ["pydantic.mypy"]
|
|
194
|
+
# `operators/` (the out-of-`src/` live-crossing transport) is type-checked strictly alongside `src`.
|
|
195
|
+
files = ["src", "operators"]
|
|
196
|
+
|
|
197
|
+
[[tool.mypy.overrides]]
|
|
198
|
+
# aiopslab is the cluster-only benchmark dependency, imported lazily by eval/runner.py and not
|
|
199
|
+
# installed in CI (it needs a live Kubernetes cluster). Don't fail strict mode on its absence.
|
|
200
|
+
module = ["aiopslab.*"]
|
|
201
|
+
ignore_missing_imports = true
|
|
202
|
+
|
|
203
|
+
[[tool.mypy.overrides]]
|
|
204
|
+
# cedarpy ships py.typed + inline annotations, so this is belt-and-braces in case a future
|
|
205
|
+
# release drops them. The Cedar PDP (policy/cedar_guard.py) is the only importer.
|
|
206
|
+
module = ["cedarpy.*"]
|
|
207
|
+
ignore_missing_imports = true
|
|
208
|
+
|
|
209
|
+
[tool.pytest.ini_options]
|
|
210
|
+
testpaths = ["tests"]
|
|
211
|
+
# Repo root on the path so tests can import the out-of-`src/` `operators` package. Coverage stays
|
|
212
|
+
# scoped to `autoops` (below), so operator code is exercised but never counts toward the 90% gate.
|
|
213
|
+
pythonpath = ["."]
|
|
214
|
+
addopts = "--cov=autoops --cov-report=term-missing --cov-fail-under=90 -q"
|
|
215
|
+
|
|
216
|
+
[tool.coverage.run]
|
|
217
|
+
source = ["autoops"]
|
|
218
|
+
branch = true
|
|
219
|
+
|
|
220
|
+
[tool.bandit]
|
|
221
|
+
exclude_dirs = ["tests"]
|