datamasque-cli 1.0.0__tar.gz → 1.2.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.
- datamasque_cli-1.2.0/.claude-plugin/marketplace.json +21 -0
- datamasque_cli-1.2.0/CHANGELOG.md +69 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/CONTRIBUTING.md +3 -6
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/Makefile +4 -7
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/PKG-INFO +92 -1
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/README.md +91 -0
- datamasque_cli-1.2.0/claude-skills/README.md +60 -0
- datamasque_cli-1.2.0/claude-skills/datamasque-cli/.claude-plugin/plugin.json +9 -0
- datamasque_cli-1.2.0/claude-skills/datamasque-cli/skills/datamasque-cli/SKILL.md +105 -0
- datamasque_cli-1.2.0/claude-skills/ruleset-builder/.claude-plugin/plugin.json +9 -0
- datamasque_cli-1.2.0/claude-skills/ruleset-splitter/.claude-plugin/plugin.json +9 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/pyproject.toml +3 -1
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/scripts/active_profile_env.py +2 -1
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/src/datamasque_cli/client.py +66 -25
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/src/datamasque_cli/commands/auth.py +14 -6
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/src/datamasque_cli/commands/connections.py +61 -30
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/src/datamasque_cli/commands/discovery.py +4 -4
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/src/datamasque_cli/commands/files.py +3 -3
- datamasque_cli-1.2.0/src/datamasque_cli/commands/ifm.py +354 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/src/datamasque_cli/commands/ruleset_libraries.py +6 -6
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/src/datamasque_cli/commands/rulesets.py +18 -6
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/src/datamasque_cli/commands/runs.py +40 -21
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/src/datamasque_cli/commands/seeds.py +3 -3
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/src/datamasque_cli/commands/system.py +3 -3
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/src/datamasque_cli/commands/users.py +4 -4
- datamasque_cli-1.2.0/src/datamasque_cli/main.py +134 -0
- datamasque_cli-1.2.0/src/datamasque_cli/output.py +250 -0
- datamasque_cli-1.2.0/tests/commands/test_catalog.py +44 -0
- datamasque_cli-1.2.0/tests/commands/test_ifm.py +577 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/tests/conftest.py +13 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/tests/test_client_auth.py +1 -1
- datamasque_cli-1.2.0/tests/test_client_ifm.py +65 -0
- datamasque_cli-1.2.0/tests/test_output.py +200 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/uv.lock +4 -4
- datamasque_cli-1.0.0/CHANGELOG.md +0 -5
- datamasque_cli-1.0.0/claude-skills/README.md +0 -46
- datamasque_cli-1.0.0/claude-skills/datamasque-cli/SKILL.md +0 -187
- datamasque_cli-1.0.0/src/datamasque_cli/main.py +0 -58
- datamasque_cli-1.0.0/src/datamasque_cli/output.py +0 -133
- datamasque_cli-1.0.0/tests/test_output.py +0 -74
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/.github/workflows/ci.yml +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/.github/workflows/release-testpypi.yml +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/.github/workflows/release.yml +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/.gitignore +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/LICENSE +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/NOTICE +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/assets/demo.gif +0 -0
- {datamasque_cli-1.0.0/claude-skills → datamasque_cli-1.2.0/claude-skills/ruleset-builder/skills}/ruleset-builder/SKILL.md +0 -0
- {datamasque_cli-1.0.0/claude-skills → datamasque_cli-1.2.0/claude-skills/ruleset-builder/skills}/ruleset-builder/references/hash-columns-guide.md +0 -0
- {datamasque_cli-1.0.0/claude-skills → datamasque_cli-1.2.0/claude-skills/ruleset-builder/skills}/ruleset-builder/references/mask-definitions-guide.md +0 -0
- {datamasque_cli-1.0.0/claude-skills → datamasque_cli-1.2.0/claude-skills/ruleset-builder/skills}/ruleset-builder/references/ruleset-libraries-guide.md +0 -0
- {datamasque_cli-1.0.0/claude-skills → datamasque_cli-1.2.0/claude-skills/ruleset-builder/skills}/ruleset-builder/references/ruleset-yaml-reference.md +0 -0
- {datamasque_cli-1.0.0/claude-skills → datamasque_cli-1.2.0/claude-skills/ruleset-splitter/skills}/ruleset-splitter/SKILL.md +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/scripts/bump_version.py +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/src/datamasque_cli/__init__.py +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/src/datamasque_cli/commands/__init__.py +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/src/datamasque_cli/config.py +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/src/datamasque_cli/py.typed +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/tests/__init__.py +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/tests/commands/__init__.py +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/tests/commands/test_auth.py +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/tests/commands/test_connections.py +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/tests/commands/test_discovery.py +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/tests/commands/test_files.py +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/tests/commands/test_ruleset_libraries.py +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/tests/commands/test_rulesets.py +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/tests/commands/test_runs.py +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/tests/commands/test_seeds.py +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/tests/commands/test_system.py +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/tests/commands/test_users.py +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/tests/integration/README.md +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/tests/integration/__init__.py +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/tests/integration/conftest.py +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/tests/integration/test_connections.py +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/tests/integration/test_delete_safety.py +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/tests/integration/test_rulesets.py +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/tests/integration/test_runs.py +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/tests/test_client_env.py +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/tests/test_client_profile.py +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/tests/test_config.py +0 -0
- {datamasque_cli-1.0.0 → datamasque_cli-1.2.0}/tests/test_version.py +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "datamasque-tools",
|
|
3
|
+
"owner": { "name": "DataMasque" },
|
|
4
|
+
"plugins": [
|
|
5
|
+
{
|
|
6
|
+
"name": "datamasque-cli",
|
|
7
|
+
"source": "./claude-skills/datamasque-cli",
|
|
8
|
+
"description": "DataMasque command-line interface integration. Drive DataMasque from Claude Code: list connections, kick off runs, stream logs, download reports."
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"name": "ruleset-builder",
|
|
12
|
+
"source": "./claude-skills/ruleset-builder",
|
|
13
|
+
"description": "Convert auto-generated DataMasque rulesets into production-ready form. Validate and iterate."
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"name": "ruleset-splitter",
|
|
17
|
+
"source": "./claude-skills/ruleset-splitter",
|
|
18
|
+
"description": "Consolidate multi-file DataMasque rulesets for editing, then re-split them back out."
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## v1.2.0
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- `dm ifm` command group
|
|
7
|
+
for managing in-flight masking ruleset plans
|
|
8
|
+
and running mask operations against the IFM service:
|
|
9
|
+
- `dm ifm list` —
|
|
10
|
+
list all IFM ruleset plans.
|
|
11
|
+
- `dm ifm get <name>` —
|
|
12
|
+
show plan metadata,
|
|
13
|
+
or the ruleset YAML with `--yaml`.
|
|
14
|
+
- `dm ifm create --name <name> --file <yaml>` —
|
|
15
|
+
create a plan from a YAML ruleset,
|
|
16
|
+
with optional `--enabled/--disabled` and `--log-level`.
|
|
17
|
+
- `dm ifm update <name>` —
|
|
18
|
+
update a plan;
|
|
19
|
+
pass any of `--file`, `--enabled/--disabled`, `--log-level`
|
|
20
|
+
and only those fields are sent.
|
|
21
|
+
- `dm ifm delete <name>` —
|
|
22
|
+
delete a plan
|
|
23
|
+
(interactive confirm,
|
|
24
|
+
or `--yes` to skip).
|
|
25
|
+
- `dm ifm mask <name> --data <file|->` —
|
|
26
|
+
mask a JSON list of records against a plan,
|
|
27
|
+
with `--disable-instance-secret`,
|
|
28
|
+
`--run-secret`,
|
|
29
|
+
`--log-level`,
|
|
30
|
+
`--request-id`,
|
|
31
|
+
and `--json/--no-json` (NDJSON) output.
|
|
32
|
+
- `dm ifm verify-token` —
|
|
33
|
+
verify the current IFM token and list its scopes.
|
|
34
|
+
|
|
35
|
+
Authentication reuses your existing `dm` profile credentials
|
|
36
|
+
via the SDK's `DataMasqueIfmClient`,
|
|
37
|
+
which transparently exchanges admin-server credentials for an IFM JWT.
|
|
38
|
+
|
|
39
|
+
## v1.1.0
|
|
40
|
+
|
|
41
|
+
### Added
|
|
42
|
+
- `dm catalog` command — emits the full subcommand tree as JSON for agent
|
|
43
|
+
introspection. `--compact` for `{path, help}` only (~1.4kB), default for
|
|
44
|
+
full options/arguments.
|
|
45
|
+
- Auto-detection of agent context: output flips to JSON automatically when
|
|
46
|
+
stdout is not a TTY, when `DM_OUTPUT=json` is set, or when the
|
|
47
|
+
vendor-neutral `AI_AGENT` env var is present. `DM_OUTPUT=table` forces
|
|
48
|
+
human output.
|
|
49
|
+
- Structured error envelope on stderr in agent mode:
|
|
50
|
+
`{"error": {"code": "...", "message": "...", "hint": "..."}}` — stdout
|
|
51
|
+
stays empty on failure so downstream pipes don't trip.
|
|
52
|
+
|
|
53
|
+
### Changed
|
|
54
|
+
- Exit codes are now differentiated by error category. Previously every
|
|
55
|
+
error returned 1; now: `not_found`=3, `invalid_input`=4, `ambiguous`=5,
|
|
56
|
+
`auth_required`=6, `auth_failed`=7, `conflict`=8, `transport_error`=9.
|
|
57
|
+
`error` (unclassified) remains 1; 2 is reserved for typer/click usage
|
|
58
|
+
errors. Stable across minor versions.
|
|
59
|
+
- Long values (UUIDs especially) now fold across lines in table output
|
|
60
|
+
rather than being silently truncated with `…` in narrow terminals.
|
|
61
|
+
|
|
62
|
+
### Internal
|
|
63
|
+
- `ErrorCode` and `ConnectionType` are now `StrEnum`s; the abort code arg
|
|
64
|
+
is type-checked at edit time and the connection-type "Valid: ..." hint
|
|
65
|
+
is generated from the enum.
|
|
66
|
+
|
|
67
|
+
## v1.0.0
|
|
68
|
+
|
|
69
|
+
Initial release.
|
|
@@ -185,13 +185,10 @@ Each target runs `make check`,
|
|
|
185
185
|
bumps the version in `pyproject.toml`,
|
|
186
186
|
refreshes `uv.lock`,
|
|
187
187
|
commits, tags, and pushes.
|
|
188
|
-
CI handles the publish.
|
|
188
|
+
CI handles the publish to PyPI.
|
|
189
189
|
|
|
190
|
-
To
|
|
191
|
-
|
|
192
|
-
```console
|
|
193
|
-
make publish
|
|
194
|
-
```
|
|
190
|
+
To smoke-test a release against TestPyPI without tagging,
|
|
191
|
+
trigger the `Release (TestPyPI)` workflow manually from the GitHub Actions tab.
|
|
195
192
|
|
|
196
193
|
## Toolchain
|
|
197
194
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.PHONY: install lint format mypy test test-integration test-integration-local check build
|
|
1
|
+
.PHONY: install lint format mypy test test-integration test-integration-local check build release-patch release-minor release-major
|
|
2
2
|
|
|
3
3
|
install:
|
|
4
4
|
uv sync
|
|
@@ -33,9 +33,6 @@ format-check:
|
|
|
33
33
|
build:
|
|
34
34
|
uv build
|
|
35
35
|
|
|
36
|
-
publish: check build
|
|
37
|
-
uv publish --index datamasque-private-pypi -u "" -p "" dist/*
|
|
38
|
-
|
|
39
36
|
# Bump version, commit, tag, push — CI publishes automatically.
|
|
40
37
|
# Usage: make release-patch (0.1.0 → 0.1.1)
|
|
41
38
|
# make release-minor (0.1.0 → 0.2.0)
|
|
@@ -47,7 +44,7 @@ release-patch: check
|
|
|
47
44
|
git commit -m "Release v$(VERSION)"
|
|
48
45
|
git tag "v$(VERSION)"
|
|
49
46
|
git push && git push --tags
|
|
50
|
-
@echo "Released v$(VERSION) — CI will publish to pypi.
|
|
47
|
+
@echo "Released v$(VERSION) — CI will publish to PyPI (https://pypi.org/p/datamasque-cli)"
|
|
51
48
|
|
|
52
49
|
release-minor: check
|
|
53
50
|
$(eval VERSION := $(shell python3 scripts/bump_version.py minor))
|
|
@@ -56,7 +53,7 @@ release-minor: check
|
|
|
56
53
|
git commit -m "Release v$(VERSION)"
|
|
57
54
|
git tag "v$(VERSION)"
|
|
58
55
|
git push && git push --tags
|
|
59
|
-
@echo "Released v$(VERSION) — CI will publish to pypi.
|
|
56
|
+
@echo "Released v$(VERSION) — CI will publish to PyPI (https://pypi.org/p/datamasque-cli)"
|
|
60
57
|
|
|
61
58
|
release-major: check
|
|
62
59
|
$(eval VERSION := $(shell python3 scripts/bump_version.py major))
|
|
@@ -65,4 +62,4 @@ release-major: check
|
|
|
65
62
|
git commit -m "Release v$(VERSION)"
|
|
66
63
|
git tag "v$(VERSION)"
|
|
67
64
|
git push && git push --tags
|
|
68
|
-
@echo "Released v$(VERSION) — CI will publish to pypi.
|
|
65
|
+
@echo "Released v$(VERSION) — CI will publish to PyPI (https://pypi.org/p/datamasque-cli)"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: datamasque-cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: Official command-line interface for the DataMasque data-masking platform.
|
|
5
5
|
Project-URL: Homepage, https://datamasque.com/
|
|
6
6
|
Project-URL: Repository, https://github.com/datamasque/datamasque-cli
|
|
@@ -39,6 +39,7 @@ so teams can use production-shaped data in non-production environments without e
|
|
|
39
39
|
DataMasque CLI `dm` covers:
|
|
40
40
|
|
|
41
41
|
- connections, rulesets, ruleset libraries, and masking runs
|
|
42
|
+
- in-flight masking (IFM) ruleset plans and on-demand mask requests
|
|
42
43
|
- schema discovery and sensitive-data discovery
|
|
43
44
|
- users, files, and DataMasque instance administration
|
|
44
45
|
|
|
@@ -89,6 +90,26 @@ dm run logs 42 --follow
|
|
|
89
90
|
`dm run start` and `dm run wait` block until the run finishes.
|
|
90
91
|
Pass `--background` to `start` to skip the wait.
|
|
91
92
|
|
|
93
|
+
## Claude Code skills
|
|
94
|
+
|
|
95
|
+
The [`claude-skills/`](claude-skills/) directory ships three
|
|
96
|
+
[Claude Code](https://claude.com/claude-code) plugins that drive `dm` on your behalf:
|
|
97
|
+
|
|
98
|
+
- **`datamasque-cli`** — operate a DataMasque instance (start runs, list connections, fetch discovery reports).
|
|
99
|
+
- **`ruleset-builder`** — turn auto-generated rulesets into production-ready ones.
|
|
100
|
+
- **`ruleset-splitter`** — join many-file rulesets into one file for editing, then re-split.
|
|
101
|
+
|
|
102
|
+
Install via the Claude Code plugin marketplace:
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
/plugin marketplace add datamasque/datamasque-cli
|
|
106
|
+
/plugin install datamasque-cli@datamasque-tools
|
|
107
|
+
/plugin install ruleset-builder@datamasque-tools
|
|
108
|
+
/plugin install ruleset-splitter@datamasque-tools
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
See [`claude-skills/README.md`](claude-skills/README.md) for more.
|
|
112
|
+
|
|
92
113
|
## Shell completion
|
|
93
114
|
|
|
94
115
|
`dm` provides built-in completion for bash, zsh, and fish:
|
|
@@ -176,6 +197,26 @@ dm libraries validate <name> # Re-validate against current
|
|
|
176
197
|
dm libraries usage <name> # Show rulesets using it
|
|
177
198
|
```
|
|
178
199
|
|
|
200
|
+
### In-flight masking
|
|
201
|
+
|
|
202
|
+
The IFM service runs alongside the admin server,
|
|
203
|
+
reached at `<DataMasque URL>/ifm` via the standard nginx topology.
|
|
204
|
+
|
|
205
|
+
```console
|
|
206
|
+
dm ifm list # List ruleset plans
|
|
207
|
+
dm ifm get <name> # Show plan metadata
|
|
208
|
+
dm ifm get <name> --yaml # Print the ruleset YAML
|
|
209
|
+
dm ifm create --name myplan --file rules.yaml # Create (server suffixes a random string to the name)
|
|
210
|
+
dm ifm create --name myplan --file rules.yaml --disabled --log-level DEBUG
|
|
211
|
+
dm ifm update <name> --file rules.yaml # Replace the ruleset YAML
|
|
212
|
+
dm ifm update <name> --enabled # Toggle without re-sending the YAML
|
|
213
|
+
dm ifm update <name> --log-level INFO
|
|
214
|
+
dm ifm delete <name> --yes # Delete a plan
|
|
215
|
+
dm ifm mask <name> --data input.json # Mask a JSON list of records
|
|
216
|
+
dm ifm mask <name> --data - # Read records from stdin
|
|
217
|
+
dm ifm verify-token # Show scopes granted to the current IFM token
|
|
218
|
+
```
|
|
219
|
+
|
|
179
220
|
### Masking runs
|
|
180
221
|
|
|
181
222
|
```console
|
|
@@ -249,6 +290,56 @@ STATUS=$(dm run status 42 --json | jq -r '.status')
|
|
|
249
290
|
dm rulesets get myruleset --json | jq -r '.yaml' > ruleset.yaml
|
|
250
291
|
```
|
|
251
292
|
|
|
293
|
+
JSON is also emitted automatically when:
|
|
294
|
+
|
|
295
|
+
- `stdout` is not a TTY (piped or captured),
|
|
296
|
+
- `DM_OUTPUT=json` is set in the environment, or
|
|
297
|
+
- a vendor-neutral `AI_AGENT` env var is set (e.g. by Claude Code).
|
|
298
|
+
|
|
299
|
+
Set `DM_OUTPUT=table` to force human-readable output regardless of context.
|
|
300
|
+
|
|
301
|
+
## Agent / scripting interface
|
|
302
|
+
|
|
303
|
+
For programmatic use (CI, AI coding agents, shell scripts), the CLI exposes
|
|
304
|
+
a discovery command and a stable error contract.
|
|
305
|
+
|
|
306
|
+
### Command catalog
|
|
307
|
+
|
|
308
|
+
`dm catalog` dumps every visible subcommand as JSON so an agent can introspect
|
|
309
|
+
the surface without paging through `--help` screens:
|
|
310
|
+
|
|
311
|
+
```console
|
|
312
|
+
dm catalog --compact # ~1.4kB — {path, help} per command
|
|
313
|
+
dm catalog # full — also includes options and arguments
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### Structured errors
|
|
317
|
+
|
|
318
|
+
In agent mode, errors are emitted as a JSON envelope on stderr (stdout stays
|
|
319
|
+
empty on failure):
|
|
320
|
+
|
|
321
|
+
```json
|
|
322
|
+
{"error": {"code": "not_found", "message": "Connection 'foo' not found.", "hint": "Run dm connections list."}}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### Exit codes
|
|
326
|
+
|
|
327
|
+
| Code | Meaning | When |
|
|
328
|
+
| ---: | ----------------- | ---------------------------------------------- |
|
|
329
|
+
| 0 | success | command completed |
|
|
330
|
+
| 1 | error | unclassified failure |
|
|
331
|
+
| 2 | usage error | unknown flag or missing argument (typer/click) |
|
|
332
|
+
| 3 | not_found | resource lookup failed |
|
|
333
|
+
| 4 | invalid_input | argument values rejected |
|
|
334
|
+
| 5 | ambiguous | name matched multiple resources |
|
|
335
|
+
| 6 | auth_required | no credentials configured |
|
|
336
|
+
| 7 | auth_failed | credentials rejected by server |
|
|
337
|
+
| 8 | conflict | operation rejected by server state |
|
|
338
|
+
| 9 | transport_error | network or TLS failure |
|
|
339
|
+
|
|
340
|
+
Exit codes are stable across minor versions. The `error.code` string in the
|
|
341
|
+
JSON envelope mirrors these names.
|
|
342
|
+
|
|
252
343
|
## Documentation
|
|
253
344
|
|
|
254
345
|
Documentation for the DataMasque product,
|
|
@@ -9,6 +9,7 @@ so teams can use production-shaped data in non-production environments without e
|
|
|
9
9
|
DataMasque CLI `dm` covers:
|
|
10
10
|
|
|
11
11
|
- connections, rulesets, ruleset libraries, and masking runs
|
|
12
|
+
- in-flight masking (IFM) ruleset plans and on-demand mask requests
|
|
12
13
|
- schema discovery and sensitive-data discovery
|
|
13
14
|
- users, files, and DataMasque instance administration
|
|
14
15
|
|
|
@@ -59,6 +60,26 @@ dm run logs 42 --follow
|
|
|
59
60
|
`dm run start` and `dm run wait` block until the run finishes.
|
|
60
61
|
Pass `--background` to `start` to skip the wait.
|
|
61
62
|
|
|
63
|
+
## Claude Code skills
|
|
64
|
+
|
|
65
|
+
The [`claude-skills/`](claude-skills/) directory ships three
|
|
66
|
+
[Claude Code](https://claude.com/claude-code) plugins that drive `dm` on your behalf:
|
|
67
|
+
|
|
68
|
+
- **`datamasque-cli`** — operate a DataMasque instance (start runs, list connections, fetch discovery reports).
|
|
69
|
+
- **`ruleset-builder`** — turn auto-generated rulesets into production-ready ones.
|
|
70
|
+
- **`ruleset-splitter`** — join many-file rulesets into one file for editing, then re-split.
|
|
71
|
+
|
|
72
|
+
Install via the Claude Code plugin marketplace:
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
/plugin marketplace add datamasque/datamasque-cli
|
|
76
|
+
/plugin install datamasque-cli@datamasque-tools
|
|
77
|
+
/plugin install ruleset-builder@datamasque-tools
|
|
78
|
+
/plugin install ruleset-splitter@datamasque-tools
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
See [`claude-skills/README.md`](claude-skills/README.md) for more.
|
|
82
|
+
|
|
62
83
|
## Shell completion
|
|
63
84
|
|
|
64
85
|
`dm` provides built-in completion for bash, zsh, and fish:
|
|
@@ -146,6 +167,26 @@ dm libraries validate <name> # Re-validate against current
|
|
|
146
167
|
dm libraries usage <name> # Show rulesets using it
|
|
147
168
|
```
|
|
148
169
|
|
|
170
|
+
### In-flight masking
|
|
171
|
+
|
|
172
|
+
The IFM service runs alongside the admin server,
|
|
173
|
+
reached at `<DataMasque URL>/ifm` via the standard nginx topology.
|
|
174
|
+
|
|
175
|
+
```console
|
|
176
|
+
dm ifm list # List ruleset plans
|
|
177
|
+
dm ifm get <name> # Show plan metadata
|
|
178
|
+
dm ifm get <name> --yaml # Print the ruleset YAML
|
|
179
|
+
dm ifm create --name myplan --file rules.yaml # Create (server suffixes a random string to the name)
|
|
180
|
+
dm ifm create --name myplan --file rules.yaml --disabled --log-level DEBUG
|
|
181
|
+
dm ifm update <name> --file rules.yaml # Replace the ruleset YAML
|
|
182
|
+
dm ifm update <name> --enabled # Toggle without re-sending the YAML
|
|
183
|
+
dm ifm update <name> --log-level INFO
|
|
184
|
+
dm ifm delete <name> --yes # Delete a plan
|
|
185
|
+
dm ifm mask <name> --data input.json # Mask a JSON list of records
|
|
186
|
+
dm ifm mask <name> --data - # Read records from stdin
|
|
187
|
+
dm ifm verify-token # Show scopes granted to the current IFM token
|
|
188
|
+
```
|
|
189
|
+
|
|
149
190
|
### Masking runs
|
|
150
191
|
|
|
151
192
|
```console
|
|
@@ -219,6 +260,56 @@ STATUS=$(dm run status 42 --json | jq -r '.status')
|
|
|
219
260
|
dm rulesets get myruleset --json | jq -r '.yaml' > ruleset.yaml
|
|
220
261
|
```
|
|
221
262
|
|
|
263
|
+
JSON is also emitted automatically when:
|
|
264
|
+
|
|
265
|
+
- `stdout` is not a TTY (piped or captured),
|
|
266
|
+
- `DM_OUTPUT=json` is set in the environment, or
|
|
267
|
+
- a vendor-neutral `AI_AGENT` env var is set (e.g. by Claude Code).
|
|
268
|
+
|
|
269
|
+
Set `DM_OUTPUT=table` to force human-readable output regardless of context.
|
|
270
|
+
|
|
271
|
+
## Agent / scripting interface
|
|
272
|
+
|
|
273
|
+
For programmatic use (CI, AI coding agents, shell scripts), the CLI exposes
|
|
274
|
+
a discovery command and a stable error contract.
|
|
275
|
+
|
|
276
|
+
### Command catalog
|
|
277
|
+
|
|
278
|
+
`dm catalog` dumps every visible subcommand as JSON so an agent can introspect
|
|
279
|
+
the surface without paging through `--help` screens:
|
|
280
|
+
|
|
281
|
+
```console
|
|
282
|
+
dm catalog --compact # ~1.4kB — {path, help} per command
|
|
283
|
+
dm catalog # full — also includes options and arguments
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Structured errors
|
|
287
|
+
|
|
288
|
+
In agent mode, errors are emitted as a JSON envelope on stderr (stdout stays
|
|
289
|
+
empty on failure):
|
|
290
|
+
|
|
291
|
+
```json
|
|
292
|
+
{"error": {"code": "not_found", "message": "Connection 'foo' not found.", "hint": "Run dm connections list."}}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Exit codes
|
|
296
|
+
|
|
297
|
+
| Code | Meaning | When |
|
|
298
|
+
| ---: | ----------------- | ---------------------------------------------- |
|
|
299
|
+
| 0 | success | command completed |
|
|
300
|
+
| 1 | error | unclassified failure |
|
|
301
|
+
| 2 | usage error | unknown flag or missing argument (typer/click) |
|
|
302
|
+
| 3 | not_found | resource lookup failed |
|
|
303
|
+
| 4 | invalid_input | argument values rejected |
|
|
304
|
+
| 5 | ambiguous | name matched multiple resources |
|
|
305
|
+
| 6 | auth_required | no credentials configured |
|
|
306
|
+
| 7 | auth_failed | credentials rejected by server |
|
|
307
|
+
| 8 | conflict | operation rejected by server state |
|
|
308
|
+
| 9 | transport_error | network or TLS failure |
|
|
309
|
+
|
|
310
|
+
Exit codes are stable across minor versions. The `error.code` string in the
|
|
311
|
+
JSON envelope mirrors these names.
|
|
312
|
+
|
|
222
313
|
## Documentation
|
|
223
314
|
|
|
224
315
|
Documentation for the DataMasque product,
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Claude Code skills
|
|
2
|
+
|
|
3
|
+
- **`datamasque-cli/`** —
|
|
4
|
+
teaches Claude how to operate a DataMasque instance with `dm`:
|
|
5
|
+
- authenticate,
|
|
6
|
+
- list connections,
|
|
7
|
+
- start runs,
|
|
8
|
+
- fetch discovery reports.
|
|
9
|
+
- **`ruleset-builder/`** —
|
|
10
|
+
turns auto-generated rulesets into production-ready ones:
|
|
11
|
+
- extracts a `ruleset_library`,
|
|
12
|
+
- adds `hash_columns`,
|
|
13
|
+
- applies `skip_defaults`,
|
|
14
|
+
- validates.
|
|
15
|
+
- **`ruleset-splitter/`** —
|
|
16
|
+
joins DataMasque's many-file generated rulesets into one file for editing, then re-splits back to the original filenames.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
In [Claude Code](https://claude.com/claude-code), add this repo as a plugin marketplace and install the plugins you want:
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
/plugin marketplace add datamasque/datamasque-cli
|
|
24
|
+
/plugin install datamasque-cli@datamasque-tools
|
|
25
|
+
/plugin install ruleset-builder@datamasque-tools
|
|
26
|
+
/plugin install ruleset-splitter@datamasque-tools
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Uninstall
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
/plugin uninstall datamasque-cli@datamasque-tools
|
|
33
|
+
/plugin uninstall ruleset-builder@datamasque-tools
|
|
34
|
+
/plugin uninstall ruleset-splitter@datamasque-tools
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Working on these skills locally
|
|
38
|
+
|
|
39
|
+
If you're editing these skills in-repo and want Claude Code to pick up changes without reinstalling, symlink each directory into `~/.claude/skills/`:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
ln -sfn ~/repos/datamasque-cli/claude-skills/datamasque-cli/skills/datamasque-cli \
|
|
43
|
+
~/.claude/skills/datamasque-cli
|
|
44
|
+
|
|
45
|
+
ln -sfn ~/repos/datamasque-cli/claude-skills/ruleset-builder/skills/ruleset-builder \
|
|
46
|
+
~/.claude/skills/ruleset-builder
|
|
47
|
+
|
|
48
|
+
ln -sfn ~/repos/datamasque-cli/claude-skills/ruleset-splitter/skills/ruleset-splitter \
|
|
49
|
+
~/.claude/skills/ruleset-splitter
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Reload inside Claude Code (`/reload-plugins` or start a new session). Edits to any `SKILL.md` go live on the next reload — no reinstall.
|
|
53
|
+
|
|
54
|
+
Remove the symlinks when done:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
rm ~/.claude/skills/datamasque-cli
|
|
58
|
+
rm ~/.claude/skills/ruleset-builder
|
|
59
|
+
rm ~/.claude/skills/ruleset-splitter
|
|
60
|
+
```
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "datamasque-cli",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "DataMasque command-line interface integration. Drive DataMasque from Claude Code: list connections, kick off runs, stream logs, download reports.",
|
|
5
|
+
"author": { "name": "DataMasque Ltd" },
|
|
6
|
+
"repository": "https://github.com/datamasque/datamasque-cli",
|
|
7
|
+
"license": "Apache-2.0",
|
|
8
|
+
"keywords": ["datamasque", "data-masking", "cli"]
|
|
9
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: datamasque-cli
|
|
3
|
+
description: Use when the user wants to interact with a DataMasque instance — start masking runs, check run status, list connections or rulesets, manage seeds, manage ruleset libraries, check system health, or any task involving the DataMasque API. Triggers on "mask the data", "start a run", "check the run", "list connections", "list rulesets", "upload a seed", "check DataMasque health", "dm status", "ruleset library", or any request to operate DataMasque programmatically.
|
|
4
|
+
argument-hint: e.g. "start a run with docx_masking on var_input_docx"
|
|
5
|
+
user-invocable: true
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# DataMasque CLI
|
|
9
|
+
|
|
10
|
+
Operate a DataMasque instance via the `dm` command-line tool.
|
|
11
|
+
|
|
12
|
+
Run `dm catalog --compact` for a JSON list of every subcommand. The sections
|
|
13
|
+
below cover idioms the catalog can't show you.
|
|
14
|
+
|
|
15
|
+
## Output and errors
|
|
16
|
+
|
|
17
|
+
In agent mode — auto-detected when stdout is not a TTY, `AI_AGENT` is set, or
|
|
18
|
+
`DM_OUTPUT=json` — output is JSON on stdout, errors are JSON on stderr:
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{"error": {"code": "not_found", "message": "...", "hint": "..."}}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`error.code` is the stable identifier; branch on it rather than the message.
|
|
25
|
+
The set is `not_found`, `invalid_input`, `ambiguous`, `auth_required`,
|
|
26
|
+
`auth_failed`, `conflict`, `transport_error`, `error`. Exit code is non-zero
|
|
27
|
+
on any error; exit 2 specifically means a CLI usage error (unknown flag,
|
|
28
|
+
missing argument) from typer.
|
|
29
|
+
|
|
30
|
+
`DM_OUTPUT=table` forces human-readable output.
|
|
31
|
+
|
|
32
|
+
## Authentication
|
|
33
|
+
|
|
34
|
+
Set `DATAMASQUE_URL`, `DATAMASQUE_USERNAME`, `DATAMASQUE_PASSWORD` to auth
|
|
35
|
+
without saving anything (right choice for CI / one-offs). For interactive
|
|
36
|
+
use, `dm auth login --profile <name>` prompts and persists to
|
|
37
|
+
`~/.config/datamasque-cli/config.toml`. `--insecure` (on login) or
|
|
38
|
+
`DATAMASQUE_VERIFY_SSL=false` (per call) skip TLS verification.
|
|
39
|
+
|
|
40
|
+
## Quick start: a masking run
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
dm connections list # find a source
|
|
44
|
+
dm rulesets list # find a ruleset
|
|
45
|
+
dm run start -c <source> -r <ruleset> [-d <dest>] # blocks until done
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Add `--background` to return immediately with the run id, then poll with
|
|
49
|
+
`dm run wait <id>`, `dm run status <id>`, or `dm run logs <id> --follow`.
|
|
50
|
+
Pass repeated `--options key=value` for server-side knobs
|
|
51
|
+
(e.g. `--options batch_size=1000 --options dry_run=true`).
|
|
52
|
+
|
|
53
|
+
## Idioms and gotchas
|
|
54
|
+
|
|
55
|
+
- **Ruleset namespaces.** `database` and `file` rulesets share a name
|
|
56
|
+
namespace, so `customers` can exist in both. `dm run start` reads the
|
|
57
|
+
source connection's type and picks the matching ruleset automatically.
|
|
58
|
+
For `get` / `create` / `delete`, pass `--type file|database` only when
|
|
59
|
+
two rows share the name and you need to disambiguate.
|
|
60
|
+
|
|
61
|
+
- **File masking needs a destination.** Database masking is in-place;
|
|
62
|
+
file masking writes through to a destination connection and fails
|
|
63
|
+
with `invalid_input` without `--destination`.
|
|
64
|
+
|
|
65
|
+
- **`dm run start` blocks by default.** No flag needed for "wait then
|
|
66
|
+
return"; use `--background` only when you genuinely want fire-and-forget.
|
|
67
|
+
|
|
68
|
+
- **`dm run report` is file-masking-only.** The CSV is one row per file
|
|
69
|
+
the worker considered, with `path`, `file_size`, `file_type`, and
|
|
70
|
+
`skip_reason` (e.g. "File archived with Glacier", "File type unsupported
|
|
71
|
+
by data discovery", "Matched a skip filter"). Database runs don't
|
|
72
|
+
produce a report — `not_found` is expected for them, and for any run
|
|
73
|
+
that hasn't reached a terminal state yet.
|
|
74
|
+
|
|
75
|
+
- **`dm libraries delete` refuses to delete libraries imported by a
|
|
76
|
+
ruleset.** Run `dm libraries usage <name>` first to see what depends on
|
|
77
|
+
it; pass `--force` only after you've made an informed decision.
|
|
78
|
+
|
|
79
|
+
- **`dm connections update` preserves the UUID.** Use it to rotate
|
|
80
|
+
passwords or change hosts without invalidating the rulesets and runs
|
|
81
|
+
that already reference the connection.
|
|
82
|
+
|
|
83
|
+
- **`dm rulesets create` is also "update"** — it reads the existing
|
|
84
|
+
`mask_type` from the server, so you only need `--type` for brand-new
|
|
85
|
+
rulesets or to disambiguate a same-name update.
|
|
86
|
+
|
|
87
|
+
- **Discovery is a kind of run.** `dm discover schema <connection>` kicks
|
|
88
|
+
off a discovery run and returns a run id. Poll with `dm run status <id>`,
|
|
89
|
+
then fetch results with `dm discover schema-results <id>` /
|
|
90
|
+
`sdd-report` / `db-report` / `file-report`.
|
|
91
|
+
|
|
92
|
+
- **`dm rulesets validate --file <file> --type <type>`** runs server-side
|
|
93
|
+
validation without committing the ruleset. Use this before `create`
|
|
94
|
+
when you want a clean failure mode for bad YAML.
|
|
95
|
+
|
|
96
|
+
- **"Build a ruleset" usually means the `ruleset-builder` skill, not
|
|
97
|
+
`dm rulesets generate`.** `generate` is server-side scaffolding from a
|
|
98
|
+
JSON generation request. The `ruleset-builder` skill (separate skill in
|
|
99
|
+
this repo) handles the production-quality workflow — hash columns,
|
|
100
|
+
library extraction, refinement — which is what users typically want.
|
|
101
|
+
|
|
102
|
+
- **Names or UUIDs, either works.** `dm connections get <x>`,
|
|
103
|
+
`dm run start -c <x>`, `dm discover schema <x>`, etc. all try the name
|
|
104
|
+
first and fall back to a UUID match. Prefer names for readability;
|
|
105
|
+
reach for UUIDs only when names collide (rare).
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ruleset-builder",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Convert auto-generated DataMasque rulesets into production-ready form. Validate and iterate.",
|
|
5
|
+
"author": { "name": "DataMasque Ltd" },
|
|
6
|
+
"repository": "https://github.com/datamasque/datamasque-cli",
|
|
7
|
+
"license": "Apache-2.0",
|
|
8
|
+
"keywords": ["datamasque", "ruleset", "yaml"]
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ruleset-splitter",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Consolidate multi-file DataMasque rulesets for editing, then re-split them back out.",
|
|
5
|
+
"author": { "name": "DataMasque Ltd" },
|
|
6
|
+
"repository": "https://github.com/datamasque/datamasque-cli",
|
|
7
|
+
"license": "Apache-2.0",
|
|
8
|
+
"keywords": ["datamasque", "ruleset", "yaml"]
|
|
9
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "datamasque-cli"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.2.0"
|
|
4
4
|
description = "Official command-line interface for the DataMasque data-masking platform."
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "DataMasque Ltd" },
|
|
@@ -99,6 +99,8 @@ ignore = [
|
|
|
99
99
|
"S",
|
|
100
100
|
"SLF001",
|
|
101
101
|
]
|
|
102
|
+
# Standalone helper scripts that legitimately print to stdout for shell consumption.
|
|
103
|
+
"scripts/**/*" = ["T20"]
|
|
102
104
|
|
|
103
105
|
[tool.ruff.lint.isort]
|
|
104
106
|
known-first-party = ["datamasque_cli"]
|
|
@@ -19,7 +19,8 @@ except ImportError:
|
|
|
19
19
|
path = os.path.expanduser("~/.config/datamasque-cli/config.toml")
|
|
20
20
|
|
|
21
21
|
try:
|
|
22
|
-
|
|
22
|
+
with open(path, "rb") as f:
|
|
23
|
+
data = tomllib.load(f)
|
|
23
24
|
except FileNotFoundError:
|
|
24
25
|
sys.exit(f"No profile config at {path}. Run 'dm auth login' first.")
|
|
25
26
|
|