csrd-utils 0.4.0__tar.gz → 0.5.0__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 (245) hide show
  1. {csrd_utils-0.4.0 → csrd_utils-0.5.0}/PKG-INFO +2 -2
  2. {csrd_utils-0.4.0 → csrd_utils-0.5.0}/README.md +1 -1
  3. {csrd_utils-0.4.0 → csrd_utils-0.5.0}/pyproject.toml +1 -1
  4. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/AGENTS.md +4 -16
  5. csrd_utils-0.5.0/src/csrd_utils/__main__.py +341 -0
  6. {csrd_utils-0.4.0 → csrd_utils-0.5.0}/src/csrd_utils/audit.py +2 -1
  7. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/compose/__init__.py +4 -0
  8. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/compose/augments.py +485 -118
  9. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/compose/operations.py +27 -4
  10. csrd_utils-0.5.0/src/csrd_utils/compose/presets.py +198 -0
  11. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/compose/renderer.py +263 -32
  12. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/compose/scaffolder.py +7 -1
  13. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/compose/service_renderers.py +92 -8
  14. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/compose/yaml_editor.py +1 -2
  15. {csrd_utils-0.4.0 → csrd_utils-0.5.0}/src/csrd_utils/doctor.py +0 -5
  16. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/generate/handlers.py +738 -282
  17. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/generate/menu.py +4 -0
  18. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/models/__init__.py +3 -1
  19. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/models/spec.py +23 -0
  20. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/augments/auth-passthrough/delegates/auth_delegate.py +19 -0
  21. csrd_utils-0.5.0/src/csrd_utils/templates/augments/auth-passthrough/dependencies/__init__.py +0 -0
  22. csrd_utils-0.5.0/src/csrd_utils/templates/augments/auth-passthrough/models/__init__.py +0 -0
  23. csrd_utils-0.5.0/src/csrd_utils/templates/augments/auth-passthrough/views/__init__.py +0 -0
  24. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/augments/auth-passthrough/views/auth_passthrough_view.py +6 -2
  25. csrd_utils-0.5.0/src/csrd_utils/templates/augments/caching/dependencies/cache.py.template +57 -0
  26. csrd_utils-0.5.0/src/csrd_utils/templates/augments/caching/views/cache_view.py.template +57 -0
  27. csrd_utils-0.5.0/src/csrd_utils/templates/augments/celery-dispatcher/celery_client.py.template +22 -0
  28. csrd_utils-0.5.0/src/csrd_utils/templates/augments/celery-dispatcher/models/an/__init__.py +1 -0
  29. csrd_utils-0.5.0/src/csrd_utils/templates/augments/celery-dispatcher/models/an/tasks.py.template +39 -0
  30. csrd_utils-0.5.0/src/csrd_utils/templates/augments/celery-dispatcher/models/tasks.py.template +25 -0
  31. csrd_utils-0.5.0/src/csrd_utils/templates/augments/celery-dispatcher/views/tasks_view.py.template +38 -0
  32. csrd_utils-0.5.0/src/csrd_utils/templates/augments/celery-worker/celery_app.py.template +34 -0
  33. csrd_utils-0.5.0/src/csrd_utils/templates/augments/celery-worker/tasks/__init__.py +5 -0
  34. csrd_utils-0.5.0/src/csrd_utils/templates/augments/celery-worker/tasks/example.py.template +62 -0
  35. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/augments/crud-scaffold/views/${entity_name_snake}_view.py.template +8 -14
  36. csrd_utils-0.5.0/src/csrd_utils/templates/augments/gateway/dependencies/proxy.py.template +47 -0
  37. csrd_utils-0.5.0/src/csrd_utils/templates/augments/gateway/middleware/auth_guard.py.template +88 -0
  38. csrd_utils-0.5.0/src/csrd_utils/templates/augments/gateway/views/proxy_view.py.template +68 -0
  39. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/augments/jwt-auth-provider/AUTH.md +1 -1
  40. csrd_utils-0.5.0/src/csrd_utils/templates/augments/jwt-auth-provider/__init__.py +0 -0
  41. csrd_utils-0.5.0/src/csrd_utils/templates/augments/jwt-auth-provider/dependencies/__init__.py +0 -0
  42. csrd_utils-0.5.0/src/csrd_utils/templates/augments/jwt-auth-provider/models/__init__.py +0 -0
  43. csrd_utils-0.5.0/src/csrd_utils/templates/augments/jwt-auth-provider/repositories/__init__.py +0 -0
  44. csrd_utils-0.5.0/src/csrd_utils/templates/augments/jwt-auth-provider/services/__init__.py +0 -0
  45. csrd_utils-0.5.0/src/csrd_utils/templates/augments/jwt-auth-provider/views/__init__.py +0 -0
  46. csrd_utils-0.4.0/src/csrd_utils/features/metrics/src/app/middleware/metrics.py → csrd_utils-0.5.0/src/csrd_utils/templates/augments/metrics/middleware/metrics.py.template +14 -27
  47. csrd_utils-0.5.0/src/csrd_utils/templates/augments/metrics/views/metrics_view.py.template +28 -0
  48. csrd_utils-0.5.0/src/csrd_utils/templates/augments/rabbit-messaging/dependencies/rabbit.py.template +69 -0
  49. csrd_utils-0.5.0/src/csrd_utils/templates/augments/rabbit-messaging/handlers/example_handler.py.template +0 -0
  50. csrd_utils-0.5.0/src/csrd_utils/templates/augments/rabbit-messaging/handlers/ping_handler.py.template +49 -0
  51. csrd_utils-0.5.0/src/csrd_utils/templates/augments/rabbit-messaging/views/messaging_view.py.template +46 -0
  52. csrd_utils-0.4.0/src/csrd_utils/features/tracing/src/app/middleware/tracing.py → csrd_utils-0.5.0/src/csrd_utils/templates/augments/tracing/middleware/tracing.py.template +27 -14
  53. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/service/cookiecutter.json +1 -0
  54. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/service/{{cookiecutter.__service_name_snake}}/Dockerfile +0 -5
  55. csrd_utils-0.5.0/src/csrd_utils/templates/service/{{cookiecutter.__service_name_snake}}/tests/__init__.py +0 -0
  56. csrd_utils-0.4.0/src/csrd_utils/__init__.py +0 -14
  57. csrd_utils-0.4.0/src/csrd_utils/__main__.py +0 -1716
  58. csrd_utils-0.4.0/src/csrd_utils/augmentor.py +0 -560
  59. csrd_utils-0.4.0/src/csrd_utils/cluster.py +0 -556
  60. csrd_utils-0.4.0/src/csrd_utils/features/caching/conftest.fragment.py +0 -22
  61. csrd_utils-0.4.0/src/csrd_utils/features/caching/docker-compose.fragment.yaml +0 -10
  62. csrd_utils-0.4.0/src/csrd_utils/features/caching/manifest.yaml +0 -22
  63. csrd_utils-0.4.0/src/csrd_utils/features/caching/requirements.fragment +0 -1
  64. csrd_utils-0.4.0/src/csrd_utils/features/caching/settings.fragment.py +0 -4
  65. csrd_utils-0.4.0/src/csrd_utils/features/caching/src/app/cache.py +0 -36
  66. csrd_utils-0.4.0/src/csrd_utils/features/caching/tests/test_cache.py +0 -39
  67. csrd_utils-0.4.0/src/csrd_utils/features/logging/conftest.fragment.py +0 -10
  68. csrd_utils-0.4.0/src/csrd_utils/features/logging/manifest.yaml +0 -18
  69. csrd_utils-0.4.0/src/csrd_utils/features/logging/requirements.fragment +0 -1
  70. csrd_utils-0.4.0/src/csrd_utils/features/logging/settings.fragment.py +0 -3
  71. csrd_utils-0.4.0/src/csrd_utils/features/logging/src/app/middleware/logging.py +0 -73
  72. csrd_utils-0.4.0/src/csrd_utils/features/logging/tests/test_logging_middleware.py +0 -41
  73. csrd_utils-0.4.0/src/csrd_utils/features/metrics/conftest.fragment.py +0 -7
  74. csrd_utils-0.4.0/src/csrd_utils/features/metrics/docker-compose.fragment.yaml +0 -12
  75. csrd_utils-0.4.0/src/csrd_utils/features/metrics/manifest.yaml +0 -21
  76. csrd_utils-0.4.0/src/csrd_utils/features/metrics/requirements.fragment +0 -1
  77. csrd_utils-0.4.0/src/csrd_utils/features/metrics/settings.fragment.py +0 -3
  78. csrd_utils-0.4.0/src/csrd_utils/features/metrics/tests/test_metrics_middleware.py +0 -79
  79. csrd_utils-0.4.0/src/csrd_utils/features/tracing/conftest.fragment.py +0 -9
  80. csrd_utils-0.4.0/src/csrd_utils/features/tracing/manifest.yaml +0 -21
  81. csrd_utils-0.4.0/src/csrd_utils/features/tracing/requirements.fragment +0 -3
  82. csrd_utils-0.4.0/src/csrd_utils/features/tracing/settings.fragment.py +0 -4
  83. csrd_utils-0.4.0/src/csrd_utils/features/tracing/tests/test_tracing_middleware.py +0 -51
  84. csrd_utils-0.4.0/src/csrd_utils/features/workers/conftest.fragment.py +0 -14
  85. csrd_utils-0.4.0/src/csrd_utils/features/workers/docker-compose.fragment.yaml +0 -22
  86. csrd_utils-0.4.0/src/csrd_utils/features/workers/manifest.yaml +0 -24
  87. csrd_utils-0.4.0/src/csrd_utils/features/workers/requirements.fragment +0 -2
  88. csrd_utils-0.4.0/src/csrd_utils/features/workers/settings.fragment.py +0 -3
  89. csrd_utils-0.4.0/src/csrd_utils/features/workers/src/app/workers/__init__.py +0 -6
  90. csrd_utils-0.4.0/src/csrd_utils/features/workers/src/app/workers/celery_app.py +0 -21
  91. csrd_utils-0.4.0/src/csrd_utils/features/workers/src/app/workers/tasks.py +0 -28
  92. csrd_utils-0.4.0/src/csrd_utils/features/workers/tests/test_workers.py +0 -19
  93. csrd_utils-0.4.0/src/csrd_utils/fragments.py +0 -332
  94. csrd_utils-0.4.0/src/csrd_utils/generator.py +0 -464
  95. csrd_utils-0.4.0/src/csrd_utils/resources.py +0 -24
  96. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/README.md +0 -53
  97. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/cookiecutter.json +0 -28
  98. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/hooks/post_gen_project.py +0 -91
  99. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/.cookiecutterignore +0 -1
  100. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/.dockerignore +0 -7
  101. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/Dockerfile +0 -10
  102. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/README.md +0 -63
  103. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/__init__.py +0 -35
  104. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/cache.py +0 -14
  105. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/delegates/__init__.py +0 -7
  106. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/delegates/upstreams.py +0 -10
  107. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +0 -25
  108. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/auth_service.py +0 -64
  109. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/delegates.py +0 -13
  110. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/item_repository.py +0 -55
  111. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/worker_broker.py +0 -12
  112. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/docker-compose.yml +0 -112
  113. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/middleware/__init__.py +0 -7
  114. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/middleware/logging.py +0 -22
  115. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/repositories/__init__.py +0 -7
  116. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/repositories/item_repository.py +0 -94
  117. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/requirements.txt +0 -42
  118. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/settings.py +0 -98
  119. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/acceptance/test_logging_middleware.py +0 -7
  120. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/conftest.py +0 -66
  121. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/test_items.py +0 -281
  122. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_cache.py +0 -30
  123. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_database_settings.py +0 -8
  124. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_delegates.py +0 -25
  125. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_settings_contracts.py +0 -86
  126. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_worker_broker.py +0 -25
  127. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -3
  128. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/views/unversioned/__init__.py +0 -10
  129. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/views/unversioned/health_view.py +0 -8
  130. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/views/unversioned/items_view.py +0 -270
  131. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/workers/__init__.py +0 -7
  132. csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/workers/tasks.py +0 -17
  133. csrd_utils-0.4.0/src/csrd_utils/templates/platform-app-service/cookiecutter.json +0 -7
  134. csrd_utils-0.4.0/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/.dockerignore +0 -7
  135. csrd_utils-0.4.0/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/Dockerfile +0 -10
  136. csrd_utils-0.4.0/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/README.md +0 -37
  137. csrd_utils-0.4.0/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/__init__.py +0 -23
  138. csrd_utils-0.4.0/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/delegates/__init__.py +0 -4
  139. csrd_utils-0.4.0/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/delegates/auth_delegate.py +0 -11
  140. csrd_utils-0.4.0/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/delegates/identity_delegate.py +0 -11
  141. csrd_utils-0.4.0/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +0 -12
  142. csrd_utils-0.4.0/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/dependencies/auth_passthrough.py +0 -25
  143. csrd_utils-0.4.0/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/dependencies/auth_service.py +0 -68
  144. csrd_utils-0.4.0/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/dependencies/item_repository.py +0 -31
  145. csrd_utils-0.4.0/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/models/__init__.py +0 -22
  146. csrd_utils-0.4.0/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/models/auth_service.py +0 -11
  147. csrd_utils-0.4.0/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/models/items.py +0 -36
  148. csrd_utils-0.4.0/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/repositories/__init__.py +0 -3
  149. csrd_utils-0.4.0/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/repositories/item_repository.py +0 -71
  150. csrd_utils-0.4.0/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/requirements.txt +0 -9
  151. csrd_utils-0.4.0/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/settings.py +0 -20
  152. csrd_utils-0.4.0/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -3
  153. csrd_utils-0.4.0/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/views/unversioned/__init__.py +0 -11
  154. csrd_utils-0.4.0/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/views/unversioned/auth_service_view.py +0 -17
  155. csrd_utils-0.4.0/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/views/unversioned/health_view.py +0 -8
  156. csrd_utils-0.4.0/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/views/unversioned/items_view.py +0 -68
  157. csrd_utils-0.4.0/src/csrd_utils/templates/platform-auth-service/cookiecutter.json +0 -6
  158. csrd_utils-0.4.0/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/.dockerignore +0 -7
  159. csrd_utils-0.4.0/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/Dockerfile +0 -10
  160. csrd_utils-0.4.0/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/README.md +0 -32
  161. csrd_utils-0.4.0/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/__init__.py +0 -23
  162. csrd_utils-0.4.0/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +0 -32
  163. csrd_utils-0.4.0/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/models/__init__.py +0 -9
  164. csrd_utils-0.4.0/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/models/auth.py +0 -34
  165. csrd_utils-0.4.0/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/repositories/__init__.py +0 -3
  166. csrd_utils-0.4.0/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/repositories/token_repository.py +0 -33
  167. csrd_utils-0.4.0/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/requirements.txt +0 -9
  168. csrd_utils-0.4.0/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/settings.py +0 -25
  169. csrd_utils-0.4.0/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -3
  170. csrd_utils-0.4.0/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/views/unversioned/__init__.py +0 -10
  171. csrd_utils-0.4.0/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/views/unversioned/auth_view.py +0 -81
  172. csrd_utils-0.4.0/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/views/unversioned/health_view.py +0 -8
  173. csrd_utils-0.4.0/src/csrd_utils/templates/platform-identity-service/cookiecutter.json +0 -5
  174. csrd_utils-0.4.0/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/.dockerignore +0 -7
  175. csrd_utils-0.4.0/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/Dockerfile +0 -10
  176. csrd_utils-0.4.0/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/README.md +0 -29
  177. csrd_utils-0.4.0/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/__init__.py +0 -23
  178. csrd_utils-0.4.0/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +0 -31
  179. csrd_utils-0.4.0/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/models/__init__.py +0 -17
  180. csrd_utils-0.4.0/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/models/users.py +0 -37
  181. csrd_utils-0.4.0/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/repositories/__init__.py +0 -3
  182. csrd_utils-0.4.0/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/repositories/user_repository.py +0 -124
  183. csrd_utils-0.4.0/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/requirements.txt +0 -6
  184. csrd_utils-0.4.0/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/settings.py +0 -17
  185. csrd_utils-0.4.0/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -3
  186. csrd_utils-0.4.0/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/views/unversioned/__init__.py +0 -10
  187. csrd_utils-0.4.0/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/views/unversioned/health_view.py +0 -8
  188. csrd_utils-0.4.0/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/views/unversioned/users_view.py +0 -59
  189. csrd_utils-0.4.0/src/csrd_utils/v2/compose/presets.py +0 -65
  190. csrd_utils-0.4.0/src/csrd_utils/v2/templates/augments/crud-proxy/delegates/${entity_name_snake}_delegate.py.template +0 -55
  191. csrd_utils-0.4.0/src/csrd_utils/v2/templates/augments/crud-proxy/dependencies/${entity_name_snake}_delegate.py.template +0 -21
  192. csrd_utils-0.4.0/src/csrd_utils/v2/templates/augments/crud-proxy/models/${entity_name_snake}.py.template +0 -31
  193. csrd_utils-0.4.0/src/csrd_utils/v2/templates/augments/crud-proxy/views/${entity_name_snake}_proxy_view.py.template +0 -61
  194. {csrd_utils-0.4.0 → csrd_utils-0.5.0}/.gitignore +0 -0
  195. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/__init__.py +0 -0
  196. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/compose/git.py +0 -0
  197. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/compose/infra.py +0 -0
  198. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/compose/loader.py +0 -0
  199. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/generate/__init__.py +0 -0
  200. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/generate/helpers.py +0 -0
  201. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/models/base.py +0 -0
  202. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/models/types.py +0 -0
  203. {csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests → csrd_utils-0.5.0/src/csrd_utils/templates}/__init__.py +0 -0
  204. {csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/acceptance → csrd_utils-0.5.0/src/csrd_utils/templates/augments}/__init__.py +0 -0
  205. {csrd_utils-0.4.0/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit → csrd_utils-0.5.0/src/csrd_utils/templates/augments/auth-passthrough}/__init__.py +0 -0
  206. {csrd_utils-0.4.0/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/tests → csrd_utils-0.5.0/src/csrd_utils/templates/augments/auth-passthrough/delegates}/__init__.py +0 -0
  207. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/augments/auth-passthrough/dependencies/auth_passthrough.py +0 -0
  208. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/augments/auth-passthrough/models/auth_passthrough.py +0 -0
  209. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/augments/crud-scaffold/dependencies/${entity_name_snake}_repository.py.template +0 -0
  210. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/augments/crud-scaffold/migrations_${entity_name_snake}.py.template +0 -0
  211. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/augments/crud-scaffold/models/${entity_name_snake}.py.template +0 -0
  212. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/augments/crud-scaffold/repositories/${entity_name_snake}_repository.py.template +0 -0
  213. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/augments/db-config/dependencies/db.py.template +0 -0
  214. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/augments/jwt-auth-consumer/dependencies/auth.py.template +0 -0
  215. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/augments/jwt-auth-provider/dependencies/auth.py +0 -0
  216. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/augments/jwt-auth-provider/dependencies/db.py.template +0 -0
  217. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/augments/jwt-auth-provider/dependencies/token_service.py +0 -0
  218. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/augments/jwt-auth-provider/migrations.py.template +0 -0
  219. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/augments/jwt-auth-provider/models/auth.py +0 -0
  220. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/augments/jwt-auth-provider/models/jwks.py +0 -0
  221. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/augments/jwt-auth-provider/models/users.py +0 -0
  222. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/augments/jwt-auth-provider/repositories/user_repository.py +0 -0
  223. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/augments/jwt-auth-provider/services/token_service.py +0 -0
  224. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/augments/jwt-auth-provider/views/auth_view.py +0 -0
  225. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/augments/jwt-auth-provider/views/jwks_view.py +0 -0
  226. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/augments/jwt-auth-provider/views/users_admin_view.py +0 -0
  227. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/augments/jwt-auth-provider/views/users_view.py +0 -0
  228. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/service/{{cookiecutter.__service_name_snake}}/README.md +0 -0
  229. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/service/{{cookiecutter.__service_name_snake}}/__init__.py +0 -0
  230. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +0 -0
  231. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/service/{{cookiecutter.__service_name_snake}}/models/__init__.py +0 -0
  232. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/service/{{cookiecutter.__service_name_snake}}/models/health.py +0 -0
  233. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/service/{{cookiecutter.__service_name_snake}}/requirements.txt +0 -0
  234. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/service/{{cookiecutter.__service_name_snake}}/settings.py +0 -0
  235. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/service/{{cookiecutter.__service_name_snake}}/tests/conftest.py +0 -0
  236. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/service/{{cookiecutter.__service_name_snake}}/tests/test_health.py +0 -0
  237. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -0
  238. {csrd_utils-0.4.0/src/csrd_utils/v2 → csrd_utils-0.5.0/src/csrd_utils}/templates/service/{{cookiecutter.__service_name_snake}}/views/health_view.py +0 -0
  239. {csrd_utils-0.4.0 → csrd_utils-0.5.0}/src/tui_wizard/__init__.py +0 -0
  240. {csrd_utils-0.4.0 → csrd_utils-0.5.0}/src/tui_wizard/exceptions.py +0 -0
  241. {csrd_utils-0.4.0 → csrd_utils-0.5.0}/src/tui_wizard/menu.py +0 -0
  242. {csrd_utils-0.4.0 → csrd_utils-0.5.0}/src/tui_wizard/models.py +0 -0
  243. {csrd_utils-0.4.0 → csrd_utils-0.5.0}/src/tui_wizard/prompts.py +0 -0
  244. {csrd_utils-0.4.0 → csrd_utils-0.5.0}/src/tui_wizard/terminal.py +0 -0
  245. {csrd_utils-0.4.0 → csrd_utils-0.5.0}/src/tui_wizard/wizard.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: csrd-utils
3
- Version: 0.4.0
3
+ Version: 0.5.0
4
4
  Summary: CLI utilities for csrd service generation and feature augmentation
5
5
  Project-URL: Repository, https://github.com/csrd-api/fastapi-common
6
6
  Project-URL: Documentation, https://github.com/csrd-api/fastapi-common/tree/main/packages/utils
@@ -126,7 +126,7 @@ csrd new service --name pricing --output ./local-dev --database postgres
126
126
  ## Bundled assets
127
127
 
128
128
  - `features/workers/` feature manifests and fragments
129
- - `templates/cookiecutter-service/` template starter
129
+ - `templates/service/` template starter
130
130
 
131
131
  ## Python API
132
132
 
@@ -111,7 +111,7 @@ csrd new service --name pricing --output ./local-dev --database postgres
111
111
  ## Bundled assets
112
112
 
113
113
  - `features/workers/` feature manifests and fragments
114
- - `templates/cookiecutter-service/` template starter
114
+ - `templates/service/` template starter
115
115
 
116
116
  ## Python API
117
117
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "csrd-utils"
3
- version = "0.4.0"
3
+ version = "0.5.0"
4
4
  description = "CLI utilities for csrd service generation and feature augmentation"
5
5
  license = { text = "MIT" }
6
6
  requires-python = ">=3.12"
@@ -1,27 +1,15 @@
1
1
  # Menu System & Compose Design Rules
2
2
 
3
- This file captures the design principles of the `v2/generate` menu system
4
- and the `v2/compose` rendering pipeline.
3
+ This file captures the design principles of the `generate` menu system
4
+ and the `compose` rendering pipeline.
5
5
  Consult it for every change that adds, removes, or modifies menus, menu items,
6
6
  prompts, interactive selection flows, or compose/renderer behavior.
7
7
 
8
8
  ## Scope
9
9
 
10
- - Applies to `packages/utils/src/csrd_utils/v2/**`.
10
+ - Applies to `packages/utils/src/csrd_utils/generate/**` and `packages/utils/src/csrd_utils/compose/**`.
11
11
  - Also follow `packages/utils/AGENTS.md` and the top-level `AGENTS.md`.
12
12
 
13
- ## Drop-in replacement intent
14
-
15
- The `v2` module is intended to **fully replace** the bare `csrd` command.
16
- Once promoted, the `v2/` directory becomes the top-level implementation and
17
- the `v2` namespace disappears.
18
-
19
- **Naming rule**: Do not use "v2" in any module name, class name, function name,
20
- variable name, constant, test name, CLI label, or user-facing string inside this
21
- package. The only place "v2" appears is the directory name itself, which will be
22
- removed at promotion time. Names should read as if `v2/` does not exist —
23
- e.g. `compose`, `generate`, `ComposeSpec`, `render_workspace`, not
24
- `v2_compose`, `V2ComposeSpec`, `render_v2_workspace`.
25
13
 
26
14
  ## Architecture overview
27
15
 
@@ -347,7 +335,7 @@ When asked to "audit the menus or compose system", verify each of the following:
347
335
  9. Names are normalized and the user is informed of changes.
348
336
  10. No new prompt primitives exist outside `helpers.py`.
349
337
  11. The three-layer separation (helpers → menu → handlers) is preserved.
350
- 12. Tests in `tests/test_cli.py` and `tests/test_v2_generate*.py` cover new/changed items.
338
+ 12. Tests in `tests/test_cli.py` and `tests/test_*.py` cover new/changed items.
351
339
  13. All multi-step interactive flows use `run_wizard()` with a list of `WizardStep` callables — no raw `while step <= N` / `if step == 0` dispatch exists in handlers.
352
340
  14. No step logic is duplicated across wizard flows — shared steps (`_step_workspace_name`, `_step_git_init`, etc.) are extracted to `_step_*` functions.
353
341
  15. Custom workflow can produce output identical to every registered preset (custom–preset parity rule #21).
@@ -0,0 +1,341 @@
1
+ """Command-line interface for csrd-utils."""
2
+
3
+ import argparse
4
+ import json
5
+ import sys
6
+ from importlib.metadata import version
7
+ from pathlib import Path
8
+
9
+ from .audit import run_audit
10
+ from .compose import apply as compose_apply
11
+ from .compose import validate as compose_validate
12
+ from .doctor import run_doctor
13
+ from .generate import run_generate_menu
14
+
15
+ # ---------------------------------------------------------------------------
16
+ # Bash completion
17
+ # ---------------------------------------------------------------------------
18
+
19
+
20
+ def _parser_shape(
21
+ parser: argparse.ArgumentParser,
22
+ chain: tuple[str, ...] = (),
23
+ ) -> tuple[dict[tuple[str, ...], list[str]], dict[tuple[str, ...], list[str]]]:
24
+ commands: dict[tuple[str, ...], list[str]] = {}
25
+ options: dict[tuple[str, ...], list[str]] = {}
26
+
27
+ subcommands: list[str] = []
28
+ flags: list[str] = []
29
+ for action in parser._actions:
30
+ if isinstance(action, argparse._SubParsersAction):
31
+ subcommands.extend(sorted(action.choices.keys()))
32
+ for name, subparser in action.choices.items():
33
+ child_chain = (*chain, name)
34
+ child_commands, child_options = _parser_shape(subparser, child_chain)
35
+ commands.update(child_commands)
36
+ options.update(child_options)
37
+ else:
38
+ flags.extend([item for item in action.option_strings if item.startswith("-")])
39
+
40
+ commands[chain] = sorted(dict.fromkeys(subcommands))
41
+ options[chain] = sorted(dict.fromkeys(flags))
42
+ return commands, options
43
+
44
+
45
+ def _render_bash_completion(parser: argparse.ArgumentParser) -> str:
46
+ commands, options = _parser_shape(parser)
47
+
48
+ lines = [
49
+ "# bash completion for csrd",
50
+ "_csrd_completion() {",
51
+ " local cur key token",
52
+ ' cur="${COMP_WORDS[COMP_CWORD]}"',
53
+ ' key=""',
54
+ "",
55
+ ' for token in "${COMP_WORDS[@]:1:COMP_CWORD-1}"; do',
56
+ ' case "$token" in',
57
+ " -*) continue ;;",
58
+ " esac",
59
+ ' if [[ -n "$key" ]]; then',
60
+ ' key="$key $token"',
61
+ " else",
62
+ ' key="$token"',
63
+ " fi",
64
+ " done",
65
+ "",
66
+ ' case "$key" in',
67
+ ]
68
+
69
+ for chain in sorted(commands.keys()):
70
+ key = " ".join(chain)
71
+ command_candidates = commands.get(chain, [])
72
+ option_candidates = options.get(chain, [])
73
+ candidates = " ".join(command_candidates + option_candidates).strip()
74
+ if not candidates:
75
+ continue
76
+ lines.append(f' "{key}") COMPREPLY=( $(compgen -W "{candidates}" -- "$cur") ) ;;')
77
+
78
+ lines.extend(
79
+ [
80
+ " *) COMPREPLY=() ;;",
81
+ " esac",
82
+ "}",
83
+ "complete -F _csrd_completion csrd csrd-utils csrt",
84
+ ]
85
+ )
86
+ return "\n".join(lines) + "\n"
87
+
88
+
89
+ # ---------------------------------------------------------------------------
90
+ # Parser
91
+ # ---------------------------------------------------------------------------
92
+
93
+
94
+ def _build_parser() -> argparse.ArgumentParser:
95
+ parser = argparse.ArgumentParser(prog="csrd", description="csrd utilities")
96
+ parser.add_argument(
97
+ "-v",
98
+ "--version",
99
+ action="version",
100
+ version=f"csrd-utils {version('csrd-utils')}",
101
+ )
102
+
103
+ sub = parser.add_subparsers(dest="command", required=True)
104
+
105
+ # ── generate ──────────────────────────────────────────────────────
106
+ gen = sub.add_parser("generate", help="Interactive generator menu")
107
+ gen.add_argument(
108
+ "target",
109
+ nargs="?",
110
+ choices=[
111
+ "workspace",
112
+ "preset",
113
+ "add-service",
114
+ "add-infra",
115
+ "remove-infra",
116
+ "add-augment",
117
+ "remove-service",
118
+ "list-augments",
119
+ "empty",
120
+ ],
121
+ help="Direct generator target",
122
+ )
123
+ gen.add_argument("--name", dest="generate_name", help="Workspace or service name")
124
+ gen.add_argument(
125
+ "--git-init",
126
+ action="store_true",
127
+ default=False,
128
+ help="Initialize a git repository in the generated workspace",
129
+ )
130
+ gen.add_argument(
131
+ "--features",
132
+ nargs="*",
133
+ choices=["database", "caching", "messaging"],
134
+ default=None,
135
+ help="Service capabilities to wire (for add-service)",
136
+ )
137
+ gen.add_argument("--port", type=int, default=None, help="Service port (for add-service)")
138
+ gen.add_argument(
139
+ "--infra-type",
140
+ dest="infra_type",
141
+ choices=["postgres", "mariadb", "sqlite", "redis", "rabbitmq"],
142
+ default=None,
143
+ help="Infrastructure type (for add-infra / remove-infra)",
144
+ )
145
+ gen.add_argument(
146
+ "--service-name",
147
+ dest="service_name",
148
+ default=None,
149
+ help="Service name (for remove-service)",
150
+ )
151
+
152
+ # ── compose ───────────────────────────────────────────────────────
153
+ compose = sub.add_parser("compose", help="Compose operations")
154
+ compose_sub = compose.add_subparsers(dest="compose_command")
155
+
156
+ val = compose_sub.add_parser("validate", help="Validate csrd-compose.yaml")
157
+ val.add_argument("--output", type=Path, default=Path.cwd(), help="Workspace root")
158
+ val.add_argument("--json", action="store_true", help="Print validated spec as JSON")
159
+
160
+ plan = compose_sub.add_parser("plan", help="Preview resolved compose baseline")
161
+ plan.add_argument("--output", type=Path, default=Path.cwd(), help="Workspace root")
162
+ plan.add_argument("--json", action="store_true", help="Print plan payload as JSON")
163
+
164
+ apply_cmd = compose_sub.add_parser("apply", help="Render baseline workspace artifacts")
165
+ apply_cmd.add_argument("--output", type=Path, default=Path.cwd(), help="Workspace root")
166
+ apply_cmd.add_argument(
167
+ "--git-init",
168
+ action="store_true",
169
+ default=False,
170
+ help="Initialize a git repository in the workspace",
171
+ )
172
+
173
+ # ── doctor ────────────────────────────────────────────────────────
174
+ doctor = sub.add_parser("doctor", help="Validate service compatibility")
175
+ doctor.add_argument("--service", type=Path, default=Path.cwd(), help="Service root path")
176
+ doctor.add_argument("--json", action="store_true", help="Print doctor report as JSON")
177
+
178
+ # ── audit ─────────────────────────────────────────────────────────
179
+ audit = sub.add_parser("audit", help="Audit weak or insecure service defaults")
180
+ audit.add_argument(
181
+ "--service",
182
+ type=Path,
183
+ default=None,
184
+ help="Service path (default: workspace root or cwd)",
185
+ )
186
+ audit.add_argument("--json", action="store_true", help="Print audit report as JSON")
187
+
188
+ # ── completion ────────────────────────────────────────────────────
189
+ completion = sub.add_parser("completion", help="Shell completion helpers")
190
+ completion_sub = completion.add_subparsers(dest="completion_shell", required=True)
191
+ completion_sub.add_parser("bash", help="Print bash completion script")
192
+
193
+ return parser
194
+
195
+
196
+ # ---------------------------------------------------------------------------
197
+ # Dispatch
198
+ # ---------------------------------------------------------------------------
199
+
200
+
201
+ def main() -> int:
202
+ # Shorthand: `csrd compose <path>` => `csrd compose apply --output <path>`
203
+ raw_argv = sys.argv[1:]
204
+ if len(raw_argv) >= 2 and raw_argv[0] == "compose":
205
+ second = raw_argv[1]
206
+ if second not in {"validate", "plan", "apply", "-h", "--help"} and not second.startswith(
207
+ "-"
208
+ ):
209
+ shorthand_dir = Path(second).resolve()
210
+ has_spec = (shorthand_dir / "csrd-compose.yaml").is_file() or (
211
+ shorthand_dir / "csrd-compose.yml"
212
+ ).is_file()
213
+ if not has_spec:
214
+ print(f"ERROR: Compose shorthand requires csrd-compose.yaml in: {shorthand_dir}")
215
+ print(
216
+ "Hint: create a spec first (csrd generate workspace --name <name>) "
217
+ "or use explicit apply: csrd compose apply --output <path>"
218
+ )
219
+ return 1
220
+ sys.argv = [sys.argv[0], "compose", "apply", "--output", second, *raw_argv[2:]]
221
+
222
+ parser = _build_parser()
223
+ args = parser.parse_args()
224
+
225
+ # ── generate ──────────────────────────────────────────────────────
226
+ if args.command == "generate":
227
+ return run_generate_menu(
228
+ target=getattr(args, "target", None),
229
+ name=getattr(args, "generate_name", None),
230
+ git_init=getattr(args, "git_init", False),
231
+ features=getattr(args, "features", None),
232
+ port=getattr(args, "port", None),
233
+ infra_type=getattr(args, "infra_type", None),
234
+ service_name=getattr(args, "service_name", None),
235
+ )
236
+
237
+ # ── compose ───────────────────────────────────────────────────────
238
+ if args.command == "compose":
239
+ compose_cmd = getattr(args, "compose_command", None)
240
+ if compose_cmd is None:
241
+ parser.print_help()
242
+ return 0
243
+
244
+ output_dir = Path(args.output).resolve()
245
+ try:
246
+ if compose_cmd == "apply":
247
+ generated = compose_apply(output_dir, git_init=getattr(args, "git_init", False))
248
+ print(f"Rendered compose workspace at: {generated}")
249
+ return 0
250
+
251
+ if compose_cmd == "validate":
252
+ spec = compose_validate(output_dir)
253
+ if args.json:
254
+ print(json.dumps(spec.model_dump(mode="python"), indent=2, sort_keys=True))
255
+ else:
256
+ print(f"Compose spec valid: {output_dir / 'csrd-compose.yaml'}")
257
+ return 0
258
+
259
+ if compose_cmd == "plan":
260
+ spec = compose_validate(output_dir)
261
+ payload = {
262
+ "workspace": spec.workspace.name,
263
+ "version": spec.version,
264
+ "services": len(spec.services),
265
+ "infra": len(spec.infra),
266
+ "presets": [p.name for p in spec.presets],
267
+ "overrides_keys": sorted(spec.overrides.keys()),
268
+ }
269
+ if args.json:
270
+ print(json.dumps(payload, indent=2, sort_keys=True))
271
+ else:
272
+ print("Compose plan")
273
+ print(f"- workspace: {payload['workspace']}")
274
+ print(f"- version: {payload['version']}")
275
+ print(f"- services: {payload['services']}")
276
+ print(f"- infra: {payload['infra']}")
277
+ presets = payload["presets"]
278
+ overrides_keys = payload["overrides_keys"]
279
+ assert isinstance(presets, list)
280
+ assert isinstance(overrides_keys, list)
281
+ print(f"- presets: {', '.join(presets) if presets else '<none>'}")
282
+ print(
283
+ f"- overrides: {', '.join(overrides_keys) if overrides_keys else '<none>'}"
284
+ )
285
+ return 0
286
+ except ValueError as exc:
287
+ print(f"ERROR: {exc}")
288
+ return 1
289
+
290
+ # ── completion ────────────────────────────────────────────────────
291
+ # ── doctor ────────────────────────────────────────────────────────
292
+ if args.command == "doctor":
293
+ service_path = Path(getattr(args, "service", Path.cwd())).resolve()
294
+ report = run_doctor(service_path)
295
+ if getattr(args, "json", False):
296
+ from dataclasses import asdict
297
+
298
+ print(json.dumps(asdict(report), indent=2, sort_keys=True))
299
+ else:
300
+ if report.ok:
301
+ print("Doctor check passed.")
302
+ else:
303
+ print("Doctor check failed.")
304
+ for err in report.errors:
305
+ print(f"ERROR: {err}")
306
+ for warning in report.warnings:
307
+ print(f"WARN: {warning}")
308
+ return 0 if report.ok else 1
309
+
310
+ # ── audit ─────────────────────────────────────────────────────────
311
+ if args.command == "audit":
312
+ audit_path = getattr(args, "service", None)
313
+ target = audit_path.resolve() if audit_path is not None else Path.cwd().resolve()
314
+ audit_report = run_audit(target)
315
+ payload = audit_report.to_payload()
316
+ if getattr(args, "json", False):
317
+ print(json.dumps(payload, indent=2, sort_keys=True))
318
+ else:
319
+ if audit_report.ok:
320
+ print("Audit passed (no high-severity findings).")
321
+ else:
322
+ print("Audit failed (high-severity findings detected).")
323
+ for finding in audit_report.findings:
324
+ print(
325
+ f"{finding.severity.upper()}: [{finding.rule}] "
326
+ f"{finding.file} :: {finding.message}"
327
+ )
328
+ print(f" evidence: {finding.evidence}")
329
+ print(f" fix: {finding.remediation}")
330
+ return 0 if audit_report.ok else 1
331
+
332
+ if args.command == "completion" and getattr(args, "completion_shell", None) == "bash":
333
+ print(_render_bash_completion(parser), end="")
334
+ return 0
335
+
336
+ parser.print_help()
337
+ return 0
338
+
339
+
340
+ if __name__ == "__main__":
341
+ raise SystemExit(main())
@@ -3,6 +3,7 @@
3
3
  import re
4
4
  from dataclasses import asdict, dataclass, field
5
5
  from pathlib import Path
6
+ from typing import Literal
6
7
 
7
8
 
8
9
  @dataclass
@@ -10,7 +11,7 @@ class AuditFinding:
10
11
  """A single hardening finding."""
11
12
 
12
13
  rule: str
13
- severity: str
14
+ severity: Literal["high", "medium", "low"]
14
15
  message: str
15
16
  file: str
16
17
  evidence: str
@@ -10,6 +10,7 @@ from ..models import (
10
10
  PresetDefinition,
11
11
  ServiceAugment,
12
12
  ServiceNode,
13
+ StyleDefinition,
13
14
  WorkspaceAugment,
14
15
  find_service_by_name,
15
16
  find_service_by_role,
@@ -19,6 +20,7 @@ from .augments import (
19
20
  ROLE_REGISTRY,
20
21
  AugmentDescriptor,
21
22
  OptionPrompt,
23
+ ProxySpec,
22
24
  RoleDescriptor,
23
25
  augment_for,
24
26
  augments_for_scope,
@@ -87,9 +89,11 @@ __all__ = [
87
89
  "InfraNode",
88
90
  "OptionPrompt",
89
91
  "PresetDefinition",
92
+ "ProxySpec",
90
93
  "RoleDescriptor",
91
94
  "ServiceAugment",
92
95
  "ServiceNode",
96
+ "StyleDefinition",
93
97
  "WorkspaceAugment",
94
98
  "add_infra",
95
99
  "add_service",