cloudfall 0.4.0__tar.gz → 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 (295) hide show
  1. {cloudfall-0.4.0 → cloudfall-0.5.1}/CHANGELOG.md +39 -0
  2. {cloudfall-0.4.0 → cloudfall-0.5.1}/PKG-INFO +1 -1
  3. cloudfall-0.5.1/config/schemas/v1/operation-decision.schema.json +368 -0
  4. cloudfall-0.5.1/config/schemas/v1/operation.schema.json +145 -0
  5. {cloudfall-0.4.0 → cloudfall-0.5.1}/pyproject.toml +1 -1
  6. cloudfall-0.5.1/sdk/src/cloudfall/catalog.py +368 -0
  7. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/cli.py +264 -6
  8. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/commands.py +31 -0
  9. cloudfall-0.5.1/sdk/src/cloudfall/decision.py +850 -0
  10. cloudfall-0.5.1/sdk/src/cloudfall/fleet_tools.py +249 -0
  11. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/mcp_server.py +242 -2
  12. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/validation.py +9 -0
  13. cloudfall-0.5.1/sdk/tests/test_catalog.py +254 -0
  14. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/tests/test_commands.py +8 -1
  15. cloudfall-0.5.1/sdk/tests/test_decision.py +717 -0
  16. cloudfall-0.5.1/sdk/tests/test_fleet_tools.py +301 -0
  17. {cloudfall-0.4.0 → cloudfall-0.5.1}/uv.lock +1 -1
  18. {cloudfall-0.4.0 → cloudfall-0.5.1}/.ansible-lint +0 -0
  19. {cloudfall-0.4.0 → cloudfall-0.5.1}/.github/workflows/ci.yml +0 -0
  20. {cloudfall-0.4.0 → cloudfall-0.5.1}/.github/workflows/release.yml +0 -0
  21. {cloudfall-0.4.0 → cloudfall-0.5.1}/.gitignore +0 -0
  22. {cloudfall-0.4.0 → cloudfall-0.5.1}/ARCHITECTURE.md +0 -0
  23. {cloudfall-0.4.0 → cloudfall-0.5.1}/CONTRIBUTING.md +0 -0
  24. {cloudfall-0.4.0 → cloudfall-0.5.1}/LICENSE +0 -0
  25. {cloudfall-0.4.0 → cloudfall-0.5.1}/MANIFESTO.md +0 -0
  26. {cloudfall-0.4.0 → cloudfall-0.5.1}/README.md +0 -0
  27. {cloudfall-0.4.0 → cloudfall-0.5.1}/ROADMAP.md +0 -0
  28. {cloudfall-0.4.0 → cloudfall-0.5.1}/SECURITY.md +0 -0
  29. {cloudfall-0.4.0 → cloudfall-0.5.1}/Taskfile.yml +0 -0
  30. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/README.md +0 -0
  31. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/examples/alert-rules/postgresql-down.yaml +0 -0
  32. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/examples/applications/crm.yaml +0 -0
  33. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/examples/components/crm-backend.yaml +0 -0
  34. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/examples/domains/crm-site.yaml +0 -0
  35. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/examples/logging-stacks/operations.yaml +0 -0
  36. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/examples/operator-policies/production.yaml +0 -0
  37. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/examples/server-types/debian-application.yaml +0 -0
  38. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/examples/servers/h1.yaml +0 -0
  39. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/examples/servers/h2.yaml +0 -0
  40. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/examples/services/postgresql-main.yaml +0 -0
  41. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/examples/services/redis-cache.yaml +0 -0
  42. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/examples/ssh-public-keys/example-admin.yaml +0 -0
  43. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/schemas/v1/alert-rule.schema.json +0 -0
  44. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/schemas/v1/application.schema.json +0 -0
  45. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/schemas/v1/artifact.schema.json +0 -0
  46. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/schemas/v1/backup-receipt.schema.json +0 -0
  47. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/schemas/v1/common.schema.json +0 -0
  48. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/schemas/v1/component.schema.json +0 -0
  49. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/schemas/v1/deployment-receipt.schema.json +0 -0
  50. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/schemas/v1/domain.schema.json +0 -0
  51. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/schemas/v1/environment-receipt.schema.json +0 -0
  52. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/schemas/v1/logging-stack.schema.json +0 -0
  53. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/schemas/v1/observed-domain.schema.json +0 -0
  54. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/schemas/v1/observed-server.schema.json +0 -0
  55. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/schemas/v1/operator-policy.schema.json +0 -0
  56. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/schemas/v1/operator-proposal.schema.json +0 -0
  57. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/schemas/v1/release-receipt.schema.json +0 -0
  58. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/schemas/v1/server-type.schema.json +0 -0
  59. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/schemas/v1/server.schema.json +0 -0
  60. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/schemas/v1/service.schema.json +0 -0
  61. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/schemas/v1/ssh-public-key.schema.json +0 -0
  62. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/tests/invalid/missing-server/applications/crm.yaml +0 -0
  63. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/tests/invalid/missing-server/components/crm-backend.yaml +0 -0
  64. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/tests/invalid/missing-server/server-types/debian-application.yaml +0 -0
  65. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/tests/invalid/missing-server/servers/h1.yaml +0 -0
  66. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/tests/invalid/schema/components/component-unknown-field.yaml +0 -0
  67. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/tests/observed/compliant/h1.json +0 -0
  68. {cloudfall-0.4.0 → cloudfall-0.5.1}/config/tests/observed/compliant/h2.json +0 -0
  69. {cloudfall-0.4.0 → cloudfall-0.5.1}/docs/ansible-context.md +0 -0
  70. {cloudfall-0.4.0 → cloudfall-0.5.1}/docs/availability-design.md +0 -0
  71. {cloudfall-0.4.0 → cloudfall-0.5.1}/docs/brownfield-design.md +0 -0
  72. {cloudfall-0.4.0 → cloudfall-0.5.1}/docs/decisions/2026-09-14-no-ansible-replacement.md +0 -0
  73. {cloudfall-0.4.0 → cloudfall-0.5.1}/docs/decisions/2026-09-14-no-nixos-base.md +0 -0
  74. {cloudfall-0.4.0 → cloudfall-0.5.1}/docs/decisions/2026-09-14-no-rust-rewrite.md +0 -0
  75. {cloudfall-0.4.0 → cloudfall-0.5.1}/docs/fleet-goals.md +0 -0
  76. {cloudfall-0.4.0 → cloudfall-0.5.1}/docs/hybrid-storage-design.md +0 -0
  77. {cloudfall-0.4.0 → cloudfall-0.5.1}/docs/landscape.md +0 -0
  78. {cloudfall-0.4.0 → cloudfall-0.5.1}/docs/logging-service-guide.md +0 -0
  79. {cloudfall-0.4.0 → cloudfall-0.5.1}/docs/neon-migration-guide.md +0 -0
  80. {cloudfall-0.4.0 → cloudfall-0.5.1}/docs/new-server-storage-guide.md +0 -0
  81. {cloudfall-0.4.0 → cloudfall-0.5.1}/docs/operator-guide.md +0 -0
  82. {cloudfall-0.4.0 → cloudfall-0.5.1}/docs/proving-runs/2026-09-08-debian-container-m1.md +0 -0
  83. {cloudfall-0.4.0 → cloudfall-0.5.1}/docs/proving-runs/2026-09-08-dns-cutover.md +0 -0
  84. {cloudfall-0.4.0 → cloudfall-0.5.1}/docs/proving-runs/2026-09-08-guided-data-migration.md +0 -0
  85. {cloudfall-0.4.0 → cloudfall-0.5.1}/docs/proving-runs/2026-09-08-hetzner-m1.md +0 -0
  86. {cloudfall-0.4.0 → cloudfall-0.5.1}/docs/proving-runs/2026-09-08-hetzner-m2-m3.md +0 -0
  87. {cloudfall-0.4.0 → cloudfall-0.5.1}/docs/proving-runs/2026-09-08-hetzner-m4-m5.md +0 -0
  88. {cloudfall-0.4.0 → cloudfall-0.5.1}/docs/proving-runs/2026-09-08-render-cutover.md +0 -0
  89. {cloudfall-0.4.0 → cloudfall-0.5.1}/docs/proving-runs/2026-09-10-hetzner-m7.md +0 -0
  90. {cloudfall-0.4.0 → cloudfall-0.5.1}/docs/proving-runs/2026-09-10-hetzner-m8.md +0 -0
  91. {cloudfall-0.4.0 → cloudfall-0.5.1}/docs/proving-runs/2026-09-10-hetzner-m9.md +0 -0
  92. {cloudfall-0.4.0 → cloudfall-0.5.1}/docs/proving-runs/2026-09-11-hetzner-m10.md +0 -0
  93. {cloudfall-0.4.0 → cloudfall-0.5.1}/docs/render-migration-guide.md +0 -0
  94. {cloudfall-0.4.0 → cloudfall-0.5.1}/docs/secrets-guide.md +0 -0
  95. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/README.md +0 -0
  96. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/ansible.cfg +0 -0
  97. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/playbooks/backup.yml +0 -0
  98. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/playbooks/baseline.yml +0 -0
  99. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/playbooks/bootstrap.yml +0 -0
  100. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/playbooks/data.yml +0 -0
  101. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/playbooks/deploy.yml +0 -0
  102. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/playbooks/domains.yml +0 -0
  103. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/playbooks/health.yml +0 -0
  104. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/playbooks/inspect.yml +0 -0
  105. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/playbooks/logging.yml +0 -0
  106. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/playbooks/restart.yml +0 -0
  107. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/playbooks/rollback.yml +0 -0
  108. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/playbooks/services.yml +0 -0
  109. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/playbooks/time.yml +0 -0
  110. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_access/defaults/main.yml +0 -0
  111. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_access/handlers/main.yml +0 -0
  112. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_access/meta/argument_specs.yml +0 -0
  113. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_access/meta/main.yml +0 -0
  114. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_access/tasks/main.yml +0 -0
  115. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_bootstrap/defaults/main.yml +0 -0
  116. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_bootstrap/meta/argument_specs.yml +0 -0
  117. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_bootstrap/meta/main.yml +0 -0
  118. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_bootstrap/tasks/main.yml +0 -0
  119. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_data_migration/defaults/main.yml +0 -0
  120. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_data_migration/meta/argument_specs.yml +0 -0
  121. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_data_migration/meta/main.yml +0 -0
  122. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_data_migration/tasks/main.yml +0 -0
  123. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_deploy/defaults/main.yml +0 -0
  124. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_deploy/meta/argument_specs.yml +0 -0
  125. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_deploy/meta/main.yml +0 -0
  126. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_deploy/tasks/health.yml +0 -0
  127. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_deploy/tasks/health_gate.yml +0 -0
  128. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_deploy/tasks/main.yml +0 -0
  129. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_deploy/tasks/restart.yml +0 -0
  130. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_deploy/tasks/rollback.yml +0 -0
  131. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_deploy/templates/component.service.j2 +0 -0
  132. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_firewall/defaults/main.yml +0 -0
  133. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_firewall/handlers/main.yml +0 -0
  134. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_firewall/meta/argument_specs.yml +0 -0
  135. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_firewall/meta/main.yml +0 -0
  136. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_firewall/tasks/main.yml +0 -0
  137. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_firewall/templates/nftables.conf.j2 +0 -0
  138. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_inspect/defaults/main.yml +0 -0
  139. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_inspect/meta/argument_specs.yml +0 -0
  140. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_inspect/meta/main.yml +0 -0
  141. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_inspect/tasks/main.yml +0 -0
  142. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_logging_backend/defaults/main.yml +0 -0
  143. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_logging_backend/handlers/main.yml +0 -0
  144. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_logging_backend/meta/argument_specs.yml +0 -0
  145. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_logging_backend/meta/main.yml +0 -0
  146. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_logging_backend/tasks/main.yml +0 -0
  147. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_logging_backend/templates/alertmanager-defaults.j2 +0 -0
  148. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_logging_backend/templates/alertmanager.yaml.j2 +0 -0
  149. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_logging_backend/templates/grafana.ini.j2 +0 -0
  150. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_logging_backend/templates/loki-datasource.yml.j2 +0 -0
  151. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_logging_backend/templates/loki-systemd-override.conf.j2 +0 -0
  152. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_logging_backend/templates/loki.yaml.j2 +0 -0
  153. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_logging_backend/templates/nginx-loki-gateway.conf.j2 +0 -0
  154. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_logging_backend/templates/prometheus-datasource.yml.j2 +0 -0
  155. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_logging_backend/templates/prometheus-defaults.j2 +0 -0
  156. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_logging_backend/templates/prometheus-rules.yaml.j2 +0 -0
  157. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_logging_backend/templates/prometheus.yaml.j2 +0 -0
  158. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_logging_collector/defaults/main.yml +0 -0
  159. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_logging_collector/handlers/main.yml +0 -0
  160. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_logging_collector/meta/argument_specs.yml +0 -0
  161. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_logging_collector/meta/main.yml +0 -0
  162. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_logging_collector/tasks/main.yml +0 -0
  163. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_logging_collector/templates/alloy-systemd-override.conf.j2 +0 -0
  164. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_logging_collector/templates/config.alloy.j2 +0 -0
  165. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_nginx_site/defaults/main.yml +0 -0
  166. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_nginx_site/handlers/main.yml +0 -0
  167. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_nginx_site/meta/argument_specs.yml +0 -0
  168. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_nginx_site/meta/main.yml +0 -0
  169. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_nginx_site/tasks/main.yml +0 -0
  170. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_nginx_site/templates/domain-site.conf.j2 +0 -0
  171. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_postgresql/defaults/main.yml +0 -0
  172. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_postgresql/handlers/main.yml +0 -0
  173. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_postgresql/meta/argument_specs.yml +0 -0
  174. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_postgresql/meta/main.yml +0 -0
  175. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_postgresql/tasks/main.yml +0 -0
  176. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_postgresql/templates/backup.service.j2 +0 -0
  177. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_postgresql/templates/backup.sh.j2 +0 -0
  178. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_postgresql/templates/backup.timer.j2 +0 -0
  179. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_postgresql/templates/cloudfall.conf.j2 +0 -0
  180. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_postgresql/templates/restore-check.service.j2 +0 -0
  181. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_postgresql/templates/restore-check.sh.j2 +0 -0
  182. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_postgresql/templates/restore-check.timer.j2 +0 -0
  183. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_redis/defaults/main.yml +0 -0
  184. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_redis/handlers/main.yml +0 -0
  185. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_redis/meta/argument_specs.yml +0 -0
  186. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_redis/meta/main.yml +0 -0
  187. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_redis/tasks/main.yml +0 -0
  188. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_redis/templates/backup.service.j2 +0 -0
  189. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_redis/templates/backup.sh.j2 +0 -0
  190. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_redis/templates/backup.timer.j2 +0 -0
  191. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_redis/templates/cloudfall.conf.j2 +0 -0
  192. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_redis/templates/restore-check.service.j2 +0 -0
  193. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_redis/templates/restore-check.sh.j2 +0 -0
  194. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_redis/templates/restore-check.timer.j2 +0 -0
  195. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_time/defaults/main.yml +0 -0
  196. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_time/meta/argument_specs.yml +0 -0
  197. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_time/meta/main.yml +0 -0
  198. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_time/tasks/main.yml +0 -0
  199. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_unattended_upgrades/defaults/main.yml +0 -0
  200. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_unattended_upgrades/meta/argument_specs.yml +0 -0
  201. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_unattended_upgrades/meta/main.yml +0 -0
  202. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/ansible/roles/cloudfall_unattended_upgrades/tasks/main.yml +0 -0
  203. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/src/cloudfall_engine/__init__.py +0 -0
  204. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/src/cloudfall_engine/__main__.py +0 -0
  205. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/src/cloudfall_engine/ansible_inventory.py +0 -0
  206. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/src/cloudfall_engine/artifact.py +0 -0
  207. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/src/cloudfall_engine/cli.py +0 -0
  208. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/src/cloudfall_engine/playbook.py +0 -0
  209. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/src/cloudfall_engine/py.typed +0 -0
  210. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/tests/test_ansible_inventory.py +0 -0
  211. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/tests/test_artifact_builder.py +0 -0
  212. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/tests/test_deploy_templates.py +0 -0
  213. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/tests/test_firewall_templates.py +0 -0
  214. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/tests/test_logging_templates.py +0 -0
  215. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/tests/test_nginx_site_templates.py +0 -0
  216. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/tests/test_playbook.py +0 -0
  217. {cloudfall-0.4.0 → cloudfall-0.5.1}/engine/tests/test_postgresql_templates.py +0 -0
  218. {cloudfall-0.4.0 → cloudfall-0.5.1}/evaluations/cloudfall/README.md +0 -0
  219. {cloudfall-0.4.0 → cloudfall-0.5.1}/evaluations/cloudfall/environment.md +0 -0
  220. {cloudfall-0.4.0 → cloudfall-0.5.1}/evaluations/cloudfall/findings.md +0 -0
  221. {cloudfall-0.4.0 → cloudfall-0.5.1}/evaluations/cloudfall/issues.md +0 -0
  222. {cloudfall-0.4.0 → cloudfall-0.5.1}/evaluations/cloudfall/linkedin.md +0 -0
  223. {cloudfall-0.4.0 → cloudfall-0.5.1}/evaluations/cloudfall/readiness.md +0 -0
  224. {cloudfall-0.4.0 → cloudfall-0.5.1}/evaluations/cloudfall/report-agent-dev.md +0 -0
  225. {cloudfall-0.4.0 → cloudfall-0.5.1}/evaluations/cloudfall/report-dev.md +0 -0
  226. {cloudfall-0.4.0 → cloudfall-0.5.1}/evaluations/cloudfall/report-index.md +0 -0
  227. {cloudfall-0.4.0 → cloudfall-0.5.1}/evaluations/cloudfall/report-issues.md +0 -0
  228. {cloudfall-0.4.0 → cloudfall-0.5.1}/evaluations/cloudfall/report-runtime.md +0 -0
  229. {cloudfall-0.4.0 → cloudfall-0.5.1}/evaluations/cloudfall/trace.md +0 -0
  230. {cloudfall-0.4.0 → cloudfall-0.5.1}/evaluations/cloudfall/x.md +0 -0
  231. {cloudfall-0.4.0 → cloudfall-0.5.1}/examples/render-demo/README.md +0 -0
  232. {cloudfall-0.4.0 → cloudfall-0.5.1}/examples/render-demo/pyproject.toml +0 -0
  233. {cloudfall-0.4.0 → cloudfall-0.5.1}/examples/render-demo/render.yaml +0 -0
  234. {cloudfall-0.4.0 → cloudfall-0.5.1}/examples/render-demo/src/demo/__init__.py +0 -0
  235. {cloudfall-0.4.0 → cloudfall-0.5.1}/examples/render-demo/src/demo/asgi.py +0 -0
  236. {cloudfall-0.4.0 → cloudfall-0.5.1}/examples/render-demo/uv.lock +0 -0
  237. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/README.md +0 -0
  238. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/__init__.py +0 -0
  239. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/__main__.py +0 -0
  240. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/agent_tools.py +0 -0
  241. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/ansible_api.py +0 -0
  242. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/ansible_reader.py +0 -0
  243. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/arguments.py +0 -0
  244. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/audit.py +0 -0
  245. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/authoring.py +0 -0
  246. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/cutover.py +0 -0
  247. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/dashboard.py +0 -0
  248. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/dashboard_server.py +0 -0
  249. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/domain.py +0 -0
  250. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/importer.py +0 -0
  251. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/inventory.py +0 -0
  252. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/lifecycle.py +0 -0
  253. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/migrate.py +0 -0
  254. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/observation.py +0 -0
  255. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/observe.py +0 -0
  256. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/operations.py +0 -0
  257. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/operator.py +0 -0
  258. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/project.py +0 -0
  259. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/py.typed +0 -0
  260. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/render_api.py +0 -0
  261. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/resources.py +0 -0
  262. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/secrets.py +0 -0
  263. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/src/cloudfall/service_evidence.py +0 -0
  264. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/tests/test_agent_tools.py +0 -0
  265. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/tests/test_ansible_reader.py +0 -0
  266. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/tests/test_arguments.py +0 -0
  267. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/tests/test_audit.py +0 -0
  268. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/tests/test_authoring.py +0 -0
  269. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/tests/test_cutover.py +0 -0
  270. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/tests/test_dashboard_server.py +0 -0
  271. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/tests/test_data_migration.py +0 -0
  272. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/tests/test_importer.py +0 -0
  273. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/tests/test_inventory.py +0 -0
  274. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/tests/test_lifecycle.py +0 -0
  275. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/tests/test_migrate.py +0 -0
  276. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/tests/test_observe.py +0 -0
  277. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/tests/test_operations_dashboard.py +0 -0
  278. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/tests/test_operator.py +0 -0
  279. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/tests/test_project.py +0 -0
  280. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/tests/test_render_api.py +0 -0
  281. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/tests/test_resources.py +0 -0
  282. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/tests/test_secrets.py +0 -0
  283. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/tests/test_service_evidence.py +0 -0
  284. {cloudfall-0.4.0 → cloudfall-0.5.1}/sdk/tests/test_validation.py +0 -0
  285. {cloudfall-0.4.0 → cloudfall-0.5.1}/site/public/apple-touch-icon.png +0 -0
  286. {cloudfall-0.4.0 → cloudfall-0.5.1}/site/public/favicon-32.png +0 -0
  287. {cloudfall-0.4.0 → cloudfall-0.5.1}/site/public/favicon.svg +0 -0
  288. {cloudfall-0.4.0 → cloudfall-0.5.1}/site/public/icon-192.png +0 -0
  289. {cloudfall-0.4.0 → cloudfall-0.5.1}/site/public/icon-512.png +0 -0
  290. {cloudfall-0.4.0 → cloudfall-0.5.1}/site/public/index.html +0 -0
  291. {cloudfall-0.4.0 → cloudfall-0.5.1}/site/public/manifesto.html +0 -0
  292. {cloudfall-0.4.0 → cloudfall-0.5.1}/site/public/og.png +0 -0
  293. {cloudfall-0.4.0 → cloudfall-0.5.1}/site/public/site.webmanifest +0 -0
  294. {cloudfall-0.4.0 → cloudfall-0.5.1}/site/src/worker.js +0 -0
  295. {cloudfall-0.4.0 → cloudfall-0.5.1}/site/wrangler.jsonc +0 -0
@@ -6,6 +6,29 @@ Notable changes to Cloudfall. The format follows
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.5.1] — 2026-09-22
10
+
11
+ ### Changed
12
+
13
+ - Decision records default to `decisions/` beside the operations rather
14
+ than to `tmp/decisions`: the record is what a team keeps, and `tmp/` is
15
+ what they throw away. The diffs and logs beside each record are raw
16
+ Ansible output, so a repository that commits them wants `no_log` on the
17
+ tasks that handle secrets
18
+
19
+ ### Fixed
20
+
21
+ - A decision is `verified` only when its verify run changed nothing. A
22
+ verify step that exits zero while changing a host found the fleet not as
23
+ the run left it and converged it further, which verifies nothing, so it
24
+ is recorded `failed`. Every approved decision now carries a `verdict`
25
+ saying why it ended where it did
26
+ - A record cites its artifacts and its observation basis as the repository
27
+ sees them rather than by absolute path, because a record is committed
28
+ and one machine's home directory means nothing in anyone else's checkout
29
+
30
+ ## [0.5.0] — 2026-09-21
31
+
9
32
  ## [0.4.0] — 2026-09-21
10
33
 
11
34
  ### Added
@@ -31,6 +54,22 @@ Notable changes to Cloudfall. The format follows
31
54
  - `StateValidator.validate_documents` validates resource documents
32
55
  assembled in memory, with the schemas, reference checks and error codes
33
56
  documents on disk get
57
+ - The operations catalog: every playbook the team runs is declared in
58
+ `operations/` with a risk level, a target scope, typed inputs,
59
+ preconditions and a verify step, and `cloudfall operations list|show`
60
+ reads it. A playbook nobody declared is not an operation
61
+ - The gate and the record: `cloudfall operations propose` runs an
62
+ operation in check mode and records the operation, targets, inputs, the
63
+ evidence it was based on and the diff by sha256;
64
+ `cloudfall operations approve --yes` records the approver, runs it, runs
65
+ the verify playbook and closes the record as executed, verified or
66
+ failed; `cloudfall operations decisions` reads the trail without the
67
+ catalog
68
+ - The agent surface: `cloudfall-mcp --repository` serves a brownfield
69
+ repository, where the tool list is the catalog. Each declared operation
70
+ is one tool carrying its risk as MCP annotations, calling it runs check
71
+ mode and records a proposal, and no tool approves anything: that stays a
72
+ command a person runs
34
73
 
35
74
  ## [0.3.0] — 2026-09-20
36
75
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: cloudfall
3
- Version: 0.4.0
3
+ Version: 0.5.1
4
4
  Summary: AI-native control plane for dedicated Debian application fleets
5
5
  Project-URL: Homepage, https://cloudfall.dev
6
6
  Project-URL: Repository, https://github.com/romamo/cloudfall
@@ -0,0 +1,368 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://cloudfall.internal/schemas/v1/operation-decision.schema.json",
4
+ "title": "Cloudfall operation decision",
5
+ "description": "What an agent proposed, what check mode showed, who let it, and what came of it.",
6
+ "type": "object",
7
+ "properties": {
8
+ "apiVersion": {
9
+ "$ref": "common.schema.json#/$defs/apiVersion"
10
+ },
11
+ "kind": {
12
+ "const": "OperationDecision"
13
+ },
14
+ "metadata": {
15
+ "$ref": "common.schema.json#/$defs/metadata"
16
+ },
17
+ "spec": {
18
+ "type": "object",
19
+ "properties": {
20
+ "proposedAt": {
21
+ "type": "string",
22
+ "format": "date-time"
23
+ },
24
+ "operation": {
25
+ "type": "object",
26
+ "properties": {
27
+ "id": {
28
+ "$ref": "common.schema.json#/$defs/resourceId"
29
+ },
30
+ "playbook": {
31
+ "type": "string",
32
+ "minLength": 1,
33
+ "maxLength": 512
34
+ },
35
+ "risk": {
36
+ "enum": [
37
+ "read",
38
+ "mutating",
39
+ "destructive"
40
+ ]
41
+ },
42
+ "verifyPlaybook": {
43
+ "type": "string",
44
+ "minLength": 1,
45
+ "maxLength": 512
46
+ }
47
+ },
48
+ "required": [
49
+ "id",
50
+ "playbook",
51
+ "risk"
52
+ ],
53
+ "additionalProperties": false
54
+ },
55
+ "targets": {
56
+ "type": "object",
57
+ "properties": {
58
+ "scope": {
59
+ "enum": [
60
+ "fleet",
61
+ "group",
62
+ "host"
63
+ ]
64
+ },
65
+ "pattern": {
66
+ "type": "string",
67
+ "minLength": 1,
68
+ "maxLength": 200
69
+ }
70
+ },
71
+ "required": [
72
+ "scope"
73
+ ],
74
+ "additionalProperties": false
75
+ },
76
+ "inputs": {
77
+ "type": "object",
78
+ "additionalProperties": {
79
+ "type": [
80
+ "string",
81
+ "integer",
82
+ "boolean"
83
+ ]
84
+ }
85
+ },
86
+ "gate": {
87
+ "type": "object",
88
+ "properties": {
89
+ "requirement": {
90
+ "enum": [
91
+ "runs-freely",
92
+ "check-then-approve",
93
+ "human-required"
94
+ ]
95
+ },
96
+ "reason": {
97
+ "type": "string",
98
+ "minLength": 1,
99
+ "maxLength": 300
100
+ }
101
+ },
102
+ "required": [
103
+ "requirement",
104
+ "reason"
105
+ ],
106
+ "additionalProperties": false
107
+ },
108
+ "basis": {
109
+ "type": "object",
110
+ "description": "The fleet evidence the proposal was made against.",
111
+ "properties": {
112
+ "observations": {
113
+ "type": "string",
114
+ "minLength": 1,
115
+ "maxLength": 512
116
+ },
117
+ "observedAt": {
118
+ "type": "object",
119
+ "additionalProperties": {
120
+ "type": "string",
121
+ "format": "date-time"
122
+ }
123
+ }
124
+ },
125
+ "required": [
126
+ "observations",
127
+ "observedAt"
128
+ ],
129
+ "additionalProperties": false
130
+ },
131
+ "check": {
132
+ "type": "object",
133
+ "description": "What check mode reported before any change was made.",
134
+ "properties": {
135
+ "exitCode": {
136
+ "type": "integer",
137
+ "minimum": 0,
138
+ "maximum": 255
139
+ },
140
+ "changed": {
141
+ "type": "array",
142
+ "items": {
143
+ "type": "string",
144
+ "minLength": 1,
145
+ "maxLength": 253
146
+ }
147
+ },
148
+ "unchanged": {
149
+ "type": "array",
150
+ "items": {
151
+ "type": "string",
152
+ "minLength": 1,
153
+ "maxLength": 253
154
+ }
155
+ },
156
+ "diff": {
157
+ "type": "object",
158
+ "properties": {
159
+ "path": {
160
+ "type": "string",
161
+ "minLength": 1,
162
+ "maxLength": 512
163
+ },
164
+ "sha256": {
165
+ "$ref": "common.schema.json#/$defs/sha256"
166
+ },
167
+ "bytes": {
168
+ "type": "integer",
169
+ "minimum": 0
170
+ }
171
+ },
172
+ "required": [
173
+ "path",
174
+ "sha256",
175
+ "bytes"
176
+ ],
177
+ "additionalProperties": false
178
+ }
179
+ },
180
+ "required": [
181
+ "exitCode",
182
+ "changed",
183
+ "unchanged",
184
+ "diff"
185
+ ],
186
+ "additionalProperties": false
187
+ },
188
+ "status": {
189
+ "enum": [
190
+ "proposed",
191
+ "approved",
192
+ "rejected",
193
+ "executed",
194
+ "verified",
195
+ "failed"
196
+ ]
197
+ },
198
+ "approval": {
199
+ "type": "object",
200
+ "properties": {
201
+ "approver": {
202
+ "type": "string",
203
+ "minLength": 1,
204
+ "maxLength": 128
205
+ },
206
+ "approvedAt": {
207
+ "type": "string",
208
+ "format": "date-time"
209
+ }
210
+ },
211
+ "required": [
212
+ "approver",
213
+ "approvedAt"
214
+ ],
215
+ "additionalProperties": false
216
+ },
217
+ "execution": {
218
+ "type": "object",
219
+ "properties": {
220
+ "ranAt": {
221
+ "type": "string",
222
+ "format": "date-time"
223
+ },
224
+ "exitCode": {
225
+ "type": "integer",
226
+ "minimum": 0,
227
+ "maximum": 255
228
+ },
229
+ "changed": {
230
+ "type": "array",
231
+ "items": {
232
+ "type": "string",
233
+ "minLength": 1,
234
+ "maxLength": 253
235
+ }
236
+ },
237
+ "unchanged": {
238
+ "type": "array",
239
+ "items": {
240
+ "type": "string",
241
+ "minLength": 1,
242
+ "maxLength": 253
243
+ }
244
+ },
245
+ "log": {
246
+ "type": "object",
247
+ "properties": {
248
+ "path": {
249
+ "type": "string",
250
+ "minLength": 1,
251
+ "maxLength": 512
252
+ },
253
+ "sha256": {
254
+ "$ref": "common.schema.json#/$defs/sha256"
255
+ },
256
+ "bytes": {
257
+ "type": "integer",
258
+ "minimum": 0
259
+ }
260
+ },
261
+ "required": [
262
+ "path",
263
+ "sha256",
264
+ "bytes"
265
+ ],
266
+ "additionalProperties": false
267
+ }
268
+ },
269
+ "required": [
270
+ "ranAt",
271
+ "exitCode",
272
+ "changed",
273
+ "unchanged",
274
+ "log"
275
+ ],
276
+ "additionalProperties": false,
277
+ "description": "What the approved run did."
278
+ },
279
+ "verify": {
280
+ "type": "object",
281
+ "properties": {
282
+ "ranAt": {
283
+ "type": "string",
284
+ "format": "date-time"
285
+ },
286
+ "exitCode": {
287
+ "type": "integer",
288
+ "minimum": 0,
289
+ "maximum": 255
290
+ },
291
+ "changed": {
292
+ "type": "array",
293
+ "items": {
294
+ "type": "string",
295
+ "minLength": 1,
296
+ "maxLength": 253
297
+ }
298
+ },
299
+ "unchanged": {
300
+ "type": "array",
301
+ "items": {
302
+ "type": "string",
303
+ "minLength": 1,
304
+ "maxLength": 253
305
+ }
306
+ },
307
+ "log": {
308
+ "type": "object",
309
+ "properties": {
310
+ "path": {
311
+ "type": "string",
312
+ "minLength": 1,
313
+ "maxLength": 512
314
+ },
315
+ "sha256": {
316
+ "$ref": "common.schema.json#/$defs/sha256"
317
+ },
318
+ "bytes": {
319
+ "type": "integer",
320
+ "minimum": 0
321
+ }
322
+ },
323
+ "required": [
324
+ "path",
325
+ "sha256",
326
+ "bytes"
327
+ ],
328
+ "additionalProperties": false
329
+ }
330
+ },
331
+ "required": [
332
+ "ranAt",
333
+ "exitCode",
334
+ "changed",
335
+ "unchanged",
336
+ "log"
337
+ ],
338
+ "additionalProperties": false,
339
+ "description": "What the operation's verify playbook reported afterwards."
340
+ },
341
+ "verdict": {
342
+ "type": "string",
343
+ "description": "Why the decision ended in its status.",
344
+ "minLength": 1,
345
+ "maxLength": 300
346
+ }
347
+ },
348
+ "required": [
349
+ "proposedAt",
350
+ "operation",
351
+ "targets",
352
+ "inputs",
353
+ "gate",
354
+ "basis",
355
+ "check",
356
+ "status"
357
+ ],
358
+ "additionalProperties": false
359
+ }
360
+ },
361
+ "required": [
362
+ "apiVersion",
363
+ "kind",
364
+ "metadata",
365
+ "spec"
366
+ ],
367
+ "additionalProperties": false
368
+ }
@@ -0,0 +1,145 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://cloudfall.internal/schemas/v1/operation.schema.json",
4
+ "title": "Cloudfall operation",
5
+ "description": "One playbook the team already runs, declared as an operation an agent may call.",
6
+ "type": "object",
7
+ "properties": {
8
+ "id": {
9
+ "$ref": "common.schema.json#/$defs/resourceId"
10
+ },
11
+ "description": {
12
+ "type": "string",
13
+ "minLength": 1,
14
+ "maxLength": 200,
15
+ "pattern": "^[^\\u0000-\\u001f\\u007f]+$"
16
+ },
17
+ "playbook": {
18
+ "$ref": "#/$defs/repositoryPath"
19
+ },
20
+ "risk": {
21
+ "enum": [
22
+ "read",
23
+ "mutating",
24
+ "destructive"
25
+ ]
26
+ },
27
+ "targets": {
28
+ "enum": [
29
+ "fleet",
30
+ "group",
31
+ "host"
32
+ ]
33
+ },
34
+ "inputs": {
35
+ "type": "object",
36
+ "propertyNames": {
37
+ "type": "string",
38
+ "pattern": "^[a-z][a-z0-9_]{0,63}$"
39
+ },
40
+ "additionalProperties": {
41
+ "oneOf": [
42
+ {
43
+ "$ref": "#/$defs/inputType"
44
+ },
45
+ {
46
+ "type": "object",
47
+ "properties": {
48
+ "type": {
49
+ "$ref": "#/$defs/inputType"
50
+ },
51
+ "required": {
52
+ "type": "boolean"
53
+ },
54
+ "description": {
55
+ "type": "string",
56
+ "minLength": 1,
57
+ "maxLength": 200,
58
+ "pattern": "^[^\\u0000-\\u001f\\u007f]+$"
59
+ }
60
+ },
61
+ "required": [
62
+ "type"
63
+ ],
64
+ "additionalProperties": false
65
+ }
66
+ ]
67
+ }
68
+ },
69
+ "preconditions": {
70
+ "type": "array",
71
+ "minItems": 1,
72
+ "items": {
73
+ "type": "object",
74
+ "properties": {
75
+ "health": {
76
+ "const": "ok"
77
+ }
78
+ },
79
+ "required": [
80
+ "health"
81
+ ],
82
+ "additionalProperties": false
83
+ }
84
+ },
85
+ "verify": {
86
+ "type": "object",
87
+ "properties": {
88
+ "playbook": {
89
+ "$ref": "#/$defs/repositoryPath"
90
+ }
91
+ },
92
+ "required": [
93
+ "playbook"
94
+ ],
95
+ "additionalProperties": false
96
+ }
97
+ },
98
+ "required": [
99
+ "id",
100
+ "playbook",
101
+ "risk",
102
+ "targets"
103
+ ],
104
+ "additionalProperties": false,
105
+ "allOf": [
106
+ {
107
+ "if": {
108
+ "properties": {
109
+ "risk": {
110
+ "enum": [
111
+ "mutating",
112
+ "destructive"
113
+ ]
114
+ }
115
+ },
116
+ "required": [
117
+ "risk"
118
+ ]
119
+ },
120
+ "then": {
121
+ "required": [
122
+ "verify"
123
+ ]
124
+ }
125
+ }
126
+ ],
127
+ "$defs": {
128
+ "inputType": {
129
+ "enum": [
130
+ "string",
131
+ "integer",
132
+ "boolean"
133
+ ]
134
+ },
135
+ "repositoryPath": {
136
+ "type": "string",
137
+ "minLength": 1,
138
+ "maxLength": 512,
139
+ "pattern": "^[A-Za-z0-9._][A-Za-z0-9._/-]*\\.ya?ml$",
140
+ "not": {
141
+ "pattern": "\\.\\."
142
+ }
143
+ }
144
+ }
145
+ }
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "cloudfall"
3
- version = "0.4.0"
3
+ version = "0.5.1"
4
4
  description = "AI-native control plane for dedicated Debian application fleets"
5
5
  readme = "README.md"
6
6
  license = "AGPL-3.0-or-later"