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
33 changes: 33 additions & 0 deletions otdfctl/migrations/namespacedpolicy/plan_utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package namespacedpolicy

import (
"strings"

"github.com/opentdf/platform/protocol/go/policy"
)

func objectIDSet[T interface{ GetId() string }](items []T) map[string]struct{} {
ids := make(map[string]struct{}, len(items))
for _, item := range items {
if id := item.GetId(); id != "" {
ids[id] = struct{}{}
}
}
return ids
}

func isStandardAction(action *policy.Action) bool {
if action == nil {
return false
}
if action.GetStandard() != policy.Action_STANDARD_ACTION_UNSPECIFIED {
return true
}

switch strings.ToLower(strings.TrimSpace(action.GetName())) {
case "create", "read", "update", "delete":
return true
default:
return false
}
}
11 changes: 10 additions & 1 deletion otdfctl/migrations/namespacedpolicy/planner.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,15 @@ func WithInteractiveReviewer(reviewer InteractiveReviewer) Option {
}

func (p *Planner) Plan(ctx context.Context) (*Plan, error) {
resolved, err := p.resolve(ctx)
if err != nil {
return nil, err
}

return finalizePlan(resolved)
}

func (p *Planner) resolve(ctx context.Context) (*ResolvedTargets, error) {
retrieved, err := p.retrieve(ctx)
if err != nil {
return nil, err
Expand Down Expand Up @@ -132,7 +141,7 @@ func (p *Planner) Plan(ctx context.Context) (*Plan, error) {
}
}

return finalizePlan(resolved)
return resolved, nil
}

// Retrieve the candidate policy constructs for items within scope or dependent
Expand Down
108 changes: 108 additions & 0 deletions otdfctl/migrations/namespacedpolicy/prune_plan.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package namespacedpolicy

import "github.com/opentdf/platform/protocol/go/policy"

type PruneStatus string

const (
PruneStatusDelete PruneStatus = "delete"
PruneStatusBlocked PruneStatus = "blocked"
PruneStatusUnresolved PruneStatus = "unresolved"
)

type PruneStatusReasonType string

const (
PruneStatusReasonTypeMigratedTargetNotFound PruneStatusReasonType = "MigratedTargetNotFound"
PruneStatusReasonTypeNoMatchingLabelsFound PruneStatusReasonType = "NoMatchingLabelsFound"
PruneStatusReasonTypeMismatchedMigrationLabel PruneStatusReasonType = "MismatchedMigrationLabel"
PruneStatusReasonTypeMissingMigrationLabel PruneStatusReasonType = "MissingMigrationLabel"
PruneStatusReasonTypeInUse PruneStatusReasonType = "InUse"
PruneStatusReasonTypeNeedsMigration PruneStatusReasonType = "NeedsMigration"
PruneStatusReasonTypeRegisteredResourceSourceMismatch PruneStatusReasonType = "RegisteredResourceSourceMismatch"
)

type PruneStatusReason struct {
Type PruneStatusReasonType `json:"type"`
Message string `json:"message"`
}

// TargetRef identifies the migrated target object that the planner
// matched to a source object. For objects that resolve to a single migrated
// target, the prune plan uses `TargetRef`. For objects that may still be
// referenced across multiple migrated namespaces, the prune plan uses
// `TargetRefs`.
type TargetRef struct {
ID string `json:"id"`
NamespaceID string `json:"namespace_id,omitempty"`
NamespaceFQN string `json:"namespace_fqn,omitempty"`
}

func (t TargetRef) IsZero() bool {
return len(t.ID) == 0 && len(t.NamespaceID) == 0 && len(t.NamespaceFQN) == 0
}

func (r PruneStatusReason) IsZero() bool {
return len(r.Type) == 0 && len(r.Message) == 0
}

type PrunePlan struct {
Scopes []Scope `json:"scopes"`
Actions []*PruneActionPlan `json:"actions"`
SubjectConditionSets []*PruneSubjectConditionSetPlan `json:"subject_condition_sets"`
SubjectMappings []*PruneSubjectMappingPlan `json:"subject_mappings"`
RegisteredResources []*PruneRegisteredResourcePlan `json:"registered_resources"`
ObligationTriggers []*PruneObligationTriggerPlan `json:"obligation_triggers"`
}

// PruneActionPlan records the source action being considered for deletion and
// any migrated target actions that still reference or replace it.
type PruneActionPlan struct {
Source *policy.Action `json:"source"`
Status PruneStatus `json:"status"`
MigratedTargets []TargetRef `json:"migrated_targets,omitempty"`
Reason PruneStatusReason `json:"reason,omitzero"`
}

// PruneSubjectConditionSetPlan records the source SCS being considered for
// deletion and any migrated target subject condition sets that still reference
// or replace it.
type PruneSubjectConditionSetPlan struct {
Source *policy.SubjectConditionSet `json:"source"`
Status PruneStatus `json:"status"`
MigratedTargets []TargetRef `json:"migrated_targets,omitempty"`
Reason PruneStatusReason `json:"reason,omitzero"`
}

// PruneSubjectMappingPlan records the source subject mapping being considered
// for deletion and the single migrated target subject mapping matched to it by
// migration metadata.
type PruneSubjectMappingPlan struct {
Source *policy.SubjectMapping `json:"source"`
Status PruneStatus `json:"status"`
MigratedTarget TargetRef `json:"migrated_target,omitzero"`
Reason PruneStatusReason `json:"reason,omitzero"`
}

// PruneRegisteredResourcePlan records the resolved RR source being considered
// for deletion and the single migrated target RR matched to it by migration
// metadata.
type PruneRegisteredResourcePlan struct {
// Source is the resolved RR source from planning and may be filtered by interactive review.
Source *policy.RegisteredResource `json:"source"`
// FullSource is the authoritative RR source reloaded from the global namespace for prune verification.
FullSource *policy.RegisteredResource `json:"full_source,omitempty"`
Status PruneStatus `json:"status"`
MigratedTarget TargetRef `json:"migrated_target,omitzero"`
Reason PruneStatusReason `json:"reason,omitzero"`
}

// PruneObligationTriggerPlan records the source obligation trigger being
// considered for deletion and the single migrated target obligation trigger
// matched to it by migration metadata.
type PruneObligationTriggerPlan struct {
Source *policy.ObligationTrigger `json:"source"`
Status PruneStatus `json:"status"`
MigratedTarget TargetRef `json:"migrated_target,omitzero"`
Reason PruneStatusReason `json:"reason,omitzero"`
}
Loading
Loading