Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
# Changelog

## v1.5.0

### Added
- Support for datamasque-python 1.2.2.
- `dm discover schema-results` handles matches with no label.
- `dm rulesets validate` and `dm libraries validate` print validation
errors for invalid YAML.
- Support for Configurable Discovery:
- `dm discover configs` — list, get, defaults, create, delete, validate,
and status for discovery configs (`database` or `file`).
- `dm discover libraries` — list, get, create, delete, validate, and status
for discovery config libraries (untyped; shared by both config types).
- `dm discover schema --config <name>` and `dm discover file
[--config <name>]` start discovery runs with or without a specific config.
- `dm discover config-snapshot <run-id>` downloads the discovery config a run
actually used.
- `dm rulesets status` and `dm libraries status` — show a stored ruleset's or
library's validation state and errors.
- `dm rulesets validate` and `dm discover configs validate` refuse YAML of
60 KiB or larger, which the server validates asynchronously; create it and
poll `status` instead.
- Safe Data Preview: `dm discover schema-results` and `dm discover file-report`
include `safe_data_preview` in their `--json` output.
- `dm rulesets generate`, `dm connections update --password`, and the
deprecated `dm system import` no longer fail.

## v1.4.0

### Added
Expand Down
45 changes: 39 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ dm rulesets create --name <n> --file rules.yaml --type file # Force a type
dm rulesets delete <name> [--type file|database] # Delete a ruleset
dm rulesets generate --file request.json # Generate from schema
dm rulesets generate --file req.json -o out.yaml # Generate to file
dm rulesets validate --file rules.yaml # Validate against server
dm rulesets validate --file rules.yaml # Validate against server (YAML under 60 KiB)
dm rulesets status <name> # Validation status; poll after creating YAML of 60 KiB+
dm rulesets export-bundle -o bundle.zip # Export rulesets + libraries + seeds
dm rulesets import-bundle --file bundle.zip # Import a previously exported bundle
dm rulesets import-bundle -f bundle.zip --overwrite-rulesets --overwrite-libraries # Replace existing entries
Expand All @@ -164,6 +165,7 @@ dm libraries create --name <n> --file lib.yaml # Create/update from file
dm libraries create --name <n> --file lib.yaml --namespace pii # With namespace
dm libraries delete <name> # Delete a library
dm libraries validate <name> # Re-validate against current server schema
dm libraries status <name> # Validation status; poll after creating YAML of 60 KiB+
dm libraries usage <name> # Show rulesets using it
```

Expand Down Expand Up @@ -216,11 +218,42 @@ dm users delete <username> # Delete a user
### Discovery

```console
dm discover schema <connection> # Start a schema-discovery run
dm discover schema-results <run-id> # List schema-discovery results once the run finishes
dm discover sdd-report <run-id> # Sensitive data discovery report
dm discover db-report <run-id> # Database discovery CSV
dm discover file-report <run-id> # File discovery report
dm discover schema <connection> # Schema discovery (built-in keyword-driven)
dm discover schema <connection> --config <name> # Schema discovery from a saved database config
dm discover schema <connection> --json # {"id": <run-id>, "status": "queued"}
dm discover schema-results <run-id> # List schema-discovery results once the run finishes
dm discover file <connection> # File data discovery (built-in keyword-driven)
dm discover file <connection> --config <name> # File data discovery from a saved file config
dm discover file <connection> --json # {"id": <run-id>, "status": "queued"}
dm discover sdd-report <run-id> # Sensitive data discovery report
dm discover db-report <run-id> # Database discovery CSV
dm discover file-report <run-id> # File discovery report
dm discover config-snapshot <run-id> -o used.yaml # Download the discovery config a run actually used
```

#### Discovery configs

```console
dm discover configs list [--type database|file] # List configs
dm discover configs get <name> [--type database] [--yaml] # Show details or raw YAML
dm discover configs defaults [--type database|file] -o cfg.yaml # Built-in default as a starting point
dm discover configs create --name <n> --type database -f cfg.yaml # Create/update from YAML
dm discover configs delete <name> [--type database] # Delete a config
dm discover configs validate -f cfg.yaml --type database # Validate against server (YAML under 60 KiB)
dm discover configs status <name> [--type database] # Validation status; poll after creating YAML of 60 KiB+
```

#### Discovery config libraries

Libraries are untyped — the same library can be imported by both database and file discovery configs.

```console
dm discover libraries list
dm discover libraries get <name> [--namespace org] [--yaml]
dm discover libraries create --name <n> --namespace org -f lib.yaml
dm discover libraries delete <name> [--namespace org] [--force] # --force if imported by configs
dm discover libraries validate -f lib.yaml
dm discover libraries status <name> [--namespace org]
```

### Seeds
Expand Down
8 changes: 8 additions & 0 deletions claude-skills/datamasque-cli/skills/datamasque-cli/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,14 @@ Pass repeated `--options key=value` for server-side knobs
then fetch results with `dm discover schema-results <id>` /
`sdd-report` / `db-report` / `file-report`.

- **Configurable discovery and Safe Data Preview.** Save a discovery config
with `dm discover configs create` (start from `dm discover configs defaults`),
then run `dm discover schema <connection> --config <name>`. When the config
enables in-data discovery with safe data preview, `dm discover schema-results
<id> --json` carries a `safe_data_preview` per column — value distributions,
patterns, and cardinality worth reading before choosing masks. It is JSON-only;
`file-report --json` exposes the same per locator.

- **`dm rulesets validate --file <file> --type <type>`** runs server-side
validation without committing the ruleset. Use this before `create`
when you want a clean failure mode for bad YAML.
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ requires-python = ">=3.11"
dependencies = [
"typer>=0.15.0",
"tomli-w>=1.0.0",
"datamasque-python>=1.0.0,<2",
"datamasque-python>=1.2.2,<2",
]
classifiers = [
"Development Status :: 4 - Beta",
Expand Down
21 changes: 18 additions & 3 deletions src/datamasque_cli/commands/connections.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import typer
from datamasque.client import DataMasqueClient
from datamasque.client.exceptions import DataMasqueApiError
from datamasque.client.models.connection import (
AzureConnectionConfig,
ConnectionConfig,
Expand All @@ -22,7 +23,14 @@
)

from datamasque_cli.client import get_client
from datamasque_cli.output import ErrorCode, abort, print_success, redact_sensitive_fields, render_output
from datamasque_cli.output import (
ErrorCode,
abort,
abort_api_error,
print_success,
redact_sensitive_fields,
render_output,
)


class ConnectionType(StrEnum):
Expand Down Expand Up @@ -298,7 +306,10 @@ def test_connection(
if match is None:
abort(f"Connection '{name}' not found.", code=ErrorCode.NOT_FOUND)

response = client.make_request("POST", f"/api/connections/{match.id}/test/", data={})
try:
response = client.make_request("POST", f"/api/connections/{match.id}/test/", data={})
except DataMasqueApiError as exc:
abort_api_error(f"Connection '{match.name}' is not reachable", exc)
body = response.json() if response.content else {}
warning = body.get("message") if isinstance(body, dict) else None

Expand Down Expand Up @@ -347,7 +358,11 @@ def update_connection(
if not updates:
abort("Pass at least one field to update (e.g. --password, --host).", code=ErrorCode.INVALID_INPUT)

client.make_request("PATCH", f"/api/connections/{match.id}/", data=updates)
payload = dict(updates)
if "password" in payload:
payload["dbpassword"] = payload.pop("password")

client.make_request("PATCH", f"/api/connections/{match.id}/", data=payload)
print_success(f"Connection '{match.name}' updated: {', '.join(updates)}.")


Expand Down
Loading
Loading