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.
- {composable_data_stack-0.10.0/composable_data_stack.egg-info → composable_data_stack-0.12.0}/PKG-INFO +13 -90
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/README.md +11 -88
- composable_data_stack-0.12.0/cli/audit_log.py +155 -0
- composable_data_stack-0.12.0/cli/composer.py +366 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/getter.py +165 -12
- composable_data_stack-0.12.0/cli/image_digest_check.py +171 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/image_verification.py +16 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/k8s_runner.py +100 -29
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/loader.py +2 -2
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/main.py +815 -65
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/overlay.py +139 -24
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/planner.py +148 -8
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/renderer.py +18 -3
- composable_data_stack-0.12.0/cli/report.py +253 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/resources/rule-schema.json +4 -2
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/resources/rule-set.json +48 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/security.py +138 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/security_common.py +55 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/up_runner.py +88 -36
- composable_data_stack-0.12.0/cli/update_check.py +128 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/validator.py +51 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0/composable_data_stack.egg-info}/PKG-INFO +13 -90
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/composable_data_stack.egg-info/SOURCES.txt +17 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/composable_data_stack.egg-info/requires.txt +1 -1
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/pyproject.toml +2 -2
- composable_data_stack-0.12.0/tests/test_audit_log.py +143 -0
- composable_data_stack-0.12.0/tests/test_build_cra_release_evidence_manifest.py +127 -0
- composable_data_stack-0.12.0/tests/test_check_cra_release_gate.py +191 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_compose_to_module.py +81 -0
- composable_data_stack-0.12.0/tests/test_composer.py +467 -0
- composable_data_stack-0.12.0/tests/test_cra_traceability.py +167 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_dagster_hardening.py +11 -1
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_getter.py +237 -0
- composable_data_stack-0.12.0/tests/test_image_digest_check.py +225 -0
- composable_data_stack-0.12.0/tests/test_image_locks.py +52 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_k8s_runner.py +61 -1
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_keycloak_postgres_wiring.py +54 -10
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_loader.py +13 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_main.py +918 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_mvp_proof_workflow.py +1 -1
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_overlay.py +184 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_planner.py +204 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_publish_images_workflow.py +83 -0
- composable_data_stack-0.12.0/tests/test_release_workflow.py +28 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_renderer.py +121 -0
- composable_data_stack-0.12.0/tests/test_report.py +525 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_security.py +107 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_superset_hardening.py +14 -12
- composable_data_stack-0.12.0/tests/test_update_check.py +70 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_validator.py +66 -0
- composable_data_stack-0.12.0/tests/test_vault_init_db.py +129 -0
- composable_data_stack-0.12.0/tests/test_vault_init_db_runtime.py +284 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/LICENSE +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/__init__.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/constants.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/diagnostics.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/graph.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/image_updates.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/k8s_renderer.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/k8s_security.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/preflight.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/resolver.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/resources/__init__.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/resources/compatibility-registry.json +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/resources/compatibility-registry.schema.json +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/resources/contract.schema.json +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/resources/module.schema.json +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/resources/profile.schema.json +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/secrets.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/state.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/cli/utils.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/composable_data_stack.egg-info/dependency_links.txt +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/composable_data_stack.egg-info/entry_points.txt +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/composable_data_stack.egg-info/top_level.txt +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/setup.cfg +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_ai_profile_review.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_bump_changelog.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_cds_workflow.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_check_roadmap_freshness.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_completion.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_compose_runtime_smoke.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_dagster_config_generation.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_dagster_definitions_uri.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_dagster_entrypoint_backend_guard.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_dbt_hardening.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_dlt_postgres_wiring.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_duckdb_hardening.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_environment_classification.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_environment_cli.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_generate_release_inventory.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_graph.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_image_security_scan_workflow.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_image_updates.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_image_verification.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_k3d_e2e_profile.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_k3d_exposure.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_k8s_renderer.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_k8s_security.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_markdown_mermaid_blocks.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_module_isolation.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_modules_no_committed_secrets.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_preflight.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_python_version_alignment.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_release_notes_support.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_release_version_check.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_render_example_profile.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_resolve_profile_path.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_resolver.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_secrets.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_smoke_example_profile.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_standalone_module_profile.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_state.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_tender_analytics.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_tender_dashboard.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_test_runner_timeout.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_trivyignore.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_up_runner.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_upstream_image_hardening.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_utils.py +0 -0
- {composable_data_stack-0.10.0 → composable_data_stack-0.12.0}/tests/test_validate_cli_sbom.py +0 -0
- {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.
|
|
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.
|
|
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
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
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
|
-
- [
|
|
1038
|
-
- [
|
|
1039
|
-
-
|
|
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
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
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
|
-
- [
|
|
1001
|
-
- [
|
|
1002
|
-
-
|
|
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
|