csrd-utils 0.3.92__tar.gz → 0.3.95__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.
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/PKG-INFO +1 -1
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/pyproject.toml +1 -1
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/AGENTS.md +3 -3
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/compose/augments.py +9 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/compose/renderer.py +15 -3
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/compose/scaffolder.py +19 -6
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/compose/service_renderers.py +22 -6
- csrd_utils-0.3.95/src/csrd_utils/v2/templates/augments/auth-passthrough/delegates/auth_delegate.py +35 -0
- csrd_utils-0.3.95/src/csrd_utils/v2/templates/augments/auth-passthrough/dependencies/auth_passthrough.py +21 -0
- csrd_utils-0.3.95/src/csrd_utils/v2/templates/augments/auth-passthrough/models/auth_passthrough.py +32 -0
- csrd_utils-0.3.95/src/csrd_utils/v2/templates/augments/auth-passthrough/views/auth_passthrough_view.py +25 -0
- csrd_utils-0.3.92/src/csrd_utils/v2/templates/augments/db-config/dependencies/db.py → csrd_utils-0.3.95/src/csrd_utils/v2/templates/augments/db-config/dependencies/db.py.template +10 -4
- csrd_utils-0.3.92/src/csrd_utils/v2/templates/augments/jwt-auth-consumer/dependencies/auth.py → csrd_utils-0.3.95/src/csrd_utils/v2/templates/augments/jwt-auth-consumer/dependencies/auth.py.template +5 -0
- csrd_utils-0.3.92/src/csrd_utils/v2/templates/augments/jwt-auth-provider/dependencies/db.py → csrd_utils-0.3.95/src/csrd_utils/v2/templates/augments/jwt-auth-provider/dependencies/db.py.template +2 -2
- csrd_utils-0.3.95/src/csrd_utils/v2/templates/augments/jwt-auth-provider/models/auth.py +39 -0
- csrd_utils-0.3.95/src/csrd_utils/v2/templates/augments/jwt-auth-provider/models/jwks.py +11 -0
- csrd_utils-0.3.95/src/csrd_utils/v2/templates/augments/jwt-auth-provider/models/users.py +26 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/templates/augments/jwt-auth-provider/repositories/user_repository.py +42 -34
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/templates/augments/jwt-auth-provider/views/auth_view.py +30 -36
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/templates/augments/jwt-auth-provider/views/jwks_view.py +7 -6
- csrd_utils-0.3.95/src/csrd_utils/v2/templates/augments/jwt-auth-provider/views/users_view.py +44 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/Dockerfile +2 -2
- csrd_utils-0.3.95/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +27 -0
- csrd_utils-0.3.95/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/models/__init__.py +1 -0
- csrd_utils-0.3.95/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/models/health.py +10 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/requirements.txt +1 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/settings.py +1 -2
- csrd_utils-0.3.95/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/views/health_view.py +11 -0
- csrd_utils-0.3.92/src/csrd_utils/v2/templates/augments/jwt-auth-provider/views/users_view.py +0 -77
- csrd_utils-0.3.92/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/views/health_view.py +0 -8
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/.gitignore +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/README.md +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/__main__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/audit.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/augmentor.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/cluster.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/doctor.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/caching/conftest.fragment.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/caching/docker-compose.fragment.yaml +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/caching/manifest.yaml +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/caching/requirements.fragment +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/caching/settings.fragment.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/caching/src/app/cache.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/caching/tests/test_cache.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/logging/conftest.fragment.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/logging/manifest.yaml +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/logging/requirements.fragment +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/logging/settings.fragment.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/logging/src/app/middleware/logging.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/logging/tests/test_logging_middleware.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/metrics/conftest.fragment.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/metrics/docker-compose.fragment.yaml +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/metrics/manifest.yaml +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/metrics/requirements.fragment +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/metrics/settings.fragment.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/metrics/src/app/middleware/metrics.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/metrics/tests/test_metrics_middleware.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/tracing/conftest.fragment.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/tracing/manifest.yaml +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/tracing/requirements.fragment +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/tracing/settings.fragment.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/tracing/src/app/middleware/tracing.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/tracing/tests/test_tracing_middleware.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/workers/conftest.fragment.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/workers/docker-compose.fragment.yaml +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/workers/manifest.yaml +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/workers/requirements.fragment +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/workers/settings.fragment.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/workers/src/app/workers/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/workers/src/app/workers/celery_app.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/workers/src/app/workers/tasks.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/features/workers/tests/test_workers.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/fragments.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/generator.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/resources.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/README.md +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/cookiecutter.json +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/hooks/post_gen_project.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/.cookiecutterignore +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/.dockerignore +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/Dockerfile +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/README.md +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/cache.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/delegates/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/delegates/upstreams.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/auth_service.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/delegates.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/item_repository.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/worker_broker.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/docker-compose.yml +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/middleware/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/middleware/logging.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/repositories/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/repositories/item_repository.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/requirements.txt +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/settings.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/acceptance/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/acceptance/test_logging_middleware.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/conftest.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/test_items.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_cache.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_database_settings.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_delegates.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_settings_contracts.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_worker_broker.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/views/unversioned/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/views/unversioned/health_view.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/views/unversioned/items_view.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/workers/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/workers/tasks.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-app-service/cookiecutter.json +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/.dockerignore +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/Dockerfile +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/README.md +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/delegates/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/delegates/auth_delegate.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/delegates/identity_delegate.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/dependencies/auth_passthrough.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/dependencies/auth_service.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/dependencies/item_repository.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/models/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/models/auth_service.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/models/items.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/repositories/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/repositories/item_repository.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/requirements.txt +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/settings.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/views/unversioned/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/views/unversioned/auth_service_view.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/views/unversioned/health_view.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/views/unversioned/items_view.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-auth-service/cookiecutter.json +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/.dockerignore +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/Dockerfile +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/README.md +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/models/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/models/auth.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/repositories/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/repositories/token_repository.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/requirements.txt +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/settings.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/views/unversioned/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/views/unversioned/auth_view.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/views/unversioned/health_view.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-identity-service/cookiecutter.json +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/.dockerignore +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/Dockerfile +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/README.md +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/models/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/models/users.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/repositories/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/repositories/user_repository.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/requirements.txt +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/settings.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/views/unversioned/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/views/unversioned/health_view.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/views/unversioned/users_view.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/compose/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/compose/git.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/compose/infra.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/compose/loader.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/compose/operations.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/compose/presets.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/compose/yaml_editor.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/generate/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/generate/handlers.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/generate/helpers.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/generate/menu.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/models/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/models/base.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/models/spec.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/models/types.py +0 -0
- /csrd_utils-0.3.92/src/csrd_utils/v2/templates/augments/db-config/migrations.py → /csrd_utils-0.3.95/src/csrd_utils/v2/templates/augments/db-config/migrations.py.template +0 -0
- /csrd_utils-0.3.92/src/csrd_utils/v2/templates/augments/jwt-auth-provider/migrations.py → /csrd_utils-0.3.95/src/csrd_utils/v2/templates/augments/jwt-auth-provider/migrations.py.template +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/templates/service/cookiecutter.json +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/README.md +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/tests/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/tests/conftest.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/tests/test_health.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/tui_wizard/__init__.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/tui_wizard/exceptions.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/tui_wizard/menu.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/tui_wizard/models.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/tui_wizard/prompts.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/src/tui_wizard/terminal.py +0 -0
- {csrd_utils-0.3.92 → csrd_utils-0.3.95}/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.3.
|
|
3
|
+
Version: 0.3.95
|
|
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
|
|
@@ -123,12 +123,12 @@ User edits to scaffolded files are never overwritten on re-render.
|
|
|
123
123
|
.gitignore ← rendered from spec
|
|
124
124
|
.csrd-workspace ← marker file
|
|
125
125
|
Dockerfile.<service-name> ← one per service, at root
|
|
126
|
-
src/<
|
|
126
|
+
src/<service_snake>/ ← service source (snake_case dir)
|
|
127
127
|
tests/unit/<service_snake>/ ← unit tests (snake_case dir)
|
|
128
128
|
tests/acceptance/<service_snake>/ ← acceptance stubs (snake_case dir)
|
|
129
129
|
```
|
|
130
130
|
|
|
131
|
-
- Service source dirs use **
|
|
131
|
+
- Service source dirs use **snake_case** (valid Python package names).
|
|
132
132
|
- Test dirs use **snake_case** (valid Python package names).
|
|
133
133
|
- Dockerfiles use kebab-case service name for the suffix, snake_case for the Python module reference in CMD.
|
|
134
134
|
|
|
@@ -345,5 +345,5 @@ When asked to "audit the menus or compose system", verify each of the following:
|
|
|
345
345
|
20. `operations.py` functions load → mutate → save spec — no rendering.
|
|
346
346
|
21. Workspace finalization uses `_finalize_workspace` — no duplicated create/add/render sequences in handlers.
|
|
347
347
|
22. `detect_configured_db` is defined once in `infra.py` — not duplicated.
|
|
348
|
-
23. Test dirs use snake_case, source dirs use
|
|
348
|
+
23. Test dirs use snake_case, source dirs use snake_case, Dockerfiles use kebab-case suffix.
|
|
349
349
|
24. No shim modules or alias re-export files exist (pre-1.0 refactor policy).
|
|
@@ -131,6 +131,15 @@ AUGMENT_REGISTRY: dict[str, AugmentDescriptor] = {
|
|
|
131
131
|
template_dir="jwt-auth-consumer",
|
|
132
132
|
# compose_env, compose_depends_on, settings_fields resolved from spec
|
|
133
133
|
),
|
|
134
|
+
"auth-passthrough": AugmentDescriptor(
|
|
135
|
+
name="auth-passthrough",
|
|
136
|
+
scope="service",
|
|
137
|
+
description="Unguarded signup/login proxy endpoints to the auth service",
|
|
138
|
+
requires_workspace_augment="jwt-auth-provider",
|
|
139
|
+
packages=["csrd-delegate", "csrd-models"],
|
|
140
|
+
template_dir="auth-passthrough",
|
|
141
|
+
# compose_env, compose_depends_on, settings_fields resolved from spec
|
|
142
|
+
),
|
|
134
143
|
"context-logging": AugmentDescriptor(
|
|
135
144
|
name="context-logging",
|
|
136
145
|
scope="service",
|
|
@@ -103,6 +103,18 @@ def _wire_augment(
|
|
|
103
103
|
env["AUTH_JWKS_URL"] = f"http://{auth_svc.name}:{auth_svc.port}/.well-known/jwks.json"
|
|
104
104
|
deps[auth_svc.name] = {"condition": "service_started"}
|
|
105
105
|
|
|
106
|
+
# ── Dynamic: auth-passthrough ────────────────────────────────────
|
|
107
|
+
#
|
|
108
|
+
# Resolve the auth service URL for signup/login proxy endpoints.
|
|
109
|
+
if augment.name == "auth-passthrough":
|
|
110
|
+
auth_svc = next(
|
|
111
|
+
(s for s in spec.services if s.role == "auth"),
|
|
112
|
+
None,
|
|
113
|
+
)
|
|
114
|
+
if auth_svc is not None and auth_svc.name != svc.name:
|
|
115
|
+
env["AUTH_SERVICE_URL"] = f"http://{auth_svc.name}:{auth_svc.port}"
|
|
116
|
+
deps[auth_svc.name] = {"condition": "service_started"}
|
|
117
|
+
|
|
106
118
|
# ── Dynamic: delegate-config ────────────────────────────────────
|
|
107
119
|
#
|
|
108
120
|
# Resolve target service URLs from the spec and inject per-target
|
|
@@ -258,7 +270,7 @@ def _render_env_example(spec: ComposeSpec) -> str:
|
|
|
258
270
|
|
|
259
271
|
lines.append("# JWT Authentication")
|
|
260
272
|
lines.append("JWT_ISSUER=csrd-auth")
|
|
261
|
-
lines.append("JWT_AUDIENCE=
|
|
273
|
+
lines.append(f"JWT_AUDIENCE={spec.workspace.name}")
|
|
262
274
|
lines.append("JWT_TTL_SECONDS=3600")
|
|
263
275
|
|
|
264
276
|
if signing == "shared-secret":
|
|
@@ -310,7 +322,7 @@ def _render_gitignore() -> str:
|
|
|
310
322
|
def _render_pyproject(spec: ComposeSpec) -> str:
|
|
311
323
|
"""Build a workspace-level ``pyproject.toml`` with pytest config."""
|
|
312
324
|
|
|
313
|
-
service_src_paths = [f"src/{svc.name}" for svc in spec.services]
|
|
325
|
+
service_src_paths = [f"src/{svc.name.replace('-', '_')}" for svc in spec.services]
|
|
314
326
|
|
|
315
327
|
lines = [
|
|
316
328
|
"[project]",
|
|
@@ -384,7 +396,7 @@ def render_workspace(output_dir: Path, *, git_init: bool = False) -> Path:
|
|
|
384
396
|
# These are deterministic outputs of the spec — like docker-compose.yml.
|
|
385
397
|
# User customization goes in scaffolded files (views, repositories, etc).
|
|
386
398
|
for svc in spec.services:
|
|
387
|
-
svc_dir = output_dir / "src" / svc.name
|
|
399
|
+
svc_dir = output_dir / "src" / svc.name.replace("-", "_")
|
|
388
400
|
if not svc_dir.exists():
|
|
389
401
|
continue
|
|
390
402
|
svc_dir.mkdir(parents=True, exist_ok=True)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Workspace layout contract::
|
|
4
4
|
|
|
5
5
|
<ws-root>/
|
|
6
|
-
src/<
|
|
6
|
+
src/<service_name_snake>/ ← service source (views, settings, __init__)
|
|
7
7
|
tests/unit/<service_name_snake>/ ← unit tests (snake_case)
|
|
8
8
|
tests/acceptance/<service_name_snake>/ ← acceptance test stub
|
|
9
9
|
Dockerfile.<service-name> ← per-service Dockerfile
|
|
@@ -33,15 +33,14 @@ _AUGMENT_TEMPLATE_DIR = Path(__file__).resolve().parent.parent / "templates" / "
|
|
|
33
33
|
def scaffold_service(service: ServiceNode, workspace_root: Path) -> None:
|
|
34
34
|
"""Scaffold a single service into the workspace layout.
|
|
35
35
|
|
|
36
|
-
Skips silently if ``src/<
|
|
36
|
+
Skips silently if ``src/<service_name_snake>/`` already exists (idempotent).
|
|
37
37
|
"""
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
service_name_snake = service.name.replace("-", "_")
|
|
40
|
+
src_dest = workspace_root / "src" / service_name_snake
|
|
40
41
|
if src_dest.exists():
|
|
41
42
|
return
|
|
42
43
|
|
|
43
|
-
service_name_snake = service.name.replace("-", "_")
|
|
44
|
-
|
|
45
44
|
with tempfile.TemporaryDirectory() as tmp:
|
|
46
45
|
tmp_path = Path(tmp)
|
|
47
46
|
|
|
@@ -190,6 +189,16 @@ def _augment_template_vars(
|
|
|
190
189
|
variables["auth_service_name"] = auth_svc.name
|
|
191
190
|
variables["auth_service_port"] = str(auth_svc.port)
|
|
192
191
|
|
|
192
|
+
# Dynamic: auth-passthrough — resolve auth service URL
|
|
193
|
+
if augment.name == "auth-passthrough":
|
|
194
|
+
auth_svc = next(
|
|
195
|
+
(s for s in spec.services if s.role == "auth"),
|
|
196
|
+
None,
|
|
197
|
+
)
|
|
198
|
+
if auth_svc is not None:
|
|
199
|
+
variables["auth_service_name"] = auth_svc.name
|
|
200
|
+
variables["auth_service_port"] = str(auth_svc.port)
|
|
201
|
+
|
|
193
202
|
# Dynamic: delegate-config — resolve targets
|
|
194
203
|
if augment.name == "delegate-config":
|
|
195
204
|
targets = augment.options.get("targets", [])
|
|
@@ -235,7 +244,7 @@ def scaffold_augment(
|
|
|
235
244
|
)
|
|
236
245
|
return
|
|
237
246
|
|
|
238
|
-
svc_dest = workspace_root / "src" / service.name
|
|
247
|
+
svc_dest = workspace_root / "src" / service.name.replace("-", "_")
|
|
239
248
|
if not svc_dest.exists():
|
|
240
249
|
return
|
|
241
250
|
|
|
@@ -251,6 +260,10 @@ def scaffold_augment(
|
|
|
251
260
|
relative = template_file.relative_to(template_dir)
|
|
252
261
|
dest = svc_dest / relative
|
|
253
262
|
|
|
263
|
+
# Strip .template suffix so e.g. db.py.template → db.py
|
|
264
|
+
if dest.name.endswith(".template"):
|
|
265
|
+
dest = dest.with_name(dest.name.removesuffix(".template"))
|
|
266
|
+
|
|
254
267
|
# Never overwrite existing files
|
|
255
268
|
if dest.exists():
|
|
256
269
|
continue
|
|
@@ -29,6 +29,7 @@ _BASE_PACKAGES: list[str] = [
|
|
|
29
29
|
"fastapi>=0.115,<1",
|
|
30
30
|
"uvicorn[standard]>=0.30,<1",
|
|
31
31
|
"pydantic-settings>=2.6,<3",
|
|
32
|
+
"csrd-models>=0.3,<1",
|
|
32
33
|
"csrd-versioning>=0.1.36,<1",
|
|
33
34
|
]
|
|
34
35
|
|
|
@@ -109,7 +110,7 @@ def _augment_settings_fields(
|
|
|
109
110
|
if ws_aug.name == "jwt-auth-provider":
|
|
110
111
|
ws_fields["jwt_algorithm"] = '"RS256"'
|
|
111
112
|
ws_fields["jwt_issuer"] = '"csrd-auth"'
|
|
112
|
-
ws_fields["jwt_audience"] = '"
|
|
113
|
+
ws_fields["jwt_audience"] = f'"{spec.workspace.name}"'
|
|
113
114
|
ws_fields["jwt_ttl_seconds"] = "3600"
|
|
114
115
|
ws_fields["jwt_key_size"] = "2048"
|
|
115
116
|
ws_fields["jwt_key_rotation_interval"] = "86400"
|
|
@@ -152,7 +153,16 @@ def _augment_settings_fields(
|
|
|
152
153
|
)
|
|
153
154
|
augment_fields["jwt_algorithm"] = '"RS256"'
|
|
154
155
|
augment_fields["jwt_issuer"] = '"csrd-auth"'
|
|
155
|
-
augment_fields["jwt_audience"] = '"
|
|
156
|
+
augment_fields["jwt_audience"] = f'"{spec.workspace.name}"'
|
|
157
|
+
|
|
158
|
+
# Dynamic: auth-passthrough
|
|
159
|
+
if augment.name == "auth-passthrough":
|
|
160
|
+
auth_svc = next(
|
|
161
|
+
(s for s in spec.services if s.role == "auth"),
|
|
162
|
+
None,
|
|
163
|
+
)
|
|
164
|
+
if auth_svc is not None:
|
|
165
|
+
augment_fields["auth_service_url"] = f'"http://{auth_svc.name}:{auth_svc.port}"'
|
|
156
166
|
|
|
157
167
|
# Dynamic: delegate-config
|
|
158
168
|
if augment.name == "delegate-config":
|
|
@@ -202,13 +212,10 @@ def render_settings(svc: ServiceNode, spec: ComposeSpec) -> str:
|
|
|
202
212
|
augment_fields = _augment_settings_fields(svc, spec)
|
|
203
213
|
|
|
204
214
|
lines = [
|
|
205
|
-
"from
|
|
215
|
+
"from csrd.models import BaseSettings",
|
|
206
216
|
"",
|
|
207
217
|
"",
|
|
208
218
|
"class Settings(BaseSettings):",
|
|
209
|
-
" model_config = SettingsConfigDict("
|
|
210
|
-
'env_file=".env", env_file_encoding="utf-8", extra="ignore"'
|
|
211
|
-
")",
|
|
212
219
|
"",
|
|
213
220
|
f' app_name: str = "{svc.name}"',
|
|
214
221
|
f" port: int = {svc.port}",
|
|
@@ -281,6 +288,10 @@ def render_init(svc: ServiceNode, spec: ComposeSpec) -> str:
|
|
|
281
288
|
imports.append("")
|
|
282
289
|
imports.append("from csrd.context.middleware import RequestContextMiddleware")
|
|
283
290
|
|
|
291
|
+
if "auth-passthrough" in augment_names:
|
|
292
|
+
imports.append("")
|
|
293
|
+
imports.append("from .views.auth_passthrough_view import router as auth_passthrough_router")
|
|
294
|
+
|
|
284
295
|
if "service-layer" in augment_names:
|
|
285
296
|
imports.append("")
|
|
286
297
|
imports.append("from csrd.service import service_exception_handler")
|
|
@@ -298,12 +309,17 @@ def render_init(svc: ServiceNode, spec: ComposeSpec) -> str:
|
|
|
298
309
|
body.append(" unversioned_app.include_router(jwks_router)")
|
|
299
310
|
body.append("")
|
|
300
311
|
|
|
312
|
+
if "auth-passthrough" in augment_names:
|
|
313
|
+
body.append(" unversioned_app.include_router(auth_passthrough_router)")
|
|
314
|
+
body.append("")
|
|
315
|
+
|
|
301
316
|
body.extend(
|
|
302
317
|
[
|
|
303
318
|
" app = compose_versioned_apps(",
|
|
304
319
|
" version_mapping={UNVERSIONED: unversioned_app},",
|
|
305
320
|
" config=VersionedAppComposeConfig(",
|
|
306
321
|
f' title="{svc.name}",',
|
|
322
|
+
' app_state={"settings": settings},',
|
|
307
323
|
" api=VersionedApiConfig(",
|
|
308
324
|
' prefix="/",',
|
|
309
325
|
" include_actuator_endpoints=settings.include_actuator_endpoints,",
|
csrd_utils-0.3.95/src/csrd_utils/v2/templates/augments/auth-passthrough/delegates/auth_delegate.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Auth service delegate for signup and login.
|
|
2
|
+
|
|
3
|
+
Proxies requests to the auth service's API endpoints.
|
|
4
|
+
This file is scaffolded once and never overwritten.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from csrd.delegate import BaseDelegate
|
|
8
|
+
|
|
9
|
+
from ..models.auth_passthrough import TokenResponse, UserResponse
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class AuthDelegate(BaseDelegate):
|
|
13
|
+
"""Delegate for the cluster auth service."""
|
|
14
|
+
|
|
15
|
+
def __init__(self, base_url: str) -> None:
|
|
16
|
+
super().__init__(base_url)
|
|
17
|
+
|
|
18
|
+
async def signup(self, username: str, password: str) -> UserResponse:
|
|
19
|
+
"""Create a new user account via the auth service."""
|
|
20
|
+
return await self.post(
|
|
21
|
+
"/api/signup",
|
|
22
|
+
json={"username": username, "password": password},
|
|
23
|
+
response_model=UserResponse,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
async def login(self, username: str, password: str) -> TokenResponse:
|
|
27
|
+
"""Authenticate and obtain a JWT token via the auth service."""
|
|
28
|
+
return await self.post(
|
|
29
|
+
"/api/token",
|
|
30
|
+
json={"username": username, "password": password},
|
|
31
|
+
response_model=TokenResponse,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
__all__ = ("AuthDelegate",)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""FastAPI dependency for the auth passthrough delegate.
|
|
2
|
+
|
|
3
|
+
This file is scaffolded once and never overwritten.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Annotated
|
|
7
|
+
|
|
8
|
+
from fastapi import Depends
|
|
9
|
+
|
|
10
|
+
from ..delegates.auth_delegate import AuthDelegate
|
|
11
|
+
from . import Settings
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def auth_delegate_factory(settings: Settings) -> AuthDelegate:
|
|
15
|
+
"""Create an ``AuthDelegate`` bound to the configured auth service URL."""
|
|
16
|
+
return AuthDelegate(settings.auth_service_url)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
AuthDelegateDep = Annotated[AuthDelegate, Depends(auth_delegate_factory)]
|
|
20
|
+
|
|
21
|
+
__all__ = ("AuthDelegateDep", "auth_delegate_factory")
|
csrd_utils-0.3.95/src/csrd_utils/v2/templates/augments/auth-passthrough/models/auth_passthrough.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Auth passthrough request/response models."""
|
|
2
|
+
|
|
3
|
+
from csrd.models import BaseModel
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class SignupRequest(BaseModel):
|
|
7
|
+
"""Signup request body."""
|
|
8
|
+
|
|
9
|
+
username: str
|
|
10
|
+
password: str
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class LoginRequest(BaseModel):
|
|
14
|
+
"""Login request body."""
|
|
15
|
+
|
|
16
|
+
username: str
|
|
17
|
+
password: str
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class TokenResponse(BaseModel):
|
|
21
|
+
"""Token response from the auth service."""
|
|
22
|
+
|
|
23
|
+
access_token: str
|
|
24
|
+
token_type: str = "bearer"
|
|
25
|
+
expires_in: int
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class UserResponse(BaseModel):
|
|
29
|
+
"""User response from the auth service."""
|
|
30
|
+
|
|
31
|
+
id: str
|
|
32
|
+
username: str
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Auth passthrough endpoints — unguarded signup and login.
|
|
2
|
+
|
|
3
|
+
Proxies signup and login requests to the cluster auth service.
|
|
4
|
+
No authentication required on these endpoints.
|
|
5
|
+
This file is scaffolded once and never overwritten.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from fastapi import APIRouter
|
|
9
|
+
|
|
10
|
+
from ..dependencies.auth_passthrough import AuthDelegateDep
|
|
11
|
+
from ..models.auth_passthrough import LoginRequest, SignupRequest, TokenResponse, UserResponse
|
|
12
|
+
|
|
13
|
+
router = APIRouter(prefix="/api/auth", tags=["Auth"])
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@router.post("/signup", status_code=201, response_model=UserResponse)
|
|
17
|
+
async def signup(body: SignupRequest, delegate: AuthDelegateDep) -> UserResponse:
|
|
18
|
+
"""Create a new user account via the auth service."""
|
|
19
|
+
return await delegate.signup(body.username, body.password)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@router.post("/login", response_model=TokenResponse)
|
|
23
|
+
async def login(body: LoginRequest, delegate: AuthDelegateDep) -> TokenResponse:
|
|
24
|
+
"""Authenticate and obtain a JWT token via the auth service."""
|
|
25
|
+
return await delegate.login(body.username, body.password)
|
|
@@ -1,15 +1,19 @@
|
|
|
1
|
-
"""Database adapter
|
|
1
|
+
"""Database adapter dependency for $service_name.
|
|
2
2
|
|
|
3
3
|
This file is scaffolded once and never overwritten. Customize the
|
|
4
4
|
adapter type, DSN construction, or add connection pooling here.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
from typing import Annotated
|
|
8
|
+
|
|
9
|
+
from fastapi import Depends
|
|
10
|
+
|
|
7
11
|
$db_adapter_import
|
|
8
12
|
|
|
9
|
-
from
|
|
13
|
+
from . import Settings
|
|
10
14
|
|
|
11
15
|
|
|
12
|
-
def
|
|
16
|
+
def _create_adapter(settings: Settings) -> $db_adapter_class:
|
|
13
17
|
"""Create the database adapter for this service.
|
|
14
18
|
|
|
15
19
|
Override this to switch adapter types (PGAdapter, MariaAdapter)
|
|
@@ -18,4 +22,6 @@ def create_adapter() -> $db_adapter_class:
|
|
|
18
22
|
return $db_adapter_constructor
|
|
19
23
|
|
|
20
24
|
|
|
21
|
-
|
|
25
|
+
Adapter = Annotated[$db_adapter_class, Depends(_create_adapter)]
|
|
26
|
+
|
|
27
|
+
__all__ = ("Adapter",)
|
|
@@ -13,6 +13,11 @@ from ..settings import settings
|
|
|
13
13
|
|
|
14
14
|
# Build the auth dependency — tokens are verified locally using
|
|
15
15
|
# the public keys from the auth service's JWKS endpoint.
|
|
16
|
+
#
|
|
17
|
+
# Note: this is constructed at module level because FastAPI security
|
|
18
|
+
# dependencies (Security / Depends) must be stable objects. The
|
|
19
|
+
# settings singleton is appropriate here — auth config is fixed
|
|
20
|
+
# for the lifetime of the process.
|
|
16
21
|
auth_dep = create_jwt_bearer(
|
|
17
22
|
key=JWKSKeyProvider(url=settings.auth_jwks_url),
|
|
18
23
|
algorithms=[settings.jwt_algorithm],
|
|
@@ -5,12 +5,12 @@ This file is scaffolded once and never overwritten.
|
|
|
5
5
|
|
|
6
6
|
$db_adapter_import
|
|
7
7
|
|
|
8
|
-
from
|
|
8
|
+
from . import Settings
|
|
9
9
|
|
|
10
10
|
_adapter: $db_adapter_class | None = None
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
async def get_adapter() -> $db_adapter_class:
|
|
13
|
+
async def get_adapter(settings: Settings) -> $db_adapter_class:
|
|
14
14
|
"""Get or create the database adapter (singleton per process)."""
|
|
15
15
|
global _adapter
|
|
16
16
|
if _adapter is None:
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""Token issuance and verification models."""
|
|
2
|
+
|
|
3
|
+
from csrd.models import BaseModel
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class TokenRequest(BaseModel):
|
|
7
|
+
username: str
|
|
8
|
+
password: str
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TokenResponse(BaseModel):
|
|
12
|
+
"""JWT token issuance response."""
|
|
13
|
+
|
|
14
|
+
access_token: str
|
|
15
|
+
token_type: str = "bearer"
|
|
16
|
+
expires_in: int
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class VerifyRequest(BaseModel):
|
|
20
|
+
token: str
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class VerifyClaims(BaseModel):
|
|
24
|
+
"""JWT claim fields returned by the verify endpoint."""
|
|
25
|
+
|
|
26
|
+
sub: str
|
|
27
|
+
user_name: str
|
|
28
|
+
authorities: list[str]
|
|
29
|
+
iat: int
|
|
30
|
+
exp: int
|
|
31
|
+
iss: str
|
|
32
|
+
aud: str
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class VerifyResponse(BaseModel):
|
|
36
|
+
"""Token verification response."""
|
|
37
|
+
|
|
38
|
+
active: bool
|
|
39
|
+
claims: VerifyClaims
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""User management models."""
|
|
2
|
+
|
|
3
|
+
from csrd.models import BaseModel
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class SignupRequest(BaseModel):
|
|
7
|
+
username: str
|
|
8
|
+
password: str
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class UserResponse(BaseModel):
|
|
12
|
+
"""Basic user info returned after signup or lookup."""
|
|
13
|
+
|
|
14
|
+
id: str
|
|
15
|
+
username: str
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class UserRolesResponse(BaseModel):
|
|
19
|
+
"""User with their assigned roles/authorities."""
|
|
20
|
+
|
|
21
|
+
user_id: str
|
|
22
|
+
roles: list[str]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class RoleRequest(BaseModel):
|
|
26
|
+
role: str
|
|
@@ -7,85 +7,93 @@ This file is scaffolded once and never overwritten.
|
|
|
7
7
|
import hashlib
|
|
8
8
|
import secrets
|
|
9
9
|
import uuid
|
|
10
|
-
from typing import Any
|
|
11
10
|
|
|
11
|
+
from fastapi import HTTPException
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
from csrd.repository import BaseRepository
|
|
14
|
+
|
|
15
|
+
from ..models.users import UserResponse, UserRolesResponse
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
|
|
18
|
+
class UserRepository(BaseRepository):
|
|
19
|
+
"""User, credential, and role storage backed by a database adapter."""
|
|
18
20
|
|
|
19
21
|
# ── User CRUD ────────────────────────────────────────────────────
|
|
20
22
|
|
|
21
|
-
async def create_user(self, username: str, password: str) ->
|
|
23
|
+
async def create_user(self, username: str, password: str) -> UserResponse:
|
|
22
24
|
"""Create a new user with hashed credentials."""
|
|
23
25
|
user_id = str(uuid.uuid4())
|
|
24
|
-
await self.
|
|
26
|
+
await self.execute(
|
|
25
27
|
"INSERT INTO users (id, username) VALUES (:id, :username)",
|
|
26
28
|
{"id": user_id, "username": username},
|
|
27
29
|
)
|
|
28
30
|
|
|
29
31
|
password_hash = self._hash_password(password)
|
|
30
|
-
await self.
|
|
32
|
+
await self.execute(
|
|
31
33
|
"INSERT INTO user_credentials (user_id, password_hash) "
|
|
32
34
|
"VALUES (:user_id, :password_hash)",
|
|
33
35
|
{"user_id": user_id, "password_hash": password_hash},
|
|
34
36
|
)
|
|
35
37
|
|
|
36
|
-
return
|
|
38
|
+
return UserResponse(id=user_id, username=username)
|
|
37
39
|
|
|
38
|
-
async def get_user(self, user_id: str) ->
|
|
39
|
-
"""Get a user by ID."""
|
|
40
|
-
return await self.
|
|
41
|
-
"SELECT id, username
|
|
40
|
+
async def get_user(self, user_id: str) -> UserResponse:
|
|
41
|
+
"""Get a user by ID. Raises 404 if not found."""
|
|
42
|
+
return await self.require_one(
|
|
43
|
+
"SELECT id, username FROM users WHERE id = :id",
|
|
42
44
|
{"id": user_id},
|
|
45
|
+
model=UserResponse,
|
|
46
|
+
detail="User not found",
|
|
43
47
|
)
|
|
44
48
|
|
|
45
|
-
async def get_user_by_username(self, username: str) ->
|
|
46
|
-
"""Get a user by username."""
|
|
47
|
-
|
|
48
|
-
"SELECT id, username
|
|
49
|
+
async def get_user_by_username(self, username: str) -> UserResponse | None:
|
|
50
|
+
"""Get a user by username, or ``None`` if not found."""
|
|
51
|
+
row = await self.fetch_one(
|
|
52
|
+
"SELECT id, username FROM users WHERE username = :username",
|
|
49
53
|
{"username": username},
|
|
50
54
|
)
|
|
55
|
+
if row is None:
|
|
56
|
+
return None
|
|
57
|
+
return self.apply_model(row, model=UserResponse)
|
|
51
58
|
|
|
52
59
|
# ── Credential verification ──────────────────────────────────────
|
|
53
60
|
|
|
54
|
-
async def verify_credentials(self, username: str, password: str) ->
|
|
55
|
-
"""Verify username + password.
|
|
61
|
+
async def verify_credentials(self, username: str, password: str) -> UserResponse:
|
|
62
|
+
"""Verify username + password. Raises 401 on failure."""
|
|
56
63
|
user = await self.get_user_by_username(username)
|
|
57
64
|
if user is None:
|
|
58
|
-
|
|
65
|
+
raise HTTPException(status_code=401, detail="Invalid credentials")
|
|
59
66
|
|
|
60
|
-
cred = await self.
|
|
67
|
+
cred = await self.fetch_one(
|
|
61
68
|
"SELECT password_hash FROM user_credentials WHERE user_id = :user_id",
|
|
62
|
-
{"user_id": user
|
|
69
|
+
{"user_id": user.id},
|
|
63
70
|
)
|
|
64
|
-
if cred is None:
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if not self._verify_password(password, cred["password_hash"]):
|
|
68
|
-
return None
|
|
71
|
+
if cred is None or not self._verify_password(password, cred["password_hash"]):
|
|
72
|
+
raise HTTPException(status_code=401, detail="Invalid credentials")
|
|
69
73
|
|
|
70
74
|
return user
|
|
71
75
|
|
|
72
76
|
# ── Role management ──────────────────────────────────────────────
|
|
73
77
|
|
|
74
|
-
async def
|
|
75
|
-
"""Get all roles for a user."""
|
|
76
|
-
|
|
78
|
+
async def get_user_roles(self, user_id: str) -> UserRolesResponse:
|
|
79
|
+
"""Get all roles for a user. Raises 404 if user not found."""
|
|
80
|
+
await self.get_user(user_id) # ensures user exists (raises 404)
|
|
81
|
+
rows = await self.fetch_all(
|
|
77
82
|
"SELECT role FROM user_roles WHERE user_id = :user_id",
|
|
78
83
|
{"user_id": user_id},
|
|
79
84
|
)
|
|
80
|
-
|
|
85
|
+
roles = [row["role"] for row in rows]
|
|
86
|
+
return UserRolesResponse(user_id=user_id, roles=roles)
|
|
81
87
|
|
|
82
|
-
async def add_role(self, user_id: str, role: str) ->
|
|
83
|
-
"""Add a role to a user. Idempotent."""
|
|
84
|
-
await self.
|
|
88
|
+
async def add_role(self, user_id: str, role: str) -> UserRolesResponse:
|
|
89
|
+
"""Add a role to a user. Idempotent. Returns updated roles."""
|
|
90
|
+
await self.get_user(user_id) # ensures user exists (raises 404)
|
|
91
|
+
await self.execute(
|
|
85
92
|
"INSERT OR IGNORE INTO user_roles (user_id, role) "
|
|
86
93
|
"VALUES (:user_id, :role)",
|
|
87
94
|
{"user_id": user_id, "role": role},
|
|
88
95
|
)
|
|
96
|
+
return await self.get_user_roles(user_id)
|
|
89
97
|
|
|
90
98
|
# ── Password hashing ─────────────────────────────────────────────
|
|
91
99
|
#
|