composable-data-stack 0.10.0__tar.gz → 0.12.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. {composable_data_stack-0.10.0/composable_data_stack.egg-info → composable_data_stack-0.12.0}/PKG-INFO +13 -90
  2. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/README.md +11 -88
  3. composable_data_stack-0.12.0/cli/audit_log.py +155 -0
  4. composable_data_stack-0.12.0/cli/composer.py +366 -0
  5. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/getter.py +165 -12
  6. composable_data_stack-0.12.0/cli/image_digest_check.py +171 -0
  7. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/image_verification.py +16 -0
  8. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/k8s_runner.py +100 -29
  9. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/loader.py +2 -2
  10. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/main.py +815 -65
  11. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/overlay.py +139 -24
  12. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/planner.py +148 -8
  13. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/renderer.py +18 -3
  14. composable_data_stack-0.12.0/cli/report.py +253 -0
  15. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/resources/rule-schema.json +4 -2
  16. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/resources/rule-set.json +48 -0
  17. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/security.py +138 -0
  18. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/security_common.py +55 -0
  19. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/up_runner.py +88 -36
  20. composable_data_stack-0.12.0/cli/update_check.py +128 -0
  21. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/validator.py +51 -0
  22. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0/composable_data_stack.egg-info}/PKG-INFO +13 -90
  23. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/composable_data_stack.egg-info/SOURCES.txt +17 -0
  24. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/composable_data_stack.egg-info/requires.txt +1 -1
  25. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/pyproject.toml +2 -2
  26. composable_data_stack-0.12.0/tests/test_audit_log.py +143 -0
  27. composable_data_stack-0.12.0/tests/test_build_cra_release_evidence_manifest.py +127 -0
  28. composable_data_stack-0.12.0/tests/test_check_cra_release_gate.py +191 -0
  29. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_compose_to_module.py +81 -0
  30. composable_data_stack-0.12.0/tests/test_composer.py +467 -0
  31. composable_data_stack-0.12.0/tests/test_cra_traceability.py +167 -0
  32. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_dagster_hardening.py +11 -1
  33. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_getter.py +237 -0
  34. composable_data_stack-0.12.0/tests/test_image_digest_check.py +225 -0
  35. composable_data_stack-0.12.0/tests/test_image_locks.py +52 -0
  36. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_k8s_runner.py +61 -1
  37. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_keycloak_postgres_wiring.py +54 -10
  38. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_loader.py +13 -0
  39. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_main.py +918 -0
  40. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_mvp_proof_workflow.py +1 -1
  41. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_overlay.py +184 -0
  42. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_planner.py +204 -0
  43. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_publish_images_workflow.py +83 -0
  44. composable_data_stack-0.12.0/tests/test_release_workflow.py +28 -0
  45. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_renderer.py +121 -0
  46. composable_data_stack-0.12.0/tests/test_report.py +525 -0
  47. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_security.py +107 -0
  48. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_superset_hardening.py +14 -12
  49. composable_data_stack-0.12.0/tests/test_update_check.py +70 -0
  50. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_validator.py +66 -0
  51. composable_data_stack-0.12.0/tests/test_vault_init_db.py +129 -0
  52. composable_data_stack-0.12.0/tests/test_vault_init_db_runtime.py +284 -0
  53. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/LICENSE +0 -0
  54. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/__init__.py +0 -0
  55. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/constants.py +0 -0
  56. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/diagnostics.py +0 -0
  57. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/graph.py +0 -0
  58. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/image_updates.py +0 -0
  59. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/k8s_renderer.py +0 -0
  60. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/k8s_security.py +0 -0
  61. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/preflight.py +0 -0
  62. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/resolver.py +0 -0
  63. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/resources/__init__.py +0 -0
  64. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/resources/compatibility-registry.json +0 -0
  65. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/resources/compatibility-registry.schema.json +0 -0
  66. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/resources/contract.schema.json +0 -0
  67. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/resources/module.schema.json +0 -0
  68. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/resources/profile.schema.json +0 -0
  69. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/secrets.py +0 -0
  70. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/state.py +0 -0
  71. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/utils.py +0 -0
  72. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/composable_data_stack.egg-info/dependency_links.txt +0 -0
  73. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/composable_data_stack.egg-info/entry_points.txt +0 -0
  74. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/composable_data_stack.egg-info/top_level.txt +0 -0
  75. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/setup.cfg +0 -0
  76. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_ai_profile_review.py +0 -0
  77. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_bump_changelog.py +0 -0
  78. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_cds_workflow.py +0 -0
  79. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_check_roadmap_freshness.py +0 -0
  80. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_completion.py +0 -0
  81. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_compose_runtime_smoke.py +0 -0
  82. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_dagster_config_generation.py +0 -0
  83. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_dagster_definitions_uri.py +0 -0
  84. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_dagster_entrypoint_backend_guard.py +0 -0
  85. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_dbt_hardening.py +0 -0
  86. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_dlt_postgres_wiring.py +0 -0
  87. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_duckdb_hardening.py +0 -0
  88. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_environment_classification.py +0 -0
  89. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_environment_cli.py +0 -0
  90. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_generate_release_inventory.py +0 -0
  91. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_graph.py +0 -0
  92. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_image_security_scan_workflow.py +0 -0
  93. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_image_updates.py +0 -0
  94. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_image_verification.py +0 -0
  95. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_k3d_e2e_profile.py +0 -0
  96. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_k3d_exposure.py +0 -0
  97. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_k8s_renderer.py +0 -0
  98. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_k8s_security.py +0 -0
  99. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_markdown_mermaid_blocks.py +0 -0
  100. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_module_isolation.py +0 -0
  101. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_modules_no_committed_secrets.py +0 -0
  102. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_preflight.py +0 -0
  103. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_python_version_alignment.py +0 -0
  104. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_release_notes_support.py +0 -0
  105. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_release_version_check.py +0 -0
  106. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_render_example_profile.py +0 -0
  107. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_resolve_profile_path.py +0 -0
  108. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_resolver.py +0 -0
  109. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_secrets.py +0 -0
  110. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_smoke_example_profile.py +0 -0
  111. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_standalone_module_profile.py +0 -0
  112. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_state.py +0 -0
  113. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_tender_analytics.py +0 -0
  114. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_tender_dashboard.py +0 -0
  115. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_test_runner_timeout.py +0 -0
  116. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_trivyignore.py +0 -0
  117. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_up_runner.py +0 -0
  118. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_upstream_image_hardening.py +0 -0
  119. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_utils.py +0 -0
  120. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_validate_cli_sbom.py +0 -0
  121. {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_vendored_llm_client.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: composable-data-stack
3
- Version: 0.10.0
3
+ Version: 0.12.0
4
4
  Summary: CLI for validating and composing composable data stack profiles
5
5
  Author: Ronald Hensbergen
6
6
  License-Expression: Apache-2.0
@@ -32,7 +32,7 @@ Provides-Extra: dev
32
32
  Requires-Dist: coverage>=7.6; extra == "dev"
33
33
  Requires-Dist: bandit>=1.7; extra == "dev"
34
34
  Requires-Dist: pip-audit>=2.7; extra == "dev"
35
- Requires-Dist: ruff==0.16.9; extra == "dev"
35
+ Requires-Dist: ruff==0.17.0; extra == "dev"
36
36
  Dynamic: license-file
37
37
 
38
38
  # 🚀 Composable Data Stack (CDS)
@@ -770,89 +770,11 @@ runs, with a dedicated diagnostic code:
770
770
 
771
771
  ## ⚙️ CLI
772
772
 
773
- |Command|Description|
774
- |---|---|
775
- |cds get \<profile\> [--remote \<owner/repo\>] [--ref \<ref\>] [--local \<dir\>] [--into \<dir\>]|Fetch a profile plus its dependent module/runtime assets from GitHub into a local CDS layout|
776
- |cds list profiles\|modules\|images [--remote \<owner/repo\>] [--ref \<ref\>] [--local \<dir\>]|List available profiles, module sources, or module images and check for newer versions; add `--remote`/`--local` to inspect another repository before fetching from it|
777
- |cds init [profile]|Generate a project `.env` template from profile secret definitions|
778
- |cds validate [profile]|Validate modules and contracts; use `--target helm` for Kubernetes checks|
779
- |cds preflight [profile]|Check runtime tools, required environment values, and host ports without starting services|
780
- |cds plan [profile]|Resolve dependencies and generate an execution plan|
781
- |cds render [profile]|Generate Docker Compose or a Helm chart from a resolved plan|
782
- |cds up [profile]|Validate, plan, render, and start the Compose or Helm target; use `--target helm` for Kubernetes|
783
- |cds down [profile]|Stop Compose or uninstall a Helm release; Helm PVCs are retained by default|
784
- |cds state [profile]|Show Compose services or Kubernetes workloads grouped by health|
785
- |cds test [profile]|One-shot smoke validation: validate, security, plan, and render|
786
- |cds security [profile]|Run rule-based security validation on a profile|
787
- |cds diff [profile] --from \<env\> --to \<env\>|Show effective configuration differences between two environment overlays, secrets never included|
788
- |cds use [profile] [--clear]|Save (show/clear) a default profile so it doesn't have to be passed to other commands|
789
- |cds config get\|set\|unset\|list|Manage persisted project defaults in `.cds/config.json`|
790
- |cds completion \<bash\|zsh\|powershell\>|Print shell setup instructions for tab-completion|
791
-
792
- `init`, `validate`, `preflight`, `plan`, `render`, `up`, `test`, and `security`
793
- all accept `--environment <name>` (or `-e <name>`) to merge
794
- `environments/<name>.yaml` over the base profile before resolving; see
795
- [Environment Overlays](#environment-overlays).
796
-
797
- `cds get` copies the selected `profiles/<name>/` tree, every referenced module
798
- directory, and any local build-context assets referenced by those modules'
799
- Dockerfiles. By design it downloads from GitHub rather than a local checkout:
800
- by default it fetches this project's upstream repository at the `main` branch,
801
- downloading a tarball via the GitHub API (no `git` binary required). Use
802
- `--remote <owner/repo>` (or a `github.com/...` URL) to fetch a fork, and
803
- `--ref <branch|tag|sha>` to select a specific revision. Pass `--local <dir>`
804
- to use an existing local directory instead of downloading (mutually exclusive
805
- with `--remote`/`--ref`) for offline/dev workflows. Use `--into` to choose a
806
- destination root, `--dry-run` to inspect the copy plan first, and `--force` to
807
- replace conflicting local files. Successful fetches record tracking metadata
808
- in `.cds/get-manifest.json` for future update workflows.
809
-
810
- `cds list profiles`, `cds list modules`, and `cds list images` accept the same
811
- `--remote`/`--ref`/`--local` source-repository selection as `cds get`, so you
812
- can discover what's available in another repository (a fork, or an existing
813
- local checkout) before running `cds get` against it. Without these flags,
814
- `cds list` inspects the local project as before.
815
-
816
- ### Project defaults
817
-
818
- `cds config` manages the gitignored `.cds/config.json` file (or the path in
819
- `CDS_CONFIG_PATH`). Supported settings are `profile`, `environment`, and
820
- `security.strict`:
821
-
822
- ```bash
823
- cds config set profile my-profile
824
- cds config set environment prod
825
- cds config set security.strict true
826
- cds config list
827
- ```
828
-
829
- `profile` is stored as its resolved path, and `environment` is validated
830
- against that profile's `environments/` directory. `security.strict true`
831
- applies the existing production security rules even if the profile declares a
832
- local environment. `cds use` remains a shortcut for setting, showing, or
833
- clearing `profile`.
834
-
835
- CLI flags take precedence over these defaults. In particular,
836
- `--environment` overrides `config environment`; `CDS_PROFILE_PATH` continues
837
- to override the saved profile.
838
-
839
- `[profile]` accepts:
840
-
841
- | Form | Example |
842
- | ---- | ------- |
843
- | Profile name | `local-dagster-postgres-superset` |
844
- | Path to a `profile.yaml` file | `profiles/local-dagster-postgres-superset/profile.yaml` |
845
- | Path to a profiles root directory | `profiles/` |
846
-
847
- When `[profile]` is omitted, resolution falls back in order to: `CDS_PROFILE_PATH` if set (accepts the same three forms), then the default profile saved via `cds config set profile` (or `cds use <profile>`), then the single profile under `profiles/` if there is exactly one. An explicitly-set env var takes precedence over the persisted project default, matching common CLI convention (env vars are per-invocation and reflect the current session more reliably than a saved, gitignored default that's easy to forget about).
848
-
849
- To view the full list of options for any command, use the `--help` flag:
850
-
851
- ```bash
852
- cds --help
853
- cds validate --help
854
- cds plan --help
855
- ```
773
+ See [docs/cli-reference.md](docs/cli-reference.md) for the full command
774
+ table, flag reference, and `[profile]` resolution rules. The commands used in
775
+ the [Quickstart](#-quickstart) above are `cds init`, `cds validate`,
776
+ `cds preflight`, `cds security`, `cds plan`, `cds render`, and `cds up`; run
777
+ `cds --help` or `cds <command> --help` for inline usage at any time.
856
778
 
857
779
  ---
858
780
 
@@ -1034,10 +956,9 @@ Please read these first:
1034
956
 
1035
957
  - [CONTRIBUTING.md](CONTRIBUTING.md)
1036
958
  - [docs/maintainer-merge-policy.md](docs/maintainer-merge-policy.md)
1037
- - [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)
1038
- - [SECURITY.md](SECURITY.md)
1039
- - [SUPPORT.md](SUPPORT.md)
1040
- - [docs/security-support-policy.md](docs/security-support-policy.md)
959
+ - [SECURITY.md](SECURITY.md) — how to report a vulnerability
960
+ - [LEGAL.md](LEGAL.md) — license, code of conduct, security, support, and
961
+ regulatory-compliance documentation index
1041
962
  - [CHANGELOG.md](CHANGELOG.md)
1042
963
  - [RELEASE.md](RELEASE.md)
1043
964
 
@@ -1049,6 +970,7 @@ Development helper tools are located in the gitignored `tools/` directory. See
1049
970
  ## 📖 Documentation
1050
971
 
1051
972
  - [Quickstart](README.md#-quickstart) — get running in 5 minutes
973
+ - [CLI Reference](docs/cli-reference.md) — full command/flag table and `[profile]` resolution rules
1052
974
  - [How CDS Works](docs/how-it-works.md) — C4 + sequence diagrams of the validate → plan → render engine
1053
975
  - [Kubernetes Target](docs/kubernetes.md): Helm rendering and isolated local k3s workflow
1054
976
  - [From Docker Compose to CDS Profile](docs/from-docker-to-cds-profile.md) — complete transformation guide
@@ -1060,4 +982,5 @@ Development helper tools are located in the gitignored `tools/` directory. See
1060
982
 
1061
983
  ## 📜 License
1062
984
 
1063
- See `LICENSE`.
985
+ See `LICENSE`. For security, support, and regulatory-compliance
986
+ documentation, see [LEGAL.md](LEGAL.md).
@@ -733,89 +733,11 @@ runs, with a dedicated diagnostic code:
733
733
 
734
734
  ## ⚙️ CLI
735
735
 
736
- |Command|Description|
737
- |---|---|
738
- |cds get \<profile\> [--remote \<owner/repo\>] [--ref \<ref\>] [--local \<dir\>] [--into \<dir\>]|Fetch a profile plus its dependent module/runtime assets from GitHub into a local CDS layout|
739
- |cds list profiles\|modules\|images [--remote \<owner/repo\>] [--ref \<ref\>] [--local \<dir\>]|List available profiles, module sources, or module images and check for newer versions; add `--remote`/`--local` to inspect another repository before fetching from it|
740
- |cds init [profile]|Generate a project `.env` template from profile secret definitions|
741
- |cds validate [profile]|Validate modules and contracts; use `--target helm` for Kubernetes checks|
742
- |cds preflight [profile]|Check runtime tools, required environment values, and host ports without starting services|
743
- |cds plan [profile]|Resolve dependencies and generate an execution plan|
744
- |cds render [profile]|Generate Docker Compose or a Helm chart from a resolved plan|
745
- |cds up [profile]|Validate, plan, render, and start the Compose or Helm target; use `--target helm` for Kubernetes|
746
- |cds down [profile]|Stop Compose or uninstall a Helm release; Helm PVCs are retained by default|
747
- |cds state [profile]|Show Compose services or Kubernetes workloads grouped by health|
748
- |cds test [profile]|One-shot smoke validation: validate, security, plan, and render|
749
- |cds security [profile]|Run rule-based security validation on a profile|
750
- |cds diff [profile] --from \<env\> --to \<env\>|Show effective configuration differences between two environment overlays, secrets never included|
751
- |cds use [profile] [--clear]|Save (show/clear) a default profile so it doesn't have to be passed to other commands|
752
- |cds config get\|set\|unset\|list|Manage persisted project defaults in `.cds/config.json`|
753
- |cds completion \<bash\|zsh\|powershell\>|Print shell setup instructions for tab-completion|
754
-
755
- `init`, `validate`, `preflight`, `plan`, `render`, `up`, `test`, and `security`
756
- all accept `--environment <name>` (or `-e <name>`) to merge
757
- `environments/<name>.yaml` over the base profile before resolving; see
758
- [Environment Overlays](#environment-overlays).
759
-
760
- `cds get` copies the selected `profiles/<name>/` tree, every referenced module
761
- directory, and any local build-context assets referenced by those modules'
762
- Dockerfiles. By design it downloads from GitHub rather than a local checkout:
763
- by default it fetches this project's upstream repository at the `main` branch,
764
- downloading a tarball via the GitHub API (no `git` binary required). Use
765
- `--remote <owner/repo>` (or a `github.com/...` URL) to fetch a fork, and
766
- `--ref <branch|tag|sha>` to select a specific revision. Pass `--local <dir>`
767
- to use an existing local directory instead of downloading (mutually exclusive
768
- with `--remote`/`--ref`) for offline/dev workflows. Use `--into` to choose a
769
- destination root, `--dry-run` to inspect the copy plan first, and `--force` to
770
- replace conflicting local files. Successful fetches record tracking metadata
771
- in `.cds/get-manifest.json` for future update workflows.
772
-
773
- `cds list profiles`, `cds list modules`, and `cds list images` accept the same
774
- `--remote`/`--ref`/`--local` source-repository selection as `cds get`, so you
775
- can discover what's available in another repository (a fork, or an existing
776
- local checkout) before running `cds get` against it. Without these flags,
777
- `cds list` inspects the local project as before.
778
-
779
- ### Project defaults
780
-
781
- `cds config` manages the gitignored `.cds/config.json` file (or the path in
782
- `CDS_CONFIG_PATH`). Supported settings are `profile`, `environment`, and
783
- `security.strict`:
784
-
785
- ```bash
786
- cds config set profile my-profile
787
- cds config set environment prod
788
- cds config set security.strict true
789
- cds config list
790
- ```
791
-
792
- `profile` is stored as its resolved path, and `environment` is validated
793
- against that profile's `environments/` directory. `security.strict true`
794
- applies the existing production security rules even if the profile declares a
795
- local environment. `cds use` remains a shortcut for setting, showing, or
796
- clearing `profile`.
797
-
798
- CLI flags take precedence over these defaults. In particular,
799
- `--environment` overrides `config environment`; `CDS_PROFILE_PATH` continues
800
- to override the saved profile.
801
-
802
- `[profile]` accepts:
803
-
804
- | Form | Example |
805
- | ---- | ------- |
806
- | Profile name | `local-dagster-postgres-superset` |
807
- | Path to a `profile.yaml` file | `profiles/local-dagster-postgres-superset/profile.yaml` |
808
- | Path to a profiles root directory | `profiles/` |
809
-
810
- When `[profile]` is omitted, resolution falls back in order to: `CDS_PROFILE_PATH` if set (accepts the same three forms), then the default profile saved via `cds config set profile` (or `cds use <profile>`), then the single profile under `profiles/` if there is exactly one. An explicitly-set env var takes precedence over the persisted project default, matching common CLI convention (env vars are per-invocation and reflect the current session more reliably than a saved, gitignored default that's easy to forget about).
811
-
812
- To view the full list of options for any command, use the `--help` flag:
813
-
814
- ```bash
815
- cds --help
816
- cds validate --help
817
- cds plan --help
818
- ```
736
+ See [docs/cli-reference.md](docs/cli-reference.md) for the full command
737
+ table, flag reference, and `[profile]` resolution rules. The commands used in
738
+ the [Quickstart](#-quickstart) above are `cds init`, `cds validate`,
739
+ `cds preflight`, `cds security`, `cds plan`, `cds render`, and `cds up`; run
740
+ `cds --help` or `cds <command> --help` for inline usage at any time.
819
741
 
820
742
  ---
821
743
 
@@ -997,10 +919,9 @@ Please read these first:
997
919
 
998
920
  - [CONTRIBUTING.md](CONTRIBUTING.md)
999
921
  - [docs/maintainer-merge-policy.md](docs/maintainer-merge-policy.md)
1000
- - [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)
1001
- - [SECURITY.md](SECURITY.md)
1002
- - [SUPPORT.md](SUPPORT.md)
1003
- - [docs/security-support-policy.md](docs/security-support-policy.md)
922
+ - [SECURITY.md](SECURITY.md) — how to report a vulnerability
923
+ - [LEGAL.md](LEGAL.md) — license, code of conduct, security, support, and
924
+ regulatory-compliance documentation index
1004
925
  - [CHANGELOG.md](CHANGELOG.md)
1005
926
  - [RELEASE.md](RELEASE.md)
1006
927
 
@@ -1012,6 +933,7 @@ Development helper tools are located in the gitignored `tools/` directory. See
1012
933
  ## 📖 Documentation
1013
934
 
1014
935
  - [Quickstart](README.md#-quickstart) — get running in 5 minutes
936
+ - [CLI Reference](docs/cli-reference.md) — full command/flag table and `[profile]` resolution rules
1015
937
  - [How CDS Works](docs/how-it-works.md) — C4 + sequence diagrams of the validate → plan → render engine
1016
938
  - [Kubernetes Target](docs/kubernetes.md): Helm rendering and isolated local k3s workflow
1017
939
  - [From Docker Compose to CDS Profile](docs/from-docker-to-cds-profile.md) — complete transformation guide
@@ -1023,4 +945,5 @@ Development helper tools are located in the gitignored `tools/` directory. See
1023
945
 
1024
946
  ## 📜 License
1025
947
 
1026
- See `LICENSE`.
948
+ See `LICENSE`. For security, support, and regulatory-compliance
949
+ documentation, see [LEGAL.md](LEGAL.md).
@@ -0,0 +1,155 @@
1
+ """
2
+ Local, append-only audit trail of rendered/applied stacks (#737).
3
+
4
+ This is distinct from `cli/getter.py`'s `.cds/get-manifest.json`, which only
5
+ tracks file provenance for `cds get`. This module instead records *what was
6
+ run* for a profile over time: timestamp, profile identity, resolved module
7
+ versions/image references, the command invoked, and its outcome. Users who
8
+ are themselves subject to incident-reporting obligations (e.g.
9
+ NIS2/Cyberbeveiligingswet-style regimes) can use this to reconstruct what
10
+ was running and when, without relying on ad hoc memory or external
11
+ infrastructure logs.
12
+
13
+ The log is strictly local evidence for the user's own purposes: nothing
14
+ here is sent to CDS or any third party. Only secret *aliases* are ever
15
+ recorded (e.g. "CDS_DB_PASSWORD"), the same `${CDS_*}` placeholder
16
+ convention used by the planner/renderer (see `cli/secrets.py`) -- never
17
+ secret values.
18
+ """
19
+ from __future__ import annotations
20
+
21
+ import json
22
+ import os
23
+ import sys
24
+ from datetime import UTC, datetime
25
+ from pathlib import Path
26
+ from typing import Any
27
+
28
+ _LOG_FILE = Path(".cds") / "audit-log.jsonl"
29
+
30
+ # Set to disable the audit log without touching project config, e.g. for a
31
+ # single invocation or a CI job that should not write local evidence files.
32
+ _ENV_DISABLE = "CDS_AUDIT_LOG_DISABLE"
33
+ _TRUTHY = {"1", "true", "yes", "on"}
34
+
35
+
36
+ def audit_log_path(project_root: Path | None = None) -> Path:
37
+ """Return the path audit entries are appended to for `project_root`.
38
+
39
+ No `cli.main` call site currently passes an explicit `project_root`, so
40
+ this defaults to `Path.cwd()` rather than the `resolve_project_root
41
+ (profile_path)` convention used elsewhere (e.g. for rendered Compose
42
+ output). That means audit entries land in whatever directory the user
43
+ happened to invoke `cds` from, not necessarily the profile's own
44
+ project root (e.g. when `CDS_PROFILE_PATH` points at a separate
45
+ profiles checkout). Tracked by #822.
46
+ """
47
+ root = (project_root or Path.cwd()).expanduser().resolve()
48
+ return root / _LOG_FILE
49
+
50
+
51
+ def is_enabled(*, config_disabled: bool = False) -> bool:
52
+ """Whether audit logging is active.
53
+
54
+ Disabled if the project config has `audit.enabled` set to `false`
55
+ (`config_disabled=True`), or if `CDS_AUDIT_LOG_DISABLE` is truthy.
56
+ """
57
+ if config_disabled:
58
+ return False
59
+ return os.environ.get(_ENV_DISABLE, "").strip().lower() not in _TRUTHY
60
+
61
+
62
+ def _module_summary(plan: dict[str, Any] | None) -> list[dict[str, Any]]:
63
+ """Resolved module id/source/version and image reference fields.
64
+
65
+ Only reference-shaped image fields (repository/tag/digest/variant) are
66
+ included -- never the full module config, which could carry
67
+ `secrets.<alias>` references or other user-provided values.
68
+ """
69
+ if not isinstance(plan, dict):
70
+ return []
71
+
72
+ summary: list[dict[str, Any]] = []
73
+ for module in plan.get("modules", []):
74
+ if not isinstance(module, dict):
75
+ continue
76
+ entry: dict[str, Any] = {
77
+ "id": module.get("id"),
78
+ "source": module.get("source"),
79
+ "version": module.get("version"),
80
+ }
81
+ config = module.get("config")
82
+ image_config = config.get("image") if isinstance(config, dict) else None
83
+ if isinstance(image_config, dict):
84
+ image_ref = {
85
+ key: image_config[key]
86
+ for key in ("repository", "tag", "digest", "variant")
87
+ if key in image_config
88
+ }
89
+ if image_ref:
90
+ entry["image"] = image_ref
91
+ summary.append(entry)
92
+ return summary
93
+
94
+
95
+ def _secret_aliases(plan: dict[str, Any] | None) -> list[str]:
96
+ """Secret alias names referenced by the plan, never their values.
97
+
98
+ `plan["secrets"]` already maps alias/env names to `CDS_*` env var
99
+ *names* (see `cli/secrets.py:load_profile_secrets`) -- no secret value
100
+ ever passes through the planner, so this is safe to record verbatim.
101
+ """
102
+ if not isinstance(plan, dict):
103
+ return []
104
+ secrets = plan.get("secrets")
105
+ if not isinstance(secrets, dict):
106
+ return []
107
+ return sorted(secrets.keys())
108
+
109
+
110
+ def record_entry(
111
+ *,
112
+ command: str,
113
+ profile: str,
114
+ outcome: str,
115
+ environment: str | None = None,
116
+ plan: dict[str, Any] | None = None,
117
+ details: dict[str, Any] | None = None,
118
+ project_root: Path | None = None,
119
+ config_disabled: bool = False,
120
+ ) -> Path | None:
121
+ """Append one JSON Lines entry describing a render/apply attempt.
122
+
123
+ Returns the log path written to, or `None` if audit logging is
124
+ disabled. Never raises: a failure to write the audit log must not
125
+ block the primary command it is observing.
126
+ """
127
+ if not is_enabled(config_disabled=config_disabled):
128
+ return None
129
+
130
+ log_path = audit_log_path(project_root)
131
+ entry: dict[str, Any] = {
132
+ "timestamp": datetime.now(UTC).isoformat(),
133
+ "command": command,
134
+ "profile": profile,
135
+ "environment": environment,
136
+ "outcome": outcome,
137
+ "modules": _module_summary(plan),
138
+ "secretAliases": _secret_aliases(plan),
139
+ }
140
+ if details:
141
+ entry["details"] = details
142
+
143
+ try:
144
+ log_path.parent.mkdir(parents=True, exist_ok=True)
145
+ if log_path.is_symlink():
146
+ # Never follow/overwrite-through a symlink planted at the log
147
+ # path (same guard as the get-manifest writer in getter.py).
148
+ log_path.unlink()
149
+ with open(log_path, "a", encoding="utf-8") as f:
150
+ f.write(json.dumps(entry, sort_keys=True) + "\n")
151
+ except OSError as exc:
152
+ print(f"WARNING Could not write audit log entry to {log_path}: {exc}", file=sys.stderr)
153
+ return None
154
+
155
+ return log_path