Skip to content
Merged
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
2 changes: 1 addition & 1 deletion otdfctl/docs/man/migrate/namespaced-policy.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Commit mode can partially apply changes before an error occurs. When that happen

The parent `migrate` command provides the shared `--commit` and `--interactive` flags.

`namespaced-policy` is intended to be non-destructive. Commit should create namespaced copies and record migration metadata, but it should not delete legacy objects. Cleanup belongs to `migrate prune`.
`namespaced-policy` is intended to be non-destructive. Commit should create namespaced copies and record migration metadata, but it should not delete legacy objects. Cleanup belongs to `migrate prune namespaced-policy`.

All target namespaces must already exist before the command runs. Planning should fail before any writes if a required namespace is missing.

Expand Down
11 changes: 1 addition & 10 deletions otdfctl/docs/man/migrate/prune/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,8 @@ command:

`prune` groups commands used to remove policy resources that are no longer needed after migration or cleanup workflows.

The end-to-end cleanup workflow is not implemented yet, but the command surface is in place.

Available subcommands currently include `namespaced-policy` for policy cleanup workflows.

The parent `migrate` command provides the shared `--commit` flag used to apply deletions.
The parent `migrate` command provides the shared `--commit` and `--interactive` flags. `--interactive` lets you review prune plans before execution, and when paired with `--commit` it also adds confirmation before deletions are applied.

`migrate prune` is not the same as `otdfctl policy subject-condition-sets prune`. The existing subject-condition-set prune command deletes unmapped subject condition sets. `migrate prune` is only for cleaning up legacy objects after a migration run.

## Planned examples

```shell
otdfctl migrate prune namespaced-policy --scope=registered-resources
otdfctl migrate prune namespaced-policy --scope=actions,subject-mappings,registered-resources --commit
```
56 changes: 50 additions & 6 deletions otdfctl/docs/man/migrate/prune/namespaced-policy.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,67 @@ command:
flags:
- name: scope
shorthand: s
description: "Comma-separated scopes: actions, subject-condition-sets, subject-mappings, registered-resources, obligation-triggers"
description: "One scope to prune: actions, subject-condition-sets, subject-mappings, registered-resources, obligation-triggers"
default: ''
---

## General Information

`namespaced-policy` is the cleanup entrypoint for namespaced policy migration.

The command surface is present, but the cleanup workflow is not implemented yet.
The command prints a human-readable prune summary to stdout. Dry runs show the planned deletions and blocked items; `--commit` shows the committed summary with the objects that were deleted.

`--scope` is required and must be exactly one of `actions`, `subject-condition-sets`, `subject-mappings`, `registered-resources`, or `obligation-triggers`.

`namespaced-policy` rebuilds the live dependency graph, inspects migration labels, and deletes only legacy objects it can prove are safe to remove for the selected scope.

The parent `migrate` command provides the shared `--commit` and `--interactive` flags. `--interactive` lets you review the prune plan before execution, and when paired with `--commit` it also asks for backup confirmation and per-delete confirmation before any deletion is applied.

## Pre-requisites

1. Run at least `v0.14.0` of the OpenTDF platform before using this prune flow.

2. Run `otdfctl migrate namespaced-policy` successfully before pruning. Prune only deletes legacy objects after it can match them to the expected migrated targets and their `migrated_from` labels.

## Delete safety

An object is safe to delete only when prune can tie the legacy source object to the expected migrated target and prove the source is no longer needed.

`--scope` is required and selects any subset of `actions`, `subject-condition-sets`, `subject-mappings`, `registered-resources`, and `obligation-triggers`.
- `delete`: the source has the expected migrated target and prune found no remaining legacy dependency that still requires the source object.
- `blocked`: prune will not delete the source. Common reasons are that the source is still referenced by legacy policy or that the source object has not actually been migrated yet.
- `unresolved`: prune found something close to a migrated target, but it cannot prove the source and target match safely. Common reasons are missing or mismatched `migrated_from` labels, no matching labeled target, or a registered resource source that still contains values outside the resolved migration view.

`namespaced-policy` rebuilds the live dependency graph, inspects migration labels, and deletes only legacy objects it can prove are safe to remove for the selected scopes. It does not require a manifest file.
In practice, prune relies on current legacy references plus `migrated_from` metadata on the namespaced targets. If that evidence is incomplete or inconsistent, the object is left in place instead of being deleted.

The parent `migrate` command provides the shared `--commit` flag used to apply deletions.
## Best practices

1. Before running any prune commands you should take a backup of your database to avoid any potential issues.

2. Turn on the `namespaced_policy` feature flag within your deployed service yaml to avoid creating any accidental non-namespaced policy objects.

3. Prune one scope at a time.

4. We recommend pruning in the reverse order of migration so dependents are removed before their dependencies:
- Registered-Resources
- Obligation-Triggers
- Subject-Mappings
- Subject-Condition-Sets
- Actions

## Examples

```shell
otdfctl migrate prune namespaced-policy --scope=registered-resources
otdfctl migrate prune namespaced-policy --scope=actions,subject-mappings,registered-resources --commit
otdfctl migrate prune namespaced-policy --scope=obligation-triggers --commit
otdfctl migrate prune namespaced-policy --scope=obligation-triggers --interactive --commit
Comment thread
coderabbitai[bot] marked this conversation as resolved.
```

## Other Information

1. Action / Subject-Condition-Set pruning

1a. Actions and subject-condition-sets are pruned a little differently from the other scopes. Instead of reusing the resolved migration view, prune classifies them directly from the current legacy objects, their current legacy references, and the canonical migrated targets it can find.

1b. We do that because actions and subject-condition-sets are expected to be pruned last. By the time you reach those scopes, their legacy dependents such as subject mappings, registered resources, and obligation triggers should already be gone, so the safest decision comes from checking the live legacy dependency graph at prune time. That also means some actions or subject-condition-sets that were never used by any other legacy policy object can still end up `blocked`.

1c. If prune cannot find a canonical migrated target for the source object, it leaves the source in place as `blocked` instead of assuming it is safe to delete. For example, if a custom action `decrypt` is no longer referenced by any legacy subject mapping, registered resource, or obligation trigger and prune finds a namespaced `decrypt` target with `metadata.labels.migrated_from=<legacy-action-id>`, the source action is safe to delete. If no canonical namespaced `decrypt` target exists, the source action is reported as `blocked` because prune cannot prove that the object was actually migrated.
Loading
Loading