Repository navigation
feat(policy): rollback migration strategy for namespaced actions #3235
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 4 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
c3eb502
migrate existing namespaces with standard actions
elizabethhealy 98c8122
Merge branch 'main' into dspx-2540-migrate-standard-actions-when-enabled
elizabethhealy 0670a40
no-op
elizabethhealy 35cb33c
rollback strategy for namespaced actions
elizabethhealy 4cdd3e5
comment for commands to run if you want to know exactly what changed
elizabethhealy b347082
Merge branch 'main' into dsxp-2540-custom-down-actions-migration
elizabethhealy 0b5ecb6
add test for new downgrade
elizabethhealy 2b3f117
coderabbit suggestions
elizabethhealy 47ec7af
coderabbit suggestion
elizabethhealy File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
45 changes: 45 additions & 0 deletions
45
service/policy/db/migrations/20260312000000_add_namespace_to_actions.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| # Add Namespace to Actions | ||
|
|
||
| This migration introduces namespace-scoped actions by adding `namespace_id` to `actions` and updating uniqueness semantics. | ||
|
|
||
| ## Why | ||
|
|
||
| Policy objects are namespaced, and action references need to support same-namespace resolution. This migration enables actions to be scoped per namespace while preserving legacy/global actions. | ||
|
|
||
| ## Up Migration | ||
|
|
||
| The Up migration: | ||
|
|
||
| - Adds nullable `namespace_id` to `actions` (`REFERENCES attribute_namespaces(id) ON DELETE CASCADE`). | ||
| - Replaces global `UNIQUE(name)` with two partial uniqueness constraints: | ||
| - `UNIQUE(namespace_id, name)` when `namespace_id IS NOT NULL` (namespaced actions) | ||
| - `UNIQUE(name)` when `namespace_id IS NULL` (legacy/global actions) | ||
| - Adds `idx_actions_namespace_id` for namespaced lookup performance. | ||
|
|
||
| ## Down Migration | ||
|
|
||
| The Down migration is data-aware and performs a deterministic canonicalization before restoring global-only action semantics. | ||
|
|
||
| Steps: | ||
|
|
||
| 1. Build an action-id remap (`old_action_id -> canonical_action_id`) by action name. | ||
| 2. Canonical action selection order per name is: | ||
| - prefer global (`namespace_id IS NULL`) | ||
| - then earliest `created_at` | ||
| - then smallest `id` | ||
| 3. Remap and deduplicate references in: | ||
| - `subject_mapping_actions` | ||
| - `registered_resource_action_attribute_values` | ||
| - `obligation_triggers` | ||
| 4. Delete duplicate (non-canonical) action rows. | ||
| 5. Drop namespace indexes, restore global `UNIQUE(name)`, and drop `namespace_id`. | ||
|
|
||
| ## Rollback Semantics | ||
|
|
||
| Rollback is intentionally **lossy** with respect to namespace-level action identity. | ||
|
|
||
| - Actions sharing the same `name` are collapsed to one canonical global action row. | ||
| - Referencing rows are rewritten to canonical action ids. | ||
| - Distinct namespace-scoped action ids for the same name are not preserved after rollback. | ||
|
|
||
| This behavior is required to safely re-establish global `UNIQUE(name)` without orphaning references. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 29 additions & 0 deletions
29
...y/db/migrations/20260331000000_seed_standard_actions_for_existing_namespaces.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| # Seed Standard Actions for Existing Namespaces | ||
|
|
||
| This migration retroactively seeds the four standard actions (create, read, update, delete) into all namespaces that already exist. | ||
|
|
||
| ## Why | ||
|
|
||
| When a namespace is created, `CreateNamespace()` automatically calls `seedStandardActionsForNamespace()` to insert the standard CRUD actions scoped to that namespace. However, namespaces created before action namespacing was introduced (`20260312000000_add_namespace_to_actions.sql`) do not have namespace-scoped standard actions — they only have the legacy global standard actions. | ||
|
|
||
| The otdfctl policy migration tooling requires that every namespace already has standard actions before migrating existing unnamespaced policy (SMs, SCSs, RRs) into namespaces. Without this seed, migrated policy referencing standard actions would have no same-namespace action to rewrite references to. | ||
|
|
||
| ## Changes | ||
|
|
||
| A single idempotent `INSERT ... ON CONFLICT DO NOTHING` that cross-joins all existing namespaces with the four standard action names and inserts any missing rows into the `actions` table. | ||
|
|
||
| ## Resulting Behavior | ||
|
|
||
| - Every existing namespace will have namespace-scoped standard actions (create, read, update, delete) with `is_standard = TRUE`. | ||
| - New namespaces continue to receive standard actions via `CreateNamespace()` as before. | ||
| - Running this migration on a system where some or all namespaces already have standard actions is safe — conflicts are silently ignored. | ||
|
|
||
| ## Rollback | ||
|
|
||
| The Down migration is intentionally a no-op. Namespace-scoped standard actions are required for namespace correctness and policy reference rewrites; deleting them on rollback could break existing namespaces. | ||
|
|
||
| ## Operational Rollback Note | ||
|
|
||
| Rolling back past `20260312000000_add_namespace_to_actions.sql` now performs an automatic action-id canonicalization and reference remap by action name before restoring global `UNIQUE(name)` semantics. This allows namespace-scoped duplicates (including standard actions) to be merged safely for rollback. | ||
|
|
||
| This rollback remains intentionally lossy with respect to namespace-level action identity: actions sharing the same name are collapsed to one global action id, and policy references are rewritten to that canonical action. |
23 changes: 23 additions & 0 deletions
23
...ice/policy/db/migrations/20260331000000_seed_standard_actions_for_existing_namespaces.sql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| -- +goose Up | ||
| -- +goose StatementBegin | ||
|
|
||
| -- Seed standard actions (create, read, update, delete) into all existing namespaces. | ||
| -- New namespaces already receive standard actions automatically via CreateNamespace(). | ||
| -- This migration retroactively seeds them for namespaces created before action namespacing was introduced. | ||
| -- ON CONFLICT DO NOTHING makes this idempotent. | ||
| INSERT INTO actions (name, is_standard, namespace_id) | ||
| SELECT a.name, TRUE, ns.id | ||
| FROM attribute_namespaces ns | ||
| CROSS JOIN (VALUES ('create'), ('read'), ('update'), ('delete')) AS a(name) | ||
| ON CONFLICT (namespace_id, name) WHERE namespace_id IS NOT NULL DO NOTHING; | ||
|
|
||
| -- +goose StatementEnd | ||
|
|
||
| -- +goose Down | ||
| -- +goose StatementBegin | ||
|
|
||
| -- No-op: namespace-scoped standard actions are required for namespace policy | ||
| -- evaluation and reference rewrites. Removing them can break existing namespaces. | ||
| SELECT 1; | ||
|
|
||
| -- +goose StatementEnd |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.