ciphergate-cli 0.7.0__tar.gz → 0.7.1__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 (142) hide show
  1. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/CHANGELOG.md +13 -1
  2. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/PKG-INFO +18 -2
  3. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/README.md +17 -1
  4. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/pyproject.toml +3 -0
  5. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/__init__.py +1 -1
  6. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/cli.py +15 -2
  7. ciphergate_cli-0.7.1/src/ciphergate/policy/templates.py +36 -0
  8. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/integration/test_cli_e2e.py +30 -0
  9. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/.gitignore +0 -0
  10. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/LICENSE +0 -0
  11. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/NOTICE +0 -0
  12. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/SECURITY.md +0 -0
  13. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/docs/architecture.md +0 -0
  14. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/docs/claude-code-tooling.md +0 -0
  15. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/docs/detector-coverage.md +0 -0
  16. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/docs/examples.md +0 -0
  17. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/docs/limitations.md +0 -0
  18. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/docs/policy-schema.md +0 -0
  19. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/docs/security-and-privacy.md +0 -0
  20. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/docs/threat-model.md +0 -0
  21. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/examples/expected/sample.dev_local_dev.csv +0 -0
  22. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/examples/expected/sample.dev_local_dev.json +0 -0
  23. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/examples/expected/sample.dev_local_dev.jsonl +0 -0
  24. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/examples/expected/sample.dev_local_dev.log +0 -0
  25. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/examples/sample.csv +0 -0
  26. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/examples/sample.json +0 -0
  27. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/examples/sample.jsonl +0 -0
  28. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/examples/sample.log +0 -0
  29. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/policies/dev_local.yml +0 -0
  30. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/policies/developer_logs.yml +0 -0
  31. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/policies/external_ai.yml +0 -0
  32. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/policies/financial_template.yml +0 -0
  33. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/policies/healthcare_template.yml +0 -0
  34. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/policies/local_debug.yml +0 -0
  35. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/policies/multi_environment.yml +0 -0
  36. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/policies/prd_external_ai.yml +0 -0
  37. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/policies/stg_test.yml +0 -0
  38. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/policies/test_dataset.yml +0 -0
  39. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/__main__.py +0 -0
  40. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/config.py +0 -0
  41. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/constants.py +0 -0
  42. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/detectors/__init__.py +0 -0
  43. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/detectors/base.py +0 -0
  44. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/detectors/custom_regex.py +0 -0
  45. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/detectors/dates.py +0 -0
  46. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/detectors/email.py +0 -0
  47. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/detectors/field_names.py +0 -0
  48. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/detectors/ip_address.py +0 -0
  49. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/detectors/network.py +0 -0
  50. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/detectors/payment_card.py +0 -0
  51. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/detectors/phone.py +0 -0
  52. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/detectors/presidio_ner.py +0 -0
  53. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/detectors/regex_safety.py +0 -0
  54. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/detectors/registry.py +0 -0
  55. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/detectors/secrets.py +0 -0
  56. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/errors.py +0 -0
  57. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/models/__init__.py +0 -0
  58. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/models/context.py +0 -0
  59. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/models/finding.py +0 -0
  60. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/models/policy.py +0 -0
  61. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/models/report.py +0 -0
  62. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/pipeline/__init__.py +0 -0
  63. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/pipeline/atomic_output.py +0 -0
  64. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/pipeline/batch.py +0 -0
  65. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/pipeline/inspector.py +0 -0
  66. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/pipeline/paths.py +0 -0
  67. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/pipeline/planner.py +0 -0
  68. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/pipeline/rescan.py +0 -0
  69. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/pipeline/sanitizer.py +0 -0
  70. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/pipeline/stdio.py +0 -0
  71. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/pipeline/streams.py +0 -0
  72. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/policy/__init__.py +0 -0
  73. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/policy/context.py +0 -0
  74. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/policy/engine.py +0 -0
  75. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/policy/loader.py +0 -0
  76. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/policy/precedence.py +0 -0
  77. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/policy/validator.py +0 -0
  78. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/py.typed +0 -0
  79. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/readers/__init__.py +0 -0
  80. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/readers/accesslog_reader.py +0 -0
  81. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/readers/base.py +0 -0
  82. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/readers/csv_reader.py +0 -0
  83. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/readers/json_reader.py +0 -0
  84. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/readers/jsonl_reader.py +0 -0
  85. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/readers/jsonlog_reader.py +0 -0
  86. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/readers/line_structure.py +0 -0
  87. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/readers/logfmt_reader.py +0 -0
  88. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/readers/stacktrace_reader.py +0 -0
  89. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/readers/syslog_reader.py +0 -0
  90. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/readers/text_reader.py +0 -0
  91. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/reporting/__init__.py +0 -0
  92. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/reporting/audit.py +0 -0
  93. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/reporting/safe_text.py +0 -0
  94. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/reporting/serializer.py +0 -0
  95. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/reporting/terminal.py +0 -0
  96. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/templates/starter_policy.yml +0 -0
  97. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/transforms/__init__.py +0 -0
  98. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/transforms/date_shift.py +0 -0
  99. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/transforms/generalize.py +0 -0
  100. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/transforms/keys.py +0 -0
  101. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/transforms/pseudonymize.py +0 -0
  102. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/transforms/redact.py +0 -0
  103. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/transforms/registry.py +0 -0
  104. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/src/ciphergate/transforms/replace.py +0 -0
  105. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/__init__.py +0 -0
  106. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/conftest.py +0 -0
  107. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/integration/__init__.py +0 -0
  108. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/integration/test_api_batch_streams.py +0 -0
  109. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/integration/test_atomic_output.py +0 -0
  110. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/integration/test_batch.py +0 -0
  111. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/integration/test_domain_templates.py +0 -0
  112. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/integration/test_environment_matrix.py +0 -0
  113. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/integration/test_pipelines.py +0 -0
  114. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/integration/test_stdio.py +0 -0
  115. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/regression/__init__.py +0 -0
  116. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/regression/test_known_cases.py +0 -0
  117. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/security/__init__.py +0 -0
  118. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/security/test_key_file.py +0 -0
  119. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/security/test_no_network.py +0 -0
  120. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/security/test_no_raw_value_leaks.py +0 -0
  121. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/security/test_path_safety.py +0 -0
  122. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/security/test_policy_fail_closed.py +0 -0
  123. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/security/test_review_findings.py +0 -0
  124. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/tooling/__init__.py +0 -0
  125. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/tooling/test_ci_supply_chain.py +0 -0
  126. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/tooling/test_claude_tooling.py +0 -0
  127. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/tooling/test_git_tooling.py +0 -0
  128. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/tooling/test_publish_workflow.py +0 -0
  129. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/unit/__init__.py +0 -0
  130. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/unit/test_accesslog.py +0 -0
  131. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/unit/test_detectors.py +0 -0
  132. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/unit/test_jsonlog.py +0 -0
  133. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/unit/test_logfmt.py +0 -0
  134. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/unit/test_policy_engine.py +0 -0
  135. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/unit/test_policy_precedence.py +0 -0
  136. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/unit/test_policy_validation.py +0 -0
  137. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/unit/test_presidio_ner.py +0 -0
  138. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/unit/test_properties.py +0 -0
  139. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/unit/test_readers.py +0 -0
  140. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/unit/test_stacktrace.py +0 -0
  141. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/unit/test_syslog.py +0 -0
  142. {ciphergate_cli-0.7.0 → ciphergate_cli-0.7.1}/tests/unit/test_transforms.py +0 -0
@@ -6,6 +6,17 @@ versioning: [PEP 440](https://peps.python.org/pep-0440/) with SemVer meaning (pr
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.7.1] - 2026-10-30
10
+
11
+ Makes the starter policy templates available after `pip install`. Existing commands and
12
+ template contents are unchanged.
13
+
14
+ ### Added
15
+
16
+ - The starter policy templates now ship in the wheel. `ciphergate init --template NAME` writes
17
+ one to a file and `ciphergate init --list-templates` lists them, so a `pip install` no longer
18
+ needs a repository clone to get them. Plain `ciphergate init` is unchanged.
19
+
9
20
  ## [0.7.0] - 2026-10-30
10
21
 
11
22
  First release published to PyPI. CLI, API and policy behaviour are unchanged, except for the
@@ -259,7 +270,8 @@ Pre-release (alpha). Licensed under Apache-2.0. Not a final release: the securit
259
270
  See `docs/limitations.md`. Deferred: optional NER/Presidio detectors, stdin/stdout streaming,
260
271
  directory processing, structured log parsers, key files, reversible token vault, lossy decoding.
261
272
 
262
- [Unreleased]: https://github.com/aashishkumar-tech/ciphergate/compare/v0.7.0...HEAD
273
+ [Unreleased]: https://github.com/aashishkumar-tech/ciphergate/compare/v0.7.1...HEAD
274
+ [0.7.1]: https://github.com/aashishkumar-tech/ciphergate/compare/v0.7.0...v0.7.1
263
275
  [0.7.0]: https://github.com/aashishkumar-tech/ciphergate/compare/v0.6.1...v0.7.0
264
276
  [0.6.1]: https://github.com/aashishkumar-tech/ciphergate/compare/v0.6.0...v0.6.1
265
277
  [0.6.0]: https://github.com/aashishkumar-tech/ciphergate/compare/v0.5.0...v0.6.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: ciphergate-cli
3
- Version: 0.7.0
3
+ Version: 0.7.1
4
4
  Summary: Local-first, environment- and destination-aware inspection and sanitization of logs and test datasets.
5
5
  Project-URL: Homepage, https://github.com/aashishkumar-tech/ciphergate
6
6
  Project-URL: Source, https://github.com/aashishkumar-tech/ciphergate
@@ -50,7 +50,7 @@ vendor ticket. CipherGate replaces that with a local, explainable, scriptable ga
50
50
  inspect -> plan -> sanitize --apply -> rescan
51
51
  ```
52
52
 
53
- > **Status: 0.7.0 (alpha).** No detector finds every sensitive value. A passing run means the
53
+ > **Status: 0.7.1 (alpha).** No detector finds every sensitive value. A passing run means the
54
54
  > configured processing completed under the selected policy; it is **not** proof that the output
55
55
  > contains no sensitive information, and it is not a compliance (GDPR, HIPAA, PCI DSS, ...) or
56
56
  > anonymization guarantee. Policy templates must be reviewed before use.
@@ -117,8 +117,24 @@ ciphergate --version
117
117
 
118
118
  Runtime dependencies: `typer`, `pydantic`, `PyYAML`.
119
119
 
120
+ ## Quick start after `pip install`
121
+
122
+ The policy templates ship with the package. Copy one, review it, then run it on your own file:
123
+
124
+ ```bash
125
+ ciphergate init --list-templates
126
+ ciphergate init --template developer_logs --output developer_logs.yml
127
+ ciphergate validate-policy developer_logs.yml
128
+ ciphergate inspect app.log --policy developer_logs.yml --environment dev --destination local_dev
129
+ ```
130
+
131
+ Every template is a starting point that requires review for your data and destination.
132
+
120
133
  ## Quick start (synthetic examples)
121
134
 
135
+ These commands run from a clone of this repository, because `examples/` is not in the package.
136
+ `policies/` in a clone holds the same templates that `ciphergate init --template` writes.
137
+
122
138
  ```bash
123
139
  # 1. Start from a template (refuses to overwrite without --force) and validate it.
124
140
  ciphergate init --output ciphergate-policy.yml
@@ -11,7 +11,7 @@ vendor ticket. CipherGate replaces that with a local, explainable, scriptable ga
11
11
  inspect -> plan -> sanitize --apply -> rescan
12
12
  ```
13
13
 
14
- > **Status: 0.7.0 (alpha).** No detector finds every sensitive value. A passing run means the
14
+ > **Status: 0.7.1 (alpha).** No detector finds every sensitive value. A passing run means the
15
15
  > configured processing completed under the selected policy; it is **not** proof that the output
16
16
  > contains no sensitive information, and it is not a compliance (GDPR, HIPAA, PCI DSS, ...) or
17
17
  > anonymization guarantee. Policy templates must be reviewed before use.
@@ -78,8 +78,24 @@ ciphergate --version
78
78
 
79
79
  Runtime dependencies: `typer`, `pydantic`, `PyYAML`.
80
80
 
81
+ ## Quick start after `pip install`
82
+
83
+ The policy templates ship with the package. Copy one, review it, then run it on your own file:
84
+
85
+ ```bash
86
+ ciphergate init --list-templates
87
+ ciphergate init --template developer_logs --output developer_logs.yml
88
+ ciphergate validate-policy developer_logs.yml
89
+ ciphergate inspect app.log --policy developer_logs.yml --environment dev --destination local_dev
90
+ ```
91
+
92
+ Every template is a starting point that requires review for your data and destination.
93
+
81
94
  ## Quick start (synthetic examples)
82
95
 
96
+ These commands run from a clone of this repository, because `examples/` is not in the package.
97
+ `policies/` in a clone holds the same templates that `ciphergate init --template` writes.
98
+
83
99
  ```bash
84
100
  # 1. Start from a template (refuses to overwrite without --force) and validate it.
85
101
  ciphergate init --output ciphergate-policy.yml
@@ -62,6 +62,9 @@ path = "src/ciphergate/__init__.py"
62
62
 
63
63
  [tool.hatch.build.targets.wheel]
64
64
  packages = ["src/ciphergate"]
65
+ # policies/ stays the one source of the starter templates; `ciphergate init --template` reads them.
66
+ [tool.hatch.build.targets.wheel.force-include]
67
+ "policies" = "ciphergate/policies"
65
68
 
66
69
  [tool.hatch.build.targets.sdist]
67
70
  include = [
@@ -22,7 +22,7 @@ Supported public API (everything else is internal and may change without notice)
22
22
  rescan_directory(root, policy, context=None, *, recursive=False, strict=None) -> BatchReport
23
23
  """
24
24
 
25
- __version__ = "0.7.0"
25
+ __version__ = "0.7.1"
26
26
 
27
27
  from ciphergate.config import RuntimeSettings
28
28
  from ciphergate.constants import (
@@ -74,6 +74,7 @@ from ciphergate.pipeline.stdio import (
74
74
  )
75
75
  from ciphergate.policy.context import evaluate_gates, resolve_context
76
76
  from ciphergate.policy.engine import PolicyEngine
77
+ from ciphergate.policy.templates import read_template, template_names
77
78
  from ciphergate.policy.validator import load_policy, validate_policy
78
79
  from ciphergate.reporting.safe_text import escape_control
79
80
  from ciphergate.reporting.serializer import (
@@ -351,6 +352,13 @@ def init_command(
351
352
  output: Annotated[
352
353
  Path, typer.Option("--output", "-o", help="Where to write the policy.")
353
354
  ] = Path("ciphergate-policy.yml"),
355
+ template: Annotated[
356
+ str | None,
357
+ typer.Option("--template", "-t", help="Named template (see --list-templates)."),
358
+ ] = None,
359
+ list_templates: Annotated[
360
+ bool, typer.Option("--list-templates", help="List named templates and exit.")
361
+ ] = False,
354
362
  force: ForceOpt = False,
355
363
  quiet: QuietOpt = False,
356
364
  debug: DebugOpt = False,
@@ -358,12 +366,17 @@ def init_command(
358
366
  """Write a starter policy template (it MUST be reviewed before real use)."""
359
367
 
360
368
  def body() -> int:
361
- validate_output_path(output, protected=[], force=force, label="policy")
369
+ if list_templates:
370
+ sys.stdout.write("".join(f"{name}\n" for name in template_names()))
371
+ return 0
362
372
  text = (
363
- resources.files("ciphergate")
373
+ read_template(template)
374
+ if template is not None
375
+ else resources.files("ciphergate")
364
376
  .joinpath("templates/starter_policy.yml")
365
377
  .read_text(encoding="utf-8")
366
378
  )
379
+ validate_output_path(output, protected=[], force=force, label="policy")
367
380
  with AtomicOutput(output, force=force) as out:
368
381
  out.stream.write(text)
369
382
  out.publish()
@@ -0,0 +1,36 @@
1
+ """Starter policy templates shipped with the package. Every template requires review before use."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from importlib import resources
6
+ from importlib.resources.abc import Traversable
7
+ from pathlib import Path
8
+
9
+ from ciphergate.errors import UsageError
10
+
11
+
12
+ def _templates_dir() -> Traversable:
13
+ packaged = resources.files("ciphergate").joinpath("policies")
14
+ if packaged.is_dir():
15
+ return packaged
16
+ # Editable install: the build copies policies/ into wheels only, so use the source checkout.
17
+ return Path(__file__).resolve().parents[3] / "policies"
18
+
19
+
20
+ def template_names() -> list[str]:
21
+ """Names accepted by `read_template`, sorted."""
22
+ return sorted(
23
+ entry.name.removesuffix(".yml")
24
+ for entry in _templates_dir().iterdir()
25
+ if entry.name.endswith(".yml")
26
+ )
27
+
28
+
29
+ def read_template(name: str) -> str:
30
+ """Return a template's text. `name` is only compared to known names, never used as a path."""
31
+ if name not in template_names():
32
+ raise UsageError(
33
+ "unknown policy template; run: ciphergate init --list-templates",
34
+ code="unknown_policy_template",
35
+ )
36
+ return _templates_dir().joinpath(f"{name}.yml").read_text(encoding="utf-8")
@@ -40,6 +40,36 @@ def test_init_refuses_overwrite(tmp_path: Path) -> None:
40
40
  assert invoke("init", "--output", target, "--force").exit_code == 0
41
41
 
42
42
 
43
+ def test_init_lists_every_policy_template() -> None:
44
+ r = invoke("init", "--list-templates")
45
+ assert r.exit_code == 0
46
+ assert r.stdout.split() == sorted(p.stem for p in POLICIES.glob("*.yml"))
47
+
48
+
49
+ @pytest.mark.parametrize("policy", sorted(POLICIES.glob("*.yml")), ids=lambda p: p.stem)
50
+ def test_init_template_writes_a_valid_copy(tmp_path: Path, policy: Path) -> None:
51
+ target = tmp_path / "p.yml"
52
+ r = invoke("init", "--template", policy.stem, "--output", target)
53
+ assert r.exit_code == 0 and "template" in r.stdout.lower()
54
+ assert target.read_text(encoding="utf-8") == policy.read_text(encoding="utf-8")
55
+ assert invoke("validate-policy", target).exit_code == 0
56
+
57
+
58
+ def test_init_template_refuses_overwrite(tmp_path: Path) -> None:
59
+ target = tmp_path / "p.yml"
60
+ target.write_text("keep", encoding="utf-8")
61
+ assert invoke("init", "--template", "dev_local", "--output", target).exit_code == 5
62
+ assert target.read_text(encoding="utf-8") == "keep"
63
+
64
+
65
+ @pytest.mark.parametrize("name", ["nope", "../pyproject", "dev_local.yml", ""])
66
+ def test_init_unknown_template_fails_and_writes_nothing(tmp_path: Path, name: str) -> None:
67
+ target = tmp_path / "p.yml"
68
+ r = invoke("init", "--template", name, "--output", target)
69
+ assert r.exit_code == 2
70
+ assert "--list-templates" in r.output and not target.exists()
71
+
72
+
43
73
  def test_validate_policy_exit_codes(tmp_path: Path) -> None:
44
74
  bad = tmp_path / "bad.yml"
45
75
  bad.write_text(
File without changes
File without changes