datex-studio-cli 0.4.12__tar.gz → 0.4.14__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.
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/.gitignore +3 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/PKG-INFO +95 -5
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/README.md +93 -3
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/pyproject.toml +1 -1
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/__init__.py +1 -1
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/cli.py +28 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/auth.py +66 -39
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/branch.py +83 -11
- datex_studio_cli-0.4.14/src/dxs/commands/cascade.py +701 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/configuration.py +31 -3
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/crm.py +966 -53
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/devops.py +64 -11
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/marketplace.py +36 -18
- datex_studio_cli-0.4.14/src/dxs/commands/ng/__init__.py +44 -0
- datex_studio_cli-0.4.14/src/dxs/commands/ng/_common.py +37 -0
- datex_studio_cli-0.4.14/src/dxs/commands/ng/api.py +149 -0
- datex_studio_cli-0.4.14/src/dxs/commands/ng/create.py +82 -0
- datex_studio_cli-0.4.14/src/dxs/commands/ng/data.py +222 -0
- datex_studio_cli-0.4.14/src/dxs/commands/ng/pack.py +63 -0
- datex_studio_cli-0.4.14/src/dxs/commands/ng/preview.py +384 -0
- datex_studio_cli-0.4.14/src/dxs/commands/reference.py +192 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/repo.py +6 -6
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/report/api.py +8 -6
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/report/folder.py +5 -2
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/report/preview.py +2 -2
- datex_studio_cli-0.4.14/src/dxs/commands/reset.py +216 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/source.py +66 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/api/app_config.py +1 -17
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/api/client.py +18 -10
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/api/endpoints.py +42 -5
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/api/models.py +33 -7
- datex_studio_cli-0.4.14/src/dxs/core/api/reference_graph.py +132 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/auth/datex_tenant.py +12 -10
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/auth/decorators.py +7 -4
- datex_studio_cli-0.4.14/src/dxs/core/auth/tenants.py +71 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/auth/token_cache.py +8 -3
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/datasource/parsers.py +2 -5
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/datasource/resolver.py +4 -8
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/devops/client.py +36 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/dynamics/client.py +255 -41
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/output/redaction.py +15 -3
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/telemetry/config.py +8 -3
- datex_studio_cli-0.4.14/src/dxs/ng/__init__.py +7 -0
- datex_studio_cli-0.4.14/src/dxs/ng/folder.py +256 -0
- datex_studio_cli-0.4.14/src/dxs/ng/manifest.py +127 -0
- datex_studio_cli-0.4.14/src/dxs/ng/mocks.py +142 -0
- datex_studio_cli-0.4.14/src/dxs/ng/preview.py +79 -0
- datex_studio_cli-0.4.14/src/dxs/ng/scaffold.py +88 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/report/datasource_binding.py +2 -5
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/report/folder.py +2 -6
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/report/preview_arjs.py +2 -2
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/utils/config.py +15 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/utils/paths.py +17 -3
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/utils/resolvers.py +119 -17
- datex_studio_cli-0.4.14/src/dxs/utils/versioning.py +22 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/report-creator.skill +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/scripts/analyze_corpus.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/scripts/generate_rdlx_schema.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/__main__.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/__init__.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/api.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/config.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/datasource.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/document.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/endpoint.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/env.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/explore.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/function.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/init.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/odata.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/organization.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/proxy.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/release_notes.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/report/__init__.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/report/add_cmds.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/report/batch.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/report/create.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/report/data.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/report/dataset.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/report/edit.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/report/schema_cmds.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/schema.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/servicepack.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/studio.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/telemetry.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/commands/user.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/context.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/__init__.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/api/__init__.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/api/metadata_models.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/auth/__init__.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/auth/msal_client.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/cache.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/datasource/__init__.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/datasource/flow_generator.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/datasource/flow_models.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/datasource/generator.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/datasource/models.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/datasource/type_def_parser.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/datasource/validator.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/designer/__init__.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/designer/flow_models.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/designer/models.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/designer/parsers.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/devops/__init__.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/devops/helpers.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/devops/models.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/dynamics/__init__.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/dynamics/metadata_cache.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/footprint/__init__.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/footprint/client.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/footprint/edmx_parser.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/footprint/metadata.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/function/__init__.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/function/generator.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/function/models.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/function/validator.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/graph.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/onboarding.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/output/__init__.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/output/csv_fmt.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/output/formatter.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/output/json_fmt.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/output/yaml_fmt.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/release_notes.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/responses.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/telemetry/__init__.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/telemetry/identity.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/telemetry/recorder.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/telemetry/scrubber.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/core/telemetry/sender.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/models/__init__.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/py.typed +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/report/__init__.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/report/engine.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/report/field_parser.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/report/manifest.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/report/models.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/report/preview.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/report/schema.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/report/svg_renderer.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/report/templates/__init__.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/report/templates/bill_of_lading.rdlx-json +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/report/templates/shipping_label.rdlx-json +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/report/validate_arjs.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/report/validator.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/report/wrapper.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/utils/__init__.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/utils/click_options.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/utils/clipboard.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/utils/errors.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/utils/filtering.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/utils/image.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/utils/responses.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/utils/restricted.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/utils/sorting.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/utils/update_check.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/__init__.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/app.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/design.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/proxy_app.py +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/404/index.html +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/404.html +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/_next/static/UgyAMtPjH-Pt0RYWOHzIT/_buildManifest.js +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/_next/static/UgyAMtPjH-Pt0RYWOHzIT/_ssgManifest.js +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/_next/static/chunks/0b24cca5-c1e1c8810348f107.js +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/_next/static/chunks/255-102f2e5b2e3dc2ef.js +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/_next/static/chunks/4bd1b696-c023c6e3521b1417.js +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/_next/static/chunks/538-84e2e111415f1fda.js +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/_next/static/chunks/697-0e000ab410d9f470.js +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/_next/static/chunks/871-1acacdb7b4022abf.js +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/_next/static/chunks/8b8f67fc-6295949a4b5485a4.js +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/_next/static/chunks/909-c88abba3cf0caec3.js +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/_next/static/chunks/app/_not-found/page-ea1be7001c230704.js +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/_next/static/chunks/app/design/capture/page-a5e129c2d223432c.js +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/_next/static/chunks/app/design/page-21ba66a3dd3b03f0.js +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/_next/static/chunks/app/layout-2cc6eac09e476c91.js +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/_next/static/chunks/app/page-20c358395882cdac.js +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/_next/static/chunks/framework-de98b93a850cfc71.js +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/_next/static/chunks/main-0f18f91200dac003.js +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/_next/static/chunks/main-app-b69998d8941231d8.js +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/_next/static/chunks/pages/_app-7d307437aca18ad4.js +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/_next/static/chunks/pages/_error-cb2a52f75f2162e2.js +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/_next/static/chunks/polyfills-42372ed130431b0a.js +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/_next/static/chunks/webpack-2b297ada5306c17f.js +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/_next/static/css/360c657de5e04df8.css +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/design/capture/index.html +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/design/capture/index.txt +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/design/index.html +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/design/index.txt +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/index.html +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/index.txt +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/render-cli.js +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/report-preview.html +0 -0
- {datex_studio_cli-0.4.12 → datex_studio_cli-0.4.14}/src/dxs/web/static/report-validate.html +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: datex-studio-cli
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.14
|
|
4
4
|
Summary: CLI for Datex Studio low-code platform, designed for LLM-based AI agents
|
|
5
5
|
Project-URL: Homepage, https://github.com/datex/datex-studio-cli
|
|
6
6
|
Project-URL: Documentation, https://github.com/datex/datex-studio-cli
|
|
@@ -247,6 +247,7 @@ Direct commands on the `source` group:
|
|
|
247
247
|
| `locks` | Show current lock status |
|
|
248
248
|
| `deps <ref>` | Show configuration dependencies |
|
|
249
249
|
| `deps-diff` | Show dependency changes between versions |
|
|
250
|
+
| `referenced-from <pkg>` | List packages/apps that reference a package |
|
|
250
251
|
| `workitems` | Extract work items from commit messages |
|
|
251
252
|
| `compare` | Compare two branches |
|
|
252
253
|
| `graph` | Show dependency graph |
|
|
@@ -278,7 +279,8 @@ dxs source compare --source 100 --target 200
|
|
|
278
279
|
| `show <id>` | Show branch details |
|
|
279
280
|
| `create` | Create a new feature branch |
|
|
280
281
|
| `delete <id>` | Delete a feature branch |
|
|
281
|
-
| `
|
|
282
|
+
| `commit <id>` | Commit (merge) a feature branch into its Main branch |
|
|
283
|
+
| `publish <id>` | Publish branch to marketplace (`--notes` is **required**) |
|
|
282
284
|
| `baseline <id>` | Find baseline (previous release) |
|
|
283
285
|
| `search <query>` | Search branches by name |
|
|
284
286
|
| `roles <id>` | Show branch roles |
|
|
@@ -305,6 +307,83 @@ dxs source branch list --repo 10 --with-changes
|
|
|
305
307
|
dxs source branch list --repo 10 --sort modified --desc
|
|
306
308
|
```
|
|
307
309
|
|
|
310
|
+
### Package References (`dxs source reference`)
|
|
311
|
+
|
|
312
|
+
| Command | Description |
|
|
313
|
+
|---------|-------------|
|
|
314
|
+
| `set` | Re-pin a direct package reference and rebuild transitive references |
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
# Pin Module1 to a newly published version on feature branch 3101
|
|
318
|
+
dxs source reference set -b 3101 -p Module1 -v 20260714.1000
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
Rebuilds the branch's flattened reference list after the bump and refuses the
|
|
322
|
+
write if the result would contain a version conflict (the same package pinned at
|
|
323
|
+
two versions) or a circular reference.
|
|
324
|
+
|
|
325
|
+
### Package Cascade (`dxs source cascade`)
|
|
326
|
+
|
|
327
|
+
When a package is republished, every package that references it stays pinned to
|
|
328
|
+
the old version until it is re-pinned and republished itself. The cascade
|
|
329
|
+
automates that fan-out.
|
|
330
|
+
|
|
331
|
+
| Command | Description |
|
|
332
|
+
|---------|-------------|
|
|
333
|
+
| `plan` | Compute the ordered set of packages to re-pin + republish |
|
|
334
|
+
| `run` | Execute a plan bottom-up (branch → re-pin → commit → publish) |
|
|
335
|
+
|
|
336
|
+
```bash
|
|
337
|
+
# 1. Plan the cascade from a package you just published
|
|
338
|
+
dxs source cascade plan -p Module1 -v 20260714.1000 -O json > plan.json
|
|
339
|
+
|
|
340
|
+
# 2. Review what it would do — mutates nothing
|
|
341
|
+
dxs source cascade run --plan plan.json --dry-run
|
|
342
|
+
|
|
343
|
+
# 3. Execute
|
|
344
|
+
dxs source cascade run --plan plan.json
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
`plan` walks reverse-references from the origin package and emits update nodes
|
|
348
|
+
grouped into topological levels, plus a `staleApplications` list — applications
|
|
349
|
+
that consume an affected package but cannot be cascaded automatically.
|
|
350
|
+
|
|
351
|
+
- `--org` scopes traversal to a single organization. **Omit it and the cascade
|
|
352
|
+
spans consumers across all organizations**, which is rarely what you want.
|
|
353
|
+
- `--max-depth` limits how far the traversal follows the reference chain.
|
|
354
|
+
|
|
355
|
+
`run` executes each level bottom-up, feeding each package's newly published
|
|
356
|
+
version forward to its dependents.
|
|
357
|
+
|
|
358
|
+
Before mutating anything it applies the same guardrails as `branch publish`:
|
|
359
|
+
each node's Main branch is resolved to its owning organization and checked
|
|
360
|
+
against the current identity (once per distinct organization), then the run is
|
|
361
|
+
confirmed. Each re-pinned feature branch is validated before it is committed, so
|
|
362
|
+
a broken reference set never reaches Main or the marketplace.
|
|
363
|
+
|
|
364
|
+
- `--dry-run` prints the resolved execution order and mutates nothing.
|
|
365
|
+
- `--yes` / `-y` skips the confirmation prompt — use this for unattended runs.
|
|
366
|
+
Branch validation still runs.
|
|
367
|
+
- `--force` / `-f` skips both the confirmation prompt and branch validation.
|
|
368
|
+
- `--select` restricts the run to named packages (repeatable). Deselecting an
|
|
369
|
+
intermediate dependency will fail the run, since its dependents need the
|
|
370
|
+
version it would have produced.
|
|
371
|
+
- `--release-notes` sets the notes for every republish; otherwise a summary of
|
|
372
|
+
the re-pins is used.
|
|
373
|
+
|
|
374
|
+
A node whose dependencies are all already at their target version is skipped
|
|
375
|
+
rather than republished for zero change, and its dependents treat it as a no-op
|
|
376
|
+
instead of failing.
|
|
377
|
+
|
|
378
|
+
Publishing can block on a build, so the publish step uses the longer
|
|
379
|
+
`publish_timeout` setting (default 300s) rather than `api_timeout`. If that call
|
|
380
|
+
still times out, the version is confirmed by looking up the exact
|
|
381
|
+
`(package, version)` pair in the marketplace — the record is committed before the
|
|
382
|
+
build runs, so a timed-out publish has usually still landed.
|
|
383
|
+
|
|
384
|
+
`cascade run` and `reference set` are both blocked when
|
|
385
|
+
`DXS_RESTRICTED_MODE=true`.
|
|
386
|
+
|
|
308
387
|
### Repository Management (`dxs source repo`)
|
|
309
388
|
|
|
310
389
|
| Command | Description |
|
|
@@ -608,11 +687,22 @@ dxs odata execute -c 1 -q "Products?\$select=Id,Name,Price&\$top=10"
|
|
|
608
687
|
|
|
609
688
|
| Command | Description |
|
|
610
689
|
|---------|-------------|
|
|
611
|
-
| `list` | List marketplace
|
|
690
|
+
| `list` | List marketplace packages available to your org |
|
|
612
691
|
| `show <id>` | Show application details |
|
|
613
692
|
| `versions <id>` | List published versions |
|
|
614
693
|
| `version <id>` | Show version details |
|
|
615
|
-
| `search <query>` | Search
|
|
694
|
+
| `search <query>` | Search available packages by name/description |
|
|
695
|
+
|
|
696
|
+
`list` and `search` mirror the Manager > Marketplace screen: they show packages
|
|
697
|
+
available to a consumer organization, each with an `included` flag indicating
|
|
698
|
+
whether that org already has access.
|
|
699
|
+
|
|
700
|
+
- `--type` selects the marketplace application type, defaulting to
|
|
701
|
+
`componentmodule`. Other types (`web`, `mobile`, `api`, `portal`,
|
|
702
|
+
`footprintapi`, `taskscheduler`) are accepted but are not what the Marketplace
|
|
703
|
+
screen shows.
|
|
704
|
+
- `--org` is the *consumer* organization being browsed on behalf of, not a
|
|
705
|
+
result filter. Omit it to browse as your own organization.
|
|
616
706
|
|
|
617
707
|
### Azure DevOps (`dxs devops`)
|
|
618
708
|
|
|
@@ -194,6 +194,7 @@ Direct commands on the `source` group:
|
|
|
194
194
|
| `locks` | Show current lock status |
|
|
195
195
|
| `deps <ref>` | Show configuration dependencies |
|
|
196
196
|
| `deps-diff` | Show dependency changes between versions |
|
|
197
|
+
| `referenced-from <pkg>` | List packages/apps that reference a package |
|
|
197
198
|
| `workitems` | Extract work items from commit messages |
|
|
198
199
|
| `compare` | Compare two branches |
|
|
199
200
|
| `graph` | Show dependency graph |
|
|
@@ -225,7 +226,8 @@ dxs source compare --source 100 --target 200
|
|
|
225
226
|
| `show <id>` | Show branch details |
|
|
226
227
|
| `create` | Create a new feature branch |
|
|
227
228
|
| `delete <id>` | Delete a feature branch |
|
|
228
|
-
| `
|
|
229
|
+
| `commit <id>` | Commit (merge) a feature branch into its Main branch |
|
|
230
|
+
| `publish <id>` | Publish branch to marketplace (`--notes` is **required**) |
|
|
229
231
|
| `baseline <id>` | Find baseline (previous release) |
|
|
230
232
|
| `search <query>` | Search branches by name |
|
|
231
233
|
| `roles <id>` | Show branch roles |
|
|
@@ -252,6 +254,83 @@ dxs source branch list --repo 10 --with-changes
|
|
|
252
254
|
dxs source branch list --repo 10 --sort modified --desc
|
|
253
255
|
```
|
|
254
256
|
|
|
257
|
+
### Package References (`dxs source reference`)
|
|
258
|
+
|
|
259
|
+
| Command | Description |
|
|
260
|
+
|---------|-------------|
|
|
261
|
+
| `set` | Re-pin a direct package reference and rebuild transitive references |
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
# Pin Module1 to a newly published version on feature branch 3101
|
|
265
|
+
dxs source reference set -b 3101 -p Module1 -v 20260714.1000
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Rebuilds the branch's flattened reference list after the bump and refuses the
|
|
269
|
+
write if the result would contain a version conflict (the same package pinned at
|
|
270
|
+
two versions) or a circular reference.
|
|
271
|
+
|
|
272
|
+
### Package Cascade (`dxs source cascade`)
|
|
273
|
+
|
|
274
|
+
When a package is republished, every package that references it stays pinned to
|
|
275
|
+
the old version until it is re-pinned and republished itself. The cascade
|
|
276
|
+
automates that fan-out.
|
|
277
|
+
|
|
278
|
+
| Command | Description |
|
|
279
|
+
|---------|-------------|
|
|
280
|
+
| `plan` | Compute the ordered set of packages to re-pin + republish |
|
|
281
|
+
| `run` | Execute a plan bottom-up (branch → re-pin → commit → publish) |
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
# 1. Plan the cascade from a package you just published
|
|
285
|
+
dxs source cascade plan -p Module1 -v 20260714.1000 -O json > plan.json
|
|
286
|
+
|
|
287
|
+
# 2. Review what it would do — mutates nothing
|
|
288
|
+
dxs source cascade run --plan plan.json --dry-run
|
|
289
|
+
|
|
290
|
+
# 3. Execute
|
|
291
|
+
dxs source cascade run --plan plan.json
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
`plan` walks reverse-references from the origin package and emits update nodes
|
|
295
|
+
grouped into topological levels, plus a `staleApplications` list — applications
|
|
296
|
+
that consume an affected package but cannot be cascaded automatically.
|
|
297
|
+
|
|
298
|
+
- `--org` scopes traversal to a single organization. **Omit it and the cascade
|
|
299
|
+
spans consumers across all organizations**, which is rarely what you want.
|
|
300
|
+
- `--max-depth` limits how far the traversal follows the reference chain.
|
|
301
|
+
|
|
302
|
+
`run` executes each level bottom-up, feeding each package's newly published
|
|
303
|
+
version forward to its dependents.
|
|
304
|
+
|
|
305
|
+
Before mutating anything it applies the same guardrails as `branch publish`:
|
|
306
|
+
each node's Main branch is resolved to its owning organization and checked
|
|
307
|
+
against the current identity (once per distinct organization), then the run is
|
|
308
|
+
confirmed. Each re-pinned feature branch is validated before it is committed, so
|
|
309
|
+
a broken reference set never reaches Main or the marketplace.
|
|
310
|
+
|
|
311
|
+
- `--dry-run` prints the resolved execution order and mutates nothing.
|
|
312
|
+
- `--yes` / `-y` skips the confirmation prompt — use this for unattended runs.
|
|
313
|
+
Branch validation still runs.
|
|
314
|
+
- `--force` / `-f` skips both the confirmation prompt and branch validation.
|
|
315
|
+
- `--select` restricts the run to named packages (repeatable). Deselecting an
|
|
316
|
+
intermediate dependency will fail the run, since its dependents need the
|
|
317
|
+
version it would have produced.
|
|
318
|
+
- `--release-notes` sets the notes for every republish; otherwise a summary of
|
|
319
|
+
the re-pins is used.
|
|
320
|
+
|
|
321
|
+
A node whose dependencies are all already at their target version is skipped
|
|
322
|
+
rather than republished for zero change, and its dependents treat it as a no-op
|
|
323
|
+
instead of failing.
|
|
324
|
+
|
|
325
|
+
Publishing can block on a build, so the publish step uses the longer
|
|
326
|
+
`publish_timeout` setting (default 300s) rather than `api_timeout`. If that call
|
|
327
|
+
still times out, the version is confirmed by looking up the exact
|
|
328
|
+
`(package, version)` pair in the marketplace — the record is committed before the
|
|
329
|
+
build runs, so a timed-out publish has usually still landed.
|
|
330
|
+
|
|
331
|
+
`cascade run` and `reference set` are both blocked when
|
|
332
|
+
`DXS_RESTRICTED_MODE=true`.
|
|
333
|
+
|
|
255
334
|
### Repository Management (`dxs source repo`)
|
|
256
335
|
|
|
257
336
|
| Command | Description |
|
|
@@ -555,11 +634,22 @@ dxs odata execute -c 1 -q "Products?\$select=Id,Name,Price&\$top=10"
|
|
|
555
634
|
|
|
556
635
|
| Command | Description |
|
|
557
636
|
|---------|-------------|
|
|
558
|
-
| `list` | List marketplace
|
|
637
|
+
| `list` | List marketplace packages available to your org |
|
|
559
638
|
| `show <id>` | Show application details |
|
|
560
639
|
| `versions <id>` | List published versions |
|
|
561
640
|
| `version <id>` | Show version details |
|
|
562
|
-
| `search <query>` | Search
|
|
641
|
+
| `search <query>` | Search available packages by name/description |
|
|
642
|
+
|
|
643
|
+
`list` and `search` mirror the Manager > Marketplace screen: they show packages
|
|
644
|
+
available to a consumer organization, each with an `included` flag indicating
|
|
645
|
+
whether that org already has access.
|
|
646
|
+
|
|
647
|
+
- `--type` selects the marketplace application type, defaulting to
|
|
648
|
+
`componentmodule`. Other types (`web`, `mobile`, `api`, `portal`,
|
|
649
|
+
`footprintapi`, `taskscheduler`) are accepted but are not what the Marketplace
|
|
650
|
+
screen shows.
|
|
651
|
+
- `--org` is the *consumer* organization being browsed on behalf of, not a
|
|
652
|
+
result filter. Omit it to browse as your own organization.
|
|
563
653
|
|
|
564
654
|
### Azure DevOps (`dxs devops`)
|
|
565
655
|
|
|
@@ -70,6 +70,29 @@ def _stdout_is_pipe() -> bool:
|
|
|
70
70
|
return False
|
|
71
71
|
|
|
72
72
|
|
|
73
|
+
def _ensure_utf8_streams() -> None:
|
|
74
|
+
"""Force stdout/stderr to UTF-8 so non-ASCII output never crashes the CLI.
|
|
75
|
+
|
|
76
|
+
On Windows a piped or redirected stream defaults to the locale encoding
|
|
77
|
+
(typically cp1252), which cannot represent characters such as U+2192 (the
|
|
78
|
+
arrow used in help text like ``dxs source cascade -h`` and in ``cascade
|
|
79
|
+
run`` progress logs). Writing them raises ``UnicodeEncodeError`` and aborts
|
|
80
|
+
the command. Reconfiguring to UTF-8 at entry is lossless and idempotent.
|
|
81
|
+
|
|
82
|
+
Streams that do not support reconfiguration (already detached, or a test
|
|
83
|
+
double) are left untouched.
|
|
84
|
+
"""
|
|
85
|
+
for stream in (sys.stdout, sys.stderr):
|
|
86
|
+
reconfigure = getattr(stream, "reconfigure", None)
|
|
87
|
+
if reconfigure is None:
|
|
88
|
+
continue
|
|
89
|
+
try:
|
|
90
|
+
reconfigure(encoding="utf-8")
|
|
91
|
+
except (ValueError, OSError):
|
|
92
|
+
# Reconfiguration is unsupported for this stream; leave it as-is.
|
|
93
|
+
pass
|
|
94
|
+
|
|
95
|
+
|
|
73
96
|
# Global options shared across all commands
|
|
74
97
|
CONTEXT_SETTINGS = {
|
|
75
98
|
"help_option_names": ["-h", "--help"],
|
|
@@ -498,10 +521,12 @@ def register_commands() -> None:
|
|
|
498
521
|
function,
|
|
499
522
|
init,
|
|
500
523
|
marketplace,
|
|
524
|
+
ng,
|
|
501
525
|
odata,
|
|
502
526
|
organization,
|
|
503
527
|
proxy,
|
|
504
528
|
report,
|
|
529
|
+
reset,
|
|
505
530
|
source,
|
|
506
531
|
studio,
|
|
507
532
|
user,
|
|
@@ -520,10 +545,12 @@ def register_commands() -> None:
|
|
|
520
545
|
cli.add_command(env.env)
|
|
521
546
|
cli.add_command(function.function)
|
|
522
547
|
cli.add_command(marketplace.marketplace)
|
|
548
|
+
cli.add_command(ng.ng)
|
|
523
549
|
cli.add_command(odata.odata)
|
|
524
550
|
cli.add_command(organization.organization)
|
|
525
551
|
cli.add_command(proxy.proxy)
|
|
526
552
|
cli.add_command(report.report)
|
|
553
|
+
cli.add_command(reset.reset)
|
|
527
554
|
cli.add_command(source.source)
|
|
528
555
|
cli.add_command(studio.studio)
|
|
529
556
|
cli.add_command(user.user)
|
|
@@ -632,6 +659,7 @@ register_commands()
|
|
|
632
659
|
# Main entry point
|
|
633
660
|
def main() -> None:
|
|
634
661
|
"""Main entry point for the CLI."""
|
|
662
|
+
_ensure_utf8_streams()
|
|
635
663
|
try:
|
|
636
664
|
try:
|
|
637
665
|
cli()
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"""Authentication commands: dxs auth [login|logout|status|list|switch]."""
|
|
2
2
|
|
|
3
|
+
import secrets
|
|
3
4
|
from collections.abc import Callable
|
|
4
5
|
from datetime import datetime, timedelta, timezone
|
|
5
6
|
from typing import Any
|
|
7
|
+
from urllib.parse import urlencode
|
|
6
8
|
|
|
7
9
|
import click
|
|
8
10
|
|
|
@@ -10,6 +12,7 @@ from dxs.context import DxsContext, pass_context
|
|
|
10
12
|
from dxs.core.auth import MSALClient, MultiIdentityTokenCache
|
|
11
13
|
from dxs.core.auth.datex_tenant import claims_are_datex, is_datex_identity
|
|
12
14
|
from dxs.core.auth.decorators import get_access_token
|
|
15
|
+
from dxs.core.auth.tenants import org_needs_tenant_login, tenant_authority_for
|
|
13
16
|
from dxs.core.auth.token_cache import CachedIdentity, get_identity_override
|
|
14
17
|
from dxs.core.footprint import get_footprint_token
|
|
15
18
|
from dxs.utils.errors import AuthenticationError, ValidationError
|
|
@@ -48,19 +51,27 @@ def run_standard_device_login(
|
|
|
48
51
|
*,
|
|
49
52
|
tenant_id: str | None = None,
|
|
50
53
|
domain: str | None = None,
|
|
54
|
+
external_entra_id: bool | None = None,
|
|
51
55
|
organization_id: int | None = None,
|
|
52
56
|
organization_name: str | None = None,
|
|
53
57
|
api_base_url: str | None = None,
|
|
54
58
|
) -> CachedIdentity:
|
|
55
59
|
"""Run the multi-resource device-code login and save the identity.
|
|
56
60
|
|
|
57
|
-
Shared by `dxs auth login`, `dxs auth switch` (
|
|
61
|
+
Shared by `dxs auth login`, `dxs auth switch` (foreign tenant) and `dxs init`.
|
|
58
62
|
|
|
59
|
-
When ``tenant_id`` is given, authenticates against that
|
|
60
|
-
(Footprint-only additional scopes)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
When ``tenant_id`` is given, authenticates against that Entra tenant
|
|
64
|
+
(Footprint-only additional scopes). Otherwise authenticates against the
|
|
65
|
+
configured home tenant with the full additional-scope set. Org id/name are
|
|
66
|
+
discovered from ``/organizations/mine`` unless ``organization_id`` is
|
|
67
|
+
supplied (staff switch already knows them).
|
|
68
|
+
|
|
69
|
+
``external_entra_id`` records whether the org has a *dedicated* Entra
|
|
70
|
+
External ID tenant, and is stored verbatim rather than inferred from
|
|
71
|
+
``tenant_id``: a customer on their own corporate tenant needs a tenant-scoped
|
|
72
|
+
login while the flag stays False. Callers that do not know the org record
|
|
73
|
+
(the ``--tenant-id`` self-service path) leave it None, and it falls back to
|
|
74
|
+
the historical "a tenant was supplied" inference.
|
|
64
75
|
|
|
65
76
|
``api_base_url`` pins the environment used for that org discovery — callers
|
|
66
77
|
that target a non-default environment (e.g. ``dxs init --target qa``) must
|
|
@@ -71,7 +82,7 @@ def run_standard_device_login(
|
|
|
71
82
|
|
|
72
83
|
cache = MultiIdentityTokenCache()
|
|
73
84
|
settings = get_settings()
|
|
74
|
-
external = tenant_id is not None
|
|
85
|
+
external = (tenant_id is not None) if external_entra_id is None else external_entra_id
|
|
75
86
|
|
|
76
87
|
def _on_consent(resource_name: str, scopes: list[str]) -> None:
|
|
77
88
|
ctx.log(f"Additional consent needed for: {resource_name}")
|
|
@@ -636,11 +647,12 @@ def status(ctx: DxsContext) -> None:
|
|
|
636
647
|
return f"{seconds // 3600} hours"
|
|
637
648
|
|
|
638
649
|
# Check all cached tokens for each resource.
|
|
639
|
-
#
|
|
650
|
+
# Foreign-tenant identities must be probed against their own tenant authority;
|
|
640
651
|
# redeeming their refresh token against the default tenant returns invalid_grant.
|
|
641
652
|
settings = get_settings()
|
|
642
|
-
|
|
643
|
-
|
|
653
|
+
foreign_tenant = tenant_authority_for(active_identity)
|
|
654
|
+
if foreign_tenant:
|
|
655
|
+
client = MSALClient.for_tenant(foreign_tenant)
|
|
644
656
|
else:
|
|
645
657
|
client = MSALClient()
|
|
646
658
|
|
|
@@ -920,15 +932,15 @@ def consent(
|
|
|
920
932
|
)
|
|
921
933
|
)
|
|
922
934
|
raise SystemExit(1)
|
|
923
|
-
if not org_info
|
|
935
|
+
if not org_needs_tenant_login(org_info):
|
|
924
936
|
ctx.output(
|
|
925
937
|
single(
|
|
926
938
|
item={
|
|
927
939
|
"status": "not_required",
|
|
928
|
-
"message": f"Organization '{org}'
|
|
940
|
+
"message": f"Organization '{org}' authenticates against the Datex home tenant",
|
|
929
941
|
"organization": org_info.name,
|
|
930
942
|
"organization_id": org_info.id,
|
|
931
|
-
"note": "Admin consent is only required for organizations with
|
|
943
|
+
"note": "Admin consent is only required for organizations with their own Entra tenant",
|
|
932
944
|
},
|
|
933
945
|
semantic_key="consent",
|
|
934
946
|
)
|
|
@@ -951,38 +963,49 @@ def consent(
|
|
|
951
963
|
resolved_domain = org_info.external_entra_id_domain_name
|
|
952
964
|
|
|
953
965
|
settings = get_settings()
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
966
|
+
redirect_uri = settings.azure_consent_redirect_uri
|
|
967
|
+
# Traceability rather than CSRF: nothing in the CLI receives the redirect, so
|
|
968
|
+
# there is no state to validate against. It lets staff correlate an admin's
|
|
969
|
+
# "I approved it" with the request they sent.
|
|
970
|
+
state = f"dxs-{secrets.token_urlsafe(12)}"
|
|
971
|
+
|
|
972
|
+
# Only the CLI app needs per-tenant admin consent. The Footprint API app is
|
|
973
|
+
# consented during customer onboarding in every case, and being a resource app
|
|
974
|
+
# it has no reply address — its consent URL could only ever fail with
|
|
975
|
+
# AADSTS500113 before reaching a consent screen.
|
|
976
|
+
query = urlencode(
|
|
977
|
+
{
|
|
978
|
+
"client_id": settings.azure_client_id,
|
|
979
|
+
"redirect_uri": redirect_uri,
|
|
980
|
+
"state": state,
|
|
981
|
+
}
|
|
982
|
+
)
|
|
983
|
+
consent_url = f"https://login.microsoftonline.com/{resolved_tenant_id}/adminconsent?{query}"
|
|
959
984
|
|
|
960
985
|
consent_apps = [
|
|
961
986
|
{
|
|
962
|
-
"name": "Datex Studio
|
|
987
|
+
"name": "Datex Studio CLI",
|
|
963
988
|
"client_id": settings.azure_client_id,
|
|
964
|
-
"url":
|
|
989
|
+
"url": consent_url,
|
|
965
990
|
},
|
|
966
991
|
]
|
|
967
|
-
if footprint_consent_url and fp_client_id:
|
|
968
|
-
consent_apps.append(
|
|
969
|
-
{"name": "Footprint API", "client_id": fp_client_id, "url": footprint_consent_url}
|
|
970
|
-
)
|
|
971
992
|
|
|
972
993
|
if open:
|
|
973
994
|
ctx.output(
|
|
974
995
|
single(
|
|
975
996
|
item={
|
|
976
997
|
"status": "opening_browser",
|
|
977
|
-
"message": f"Opening admin consent
|
|
998
|
+
"message": f"Opening the admin consent page for {org_name}",
|
|
978
999
|
"organization": org_name,
|
|
979
1000
|
"organization_id": org_id,
|
|
980
1001
|
"tenant_id": resolved_tenant_id,
|
|
981
1002
|
"domain": resolved_domain,
|
|
1003
|
+
"redirect_uri": redirect_uri,
|
|
1004
|
+
"state": state,
|
|
982
1005
|
"consent_apps": consent_apps,
|
|
983
1006
|
"instructions": (
|
|
984
|
-
"A tenant admin must complete the consent flow
|
|
985
|
-
"
|
|
1007
|
+
"A tenant admin must complete the consent flow. A browser tab "
|
|
1008
|
+
"will open -- approve it."
|
|
986
1009
|
),
|
|
987
1010
|
},
|
|
988
1011
|
semantic_key="consent",
|
|
@@ -995,15 +1018,18 @@ def consent(
|
|
|
995
1018
|
single(
|
|
996
1019
|
item={
|
|
997
1020
|
"status": "url_generated",
|
|
998
|
-
"message": f"Admin consent
|
|
1021
|
+
"message": f"Admin consent URL for {org_name}",
|
|
999
1022
|
"organization": org_name,
|
|
1000
1023
|
"organization_id": org_id,
|
|
1001
1024
|
"tenant_id": resolved_tenant_id,
|
|
1002
1025
|
"domain": resolved_domain,
|
|
1026
|
+
"redirect_uri": redirect_uri,
|
|
1027
|
+
"state": state,
|
|
1003
1028
|
"consent_apps": consent_apps,
|
|
1004
1029
|
"instructions": (
|
|
1005
|
-
"Have a tenant admin open
|
|
1006
|
-
"
|
|
1030
|
+
"Have a tenant admin open this URL and approve it. "
|
|
1031
|
+
"After approving, the browser lands on a Microsoft page carrying "
|
|
1032
|
+
"this state value -- that is success, not an error."
|
|
1007
1033
|
),
|
|
1008
1034
|
},
|
|
1009
1035
|
semantic_key="consent",
|
|
@@ -1268,14 +1294,14 @@ def _switch_by_organization(
|
|
|
1268
1294
|
)
|
|
1269
1295
|
raise SystemExit(1)
|
|
1270
1296
|
|
|
1271
|
-
# Step 3: Check
|
|
1272
|
-
if not org_info
|
|
1273
|
-
#
|
|
1297
|
+
# Step 3: Check whether this org lives in a tenant of its own
|
|
1298
|
+
if not org_needs_tenant_login(org_info):
|
|
1299
|
+
# Home-tenant org (Datex): the current identity already covers it.
|
|
1274
1300
|
ctx.output(
|
|
1275
1301
|
single(
|
|
1276
1302
|
item={
|
|
1277
1303
|
"status": "no_action_required",
|
|
1278
|
-
"message": f"Organization '{org_name}'
|
|
1304
|
+
"message": f"Organization '{org_name}' authenticates against the Datex home tenant",
|
|
1279
1305
|
"organization": org_info.name,
|
|
1280
1306
|
"organization_id": org_info.id,
|
|
1281
1307
|
"suggestion": "Your current identity should work with this organization",
|
|
@@ -1285,7 +1311,7 @@ def _switch_by_organization(
|
|
|
1285
1311
|
)
|
|
1286
1312
|
return
|
|
1287
1313
|
|
|
1288
|
-
# Step 4:
|
|
1314
|
+
# Step 4: Tenant login required - check if we have identity for that tenant
|
|
1289
1315
|
if org_info.tenant_id:
|
|
1290
1316
|
existing_by_tenant = cache.get_identity_by_tenant(org_info.tenant_id)
|
|
1291
1317
|
if existing_by_tenant and existing_by_tenant.account_username:
|
|
@@ -1457,6 +1483,7 @@ def _authenticate_external_tenant(
|
|
|
1457
1483
|
on_additional_consent_needed=on_additional_consent_needed,
|
|
1458
1484
|
tenant_id=org_info.tenant_id,
|
|
1459
1485
|
domain=org_info.external_entra_id_domain_name,
|
|
1486
|
+
external_entra_id=org_info.external_entra_id,
|
|
1460
1487
|
organization_id=org_info.id,
|
|
1461
1488
|
organization_name=org_info.name,
|
|
1462
1489
|
)
|
|
@@ -1553,13 +1580,13 @@ def _login_to_organization(
|
|
|
1553
1580
|
)
|
|
1554
1581
|
raise SystemExit(1)
|
|
1555
1582
|
|
|
1556
|
-
# Check
|
|
1557
|
-
if not org_info
|
|
1583
|
+
# Check whether this org lives in a tenant of its own
|
|
1584
|
+
if not org_needs_tenant_login(org_info):
|
|
1558
1585
|
ctx.output(
|
|
1559
1586
|
single(
|
|
1560
1587
|
item={
|
|
1561
1588
|
"status": "no_external_auth",
|
|
1562
|
-
"message": f"Organization '{org_name}'
|
|
1589
|
+
"message": f"Organization '{org_name}' authenticates against the Datex home tenant",
|
|
1563
1590
|
"organization": org_info.name,
|
|
1564
1591
|
"organization_id": org_info.id,
|
|
1565
1592
|
"suggestion": "Your current identity can access this organization directly",
|
|
@@ -1569,7 +1596,7 @@ def _login_to_organization(
|
|
|
1569
1596
|
)
|
|
1570
1597
|
return
|
|
1571
1598
|
|
|
1572
|
-
#
|
|
1599
|
+
# Tenant login required - authenticate against the org's own tenant
|
|
1573
1600
|
if not org_info.tenant_id:
|
|
1574
1601
|
ctx.output_error(
|
|
1575
1602
|
AuthenticationError(
|