diracx 0.0.1a49__tar.gz → 0.0.1a50__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.
- diracx-0.0.1a50/.github/workflows/generate_pixi_tasks_doc.py +61 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/.github/workflows/main.yml +0 -1
- {diracx-0.0.1a49 → diracx-0.0.1a50}/.pre-commit-config.yaml +14 -2
- {diracx-0.0.1a49 → diracx-0.0.1a50}/.readthedocs.yaml +11 -3
- {diracx-0.0.1a49 → diracx-0.0.1a50}/PKG-INFO +1 -1
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-core/pyproject.toml +1 -1
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-core/src/diracx/core/config/schema.py +14 -5
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/sql/auth/schema.py +6 -2
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/sql/utils/__init__.py +15 -11
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/sql/utils/base.py +33 -1
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/tests/auth/test_refresh_token.py +0 -2
- diracx-0.0.1a50/diracx-db/tests/utils/test_uuid.py +221 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-logic/pyproject.toml +1 -1
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-logic/src/diracx/logic/auth/token.py +16 -12
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-logic/src/diracx/logic/jobs/utils.py +1 -1
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/src/diracx/routers/auth/authorize_code_flow.py +1 -30
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/src/diracx/routers/auth/device_flow.py +1 -50
- diracx-0.0.1a50/docs/SECURITY.md +4 -0
- diracx-0.0.1a50/docs/admin/explanations/auth-with-diracx.md +324 -0
- diracx-0.0.1a50/docs/admin/explanations/auth-with-external.md +32 -0
- diracx-0.0.1a50/docs/admin/how-to/install/embracing.md +128 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/admin/how-to/install/index.md +1 -0
- diracx-0.0.1a50/docs/admin/how-to/install/minimal-requirements.md +15 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/admin/how-to/install/register-a-vo.md +6 -4
- diracx-0.0.1a50/docs/admin/reference/env-variables.md +39 -0
- diracx-0.0.1a50/docs/admin/reference/settings-and-preferences.md +7 -0
- {diracx-0.0.1a49/docs/dev/explanations → diracx-0.0.1a50/docs/dev/explanations/components}/client.md +3 -3
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/explanations/components/db.md +1 -1
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/explanations/components/index.md +2 -2
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/explanations/components/routes.md +7 -5
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/explanations/extensions.md +19 -10
- diracx-0.0.1a50/docs/dev/how-to/client-generation.md +13 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/how-to/contribute.md +2 -2
- diracx-0.0.1a50/docs/dev/reference/entrypoints.md +42 -0
- diracx-0.0.1a50/docs/dev/reference/env-variables.md +5 -0
- diracx-0.0.1a50/docs/dev/reference/pixi-tasks.md +53 -0
- diracx-0.0.1a50/docs/user/index.md +10 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/user/reference/known-installations.md +12 -2
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/containers/services/Dockerfile +2 -1
- {diracx-0.0.1a49 → diracx-0.0.1a50}/mkdocs.yml +6 -5
- {diracx-0.0.1a49 → diracx-0.0.1a50}/pixi.toml +22 -2
- diracx-0.0.1a50/release.notes.new +22 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/tests/make_token_local.py +6 -4
- diracx-0.0.1a49/docs/SECURITY.md +0 -3
- diracx-0.0.1a49/docs/admin/explanations/authentication.md +0 -3
- diracx-0.0.1a49/docs/admin/how-to/install/embracing.md +0 -13
- diracx-0.0.1a49/docs/admin/reference/settings-and-preferences.md +0 -0
- diracx-0.0.1a49/docs/assets/images/pic02.jpg +0 -0
- diracx-0.0.1a49/docs/dev/how-to/client-generation.md +0 -2
- diracx-0.0.1a49/docs/dev/reference/entrypoints.md +0 -3
- diracx-0.0.1a49/docs/dev/reference/pixi-tasks.md +0 -3
- diracx-0.0.1a49/docs/user/index.md +0 -3
- diracx-0.0.1a49/release.notes.new +0 -43
- {diracx-0.0.1a49 → diracx-0.0.1a50}/.coveragerc +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/.gitattributes +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/.github/dependabot.yml +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/.github/workflows/deployment.yml +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/.github/workflows/integration.yml +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/.github/workflows/make_release.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/.github/workflows/update_chart_version.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/.github/workflows/update_security_txt_expiry.yml +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/.github/workflows/vulnerabilities.yml +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/.gitignore +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/LICENSE +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/MANIFEST.in +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/README.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/codecov.yml +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/containers/client/Dockerfile +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/containers/services/Dockerfile +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-api/README.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-api/pyproject.toml +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-api/src/diracx/api/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-api/src/diracx/api/jobs.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-api/src/diracx/api/py.typed +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-api/src/diracx/api/utils.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-api/tests/test_jobs.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-api/tests/test_utils.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-cli/README.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-cli/pyproject.toml +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-cli/src/diracx/cli/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-cli/src/diracx/cli/__main__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-cli/src/diracx/cli/auth.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-cli/src/diracx/cli/config.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-cli/src/diracx/cli/internal/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-cli/src/diracx/cli/internal/config.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-cli/src/diracx/cli/internal/legacy.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-cli/src/diracx/cli/jobs.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-cli/src/diracx/cli/py.typed +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-cli/src/diracx/cli/utils.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-cli/tests/legacy/cs_sync/integration_test.cfg +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-cli/tests/legacy/cs_sync/integration_test.yaml +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-cli/tests/legacy/cs_sync/integration_test_buggy.cfg +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-cli/tests/legacy/cs_sync/integration_test_secret.cfg +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-cli/tests/legacy/cs_sync/test_cssync.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-cli/tests/legacy/test_legacy.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-cli/tests/test_internal.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-cli/tests/test_jobs.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-cli/tests/test_login.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/README.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/pyproject.toml +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/_diracx_client_importer.pth +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/_client_importer.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/_generated/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/_generated/_client.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/_generated/_configuration.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/_generated/_patch.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/_generated/_serialization.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/_generated/_utils/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/_generated/_utils/serialization.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/_generated/_utils/utils.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/_generated/_vendor.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/_generated/aio/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/_generated/aio/_client.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/_generated/aio/_configuration.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/_generated/aio/_patch.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/_generated/aio/_vendor.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/_generated/aio/operations/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/_generated/aio/operations/_operations.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/_generated/aio/operations/_patch.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/_generated/models/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/_generated/models/_enums.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/_generated/models/_models.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/_generated/models/_patch.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/_generated/operations/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/_generated/operations/_operations.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/_generated/operations/_patch.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/_generated/py.typed +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/aio.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/models.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/patches/auth/aio.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/patches/auth/common.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/patches/auth/sync.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/patches/client/aio.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/patches/client/common.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/patches/client/sync.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/patches/jobs/aio.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/patches/jobs/common.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/patches/jobs/sync.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/patches/utils.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/py.typed +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/src/diracx/client/sync.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-client/tests/test_auth.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-core/README.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-core/src/diracx/core/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-core/src/diracx/core/config/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-core/src/diracx/core/config/sources.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-core/src/diracx/core/exceptions.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-core/src/diracx/core/extensions.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-core/src/diracx/core/models.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-core/src/diracx/core/preferences.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-core/src/diracx/core/properties.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-core/src/diracx/core/py.typed +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-core/src/diracx/core/resources.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-core/src/diracx/core/s3.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-core/src/diracx/core/settings.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-core/src/diracx/core/utils.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-core/tests/test_config_source.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-core/tests/test_entry_points.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-core/tests/test_extensions.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-core/tests/test_resources.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-core/tests/test_s3.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-core/tests/test_secrets.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-core/tests/test_utils.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/README.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/pyproject.toml +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/__main__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/exceptions.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/os/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/os/job_parameters.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/os/utils.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/py.typed +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/sql/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/sql/auth/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/sql/auth/db.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/sql/dummy/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/sql/dummy/db.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/sql/dummy/schema.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/sql/job/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/sql/job/db.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/sql/job/schema.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/sql/job_logging/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/sql/job_logging/db.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/sql/job_logging/schema.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/sql/pilot_agents/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/sql/pilot_agents/db.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/sql/pilot_agents/schema.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/sql/sandbox_metadata/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/sql/sandbox_metadata/db.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/sql/sandbox_metadata/schema.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/sql/task_queue/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/sql/task_queue/db.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/sql/task_queue/schema.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/sql/utils/functions.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/src/diracx/db/sql/utils/types.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/tests/auth/test_authorization_flow.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/tests/auth/test_device_flow.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/tests/jobs/test_job_db.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/tests/jobs/test_job_logging_db.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/tests/jobs/test_sandbox_metadata.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/tests/opensearch/test_connection.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/tests/opensearch/test_index_template.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/tests/opensearch/test_search.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/tests/pilot_agents/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/tests/pilot_agents/test_pilot_agents_db.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/tests/test_dummy_db.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-db/tests/test_freeze_time.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-logic/README.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-logic/src/diracx/logic/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-logic/src/diracx/logic/__main__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-logic/src/diracx/logic/auth/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-logic/src/diracx/logic/auth/authorize_code_flow.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-logic/src/diracx/logic/auth/device_flow.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-logic/src/diracx/logic/auth/management.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-logic/src/diracx/logic/auth/utils.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-logic/src/diracx/logic/auth/well_known.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-logic/src/diracx/logic/jobs/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-logic/src/diracx/logic/jobs/query.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-logic/src/diracx/logic/jobs/sandboxes.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-logic/src/diracx/logic/jobs/status.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-logic/src/diracx/logic/jobs/submission.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-logic/src/diracx/logic/py.typed +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-logic/src/diracx/logic/task_queues/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-logic/src/diracx/logic/task_queues/priority.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-logic/tests/jobs/test_sandboxes.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-logic/tests/jobs/test_status.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/README.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/pyproject.toml +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/src/diracx/routers/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/src/diracx/routers/access_policies.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/src/diracx/routers/auth/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/src/diracx/routers/auth/management.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/src/diracx/routers/auth/token.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/src/diracx/routers/auth/utils.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/src/diracx/routers/auth/well_known.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/src/diracx/routers/configuration.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/src/diracx/routers/dependencies.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/src/diracx/routers/factory.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/src/diracx/routers/fastapi_classes.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/src/diracx/routers/health/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/src/diracx/routers/health/probes.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/src/diracx/routers/jobs/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/src/diracx/routers/jobs/access_policies.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/src/diracx/routers/jobs/legacy.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/src/diracx/routers/jobs/query.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/src/diracx/routers/jobs/sandboxes.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/src/diracx/routers/jobs/status.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/src/diracx/routers/jobs/submission.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/src/diracx/routers/otel.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/src/diracx/routers/py.typed +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/src/diracx/routers/utils/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/src/diracx/routers/utils/users.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/tests/auth/test_legacy_exchange.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/tests/auth/test_standard.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/tests/data/idp-server.invalid/.well-known/openid-configuration +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/tests/health/test_probes.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/tests/jobs/conftest.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/tests/jobs/test_query.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/tests/jobs/test_sandboxes.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/tests/jobs/test_status.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/tests/jobs/test_wms_access_policy.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/tests/test_config_manager.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/tests/test_generic.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/tests/test_policy.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-testing/README.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-testing/pyproject.toml +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-testing/src/diracx/testing/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-testing/src/diracx/testing/__main__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-testing/src/diracx/testing/client_generation.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-testing/src/diracx/testing/client_generation_pytest.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-testing/src/diracx/testing/dummy_osdb.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-testing/src/diracx/testing/entrypoints.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-testing/src/diracx/testing/mock_osdb.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-testing/src/diracx/testing/osdb.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-testing/src/diracx/testing/routers.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-testing/src/diracx/testing/scripts/collect_demo_coverage.sh +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-testing/src/diracx/testing/time.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-testing/src/diracx/testing/utils.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/admin/explanations/configuration.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/admin/explanations/opentelemetry.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/admin/explanations/sandbox-store.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/admin/explanations/user-management.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/admin/how-to/install/convert-cs.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/admin/how-to/install/register-the-admin-vo.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/admin/index.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/admin/reference/security_model.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/admin/tutorials/authentication.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/assets/css/extra.css +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/assets/css/fontawesome-all.min.css +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/assets/css/images/arrow.svg +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/assets/css/images/overlay.png +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/assets/css/main.css +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/assets/home.html +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/assets/images/diracx-logo-square.svg +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/assets/images/logo.svg +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/assets/styles/extra.css +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/assets/webfonts/fa-brands-400.woff2 +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/assets/webfonts/fa-solid-900.woff +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/explanations/components/api.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/explanations/components/cli.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/explanations/designing-functionality.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/explanations/index.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/explanations/testing.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/how-to/add-a-cli-command.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/how-to/add-a-db.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/how-to/add-a-route.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/how-to/add-a-setting.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/how-to/add-a-task.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/how-to/add-a-test.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/how-to/add-functionality/index.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/how-to/client-customization.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/how-to/client-extension.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/how-to/develop-legacy-dirac.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/how-to/extend-diracx/index.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/how-to/use-the-demo/index.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/how-to/use-the-demo/swagger.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/how-to/use-the-demo/web.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/index.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/reference/application-state.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/reference/client-metapathfinder.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/reference/coding-conventions.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/reference/configuration.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/reference/db-transaction-model.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/reference/dependency-injection.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/reference/security-policies.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/reference/security-properties.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/reference/test-recipes.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/reference/writing-tests.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/tutorials/advanced-tutorial.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/tutorials/develop-web.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/tutorials/getting-started.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/tutorials/larger-developments.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/tutorials/making-changes.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/tutorials/play-with-auth.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/tutorials/run-locally.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/dev/tutorials/write-docs.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/index.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/overrides/main.html +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/roadmap.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/user/reference/client-configuration.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/user/reference/programmatic-usage/command-line-interface.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/user/reference/programmatic-usage/https-interface.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/user/reference/programmatic-usage/index.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/user/reference/programmatic-usage/python-interface.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/docs/user/tutorials/getting-started.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/containers/client/Dockerfile +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/.github/workflows/main.yml +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/README.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-api/README.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-api/pyproject.toml +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-api/src/gubbins/api/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-api/src/gubbins/api/py.typed +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-api/tests/test_gubbins_api.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-cli/README.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-cli/pyproject.toml +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-cli/src/gubbins/cli/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-cli/src/gubbins/cli/config.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-cli/src/gubbins/cli/lollygag.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-cli/src/gubbins/cli/py.typed +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-cli/tests/test_gubbins_cli.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/README.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/pyproject.toml +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/_client.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/_configuration.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/_patch.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/_serialization.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/_utils/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/_utils/serialization.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/_utils/utils.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/_vendor.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/aio/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/aio/_client.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/aio/_configuration.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/aio/_patch.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/aio/_vendor.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/aio/operations/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/aio/operations/_operations.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/aio/operations/_patch.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/models/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/models/_enums.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/models/_models.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/operations/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/operations/_operations.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/operations/_patch.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/_generated/py.typed +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/aio.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/models.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/py.typed +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/src/gubbins/client/sync.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-client/tests/test_gubbins_client.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-core/README.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-core/pyproject.toml +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-core/src/gubbins/core/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-core/src/gubbins/core/config/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-core/src/gubbins/core/config/schema.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-core/src/gubbins/core/models.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-core/src/gubbins/core/properties.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-core/src/gubbins/core/py.typed +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-core/tests/test_config.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-core/tests/test_properties.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-db/README.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-db/pyproject.toml +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-db/src/gubbins/db/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-db/src/gubbins/db/py.typed +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-db/src/gubbins/db/sql/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-db/src/gubbins/db/sql/jobs/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-db/src/gubbins/db/sql/jobs/db.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-db/src/gubbins/db/sql/jobs/schema.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-db/src/gubbins/db/sql/lollygag/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-db/src/gubbins/db/sql/lollygag/db.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-db/src/gubbins/db/sql/lollygag/schema.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-db/tests/test_gubbins_job_db.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-db/tests/test_lollygag_db.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-logic/README.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-logic/pyproject.toml +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-logic/src/gubbins/logic/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-logic/src/gubbins/logic/auth/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-logic/src/gubbins/logic/auth/well_known.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-logic/src/gubbins/logic/lollygag/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-logic/src/gubbins/logic/lollygag/lollygag.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-logic/src/gubbins/logic/py.typed +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-logic/tests/test_gubbins_logic.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-routers/README.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-routers/pyproject.toml +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-routers/src/gubbins/routers/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-routers/src/gubbins/routers/dependencies.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-routers/src/gubbins/routers/lollygag/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-routers/src/gubbins/routers/lollygag/access_policy.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-routers/src/gubbins/routers/lollygag/lollygag.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-routers/src/gubbins/routers/py.typed +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-routers/src/gubbins/routers/well_known.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-routers/tests/data/idp-server.invalid/.well-known/openid-configuration +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-routers/tests/test_gubbins_job_manager.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-routers/tests/test_lollybag.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-routers/tests/test_wellknown.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-testing/README.md +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-testing/pyproject.toml +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/gubbins-testing/src/gubbins/testing/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/pixi.toml +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/pyproject.toml +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins/release.notes +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/extensions/gubbins_values.yaml +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/pyproject.toml +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/release.notes +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/release.notes.old +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/run_local.sh +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/tests/__init__.py +0 -0
- {diracx-0.0.1a49 → diracx-0.0.1a50}/tests/test_generic.py +0 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import subprocess
|
|
5
|
+
from collections import defaultdict
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_task_group(task_name):
|
|
9
|
+
if task_name.startswith("pytest-diracx"):
|
|
10
|
+
return "DiracX"
|
|
11
|
+
if task_name.startswith("pytest-gubbins"):
|
|
12
|
+
return "Gubbins"
|
|
13
|
+
if task_name.startswith("mkdocs"):
|
|
14
|
+
return "Documentation"
|
|
15
|
+
if task_name == "pre-commit":
|
|
16
|
+
return "Pre-commit"
|
|
17
|
+
if task_name == "generate-client":
|
|
18
|
+
return "Client Generation"
|
|
19
|
+
if task_name == "shellcheck":
|
|
20
|
+
return "Shellcheck"
|
|
21
|
+
return "Default"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def main():
|
|
25
|
+
"""Generate the pixi-tasks.md file."""
|
|
26
|
+
result = subprocess.run(
|
|
27
|
+
["pixi", "task", "list", "--json"], # noqa: S607
|
|
28
|
+
capture_output=True,
|
|
29
|
+
text=True,
|
|
30
|
+
)
|
|
31
|
+
environments = json.loads(result.stdout)
|
|
32
|
+
|
|
33
|
+
tasks_by_group = defaultdict(list)
|
|
34
|
+
for env in environments:
|
|
35
|
+
for feature in env["features"]:
|
|
36
|
+
for task in feature["tasks"]:
|
|
37
|
+
group = get_task_group(task["name"])
|
|
38
|
+
tasks_by_group[group].append(task)
|
|
39
|
+
|
|
40
|
+
with open("docs/dev/reference/pixi-tasks.md", "w") as f:
|
|
41
|
+
f.write("# Pixi Tasks\n\n")
|
|
42
|
+
f.write("*This page is auto-generated. Do not edit directly.*\n\n")
|
|
43
|
+
f.write("DiracX uses [Pixi](https://pixi.dev/) as package manager\n")
|
|
44
|
+
f.write("This page documents the available pixi tasks.\n\n")
|
|
45
|
+
|
|
46
|
+
for group in sorted(tasks_by_group.keys()):
|
|
47
|
+
f.write(f"## {group} Tasks\n\n")
|
|
48
|
+
# Remove duplicates
|
|
49
|
+
tasks = list({v["name"]: v for v in tasks_by_group[group]}.values())
|
|
50
|
+
for task in sorted(tasks, key=lambda x: x["name"]):
|
|
51
|
+
description = (
|
|
52
|
+
task.get("description") or task.get("cmd") or "No description"
|
|
53
|
+
)
|
|
54
|
+
f.write(f"- `{task['name']}`: {description}\n")
|
|
55
|
+
f.write("\n")
|
|
56
|
+
|
|
57
|
+
f.write("Generated by .github/workflows/generate_pixi_tasks_doc.py\n")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
if __name__ == "__main__":
|
|
61
|
+
main()
|
|
@@ -7,6 +7,9 @@ default_install_hook_types:
|
|
|
7
7
|
default_language_version:
|
|
8
8
|
python: python3
|
|
9
9
|
|
|
10
|
+
ci:
|
|
11
|
+
skip: [generate-pixi-docs]
|
|
12
|
+
|
|
10
13
|
default_stages: [pre-commit]
|
|
11
14
|
|
|
12
15
|
repos:
|
|
@@ -27,14 +30,14 @@ repos:
|
|
|
27
30
|
- id: check-added-large-files
|
|
28
31
|
|
|
29
32
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
30
|
-
rev: 'v0.
|
|
33
|
+
rev: 'v0.13.0'
|
|
31
34
|
hooks:
|
|
32
35
|
- id: ruff
|
|
33
36
|
args: ["--fix", "--show-fixes"]
|
|
34
37
|
- id: ruff-format
|
|
35
38
|
|
|
36
39
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
|
37
|
-
rev: v1.
|
|
40
|
+
rev: v1.18.1
|
|
38
41
|
hooks:
|
|
39
42
|
- id: mypy
|
|
40
43
|
additional_dependencies:
|
|
@@ -71,3 +74,12 @@ repos:
|
|
|
71
74
|
entry: '(?i)lollygag'
|
|
72
75
|
language: pygrep
|
|
73
76
|
files: ^diracx
|
|
77
|
+
|
|
78
|
+
- repo: local
|
|
79
|
+
hooks:
|
|
80
|
+
- id: generate-pixi-docs
|
|
81
|
+
name: Generate pixi tasks documentation
|
|
82
|
+
entry: pixi run -e default python .github/workflows/generate_pixi_tasks_doc.py
|
|
83
|
+
language: system
|
|
84
|
+
pass_filenames: false
|
|
85
|
+
files: ^pixi\.toml$|^pixi\.lock$ # only run if pixi files change
|
|
@@ -8,9 +8,17 @@
|
|
|
8
8
|
# This is just a quick example to get started.
|
|
9
9
|
# https://docs.readthedocs.io/page/guides/reproducible-builds.html
|
|
10
10
|
jobs:
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
create_environment:
|
|
12
|
+
- asdf plugin add pixi
|
|
13
|
+
- asdf install pixi latest
|
|
14
|
+
- asdf global pixi latest
|
|
15
|
+
|
|
16
|
+
install:
|
|
17
|
+
- pixi install -e mkdocs
|
|
18
|
+
|
|
19
|
+
build:
|
|
20
|
+
html:
|
|
21
|
+
- pixi run -e mkdocs mkdocs-build --site-dir $READTHEDOCS_OUTPUT/html
|
|
14
22
|
|
|
15
23
|
mkdocs:
|
|
16
24
|
configuration: mkdocs.yml
|
|
@@ -147,20 +147,29 @@ class JobDescriptionConfig(BaseModel):
|
|
|
147
147
|
AllowedJobTypes: list[str] = ["User", "Test", "Hospital"]
|
|
148
148
|
|
|
149
149
|
|
|
150
|
-
class
|
|
151
|
-
|
|
150
|
+
class InputDataPolicyProtocolsConfig(BaseModel):
|
|
151
|
+
Remote: list[str] = []
|
|
152
|
+
Local: list[str] = []
|
|
152
153
|
|
|
153
154
|
|
|
154
|
-
class
|
|
155
|
-
|
|
155
|
+
class InputDataPolicyConfig(BaseModel):
|
|
156
|
+
# TODO: Remove this once the model is extended to support everything
|
|
157
|
+
model_config = ConfigDict(extra="ignore", frozen=True)
|
|
158
|
+
|
|
159
|
+
Default: str = "Default = DIRAC.WorkloadManagementSystem.Client.InputDataByProtocol"
|
|
160
|
+
Download: str = "DIRAC.WorkloadManagementSystem.Client.DownloadInputData"
|
|
161
|
+
Protocol: str = "DIRAC.WorkloadManagementSystem.Client.InputDataByProtocol"
|
|
162
|
+
AllReplicas: bool = True
|
|
163
|
+
Protocols: InputDataPolicyProtocolsConfig = InputDataPolicyProtocolsConfig()
|
|
164
|
+
InputDataModule: str = "DIRAC.Core.Utilities.InputDataResolution"
|
|
156
165
|
|
|
157
166
|
|
|
158
167
|
class OperationsConfig(BaseModel):
|
|
159
168
|
EnableSecurityLogging: bool = False
|
|
160
|
-
ExternalsPolicy: ExternalsPolicyConfig = ExternalsPolicyConfig()
|
|
161
169
|
InputDataPolicy: InputDataPolicyConfig = InputDataPolicyConfig()
|
|
162
170
|
JobDescription: JobDescriptionConfig = JobDescriptionConfig()
|
|
163
171
|
Services: ServicesConfig = ServicesConfig()
|
|
172
|
+
SoftwareDistModule: str = "LocalSoftwareDist"
|
|
164
173
|
|
|
165
174
|
Cloud: MutableMapping[str, Any] | None = None
|
|
166
175
|
DataConsistency: MutableMapping[str, Any] | None = None
|
|
@@ -10,7 +10,12 @@ from sqlalchemy import (
|
|
|
10
10
|
)
|
|
11
11
|
from sqlalchemy.orm import declarative_base
|
|
12
12
|
|
|
13
|
-
from diracx.db.sql.utils import
|
|
13
|
+
from diracx.db.sql.utils import (
|
|
14
|
+
Column,
|
|
15
|
+
DateNowColumn,
|
|
16
|
+
EnumColumn,
|
|
17
|
+
NullColumn,
|
|
18
|
+
)
|
|
14
19
|
|
|
15
20
|
USER_CODE_LENGTH = 8
|
|
16
21
|
|
|
@@ -92,7 +97,6 @@ class RefreshTokens(Base):
|
|
|
92
97
|
status = EnumColumn(
|
|
93
98
|
"Status", RefreshTokenStatus, server_default=RefreshTokenStatus.CREATED.name
|
|
94
99
|
)
|
|
95
|
-
creation_time = DateNowColumn("CreationTime", index=True)
|
|
96
100
|
scope = Column("Scope", String(1024))
|
|
97
101
|
|
|
98
102
|
# User attributes bound to the refresh token
|
|
@@ -1,16 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
BaseSQLDB,
|
|
5
|
-
SQLDBUnavailableError,
|
|
6
|
-
_get_columns,
|
|
7
|
-
apply_search_filters,
|
|
8
|
-
apply_sort_constraints,
|
|
9
|
-
)
|
|
10
|
-
from .functions import hash, substract_date, utcnow
|
|
11
|
-
from .types import Column, DateNowColumn, EnumBackedBool, EnumColumn, NullColumn
|
|
12
|
-
|
|
13
|
-
__all__ = (
|
|
3
|
+
__all__ = [
|
|
14
4
|
"_get_columns",
|
|
15
5
|
"utcnow",
|
|
16
6
|
"Column",
|
|
@@ -24,4 +14,18 @@ __all__ = (
|
|
|
24
14
|
"substract_date",
|
|
25
15
|
"hash",
|
|
26
16
|
"SQLDBUnavailableError",
|
|
17
|
+
"uuid7_from_datetime",
|
|
18
|
+
"uuid7_to_datetime",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
from .base import (
|
|
22
|
+
BaseSQLDB,
|
|
23
|
+
SQLDBUnavailableError,
|
|
24
|
+
_get_columns,
|
|
25
|
+
apply_search_filters,
|
|
26
|
+
apply_sort_constraints,
|
|
27
|
+
uuid7_from_datetime,
|
|
28
|
+
uuid7_to_datetime,
|
|
27
29
|
)
|
|
30
|
+
from .functions import hash, substract_date, utcnow
|
|
31
|
+
from .types import Column, DateNowColumn, EnumBackedBool, EnumColumn, NullColumn
|
|
@@ -7,13 +7,15 @@ import re
|
|
|
7
7
|
from abc import ABCMeta
|
|
8
8
|
from collections.abc import AsyncIterator
|
|
9
9
|
from contextvars import ContextVar
|
|
10
|
-
from datetime import datetime
|
|
10
|
+
from datetime import datetime, timezone
|
|
11
11
|
from typing import Any, Self, cast
|
|
12
|
+
from uuid import UUID as StdUUID # noqa: N811
|
|
12
13
|
|
|
13
14
|
from pydantic import TypeAdapter
|
|
14
15
|
from sqlalchemy import DateTime, MetaData, func, select
|
|
15
16
|
from sqlalchemy.exc import OperationalError
|
|
16
17
|
from sqlalchemy.ext.asyncio import AsyncConnection, AsyncEngine, create_async_engine
|
|
18
|
+
from uuid_utils import UUID, uuid7
|
|
17
19
|
|
|
18
20
|
from diracx.core.exceptions import InvalidQueryError
|
|
19
21
|
from diracx.core.extensions import select_from_extension
|
|
@@ -416,3 +418,33 @@ def apply_sort_constraints(column_mapping, stmt, sorts):
|
|
|
416
418
|
if sort_columns:
|
|
417
419
|
stmt = stmt.order_by(*sort_columns)
|
|
418
420
|
return stmt
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
def uuid7_to_datetime(uuid: UUID | StdUUID | str) -> datetime:
|
|
424
|
+
"""Convert a UUIDv7 to a datetime."""
|
|
425
|
+
if isinstance(uuid, StdUUID):
|
|
426
|
+
# Convert stdlib UUID to uuid_utils.UUID
|
|
427
|
+
uuid = UUID(str(uuid))
|
|
428
|
+
elif not isinstance(uuid, UUID):
|
|
429
|
+
# Convert string or other types to uuid_utils.UUID
|
|
430
|
+
uuid = UUID(uuid)
|
|
431
|
+
if uuid.version != 7:
|
|
432
|
+
raise ValueError(f"UUID {uuid} is not a UUIDv7")
|
|
433
|
+
return datetime.fromtimestamp(uuid.timestamp / 1000.0, tz=timezone.utc)
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
def uuid7_from_datetime(dt: datetime, *, randomize: bool = True) -> UUID:
|
|
437
|
+
"""Generate a UUIDv7 corresponding to the given datetime.
|
|
438
|
+
|
|
439
|
+
If randomize is True, the standard uuid7 function is used resulting in the
|
|
440
|
+
lowest 62-bits being random. If randomize is False, the UUIDv7 will be the
|
|
441
|
+
lowest possible UUIDv7 for the given datetime.
|
|
442
|
+
"""
|
|
443
|
+
timestamp = dt.timestamp()
|
|
444
|
+
if randomize:
|
|
445
|
+
uuid = uuid7(int(timestamp), int((timestamp % 1) * 1e9))
|
|
446
|
+
else:
|
|
447
|
+
time_high = int(timestamp * 1000) >> 16
|
|
448
|
+
time_low = int(timestamp * 1000) & 0xFFFF
|
|
449
|
+
uuid = UUID.from_fields((time_high, time_low, 0x7000, 0x80, 0, 0))
|
|
450
|
+
return uuid
|
|
@@ -56,7 +56,6 @@ async def test_get(auth_db: AuthDB):
|
|
|
56
56
|
refresh_token_details["sub"],
|
|
57
57
|
refresh_token_details["scope"],
|
|
58
58
|
)
|
|
59
|
-
creation_time = (await auth_db.get_refresh_token(jti))["CreationTime"]
|
|
60
59
|
|
|
61
60
|
# Enrich the dict with the generated refresh token attributes
|
|
62
61
|
expected_refresh_token = {
|
|
@@ -64,7 +63,6 @@ async def test_get(auth_db: AuthDB):
|
|
|
64
63
|
"Scope": refresh_token_details["scope"],
|
|
65
64
|
"JTI": jti,
|
|
66
65
|
"Status": RefreshTokenStatus.CREATED,
|
|
67
|
-
"CreationTime": creation_time,
|
|
68
66
|
}
|
|
69
67
|
|
|
70
68
|
# Get refresh token details
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from datetime import datetime, timedelta, timezone
|
|
4
|
+
from uuid import UUID as StdUUID # noqa: N811
|
|
5
|
+
|
|
6
|
+
import freezegun
|
|
7
|
+
import pytest
|
|
8
|
+
from uuid_utils import UUID, uuid7
|
|
9
|
+
|
|
10
|
+
from diracx.db.sql.utils import uuid7_from_datetime, uuid7_to_datetime
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def frozen_uuid7() -> UUID:
|
|
14
|
+
"""Create a UUID7 in a way which respects the freezegun context."""
|
|
15
|
+
timestamp = datetime.now(tz=timezone.utc).timestamp()
|
|
16
|
+
return uuid7(int(timestamp), int((timestamp % 1) * 1e9))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TestDatetimeToUuid7:
|
|
20
|
+
"""Test cases for the datetime_to_uuid7 function."""
|
|
21
|
+
|
|
22
|
+
def test_datetime_to_uuid7_random(self):
|
|
23
|
+
"""Test that the datetime_to_uuid7 function returns a UUID7 with the current timestamp."""
|
|
24
|
+
dt = datetime.fromisoformat("2024-01-15T12:30:45.123456+00:00")
|
|
25
|
+
result = uuid7_from_datetime(dt, randomize=True)
|
|
26
|
+
assert str(result)[:15] == "018d0d1a-5183-7"
|
|
27
|
+
assert len(set(str(result)[15:])) > 4
|
|
28
|
+
|
|
29
|
+
def test_datetime_to_uuid7_deterministic(self):
|
|
30
|
+
"""Test that the datetime_to_uuid7 function returns a UUID7 with the current timestamp."""
|
|
31
|
+
dt = datetime.fromisoformat("2024-01-15T12:30:45.123456+00:00")
|
|
32
|
+
result = uuid7_from_datetime(dt, randomize=False)
|
|
33
|
+
assert str(result) == "018d0d1a-5183-7000-8000-000000000000"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class TestUuid7ToDatetime:
|
|
37
|
+
"""Test cases for the uuid7_to_datetime function."""
|
|
38
|
+
|
|
39
|
+
def test_uuid7_now(self):
|
|
40
|
+
"""Test that the uuid7 function returns a UUID7 with the current timestamp."""
|
|
41
|
+
test_uuid = frozen_uuid7()
|
|
42
|
+
result = uuid7_to_datetime(test_uuid)
|
|
43
|
+
assert result.tzinfo == timezone.utc
|
|
44
|
+
assert result - datetime.now(tz=timezone.utc) < timedelta(milliseconds=2)
|
|
45
|
+
|
|
46
|
+
@freezegun.freeze_time("2024-01-15 12:30:45.123456")
|
|
47
|
+
def test_uuid7_to_datetime_with_uuid_utils_uuid(self):
|
|
48
|
+
"""Test conversion with uuid_utils.UUID object."""
|
|
49
|
+
test_uuid = frozen_uuid7()
|
|
50
|
+
result = uuid7_to_datetime(test_uuid)
|
|
51
|
+
|
|
52
|
+
assert isinstance(result, datetime)
|
|
53
|
+
assert result.tzinfo == timezone.utc
|
|
54
|
+
assert result.isoformat() == "2024-01-15T12:30:45.123000+00:00"
|
|
55
|
+
|
|
56
|
+
@freezegun.freeze_time("2024-01-15 12:30:45.123456")
|
|
57
|
+
def test_uuid7_to_datetime_with_stdlib_uuid(self):
|
|
58
|
+
"""Test conversion with standard library UUID object."""
|
|
59
|
+
test_uuid = frozen_uuid7()
|
|
60
|
+
stdlib_uuid = StdUUID(str(test_uuid))
|
|
61
|
+
|
|
62
|
+
result = uuid7_to_datetime(stdlib_uuid)
|
|
63
|
+
assert isinstance(result, datetime)
|
|
64
|
+
assert result.tzinfo == timezone.utc
|
|
65
|
+
|
|
66
|
+
@freezegun.freeze_time("2024-01-15 12:30:45.123456")
|
|
67
|
+
def test_uuid7_to_datetime_with_string_uuid(self):
|
|
68
|
+
"""Test conversion with string UUID that gets converted to uuid_utils.UUID."""
|
|
69
|
+
test_uuid = frozen_uuid7()
|
|
70
|
+
uuid_string = str(test_uuid)
|
|
71
|
+
|
|
72
|
+
result = uuid7_to_datetime(uuid_string)
|
|
73
|
+
assert isinstance(result, datetime)
|
|
74
|
+
assert result.tzinfo == timezone.utc
|
|
75
|
+
|
|
76
|
+
@freezegun.freeze_time("2024-01-15 12:30:45.123456")
|
|
77
|
+
def test_uuid7_to_datetime_precision(self):
|
|
78
|
+
"""Test that the conversion maintains reasonable precision."""
|
|
79
|
+
test_uuid = frozen_uuid7()
|
|
80
|
+
result = uuid7_to_datetime(test_uuid)
|
|
81
|
+
|
|
82
|
+
assert isinstance(result, datetime)
|
|
83
|
+
assert result.tzinfo == timezone.utc
|
|
84
|
+
assert result.isoformat() == "2024-01-15T12:30:45.123000+00:00"
|
|
85
|
+
|
|
86
|
+
@freezegun.freeze_time("1970-01-01 00:00:00.000000")
|
|
87
|
+
def test_uuid7_to_datetime_epoch_boundary(self):
|
|
88
|
+
"""Test conversion with UUID7 at epoch boundary."""
|
|
89
|
+
test_uuid = frozen_uuid7()
|
|
90
|
+
result = uuid7_to_datetime(test_uuid)
|
|
91
|
+
|
|
92
|
+
assert isinstance(result, datetime)
|
|
93
|
+
assert result.tzinfo == timezone.utc
|
|
94
|
+
assert result.isoformat() == "1970-01-01T00:00:00+00:00"
|
|
95
|
+
|
|
96
|
+
@freezegun.freeze_time("2100-01-01 00:00:00.000000")
|
|
97
|
+
def test_uuid7_to_datetime_future_timestamp(self):
|
|
98
|
+
"""Test conversion with future timestamp."""
|
|
99
|
+
test_uuid = frozen_uuid7()
|
|
100
|
+
result = uuid7_to_datetime(test_uuid)
|
|
101
|
+
|
|
102
|
+
assert isinstance(result, datetime)
|
|
103
|
+
assert result.tzinfo == timezone.utc
|
|
104
|
+
assert result.isoformat() == "2100-01-01T00:00:00+00:00"
|
|
105
|
+
|
|
106
|
+
@freezegun.freeze_time("2024-01-15 12:30:45.123456")
|
|
107
|
+
def test_uuid7_to_datetime_consistency(self):
|
|
108
|
+
"""Test that multiple calls with the same UUID return the same result."""
|
|
109
|
+
test_uuid = frozen_uuid7()
|
|
110
|
+
|
|
111
|
+
result1 = uuid7_to_datetime(test_uuid)
|
|
112
|
+
result2 = uuid7_to_datetime(test_uuid)
|
|
113
|
+
|
|
114
|
+
assert result1.isoformat() == result2.isoformat()
|
|
115
|
+
assert result1 == result2
|
|
116
|
+
|
|
117
|
+
@freezegun.freeze_time("2024-01-15 12:30:45.123456")
|
|
118
|
+
def test_uuid7_to_datetime_different_input_types_same_result(self):
|
|
119
|
+
"""Test that different input types representing the same UUID return the same result."""
|
|
120
|
+
test_uuid = frozen_uuid7()
|
|
121
|
+
uuid_string = str(test_uuid)
|
|
122
|
+
stdlib_uuid = StdUUID(uuid_string)
|
|
123
|
+
|
|
124
|
+
result_from_uuid_utils = uuid7_to_datetime(test_uuid)
|
|
125
|
+
result_from_string = uuid7_to_datetime(uuid_string)
|
|
126
|
+
result_from_stdlib = uuid7_to_datetime(stdlib_uuid)
|
|
127
|
+
|
|
128
|
+
# All results should be identical
|
|
129
|
+
assert result_from_uuid_utils == result_from_string == result_from_stdlib
|
|
130
|
+
|
|
131
|
+
def test_uuid7_to_datetime_invalid_input_type(self):
|
|
132
|
+
"""Test that invalid input types raise appropriate errors."""
|
|
133
|
+
with pytest.raises(TypeError):
|
|
134
|
+
uuid7_to_datetime(123) # type: ignore
|
|
135
|
+
|
|
136
|
+
with pytest.raises(TypeError):
|
|
137
|
+
uuid7_to_datetime(123.45) # type: ignore
|
|
138
|
+
|
|
139
|
+
with pytest.raises(TypeError):
|
|
140
|
+
uuid7_to_datetime([]) # type: ignore
|
|
141
|
+
|
|
142
|
+
with pytest.raises(TypeError):
|
|
143
|
+
uuid7_to_datetime({}) # type: ignore
|
|
144
|
+
|
|
145
|
+
def test_uuid7_to_datetime_invalid_uuid_string(self):
|
|
146
|
+
"""Test that invalid UUID strings raise appropriate errors."""
|
|
147
|
+
with pytest.raises(ValueError):
|
|
148
|
+
uuid7_to_datetime("not-a-uuid")
|
|
149
|
+
|
|
150
|
+
with pytest.raises(ValueError):
|
|
151
|
+
uuid7_to_datetime("12345")
|
|
152
|
+
|
|
153
|
+
with pytest.raises(ValueError):
|
|
154
|
+
uuid7_to_datetime("")
|
|
155
|
+
|
|
156
|
+
def test_uuid7_to_datetime_non_uuid7_uuid(self):
|
|
157
|
+
"""Test behavior with non-UUID7 UUIDs."""
|
|
158
|
+
uuid4 = StdUUID("550e8400-e29b-41d4-a716-446655440000")
|
|
159
|
+
|
|
160
|
+
with pytest.raises(ValueError, match="is not a UUIDv7"):
|
|
161
|
+
uuid7_to_datetime(uuid4)
|
|
162
|
+
|
|
163
|
+
@freezegun.freeze_time("2024-01-15 12:30:45.123456")
|
|
164
|
+
def test_uuid7_to_datetime_timezone_awareness(self):
|
|
165
|
+
"""Test that the returned datetime is always timezone-aware and in UTC."""
|
|
166
|
+
test_uuid = frozen_uuid7()
|
|
167
|
+
result = uuid7_to_datetime(test_uuid)
|
|
168
|
+
|
|
169
|
+
assert result.tzinfo is not None
|
|
170
|
+
|
|
171
|
+
assert result.tzinfo == timezone.utc
|
|
172
|
+
|
|
173
|
+
assert result.tzinfo.utcoffset(result) is not None
|
|
174
|
+
|
|
175
|
+
@freezegun.freeze_time("2024-01-15 12:30:45.123456")
|
|
176
|
+
def test_uuid7_to_datetime_millisecond_precision(self):
|
|
177
|
+
"""Test that the conversion handles millisecond precision correctly."""
|
|
178
|
+
uuids = [frozen_uuid7() for _ in range(5)]
|
|
179
|
+
results = [uuid7_to_datetime(uuid) for uuid in uuids]
|
|
180
|
+
|
|
181
|
+
for result in results:
|
|
182
|
+
assert isinstance(result, datetime)
|
|
183
|
+
assert result.tzinfo == timezone.utc
|
|
184
|
+
|
|
185
|
+
timestamps = [r.timestamp() for r in results]
|
|
186
|
+
assert timestamps == sorted(timestamps)
|
|
187
|
+
|
|
188
|
+
@freezegun.freeze_time("2024-01-15 12:30:45.123456")
|
|
189
|
+
def test_uuid7_to_datetime_timestamp_property(self):
|
|
190
|
+
"""Test that the function correctly uses the timestamp property."""
|
|
191
|
+
test_uuid = frozen_uuid7()
|
|
192
|
+
result = uuid7_to_datetime(test_uuid)
|
|
193
|
+
|
|
194
|
+
expected_timestamp = test_uuid.timestamp / 1000.0
|
|
195
|
+
actual_timestamp = result.timestamp()
|
|
196
|
+
|
|
197
|
+
assert abs(actual_timestamp - expected_timestamp) < 0.001
|
|
198
|
+
|
|
199
|
+
@freezegun.freeze_time("2024-01-15 12:30:45.123456")
|
|
200
|
+
def test_uuid7_to_datetime_deterministic_with_freeze(self):
|
|
201
|
+
"""Test that the function works deterministically with freezegun."""
|
|
202
|
+
with freezegun.freeze_time("2024-01-15 12:30:45.123000"):
|
|
203
|
+
uuid1 = frozen_uuid7()
|
|
204
|
+
result1 = uuid7_to_datetime(uuid1)
|
|
205
|
+
|
|
206
|
+
with freezegun.freeze_time("2024-01-15 12:30:45.123000"):
|
|
207
|
+
uuid2 = frozen_uuid7()
|
|
208
|
+
result2 = uuid7_to_datetime(uuid2)
|
|
209
|
+
|
|
210
|
+
time_diff = abs((result1 - result2).total_seconds())
|
|
211
|
+
assert time_diff < 1.0
|
|
212
|
+
|
|
213
|
+
@freezegun.freeze_time("1970-01-01 00:00:00")
|
|
214
|
+
def test_uuid7_to_datetime_edge_case_zero_timestamp(self):
|
|
215
|
+
"""Test edge case with very small timestamp values."""
|
|
216
|
+
test_uuid = frozen_uuid7()
|
|
217
|
+
result = uuid7_to_datetime(test_uuid)
|
|
218
|
+
|
|
219
|
+
assert isinstance(result, datetime)
|
|
220
|
+
assert result.tzinfo == timezone.utc
|
|
221
|
+
assert result.isoformat() == "1970-01-01T00:00:00+00:00"
|
|
@@ -28,6 +28,7 @@ from diracx.core.properties import SecurityProperty
|
|
|
28
28
|
from diracx.core.settings import AuthSettings
|
|
29
29
|
from diracx.db.sql import AuthDB
|
|
30
30
|
from diracx.db.sql.auth.schema import FlowStatus, RefreshTokenStatus
|
|
31
|
+
from diracx.db.sql.utils import uuid7_to_datetime
|
|
31
32
|
from diracx.db.sql.utils.functions import substract_date
|
|
32
33
|
|
|
33
34
|
from .utils import (
|
|
@@ -315,12 +316,11 @@ async def exchange_token(
|
|
|
315
316
|
# Merge the VO with the subject to get a unique DIRAC sub
|
|
316
317
|
sub = f"{vo}:{sub}"
|
|
317
318
|
|
|
318
|
-
creation_time = datetime.now(timezone.utc)
|
|
319
319
|
refresh_payload: RefreshTokenPayload | None = None
|
|
320
320
|
if include_refresh_token:
|
|
321
321
|
# Insert the refresh token with user details into the RefreshTokens table
|
|
322
322
|
# User details are needed to regenerate access tokens later
|
|
323
|
-
|
|
323
|
+
refresh_jti = await insert_refresh_token(
|
|
324
324
|
auth_db=auth_db,
|
|
325
325
|
subject=sub,
|
|
326
326
|
scope=scope,
|
|
@@ -329,9 +329,12 @@ async def exchange_token(
|
|
|
329
329
|
# Generate refresh token payload
|
|
330
330
|
if refresh_token_expire_minutes is None:
|
|
331
331
|
refresh_token_expire_minutes = settings.refresh_token_expire_minutes
|
|
332
|
+
refresh_exp = uuid7_to_datetime(refresh_jti) + timedelta(
|
|
333
|
+
minutes=refresh_token_expire_minutes
|
|
334
|
+
)
|
|
332
335
|
refresh_payload = {
|
|
333
|
-
"jti": str(
|
|
334
|
-
"exp":
|
|
336
|
+
"jti": str(refresh_jti),
|
|
337
|
+
"exp": refresh_exp,
|
|
335
338
|
# legacy_exchange is used to indicate that the original refresh token
|
|
336
339
|
# was obtained from the legacy_exchange endpoint
|
|
337
340
|
"legacy_exchange": legacy_exchange,
|
|
@@ -341,15 +344,19 @@ async def exchange_token(
|
|
|
341
344
|
# Generate access token payload
|
|
342
345
|
# For now, the access token is only used to access DIRAC services,
|
|
343
346
|
# therefore, the audience is not set and checked
|
|
347
|
+
access_jti = uuid7()
|
|
348
|
+
access_exp = uuid7_to_datetime(access_jti) + timedelta(
|
|
349
|
+
minutes=settings.access_token_expire_minutes
|
|
350
|
+
)
|
|
344
351
|
access_payload: AccessTokenPayload = {
|
|
345
352
|
"sub": sub,
|
|
346
353
|
"vo": vo,
|
|
347
354
|
"iss": settings.token_issuer,
|
|
348
355
|
"dirac_properties": list(properties),
|
|
349
|
-
"jti": str(
|
|
356
|
+
"jti": str(access_jti),
|
|
350
357
|
"preferred_username": preferred_username,
|
|
351
358
|
"dirac_group": dirac_group,
|
|
352
|
-
"exp":
|
|
359
|
+
"exp": access_exp,
|
|
353
360
|
"dirac_policies": {},
|
|
354
361
|
}
|
|
355
362
|
|
|
@@ -382,8 +389,8 @@ async def insert_refresh_token(
|
|
|
382
389
|
auth_db: AuthDB,
|
|
383
390
|
subject: str,
|
|
384
391
|
scope: str,
|
|
385
|
-
) ->
|
|
386
|
-
"""Insert a refresh token into the database and return the JWT ID
|
|
392
|
+
) -> UUID:
|
|
393
|
+
"""Insert a refresh token into the database and return the JWT ID."""
|
|
387
394
|
# Generate a JWT ID
|
|
388
395
|
jti = uuid7()
|
|
389
396
|
|
|
@@ -393,10 +400,7 @@ async def insert_refresh_token(
|
|
|
393
400
|
subject=subject,
|
|
394
401
|
scope=scope,
|
|
395
402
|
)
|
|
396
|
-
|
|
397
|
-
# Get the creation time of the refresh token
|
|
398
|
-
refresh_token = await auth_db.get_refresh_token(jti)
|
|
399
|
-
return jti, refresh_token["CreationTime"]
|
|
403
|
+
return jti
|
|
400
404
|
|
|
401
405
|
|
|
402
406
|
async def get_device_flow(auth_db: AuthDB, device_code: str, max_validity: int):
|
|
@@ -39,7 +39,7 @@ def make_check_and_prepare_job_config(config: Config, vo: str):
|
|
|
39
39
|
ops = config.Operations[vo]
|
|
40
40
|
return {
|
|
41
41
|
"inputDataPolicyForVO": ops.InputDataPolicy.InputDataModule,
|
|
42
|
-
"softwareDistModuleForVO": ops.
|
|
42
|
+
"softwareDistModuleForVO": ops.SoftwareDistModule,
|
|
43
43
|
"defaultCPUTimeForOwnerGroup": ops.JobDescription.DefaultCPUTime,
|
|
44
44
|
"getDIRACPlatform": partial(find_compatible_platforms, config=config),
|
|
45
45
|
}
|
{diracx-0.0.1a49 → diracx-0.0.1a50}/diracx-routers/src/diracx/routers/auth/authorize_code_flow.py
RENAMED
|
@@ -1,35 +1,6 @@
|
|
|
1
1
|
"""Authorization code flow.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
------------------ ------------------ --------------------------------
|
|
5
|
-
| | |
|
|
6
|
-
|---(A)--- Authorization Request ---->| |
|
|
7
|
-
| |---(B)--- Authorization Request -------->|
|
|
8
|
-
| | |
|
|
9
|
-
| |<--(C)--- Authorization Grant -----------|
|
|
10
|
-
| | |
|
|
11
|
-
| |---(D)--- ID Token Request ------------->|
|
|
12
|
-
| | |
|
|
13
|
-
| |<--(E)--- ID Token ----------------------|
|
|
14
|
-
|<--(F)--- Authorization Grant -------| |
|
|
15
|
-
| | |
|
|
16
|
-
|---(G)--- Access Token Request ----->| |
|
|
17
|
-
| | |
|
|
18
|
-
|<--(H)--- Access Token --------------| |
|
|
19
|
-
| | |
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
* (A) The flow is initiated by the client making a request to the DIRAC auth service (GET /authorize) with PKCE.
|
|
23
|
-
* (B) The DIRAC auth service stores the request details and redirects the user to the IAM's authorization flow
|
|
24
|
-
by performing an authorization request on behalf of the user.
|
|
25
|
-
* (C) Once done, the IAM redirects the user back to the DIRAC auth service (GET /authorize/complete).
|
|
26
|
-
* (D) The DIRAC auth service exchanges the code for an ID token by making a token request to the IAM.
|
|
27
|
-
* (E) The IAM responds with an access, a refresh and an ID tokens.
|
|
28
|
-
* (F) The DIRAC auth service only stores the ID token and redirects the user to the client's redirect URI.
|
|
29
|
-
* (G) The client requests an access token from the DIRAC auth service by making a request to
|
|
30
|
-
the token endpoint (POST /token).
|
|
31
|
-
* (H) The DIRAC auth service responds with a DIRAC access token, based on the ID token.
|
|
32
|
-
* The client can then use the access token to access the DIRAC services.
|
|
3
|
+
See docs/admin/explanations/authentication.md
|
|
33
4
|
"""
|
|
34
5
|
|
|
35
6
|
from __future__ import annotations
|