diff --git a/otdfctl/e2e/migrate-namespaced-policy.bats b/otdfctl/e2e/migrate-namespaced-policy.bats index f8a71631e6..86bfad78f5 100644 --- a/otdfctl/e2e/migrate-namespaced-policy.bats +++ b/otdfctl/e2e/migrate-namespaced-policy.bats @@ -118,7 +118,8 @@ subject_mapping_plan_target_count() { [ .subject_mappings[] | select(.source.id == $source_mapping_id) - | .targets[] + | .target + | select(. != null) ] | length ' "$output_file" } @@ -130,7 +131,7 @@ subject_mapping_plan_target_status() { jq -er --arg source_mapping_id "$source_mapping_id" --arg namespace_fqn "$namespace_fqn" ' .subject_mappings[] | select(.source.id == $source_mapping_id) - | .targets[] + | .target | select(.namespace.fqn == $namespace_fqn) | .status ' "$output_file" @@ -143,9 +144,9 @@ subject_mapping_plan_target_effective_id() { jq -er --arg source_mapping_id "$source_mapping_id" --arg namespace_fqn "$namespace_fqn" ' .subject_mappings[] | select(.source.id == $source_mapping_id) - | .targets[] + | .target | select(.namespace.fqn == $namespace_fqn) - | (.execution.created_target_id // .existing.id // empty) + | (.execution.created_target_id // .existing_id // empty) ' "$output_file" } @@ -155,12 +156,10 @@ subject_mapping_plan_action_status() { local namespace_fqn="$3" local source_action_id="$4" jq -er --arg source_mapping_id "$source_mapping_id" --arg namespace_fqn "$namespace_fqn" --arg source_action_id "$source_action_id" ' - .subject_mappings[] - | select(.source.id == $source_mapping_id) + .actions[] + | select(.source.id == $source_action_id) | .targets[] | select(.namespace.fqn == $namespace_fqn) - | .actions[] - | select(.source_id == $source_action_id) | .status ' "$output_file" } @@ -170,11 +169,17 @@ subject_mapping_plan_scs_status() { local source_mapping_id="$2" local namespace_fqn="$3" jq -er --arg source_mapping_id "$source_mapping_id" --arg namespace_fqn "$namespace_fqn" ' - .subject_mappings[] + . as $plan + | $plan.subject_mappings[] | select(.source.id == $source_mapping_id) + | .target + | select(.namespace.fqn == $namespace_fqn) + | .subject_condition_set_source_id as $source_scs_id + | $plan.subject_condition_sets[] + | select(.source.id == $source_scs_id) | .targets[] | select(.namespace.fqn == $namespace_fqn) - | .subject_condition_set.status + | .status ' "$output_file" } @@ -364,7 +369,7 @@ action_plan_target_effective_id() { | select(.source.name == $action_name) | .targets[] | select(.namespace.fqn == $namespace_fqn) - | (.execution.created_target_id // .existing.id // empty) + | (.execution.created_target_id // .existing_id // empty) ' "$output_file" } @@ -402,7 +407,7 @@ scs_plan_target_effective_id() { | select(.source.id == $source_scs_id) | .targets[] | select(.namespace.fqn == $namespace_fqn) - | (.execution.created_target_id // .existing.id // empty) + | (.execution.created_target_id // .existing_id // empty) ' "$output_file" } diff --git a/otdfctl/migrations/namespacedpolicy/actions_execute_test.go b/otdfctl/migrations/namespacedpolicy/actions_execute_test.go index 68e5e3bdde..53713fe7e7 100644 --- a/otdfctl/migrations/namespacedpolicy/actions_execute_test.go +++ b/otdfctl/migrations/namespacedpolicy/actions_execute_test.go @@ -46,14 +46,14 @@ func TestExecuteActions(t *testing.T) { Status: TargetStatusCreate, }, { - Namespace: namespace2, - Status: TargetStatusExistingStandard, - Existing: &policy.Action{Id: "standard-action"}, + Namespace: namespace2, + Status: TargetStatusExistingStandard, + ExistingID: "standard-action", }, { - Namespace: namespace3, - Status: TargetStatusAlreadyMigrated, - Existing: &policy.Action{Id: "migrated-action"}, + Namespace: namespace3, + Status: TargetStatusAlreadyMigrated, + ExistingID: "migrated-action", }, }, }, @@ -85,7 +85,7 @@ func TestExecuteActions(t *testing.T) { createdTarget := plan.Actions[0].Targets[0] assert.Equal(t, TargetStatusCreate, createdTarget.Status) - assert.Nil(t, createdTarget.Existing) + assert.Empty(t, createdTarget.ExistingID) require.NotNil(t, createdTarget.Execution) assert.True(t, createdTarget.Execution.Applied) assert.Equal(t, "created-action-1", createdTarget.Execution.CreatedTargetID) diff --git a/otdfctl/migrations/namespacedpolicy/execute.go b/otdfctl/migrations/namespacedpolicy/execute.go index 78123c21d4..bb03df3788 100644 --- a/otdfctl/migrations/namespacedpolicy/execute.go +++ b/otdfctl/migrations/namespacedpolicy/execute.go @@ -40,6 +40,7 @@ type ExecutorHandler interface { CreateObligationTrigger(ctx context.Context, attributeValue, action, obligationValue, clientID string, metadata *common.MetadataMutable) (*policy.ObligationTrigger, error) CreateRegisteredResource(ctx context.Context, namespace string, name string, values []string, metadata *common.MetadataMutable) (*policy.RegisteredResource, error) CreateRegisteredResourceValue(ctx context.Context, resourceID string, value string, actionAttributeValues []*registeredresources.ActionAttributeValue, metadata *common.MetadataMutable) (*policy.RegisteredResourceValue, error) + GetRegisteredResource(ctx context.Context, id, name, namespace string) (*policy.RegisteredResource, error) } type Executor struct { @@ -93,8 +94,10 @@ func (e *Executor) validatePlan(plan *Plan) error { if plan == nil { return ErrNilExecutionPlan } - if plan.Unresolved != nil && hasUnresolved(*plan.Unresolved) { - return fmt.Errorf("%w: finalized plan contains unresolved entries", ErrPlanNotExecutable) + for _, resource := range plan.RegisteredResources { // ? This should be a function withint the plan.go file + if resource != nil && resource.Unresolved != "" { + return fmt.Errorf("%w: finalized plan contains unresolved registered resources", ErrPlanNotExecutable) + } } return nil diff --git a/otdfctl/migrations/namespacedpolicy/execute_test_helpers_test.go b/otdfctl/migrations/namespacedpolicy/execute_test_helpers_test.go index a7d09b27aa..5808a5ec11 100644 --- a/otdfctl/migrations/namespacedpolicy/execute_test_helpers_test.go +++ b/otdfctl/migrations/namespacedpolicy/execute_test_helpers_test.go @@ -47,6 +47,7 @@ type mockExecutorHandler struct { obligationTriggerErrs map[string]map[string]error createdRegisteredResources map[string]map[string]*createdRegisteredResourceCall registeredResourceResult map[string]map[string]*policy.RegisteredResource + registeredResourcesByID map[string]*policy.RegisteredResource registeredResourceErrs map[string]map[string]error createdRegisteredResourceValues map[string]map[string]*createdRegisteredResourceValueCall registeredResourceValueResult map[string]map[string]*policy.RegisteredResourceValue @@ -242,6 +243,10 @@ func (m *mockExecutorHandler) CreateRegisteredResource(_ context.Context, namesp } if m.registeredResourceResult != nil && m.registeredResourceResult[sourceID] != nil { if result := m.registeredResourceResult[sourceID][namespace]; result != nil { + if m.registeredResourcesByID == nil { + m.registeredResourcesByID = make(map[string]*policy.RegisteredResource) + } + m.registeredResourcesByID[result.GetId()] = result return result, nil } } @@ -249,6 +254,18 @@ func (m *mockExecutorHandler) CreateRegisteredResource(_ context.Context, namesp return nil, errMissingMockRegisteredResourceResult } +func (m *mockExecutorHandler) GetRegisteredResource(_ context.Context, id, _, _ string) (*policy.RegisteredResource, error) { + if id == "" { + return nil, errMissingMockRegisteredResourceResult + } + if m.registeredResourcesByID != nil { + if result := m.registeredResourcesByID[id]; result != nil { + return result, nil + } + } + return nil, errMissingMockRegisteredResourceResult +} + func (m *mockExecutorHandler) CreateRegisteredResourceValue(_ context.Context, resourceID string, value string, actionAttributeValues []*registeredresources.ActionAttributeValue, metadata *common.MetadataMutable) (*policy.RegisteredResourceValue, error) { sourceID := metadata.GetLabels()[migrationLabelMigratedFrom] diff --git a/otdfctl/migrations/namespacedpolicy/finalize_plan.go b/otdfctl/migrations/namespacedpolicy/finalize_plan.go index fbc5b1c3e4..9a9518cd16 100644 --- a/otdfctl/migrations/namespacedpolicy/finalize_plan.go +++ b/otdfctl/migrations/namespacedpolicy/finalize_plan.go @@ -8,8 +8,6 @@ import ( var ErrNilResolvedTargets = errors.New("planner resolved state is required") -const unusedActionReason = "action is not referenced by any subject mapping, registered resource, or obligation trigger" - // finalizePlan converts the fully resolved graph into the current Plan shape. // This is the last planner stage before artifact building/execution wiring. func finalizePlan(resolved *ResolvedTargets, namespaces []*policy.Namespace) (*Plan, error) { @@ -68,10 +66,6 @@ type planFinalizer struct { subjectMappings []*SubjectMappingPlan registeredResources []*RegisteredResourcePlan obligationTriggers []*ObligationTriggerPlan - actionTargetsByKey map[string]*ActionTargetPlan - scsTargetsByKey map[string]*SubjectConditionSetTargetPlan - unused UnusedPlan - unresolved UnresolvedPlan } func newPlanFinalizer(resolved *ResolvedTargets, namespaces []*policy.Namespace) *planFinalizer { @@ -79,8 +73,6 @@ func newPlanFinalizer(resolved *ResolvedTargets, namespaces []*policy.Namespace) resolved: resolved, namespaces: namespaces, namespacePlansByID: make(map[string]*NamespacePlan), - actionTargetsByKey: make(map[string]*ActionTargetPlan), - scsTargetsByKey: make(map[string]*SubjectConditionSetTargetPlan), } } @@ -104,14 +96,6 @@ func (f *planFinalizer) build() *Plan { } } - if hasUnused(f.unused) { - plan.Unused = &f.unused - } - - if hasUnresolved(f.unresolved) { - plan.Unresolved = &f.unresolved - } - return plan } @@ -120,8 +104,7 @@ func (f *planFinalizer) addResolvedAction(item *ResolvedAction) { return } - if len(item.Results) == 0 && len(item.References) == 0 { - f.addUnusedAction(item.Source, item.References, unusedActionReason) + if len(item.Results) == 0 { return } @@ -137,7 +120,6 @@ func (f *planFinalizer) addResolvedAction(item *ResolvedAction) { continue } actionPlan.Targets = append(actionPlan.Targets, target) - f.storeActionTarget(item.Source.GetId(), target) f.addNamespacePlacement(target.Namespace, ScopeActions, item.Source.GetId()) } @@ -161,7 +143,6 @@ func (f *planFinalizer) addResolvedSubjectConditionSet(item *ResolvedSubjectCond continue } scsPlan.Targets = append(scsPlan.Targets, target) - f.storeSubjectConditionSetTarget(item.Source.GetId(), target) f.addNamespacePlacement(target.Namespace, ScopeSubjectConditionSets, item.Source.GetId()) } @@ -178,7 +159,7 @@ func (f *planFinalizer) addResolvedSubjectMapping(item *ResolvedSubjectMapping) target := f.newSubjectMappingTarget(item) if target != nil { - mappingPlan.Targets = append(mappingPlan.Targets, target) + mappingPlan.Target = target f.addNamespacePlacement(target.Namespace, ScopeSubjectMappings, item.Source.GetId()) } @@ -197,14 +178,8 @@ func (f *planFinalizer) addResolvedRegisteredResource(item *ResolvedRegisteredRe target := f.newRegisteredResourceTarget(item) if target != nil { - resourcePlan.Targets = append(resourcePlan.Targets, target) - if target.Status == TargetStatusUnresolved { - f.addRegisteredResourceIssue(item.Source, target.Namespace, target.Reason) - } else { - f.addNamespacePlacement(target.Namespace, ScopeRegisteredResources, item.Source.GetId()) - } - } else if item.Unresolved != nil { - f.addRegisteredResourceIssue(item.Source, item.Namespace, item.Unresolved.Message) + resourcePlan.Target = target + f.addNamespacePlacement(target.Namespace, ScopeRegisteredResources, item.Source.GetId()) } f.registeredResources = append(f.registeredResources, resourcePlan) @@ -219,7 +194,7 @@ func (f *planFinalizer) addResolvedObligationTrigger(item *ResolvedObligationTri target := f.newObligationTriggerTarget(item) if target != nil { - triggerPlan.Targets = append(triggerPlan.Targets, target) + triggerPlan.Target = target f.addNamespacePlacement(target.Namespace, ScopeObligationTriggers, item.Source.GetId()) } @@ -267,34 +242,20 @@ func (f *planFinalizer) addNamespacePlacement(namespace *policy.Namespace, scope } } -func (f *planFinalizer) storeActionTarget(sourceID string, target *ActionTargetPlan) { - if sourceID == "" || target == nil || target.Namespace == nil || target.Namespace.GetId() == "" { - return - } - f.actionTargetsByKey[resolvedResultKey(sourceID, target.Namespace.GetId())] = target -} - -func (f *planFinalizer) storeSubjectConditionSetTarget(sourceID string, target *SubjectConditionSetTargetPlan) { - if sourceID == "" || target == nil || target.Namespace == nil || target.Namespace.GetId() == "" { - return - } - f.scsTargetsByKey[resolvedResultKey(sourceID, target.Namespace.GetId())] = target -} - func (f *planFinalizer) newSubjectMappingTarget(item *ResolvedSubjectMapping) *SubjectMappingTargetPlan { if item == nil || item.Namespace == nil { return nil } target := &SubjectMappingTargetPlan{ - Namespace: item.Namespace, - Actions: make([]*ActionBinding, 0, len(item.Source.GetActions())), + Namespace: item.Namespace, + ActionSourceIDs: make([]string, 0, len(item.Source.GetActions())), } switch { case item.AlreadyMigrated != nil: target.Status = TargetStatusAlreadyMigrated - target.Existing = item.AlreadyMigrated + target.ExistingID = item.AlreadyMigrated.GetId() case item.NeedsCreate: target.Status = TargetStatusCreate default: @@ -302,9 +263,9 @@ func (f *planFinalizer) newSubjectMappingTarget(item *ResolvedSubjectMapping) *S } for _, action := range item.Source.GetActions() { - target.Actions = append(target.Actions, f.actionBinding(action.GetId(), item.Namespace)) + target.ActionSourceIDs = append(target.ActionSourceIDs, action.GetId()) } - target.SubjectConditionSet = f.subjectConditionSetBinding(item.Source.GetSubjectConditionSet().GetId(), item.Namespace) + target.SubjectConditionSetSourceID = item.Source.GetSubjectConditionSet().GetId() return target } @@ -322,7 +283,7 @@ func (f *planFinalizer) newRegisteredResourceTarget(item *ResolvedRegisteredReso switch { case item.AlreadyMigrated != nil: target.Status = TargetStatusAlreadyMigrated - target.Existing = item.AlreadyMigrated + target.ExistingID = item.AlreadyMigrated.GetId() case item.NeedsCreate: target.Status = TargetStatusCreate default: @@ -341,10 +302,6 @@ func (f *planFinalizer) newRegisteredResourceTarget(item *ResolvedRegisteredReso valuePlan.ActionBindings = append(valuePlan.ActionBindings, &RegisteredResourceActionBinding{ SourceActionID: aav.GetAction().GetId(), AttributeValue: aav.GetAttributeValue(), - ActionTargetRef: f.actionBinding( - aav.GetAction().GetId(), - item.Namespace, - ), }) } target.Values = append(target.Values, valuePlan) @@ -364,100 +321,17 @@ func (f *planFinalizer) newObligationTriggerTarget(item *ResolvedObligationTrigg switch { case item.AlreadyMigrated != nil: target.Status = TargetStatusAlreadyMigrated - target.Existing = item.AlreadyMigrated + target.ExistingID = item.AlreadyMigrated.GetId() case item.NeedsCreate: target.Status = TargetStatusCreate default: return nil } - target.Action = f.actionBinding(item.Source.GetAction().GetId(), item.Namespace) + target.ActionSourceID = item.Source.GetAction().GetId() return target } -func (f *planFinalizer) actionBinding(sourceID string, namespace *policy.Namespace) *ActionBinding { - if sourceID == "" || namespace == nil { - return nil - } - - target := f.actionTargetsByKey[resolvedResultKey(sourceID, namespace.GetId())] - if target == nil { - return &ActionBinding{ - SourceID: sourceID, - Namespace: namespace, - Status: TargetStatusUnresolved, - Reason: "action target is not available in the finalized plan", - } - } - - return &ActionBinding{ - SourceID: sourceID, - Namespace: namespace, - Status: target.Status, - TargetID: target.TargetID(), - Reason: target.Reason, - } -} - -func (f *planFinalizer) subjectConditionSetBinding(sourceID string, namespace *policy.Namespace) *SubjectConditionSetBinding { - if sourceID == "" || namespace == nil { - return nil - } - - target := f.scsTargetsByKey[resolvedResultKey(sourceID, namespace.GetId())] - if target == nil { - return &SubjectConditionSetBinding{ - SourceID: sourceID, - Namespace: namespace, - Status: TargetStatusUnresolved, - Reason: "subject condition set target is not available in the finalized plan", - } - } - - return &SubjectConditionSetBinding{ - SourceID: sourceID, - Namespace: namespace, - Status: target.Status, - TargetID: target.TargetID(), - Reason: target.Reason, - } -} - -func (f *planFinalizer) addUnusedAction(action *policy.Action, references []*ActionReference, reason string) { - if action == nil || reason == "" { - return - } - for _, unused := range f.unused.Actions { - if unused != nil && unused.Source != nil && unused.Source.GetId() == action.GetId() && unused.Reason == reason { - return - } - } - f.unused.Actions = append(f.unused.Actions, &UnusedAction{ - Source: action, - References: append([]*ActionReference(nil), references...), - Reason: reason, - }) -} - -func (f *planFinalizer) addRegisteredResourceIssue(resource *policy.RegisteredResource, namespace *policy.Namespace, reason string) { - if resource == nil || reason == "" { - return - } - for _, issue := range f.unresolved.RegisteredResources { - if issue != nil && issue.Resource != nil && - issue.Resource.GetId() == resource.GetId() && - sameNamespace(issue.Namespace, namespace) && - issue.Reason == reason { - return - } - } - f.unresolved.RegisteredResources = append(f.unresolved.RegisteredResources, &RegisteredResourceIssue{ - Resource: resource, - Namespace: namespace, - Reason: reason, - }) -} - func newActionTargetPlan(result *ResolvedActionResult) *ActionTargetPlan { if result == nil || result.Namespace == nil { return nil @@ -467,10 +341,10 @@ func newActionTargetPlan(result *ResolvedActionResult) *ActionTargetPlan { switch { case result.AlreadyMigrated != nil: target.Status = TargetStatusAlreadyMigrated - target.Existing = result.AlreadyMigrated + target.ExistingID = result.AlreadyMigrated.GetId() case result.ExistingStandard != nil: target.Status = TargetStatusExistingStandard - target.Existing = result.ExistingStandard + target.ExistingID = result.ExistingStandard.GetId() case result.NeedsCreate: target.Status = TargetStatusCreate default: @@ -489,7 +363,7 @@ func newSubjectConditionSetTargetPlan(result *ResolvedSubjectConditionSetResult) switch { case result.AlreadyMigrated != nil: target.Status = TargetStatusAlreadyMigrated - target.Existing = result.AlreadyMigrated + target.ExistingID = result.AlreadyMigrated.GetId() case result.NeedsCreate: target.Status = TargetStatusCreate default: diff --git a/otdfctl/migrations/namespacedpolicy/finalize_plan_test.go b/otdfctl/migrations/namespacedpolicy/finalize_plan_test.go index 3de1af4ee2..0d8d7b98eb 100644 --- a/otdfctl/migrations/namespacedpolicy/finalize_plan_test.go +++ b/otdfctl/migrations/namespacedpolicy/finalize_plan_test.go @@ -88,25 +88,20 @@ func TestFinalizePlanBuildsBindingsForDependentObjects(t *testing.T) { require.NoError(t, err) require.Len(t, plan.SubjectMappings, 1) - require.Len(t, plan.SubjectMappings[0].Targets, 1) - assert.Equal(t, TargetStatusCreate, plan.SubjectMappings[0].Targets[0].Status) - require.Len(t, plan.SubjectMappings[0].Targets[0].Actions, 1) - assert.Equal(t, TargetStatusCreate, plan.SubjectMappings[0].Targets[0].Actions[0].Status) - assert.Equal(t, "action-1", plan.SubjectMappings[0].Targets[0].Actions[0].SourceID) - require.NotNil(t, plan.SubjectMappings[0].Targets[0].SubjectConditionSet) - assert.Equal(t, TargetStatusAlreadyMigrated, plan.SubjectMappings[0].Targets[0].SubjectConditionSet.Status) - assert.Equal(t, "scs-target", plan.SubjectMappings[0].Targets[0].SubjectConditionSet.TargetID) + require.NotNil(t, plan.SubjectMappings[0].Target) + assert.Equal(t, TargetStatusCreate, plan.SubjectMappings[0].Target.Status) + assert.Equal(t, []string{"action-1"}, plan.SubjectMappings[0].Target.ActionSourceIDs) + assert.Equal(t, "scs-1", plan.SubjectMappings[0].Target.SubjectConditionSetSourceID) require.Len(t, plan.RegisteredResources, 1) - require.Len(t, plan.RegisteredResources[0].Targets, 1) - require.Len(t, plan.RegisteredResources[0].Targets[0].Values, 1) - require.Len(t, plan.RegisteredResources[0].Targets[0].Values[0].ActionBindings, 1) - assert.Equal(t, TargetStatusCreate, plan.RegisteredResources[0].Targets[0].Values[0].ActionBindings[0].ActionTargetRef.Status) + require.NotNil(t, plan.RegisteredResources[0].Target) + require.Len(t, plan.RegisteredResources[0].Target.Values, 1) + require.Len(t, plan.RegisteredResources[0].Target.Values[0].ActionBindings, 1) + assert.Equal(t, "action-1", plan.RegisteredResources[0].Target.Values[0].ActionBindings[0].SourceActionID) require.Len(t, plan.ObligationTriggers, 1) - require.Len(t, plan.ObligationTriggers[0].Targets, 1) - require.NotNil(t, plan.ObligationTriggers[0].Targets[0].Action) - assert.Equal(t, TargetStatusCreate, plan.ObligationTriggers[0].Targets[0].Action.Status) + require.NotNil(t, plan.ObligationTriggers[0].Target) + assert.Equal(t, "action-1", plan.ObligationTriggers[0].Target.ActionSourceID) require.Len(t, plan.Namespaces, 1) assert.Equal(t, []string{"mapping-1"}, plan.Namespaces[0].SubjectMappings) diff --git a/otdfctl/migrations/namespacedpolicy/obligation_triggers_execute.go b/otdfctl/migrations/namespacedpolicy/obligation_triggers_execute.go index a9e19b527e..86a18ffa34 100644 --- a/otdfctl/migrations/namespacedpolicy/obligation_triggers_execute.go +++ b/otdfctl/migrations/namespacedpolicy/obligation_triggers_execute.go @@ -18,14 +18,12 @@ func (e *Executor) executeObligationTriggers(ctx context.Context, plans []*Oblig continue } - for _, target := range triggerPlan.Targets { - if target == nil { - continue - } - - if err := e.executeObligationTriggerTarget(ctx, triggerPlan, target); err != nil { - return err - } + if triggerPlan.Target == nil { + continue + } + + if err := e.executeObligationTriggerTarget(ctx, triggerPlan, triggerPlan.Target); err != nil { + return err } } @@ -50,7 +48,7 @@ func (e *Executor) executeObligationTriggerTarget(ctx context.Context, triggerPl } func (e *Executor) createObligationTriggerTarget(ctx context.Context, triggerPlan *ObligationTriggerPlan, target *ObligationTriggerTargetPlan) error { - actionID, err := e.requireActionTargetID(target.Action, target.Namespace, triggerPlan.Source.GetId()) + actionID, err := e.requireActionTargetID(target.ActionSourceID, target.Namespace, triggerPlan.Source.GetId()) if err != nil { return err } @@ -92,17 +90,17 @@ func (e *Executor) createObligationTriggerTarget(ctx context.Context, triggerPla } // TODO: Eventually make this generic when we merge sm / rr -func (e *Executor) requireActionTargetID(binding *ActionBinding, targetNamespace *policy.Namespace, ownerID string) (string, error) { - if binding == nil { - return "", fmt.Errorf("%w: obligation trigger %q action binding is missing", ErrMissingMigratedTarget, ownerID) +func (e *Executor) requireActionTargetID(sourceID string, targetNamespace *policy.Namespace, ownerID string) (string, error) { + if sourceID == "" { + return "", fmt.Errorf("%w: obligation trigger %q action source id is missing", ErrMissingMigratedTarget, ownerID) } - actionID := e.cachedActionTargetID(binding.SourceID, targetNamespace) + actionID := e.cachedActionTargetID(sourceID, targetNamespace) if actionID != "" { return actionID, nil } - return "", fmt.Errorf("%w: obligation trigger %q action %q target %q", ErrMissingMigratedTarget, ownerID, binding.SourceID, namespaceLabel(targetNamespace)) + return "", fmt.Errorf("%w: obligation trigger %q action %q target %q", ErrMissingMigratedTarget, ownerID, sourceID, namespaceLabel(targetNamespace)) } func valueIDOrFQN(value *policy.Value) string { diff --git a/otdfctl/migrations/namespacedpolicy/obligation_triggers_execute_test.go b/otdfctl/migrations/namespacedpolicy/obligation_triggers_execute_test.go index b7f47848c4..8f0c33a741 100644 --- a/otdfctl/migrations/namespacedpolicy/obligation_triggers_execute_test.go +++ b/otdfctl/migrations/namespacedpolicy/obligation_triggers_execute_test.go @@ -38,9 +38,9 @@ func TestExecuteObligationTriggers(t *testing.T) { Status: TargetStatusCreate, }, { - Namespace: namespace2, - Status: TargetStatusExistingStandard, - Existing: &policy.Action{Id: "existing-standard-action"}, + Namespace: namespace2, + Status: TargetStatusExistingStandard, + ExistingID: "existing-standard-action", }, }, }, @@ -68,16 +68,10 @@ func TestExecuteObligationTriggers(t *testing.T) { }, }, }, - Targets: []*ObligationTriggerTargetPlan{ - { - Namespace: namespace1, - Status: TargetStatusCreate, - Action: &ActionBinding{ - SourceID: "action-1", - Namespace: namespace1, - Status: TargetStatusCreate, - }, - }, + Target: &ObligationTriggerTargetPlan{ + Namespace: namespace1, + Status: TargetStatusCreate, + ActionSourceID: "action-1", }, }, { @@ -85,18 +79,11 @@ func TestExecuteObligationTriggers(t *testing.T) { Id: "trigger-2", Action: &policy.Action{Id: "action-1"}, }, - Targets: []*ObligationTriggerTargetPlan{ - { - Namespace: namespace2, - Status: TargetStatusAlreadyMigrated, - Existing: &policy.ObligationTrigger{Id: "migrated-trigger-2"}, - Action: &ActionBinding{ - SourceID: "action-1", - Namespace: namespace2, - Status: TargetStatusExistingStandard, - TargetID: "existing-standard-action", - }, - }, + Target: &ObligationTriggerTargetPlan{ + Namespace: namespace2, + Status: TargetStatusAlreadyMigrated, + ExistingID: "migrated-trigger-2", + ActionSourceID: "action-1", }, }, }, @@ -133,14 +120,14 @@ func TestExecuteObligationTriggers(t *testing.T) { migrationLabelRun: "run-789", }, createdCall.Metadata.GetLabels()) - createdTarget := plan.ObligationTriggers[0].Targets[0] + createdTarget := plan.ObligationTriggers[0].Target require.NotNil(t, createdTarget.Execution) assert.True(t, createdTarget.Execution.Applied) assert.Equal(t, "created-trigger-1", createdTarget.Execution.CreatedTargetID) assert.Equal(t, "run-789", createdTarget.Execution.RunID) assert.Equal(t, "created-trigger-1", createdTarget.TargetID()) - migratedTarget := plan.ObligationTriggers[1].Targets[0] + migratedTarget := plan.ObligationTriggers[1].Target assert.Equal(t, "migrated-trigger-2", migratedTarget.TargetID()) assert.Nil(t, migratedTarget.Execution) }, @@ -152,12 +139,10 @@ func TestExecuteObligationTriggers(t *testing.T) { ObligationTriggers: []*ObligationTriggerPlan{ { Source: &policy.ObligationTrigger{Id: "trigger-1"}, - Targets: []*ObligationTriggerTargetPlan{ - { - Namespace: namespace1, - Status: TargetStatusUnresolved, - Reason: "missing target namespace mapping", - }, + Target: &ObligationTriggerTargetPlan{ + Namespace: namespace1, + Status: TargetStatusUnresolved, + Reason: "missing target namespace mapping", }, }, }, @@ -189,16 +174,10 @@ func TestExecuteObligationTriggers(t *testing.T) { AttributeValue: &policy.Value{Id: "attribute-value-1"}, ObligationValue: &policy.ObligationValue{Id: "obligation-value-1"}, }, - Targets: []*ObligationTriggerTargetPlan{ - { - Namespace: namespace1, - Status: TargetStatusCreate, - Action: &ActionBinding{ - SourceID: "action-1", - Namespace: namespace1, - Status: TargetStatusCreate, - }, - }, + Target: &ObligationTriggerTargetPlan{ + Namespace: namespace1, + Status: TargetStatusCreate, + ActionSourceID: "action-1", }, }, }, @@ -210,7 +189,7 @@ func TestExecuteObligationTriggers(t *testing.T) { require.Error(t, err) assert.Empty(t, handler.createdObligationTriggers) - assert.Nil(t, plan.ObligationTriggers[0].Targets[0].Execution) + assert.Nil(t, plan.ObligationTriggers[0].Target.Execution) }, }, { @@ -220,11 +199,9 @@ func TestExecuteObligationTriggers(t *testing.T) { ObligationTriggers: []*ObligationTriggerPlan{ { Source: &policy.ObligationTrigger{Id: "trigger-1"}, - Targets: []*ObligationTriggerTargetPlan{ - { - Namespace: namespace1, - Status: TargetStatusAlreadyMigrated, - }, + Target: &ObligationTriggerTargetPlan{ + Namespace: namespace1, + Status: TargetStatusAlreadyMigrated, }, }, }, @@ -261,16 +238,10 @@ func TestExecuteObligationTriggers(t *testing.T) { AttributeValue: &policy.Value{Id: "attribute-value-1"}, ObligationValue: &policy.ObligationValue{Id: "obligation-value-1"}, }, - Targets: []*ObligationTriggerTargetPlan{ - { - Namespace: namespace1, - Status: TargetStatusCreate, - Action: &ActionBinding{ - SourceID: "action-1", - Namespace: namespace1, - Status: TargetStatusCreate, - }, - }, + Target: &ObligationTriggerTargetPlan{ + Namespace: namespace1, + Status: TargetStatusCreate, + ActionSourceID: "action-1", }, }, }, @@ -293,8 +264,8 @@ func TestExecuteObligationTriggers(t *testing.T) { require.Error(t, err) require.Contains(t, handler.createdObligationTriggers, "trigger-1") - require.NotNil(t, plan.ObligationTriggers[0].Targets[0].Execution) - assert.Equal(t, ErrMissingCreatedTargetID.Error(), plan.ObligationTriggers[0].Targets[0].Execution.Failure) + require.NotNil(t, plan.ObligationTriggers[0].Target.Execution) + assert.Equal(t, ErrMissingCreatedTargetID.Error(), plan.ObligationTriggers[0].Target.Execution.Failure) }, }, { @@ -320,16 +291,10 @@ func TestExecuteObligationTriggers(t *testing.T) { AttributeValue: &policy.Value{Id: "attribute-value-1"}, ObligationValue: &policy.ObligationValue{Id: "obligation-value-1"}, }, - Targets: []*ObligationTriggerTargetPlan{ - { - Namespace: namespace1, - Status: TargetStatusCreate, - Action: &ActionBinding{ - SourceID: "action-1", - Namespace: namespace1, - Status: TargetStatusCreate, - }, - }, + Target: &ObligationTriggerTargetPlan{ + Namespace: namespace1, + Status: TargetStatusCreate, + ActionSourceID: "action-1", }, }, }, @@ -355,8 +320,8 @@ func TestExecuteObligationTriggers(t *testing.T) { require.Error(t, err) require.Contains(t, handler.createdObligationTriggers, "trigger-1") - require.NotNil(t, plan.ObligationTriggers[0].Targets[0].Execution) - assert.Equal(t, "boom", plan.ObligationTriggers[0].Targets[0].Execution.Failure) + require.NotNil(t, plan.ObligationTriggers[0].Target.Execution) + assert.Equal(t, "boom", plan.ObligationTriggers[0].Target.Execution.Failure) }, }, { @@ -366,11 +331,9 @@ func TestExecuteObligationTriggers(t *testing.T) { ObligationTriggers: []*ObligationTriggerPlan{ { Source: &policy.ObligationTrigger{Id: "trigger-1"}, - Targets: []*ObligationTriggerTargetPlan{ - { - Namespace: namespace1, - Status: TargetStatus("bogus"), - }, + Target: &ObligationTriggerTargetPlan{ + Namespace: namespace1, + Status: TargetStatus("bogus"), }, }, }, diff --git a/otdfctl/migrations/namespacedpolicy/plan.go b/otdfctl/migrations/namespacedpolicy/plan.go index 31f47439b2..a0e5126c87 100644 --- a/otdfctl/migrations/namespacedpolicy/plan.go +++ b/otdfctl/migrations/namespacedpolicy/plan.go @@ -34,8 +34,6 @@ type Plan struct { SubjectMappings []*SubjectMappingPlan `json:"subject_mappings"` RegisteredResources []*RegisteredResourcePlan `json:"registered_resources"` ObligationTriggers []*ObligationTriggerPlan `json:"obligation_triggers"` - Unused *UnusedPlan `json:"unused,omitempty"` - Unresolved *UnresolvedPlan `json:"unresolved,omitempty"` } type NamespacePlan struct { @@ -87,11 +85,11 @@ type ActionReference struct { } type ActionTargetPlan struct { - Namespace *policy.Namespace `json:"namespace"` - Status TargetStatus `json:"status"` - Existing *policy.Action `json:"existing,omitempty"` - Execution *ExecutionResult `json:"execution,omitempty"` - Reason string `json:"reason,omitempty"` + Namespace *policy.Namespace `json:"namespace"` + Status TargetStatus `json:"status"` + ExistingID string `json:"existing_id,omitempty"` + Execution *ExecutionResult `json:"execution,omitempty"` + Reason string `json:"reason,omitempty"` } type SubjectConditionSetPlan struct { @@ -100,44 +98,44 @@ type SubjectConditionSetPlan struct { } type SubjectConditionSetTargetPlan struct { - Namespace *policy.Namespace `json:"namespace"` - Status TargetStatus `json:"status"` - Existing *policy.SubjectConditionSet `json:"existing,omitempty"` - Execution *ExecutionResult `json:"execution,omitempty"` - Reason string `json:"reason,omitempty"` + Namespace *policy.Namespace `json:"namespace"` + Status TargetStatus `json:"status"` + ExistingID string `json:"existing_id,omitempty"` + Execution *ExecutionResult `json:"execution,omitempty"` + Reason string `json:"reason,omitempty"` } type SubjectMappingPlan struct { - Source *policy.SubjectMapping `json:"source"` - Targets []*SubjectMappingTargetPlan `json:"targets,omitempty"` + Source *policy.SubjectMapping `json:"source"` + Target *SubjectMappingTargetPlan `json:"target,omitempty"` } type SubjectMappingTargetPlan struct { - Namespace *policy.Namespace `json:"namespace"` - Status TargetStatus `json:"status"` - Existing *policy.SubjectMapping `json:"existing,omitempty"` - Execution *ExecutionResult `json:"execution,omitempty"` - Reason string `json:"reason,omitempty"` - Actions []*ActionBinding `json:"actions,omitempty"` - SubjectConditionSet *SubjectConditionSetBinding `json:"subject_condition_set,omitempty"` + Namespace *policy.Namespace `json:"namespace"` + Status TargetStatus `json:"status"` + ExistingID string `json:"existing_id,omitempty"` + Execution *ExecutionResult `json:"execution,omitempty"` + Reason string `json:"reason,omitempty"` + ActionSourceIDs []string `json:"action_source_ids,omitempty"` + SubjectConditionSetSourceID string `json:"subject_condition_set_source_id,omitempty"` } type RegisteredResourcePlan struct { - Source *policy.RegisteredResource `json:"source"` - Targets []*RegisteredResourceTargetPlan `json:"targets,omitempty"` - Unresolved string `json:"unresolved,omitempty"` + Source *policy.RegisteredResource `json:"source"` + Target *RegisteredResourceTargetPlan `json:"target,omitempty"` + Unresolved string `json:"unresolved,omitempty"` } type RegisteredResourceTargetPlan struct { Namespace *policy.Namespace `json:"namespace"` Status TargetStatus `json:"status"` - // For registered resources, Existing is also used on create targets to mean + // For registered resources, ExistingID is also used on create targets to mean // "reuse this parent RR and reconcile missing values under it" rather than // creating a new top-level RR. - Existing *policy.RegisteredResource `json:"existing,omitempty"` - Execution *ExecutionResult `json:"execution,omitempty"` - Reason string `json:"reason,omitempty"` - Values []*RegisteredResourceValuePlan `json:"values,omitempty"` + ExistingID string `json:"existing_id,omitempty"` + Execution *ExecutionResult `json:"execution,omitempty"` + Reason string `json:"reason,omitempty"` + Values []*RegisteredResourceValuePlan `json:"values,omitempty"` } type RegisteredResourceValuePlan struct { @@ -147,60 +145,22 @@ type RegisteredResourceValuePlan struct { } type RegisteredResourceActionBinding struct { - SourceActionID string `json:"source_action_id"` - AttributeValue *policy.Value `json:"attribute_value,omitempty"` - ActionTargetRef *ActionBinding `json:"action_target,omitempty"` + SourceActionID string `json:"source_action_id"` + AttributeValue *policy.Value `json:"attribute_value,omitempty"` } type ObligationTriggerPlan struct { - Source *policy.ObligationTrigger `json:"source"` - Targets []*ObligationTriggerTargetPlan `json:"targets,omitempty"` + Source *policy.ObligationTrigger `json:"source"` + Target *ObligationTriggerTargetPlan `json:"target,omitempty"` } type ObligationTriggerTargetPlan struct { - Namespace *policy.Namespace `json:"namespace"` - Status TargetStatus `json:"status"` - Existing *policy.ObligationTrigger `json:"existing,omitempty"` - Execution *ExecutionResult `json:"execution,omitempty"` - Reason string `json:"reason,omitempty"` - Action *ActionBinding `json:"action,omitempty"` -} - -// TODO: Revisit this and Scs binding to see what is actually useful -type ActionBinding struct { - SourceID string `json:"source_id"` - Namespace *policy.Namespace `json:"namespace,omitempty"` - Status TargetStatus `json:"status"` - TargetID string `json:"target_id,omitempty"` - Reason string `json:"reason,omitempty"` -} - -type SubjectConditionSetBinding struct { - SourceID string `json:"source_id"` - Namespace *policy.Namespace `json:"namespace,omitempty"` - Status TargetStatus `json:"status"` - TargetID string `json:"target_id,omitempty"` - Reason string `json:"reason,omitempty"` -} - -type UnusedPlan struct { - Actions []*UnusedAction `json:"actions,omitempty"` -} - -type UnusedAction struct { - Source *policy.Action `json:"source"` - References []*ActionReference `json:"references,omitempty"` - Reason string `json:"reason"` -} - -type UnresolvedPlan struct { - RegisteredResources []*RegisteredResourceIssue `json:"registered_resources,omitempty"` -} - -type RegisteredResourceIssue struct { - Resource *policy.RegisteredResource `json:"resource"` - Namespace *policy.Namespace `json:"namespace,omitempty"` - Reason string `json:"reason"` + Namespace *policy.Namespace `json:"namespace"` + Status TargetStatus `json:"status"` + ExistingID string `json:"existing_id,omitempty"` + Execution *ExecutionResult `json:"execution,omitempty"` + Reason string `json:"reason,omitempty"` + ActionSourceID string `json:"action_source_id,omitempty"` } func namespaceFromAttributeValue(value *policy.Value) *policy.Namespace { @@ -252,14 +212,6 @@ func hasObject[T interface{ GetId() string }](items []T, id string) bool { return false } -func hasUnresolved(plan UnresolvedPlan) bool { - return len(plan.RegisteredResources) > 0 -} - -func hasUnused(plan UnusedPlan) bool { - return len(plan.Actions) > 0 -} - // sameNamespace reports whether two namespace references identify the same // namespace. IDs are compared with whitespace trimmed; FQNs are compared // case-insensitively with whitespace trimmed. Two nil namespaces are @@ -295,10 +247,7 @@ func (t *ActionTargetPlan) TargetID() string { if t.Execution != nil && t.Execution.CreatedTargetID != "" { return t.Execution.CreatedTargetID } - if t.Existing == nil { - return "" - } - return t.Existing.GetId() + return t.ExistingID } func (t *SubjectConditionSetTargetPlan) TargetID() string { @@ -308,10 +257,7 @@ func (t *SubjectConditionSetTargetPlan) TargetID() string { if t.Execution != nil && t.Execution.CreatedTargetID != "" { return t.Execution.CreatedTargetID } - if t.Existing == nil { - return "" - } - return t.Existing.GetId() + return t.ExistingID } func (t *SubjectMappingTargetPlan) TargetID() string { @@ -321,10 +267,7 @@ func (t *SubjectMappingTargetPlan) TargetID() string { if t.Execution != nil && t.Execution.CreatedTargetID != "" { return t.Execution.CreatedTargetID } - if t.Existing == nil { - return "" - } - return t.Existing.GetId() + return t.ExistingID } func (t *RegisteredResourceTargetPlan) TargetID() string { @@ -334,10 +277,7 @@ func (t *RegisteredResourceTargetPlan) TargetID() string { if t.Execution != nil && t.Execution.CreatedTargetID != "" { return t.Execution.CreatedTargetID } - if t.Existing == nil { - return "" - } - return t.Existing.GetId() + return t.ExistingID } func (p *RegisteredResourceValuePlan) TargetID() string { @@ -354,10 +294,7 @@ func (t *ObligationTriggerTargetPlan) TargetID() string { if t.Execution != nil && t.Execution.CreatedTargetID != "" { return t.Execution.CreatedTargetID } - if t.Existing == nil { - return "" - } - return t.Existing.GetId() + return t.ExistingID } func (p *Plan) LookupActionTarget(sourceID, namespaceID string) *ActionTargetPlan { diff --git a/otdfctl/migrations/namespacedpolicy/planner_test.go b/otdfctl/migrations/namespacedpolicy/planner_test.go index a4eafa9d7d..9a5aab3535 100644 --- a/otdfctl/migrations/namespacedpolicy/planner_test.go +++ b/otdfctl/migrations/namespacedpolicy/planner_test.go @@ -77,8 +77,7 @@ func TestPlannerPlanMarksActionAlreadyMigratedWithoutMetadata(t *testing.T) { require.Len(t, plan.Actions[0].Targets, 1) assert.Equal(t, TargetStatusAlreadyMigrated, plan.Actions[0].Targets[0].Status) - require.NotNil(t, plan.Actions[0].Targets[0].Existing) - assert.Equal(t, targetAction.GetId(), plan.Actions[0].Targets[0].Existing.GetId()) + assert.Equal(t, targetAction.GetId(), plan.Actions[0].Targets[0].ExistingID) assert.Equal(t, []string{"", targetNamespace.GetId()}, handler.actionCalls) assert.Equal(t, []string{""}, handler.subjectMappingCalls) } @@ -515,23 +514,20 @@ func TestPlannerPlanAllScopesBuildsAllPlanSections(t *testing.T) { assert.Equal(t, TargetStatusCreate, plan.SubjectConditionSets[0].Targets[0].Status) require.Len(t, plan.SubjectMappings, 1) - require.Len(t, plan.SubjectMappings[0].Targets, 1) - assert.Equal(t, TargetStatusCreate, plan.SubjectMappings[0].Targets[0].Status) - require.Len(t, plan.SubjectMappings[0].Targets[0].Actions, 1) - assert.Equal(t, TargetStatusCreate, plan.SubjectMappings[0].Targets[0].Actions[0].Status) - require.NotNil(t, plan.SubjectMappings[0].Targets[0].SubjectConditionSet) - assert.Equal(t, TargetStatusCreate, plan.SubjectMappings[0].Targets[0].SubjectConditionSet.Status) + require.NotNil(t, plan.SubjectMappings[0].Target) + assert.Equal(t, TargetStatusCreate, plan.SubjectMappings[0].Target.Status) + assert.Equal(t, []string{legacyAction.GetId()}, plan.SubjectMappings[0].Target.ActionSourceIDs) + assert.Equal(t, legacySCS.GetId(), plan.SubjectMappings[0].Target.SubjectConditionSetSourceID) require.Len(t, plan.RegisteredResources, 1) - require.Len(t, plan.RegisteredResources[0].Targets, 1) - require.Len(t, plan.RegisteredResources[0].Targets[0].Values, 1) - require.Len(t, plan.RegisteredResources[0].Targets[0].Values[0].ActionBindings, 1) - assert.Equal(t, TargetStatusCreate, plan.RegisteredResources[0].Targets[0].Values[0].ActionBindings[0].ActionTargetRef.Status) + require.NotNil(t, plan.RegisteredResources[0].Target) + require.Len(t, plan.RegisteredResources[0].Target.Values, 1) + require.Len(t, plan.RegisteredResources[0].Target.Values[0].ActionBindings, 1) + assert.Equal(t, legacyAction.GetId(), plan.RegisteredResources[0].Target.Values[0].ActionBindings[0].SourceActionID) require.Len(t, plan.ObligationTriggers, 1) - require.Len(t, plan.ObligationTriggers[0].Targets, 1) - require.NotNil(t, plan.ObligationTriggers[0].Targets[0].Action) - assert.Equal(t, TargetStatusCreate, plan.ObligationTriggers[0].Targets[0].Action.Status) + require.NotNil(t, plan.ObligationTriggers[0].Target) + assert.Equal(t, legacyAction.GetId(), plan.ObligationTriggers[0].Target.ActionSourceID) require.Len(t, plan.Namespaces, 1) assert.Equal(t, []string{legacyAction.GetId()}, plan.Namespaces[0].Actions) @@ -723,11 +719,7 @@ func TestPlannerPlanInteractiveReviewerLeavesCurrentUnresolvedPlanShapeUntouched assert.Equal(t, 1, reviewer.calls) require.Len(t, plan.RegisteredResources, 1) assert.Equal(t, ErrUndeterminedTargetMapping.Error()+": registered resource spans multiple target namespaces", plan.RegisteredResources[0].Unresolved) - assert.Empty(t, plan.RegisteredResources[0].Targets) - require.NotNil(t, plan.Unresolved) - require.Len(t, plan.Unresolved.RegisteredResources, 1) - assert.Equal(t, legacyResource.GetId(), plan.Unresolved.RegisteredResources[0].Resource.GetId()) - assert.Equal(t, plan.RegisteredResources[0].Unresolved, plan.Unresolved.RegisteredResources[0].Reason) + assert.Nil(t, plan.RegisteredResources[0].Target) } func TestPlannerPlanHuhInteractiveReviewerResolvesRegisteredResourceConflict(t *testing.T) { @@ -800,15 +792,12 @@ func TestPlannerPlanHuhInteractiveReviewerResolvesRegisteredResourceConflict(t * assert.Equal(t, 1, prompter.selectCalls) require.Len(t, plan.RegisteredResources, 1) assert.Empty(t, plan.RegisteredResources[0].Unresolved) - require.Len(t, plan.RegisteredResources[0].Targets, 1) - assert.Equal(t, TargetStatusCreate, plan.RegisteredResources[0].Targets[0].Status) - assert.True(t, sameNamespace(namespaceOne, plan.RegisteredResources[0].Targets[0].Namespace)) - require.Len(t, plan.RegisteredResources[0].Targets[0].Values, 1) - require.Len(t, plan.RegisteredResources[0].Targets[0].Values[0].ActionBindings, 1) - assert.Equal(t, "action-legacy", plan.RegisteredResources[0].Targets[0].Values[0].ActionBindings[0].SourceActionID) - require.NotNil(t, plan.RegisteredResources[0].Targets[0].Values[0].ActionBindings[0].ActionTargetRef) - assert.Equal(t, TargetStatusCreate, plan.RegisteredResources[0].Targets[0].Values[0].ActionBindings[0].ActionTargetRef.Status) - assert.Nil(t, plan.Unresolved) + require.NotNil(t, plan.RegisteredResources[0].Target) + assert.Equal(t, TargetStatusCreate, plan.RegisteredResources[0].Target.Status) + assert.True(t, sameNamespace(namespaceOne, plan.RegisteredResources[0].Target.Namespace)) + require.Len(t, plan.RegisteredResources[0].Target.Values, 1) + require.Len(t, plan.RegisteredResources[0].Target.Values[0].ActionBindings, 1) + assert.Equal(t, "action-legacy", plan.RegisteredResources[0].Target.Values[0].ActionBindings[0].SourceActionID) require.Len(t, plan.Actions, 1) require.Len(t, plan.Actions[0].Targets, 1) assert.Equal(t, TargetStatusCreate, plan.Actions[0].Targets[0].Status) diff --git a/otdfctl/migrations/namespacedpolicy/registered_resources_execute.go b/otdfctl/migrations/namespacedpolicy/registered_resources_execute.go index 3c8703ca68..cc47ec171a 100644 --- a/otdfctl/migrations/namespacedpolicy/registered_resources_execute.go +++ b/otdfctl/migrations/namespacedpolicy/registered_resources_execute.go @@ -20,14 +20,12 @@ func (e *Executor) executeRegisteredResources(ctx context.Context, plans []*Regi continue } - for _, target := range plan.Targets { - if target == nil { - continue - } + if plan.Target == nil { + continue + } - if err := e.executeRegisteredResourceTarget(ctx, plan, target); err != nil { - return err - } + if err := e.executeRegisteredResourceTarget(ctx, plan, plan.Target); err != nil { + return err } } @@ -60,8 +58,15 @@ func (e *Executor) createRegisteredResourceTarget(ctx context.Context, plan *Reg // Create the parent RR only when the plan did not already select an existing // target RR to reuse for this namespace. - created := target.Existing - if created == nil { + created, hasExistingParent, err := e.existingRegisteredResource(ctx, target) + if err != nil { + target.Execution = &ExecutionResult{ + RunID: e.runID, + Failure: err.Error(), + } + return fmt.Errorf("load registered resource %q target %q: %w", plan.Source.GetId(), namespaceLabel(target.Namespace), err) + } + if !hasExistingParent { var err error created, err = e.handler.CreateRegisteredResource( ctx, @@ -128,6 +133,18 @@ func (e *Executor) createRegisteredResourceTarget(ctx context.Context, plan *Reg return nil } +func (e *Executor) existingRegisteredResource(ctx context.Context, target *RegisteredResourceTargetPlan) (*policy.RegisteredResource, bool, error) { + if target == nil || target.ExistingID == "" { + return nil, false, nil + } + + resource, err := e.handler.GetRegisteredResource(ctx, target.ExistingID, "", "") + if err != nil { + return nil, true, err + } + return resource, true, nil +} + func (e *Executor) createRegisteredResourceValue(ctx context.Context, target *RegisteredResourceTargetPlan, valuePlan *RegisteredResourceValuePlan) error { actionAttributeValues, err := e.registeredResourceActionAttributeValues(target.Namespace, valuePlan) if err != nil { diff --git a/otdfctl/migrations/namespacedpolicy/registered_resources_execute_test.go b/otdfctl/migrations/namespacedpolicy/registered_resources_execute_test.go index 7bba2e388c..405e7abf64 100644 --- a/otdfctl/migrations/namespacedpolicy/registered_resources_execute_test.go +++ b/otdfctl/migrations/namespacedpolicy/registered_resources_execute_test.go @@ -42,9 +42,9 @@ func TestExecuteRegisteredResources(t *testing.T) { Source: &policy.Action{Id: "action-2", Name: "standard-read"}, Targets: []*ActionTargetPlan{ { - Namespace: namespace1, - Status: TargetStatusExistingStandard, - Existing: &policy.Action{Id: "existing-standard-action-2", Name: "standard-read"}, + Namespace: namespace1, + Status: TargetStatusExistingStandard, + ExistingID: "existing-standard-action-2", }, }, }, @@ -60,46 +60,32 @@ func TestExecuteRegisteredResources(t *testing.T) { }, }, }, - Targets: []*RegisteredResourceTargetPlan{ - { - Namespace: namespace1, - Status: TargetStatusCreate, - Values: []*RegisteredResourceValuePlan{ - { - Source: &policy.RegisteredResourceValue{ - Id: "rrv-1", - Value: "repo-a", - Metadata: &common.Metadata{ - Labels: map[string]string{ - "classification": "secret", - }, + Target: &RegisteredResourceTargetPlan{ + Namespace: namespace1, + Status: TargetStatusCreate, + Values: []*RegisteredResourceValuePlan{ + { + Source: &policy.RegisteredResourceValue{ + Id: "rrv-1", + Value: "repo-a", + Metadata: &common.Metadata{ + Labels: map[string]string{ + "classification": "secret", }, }, - ActionBindings: []*RegisteredResourceActionBinding{ - { - SourceActionID: "action-1", - AttributeValue: &policy.Value{ - Id: "attribute-value-id-1", - Fqn: "https://example.com/attr/classification/value/secret", - }, - ActionTargetRef: &ActionBinding{ - SourceID: "action-1", - Namespace: namespace1, - Status: TargetStatusCreate, - TargetID: "stale-created-action-id", - }, + }, + ActionBindings: []*RegisteredResourceActionBinding{ + { + SourceActionID: "action-1", + AttributeValue: &policy.Value{ + Id: "attribute-value-id-1", + Fqn: "https://example.com/attr/classification/value/secret", }, - { - SourceActionID: "action-2", - AttributeValue: &policy.Value{ - Fqn: "https://example.com/attr/project/value/apollo", - }, - ActionTargetRef: &ActionBinding{ - SourceID: "action-2", - Namespace: namespace1, - Status: TargetStatusExistingStandard, - TargetID: "stale-standard-action-id", - }, + }, + { + SourceActionID: "action-2", + AttributeValue: &policy.Value{ + Fqn: "https://example.com/attr/project/value/apollo", }, }, }, @@ -160,14 +146,14 @@ func TestExecuteRegisteredResources(t *testing.T) { assert.Equal(t, "existing-standard-action-2", valueCall.ActionAttributeValues[1].GetActionId()) assert.Equal(t, "https://example.com/attr/project/value/apollo", valueCall.ActionAttributeValues[1].GetAttributeValueFqn()) - resourceTarget := plan.RegisteredResources[0].Targets[0] + resourceTarget := plan.RegisteredResources[0].Target require.NotNil(t, resourceTarget.Execution) assert.True(t, resourceTarget.Execution.Applied) assert.Equal(t, "created-rr-1", resourceTarget.Execution.CreatedTargetID) assert.Equal(t, "run-rr-123", resourceTarget.Execution.RunID) assert.Equal(t, "created-rr-1", resourceTarget.TargetID()) - valueTarget := plan.RegisteredResources[0].Targets[0].Values[0] + valueTarget := plan.RegisteredResources[0].Target.Values[0] require.NotNil(t, valueTarget.Execution) assert.True(t, valueTarget.Execution.Applied) assert.Equal(t, "created-rrv-1", valueTarget.Execution.CreatedTargetID) @@ -185,15 +171,13 @@ func TestExecuteRegisteredResources(t *testing.T) { RegisteredResources: []*RegisteredResourcePlan{ { Source: &policy.RegisteredResource{Id: "rr-1", Name: "repo"}, - Targets: []*RegisteredResourceTargetPlan{ - { - Namespace: namespace1, - Status: TargetStatusAlreadyMigrated, - Existing: &policy.RegisteredResource{Id: "migrated-rr-1", Name: "repo"}, - Values: []*RegisteredResourceValuePlan{ - { - Source: &policy.RegisteredResourceValue{Id: "rrv-1", Value: "repo-a"}, - }, + Target: &RegisteredResourceTargetPlan{ + Namespace: namespace1, + Status: TargetStatusAlreadyMigrated, + ExistingID: "migrated-rr-1", + Values: []*RegisteredResourceValuePlan{ + { + Source: &policy.RegisteredResourceValue{Id: "rrv-1", Value: "repo-a"}, }, }, }, @@ -207,9 +191,9 @@ func TestExecuteRegisteredResources(t *testing.T) { require.NoError(t, err) assert.Nil(t, handler.createdRegisteredResources) assert.Nil(t, handler.createdRegisteredResourceValues) - assert.Equal(t, "migrated-rr-1", plan.RegisteredResources[0].Targets[0].TargetID()) - assert.Nil(t, plan.RegisteredResources[0].Targets[0].Execution) - assert.Nil(t, plan.RegisteredResources[0].Targets[0].Values[0].Execution) + assert.Equal(t, "migrated-rr-1", plan.RegisteredResources[0].Target.TargetID()) + assert.Nil(t, plan.RegisteredResources[0].Target.Execution) + assert.Nil(t, plan.RegisteredResources[0].Target.Values[0].Execution) }, }, { @@ -219,12 +203,10 @@ func TestExecuteRegisteredResources(t *testing.T) { RegisteredResources: []*RegisteredResourcePlan{ { Source: &policy.RegisteredResource{Id: "rr-1", Name: "repo"}, - Targets: []*RegisteredResourceTargetPlan{ - { - Namespace: namespace1, - Status: TargetStatusUnresolved, - Reason: ErrDuplicateCanonicalMatch.Error(), - }, + Target: &RegisteredResourceTargetPlan{ + Namespace: namespace1, + Status: TargetStatusUnresolved, + Reason: ErrDuplicateCanonicalMatch.Error(), }, }, }, @@ -263,34 +245,26 @@ func TestExecuteRegisteredResources(t *testing.T) { RegisteredResources: []*RegisteredResourcePlan{ { Source: &policy.RegisteredResource{Id: "rr-1", Name: "repo"}, - Targets: []*RegisteredResourceTargetPlan{ - { - Namespace: namespace1, - Status: TargetStatusCreate, - Existing: &policy.RegisteredResource{ - Id: "existing-rr-1", - Name: "repo", - Values: []*policy.RegisteredResourceValue{ - {Id: "existing-rrv-1", Value: "repo-a"}, - }, - }, - Values: []*RegisteredResourceValuePlan{ - { - Source: &policy.RegisteredResourceValue{Id: "rrv-1", Value: "repo-a"}, - ActionBindings: []*RegisteredResourceActionBinding{ - { - SourceActionID: "action-1", - AttributeValue: &policy.Value{Id: "attribute-value-id-1"}, - }, + Target: &RegisteredResourceTargetPlan{ + Namespace: namespace1, + Status: TargetStatusCreate, + ExistingID: "existing-rr-1", + Values: []*RegisteredResourceValuePlan{ + { + Source: &policy.RegisteredResourceValue{Id: "rrv-1", Value: "repo-a"}, + ActionBindings: []*RegisteredResourceActionBinding{ + { + SourceActionID: "action-1", + AttributeValue: &policy.Value{Id: "attribute-value-id-1"}, }, }, - { - Source: &policy.RegisteredResourceValue{Id: "rrv-2", Value: "repo-b"}, - ActionBindings: []*RegisteredResourceActionBinding{ - { - SourceActionID: "action-1", - AttributeValue: &policy.Value{Id: "attribute-value-id-2"}, - }, + }, + { + Source: &policy.RegisteredResourceValue{Id: "rrv-2", Value: "repo-b"}, + ActionBindings: []*RegisteredResourceActionBinding{ + { + SourceActionID: "action-1", + AttributeValue: &policy.Value{Id: "attribute-value-id-2"}, }, }, }, @@ -310,6 +284,15 @@ func TestExecuteRegisteredResources(t *testing.T) { "existing-rr-1": {Id: "created-rrv-2", Value: "repo-b"}, }, }, + registeredResourcesByID: map[string]*policy.RegisteredResource{ + "existing-rr-1": { + Id: "existing-rr-1", + Name: "repo", + Values: []*policy.RegisteredResourceValue{ + {Id: "existing-rrv-1", Value: "repo-a"}, + }, + }, + }, }, assert: func(t *testing.T, err error, _ *Executor, handler *mockExecutorHandler, plan *Plan) { t.Helper() @@ -320,7 +303,7 @@ func TestExecuteRegisteredResources(t *testing.T) { require.Contains(t, handler.createdRegisteredResourceValues["rrv-2"], "existing-rr-1") assert.NotContains(t, handler.createdRegisteredResourceValues, "rrv-1") - target := plan.RegisteredResources[0].Targets[0] + target := plan.RegisteredResources[0].Target require.NotNil(t, target.Execution) assert.True(t, target.Execution.Applied) assert.Equal(t, "existing-rr-1", target.Execution.CreatedTargetID) @@ -344,11 +327,9 @@ func TestExecuteRegisteredResources(t *testing.T) { RegisteredResources: []*RegisteredResourcePlan{ { Source: &policy.RegisteredResource{Id: "rr-1", Name: "repo"}, - Targets: []*RegisteredResourceTargetPlan{ - { - Namespace: namespace1, - Status: TargetStatusCreate, - }, + Target: &RegisteredResourceTargetPlan{ + Namespace: namespace1, + Status: TargetStatusCreate, }, }, }, @@ -366,8 +347,8 @@ func TestExecuteRegisteredResources(t *testing.T) { require.Error(t, err) require.Contains(t, handler.createdRegisteredResources, "rr-1") - require.NotNil(t, plan.RegisteredResources[0].Targets[0].Execution) - assert.Equal(t, "boom", plan.RegisteredResources[0].Targets[0].Execution.Failure) + require.NotNil(t, plan.RegisteredResources[0].Target.Execution) + assert.Equal(t, "boom", plan.RegisteredResources[0].Target.Execution.Failure) }, }, { @@ -377,23 +358,16 @@ func TestExecuteRegisteredResources(t *testing.T) { RegisteredResources: []*RegisteredResourcePlan{ { Source: &policy.RegisteredResource{Id: "rr-1", Name: "repo"}, - Targets: []*RegisteredResourceTargetPlan{ - { - Namespace: namespace1, - Status: TargetStatusCreate, - Values: []*RegisteredResourceValuePlan{ - { - Source: &policy.RegisteredResourceValue{Id: "rrv-1", Value: "repo-a"}, - ActionBindings: []*RegisteredResourceActionBinding{ - { - SourceActionID: "missing-action", - AttributeValue: &policy.Value{Id: "attribute-value-id-1"}, - ActionTargetRef: &ActionBinding{ - SourceID: "missing-action", - Namespace: namespace1, - Status: TargetStatusCreate, - }, - }, + Target: &RegisteredResourceTargetPlan{ + Namespace: namespace1, + Status: TargetStatusCreate, + Values: []*RegisteredResourceValuePlan{ + { + Source: &policy.RegisteredResourceValue{Id: "rrv-1", Value: "repo-a"}, + ActionBindings: []*RegisteredResourceActionBinding{ + { + SourceActionID: "missing-action", + AttributeValue: &policy.Value{Id: "attribute-value-id-1"}, }, }, }, @@ -423,10 +397,10 @@ func TestExecuteRegisteredResources(t *testing.T) { require.Error(t, err) require.Contains(t, handler.createdRegisteredResources, "rr-1") assert.Nil(t, handler.createdRegisteredResourceValues) - require.NotNil(t, plan.RegisteredResources[0].Targets[0].Execution) - assert.True(t, plan.RegisteredResources[0].Targets[0].Execution.Applied) - require.NotNil(t, plan.RegisteredResources[0].Targets[0].Values[0].Execution) - assert.Contains(t, plan.RegisteredResources[0].Targets[0].Values[0].Execution.Failure, `missing migrated target: action "missing-action" target "https://example.com"`) + require.NotNil(t, plan.RegisteredResources[0].Target.Execution) + assert.True(t, plan.RegisteredResources[0].Target.Execution.Applied) + require.NotNil(t, plan.RegisteredResources[0].Target.Values[0].Execution) + assert.Contains(t, plan.RegisteredResources[0].Target.Values[0].Execution.Failure, `missing migrated target: action "missing-action" target "https://example.com"`) }, }, { @@ -447,23 +421,16 @@ func TestExecuteRegisteredResources(t *testing.T) { RegisteredResources: []*RegisteredResourcePlan{ { Source: &policy.RegisteredResource{Id: "rr-1", Name: "repo"}, - Targets: []*RegisteredResourceTargetPlan{ - { - Namespace: namespace1, - Status: TargetStatusCreate, - Values: []*RegisteredResourceValuePlan{ - { - Source: &policy.RegisteredResourceValue{Id: "rrv-1", Value: "repo-a"}, - ActionBindings: []*RegisteredResourceActionBinding{ - { - SourceActionID: "action-1", - AttributeValue: &policy.Value{Id: "attribute-value-id-1"}, - ActionTargetRef: &ActionBinding{ - SourceID: "action-1", - Namespace: namespace1, - Status: TargetStatusCreate, - }, - }, + Target: &RegisteredResourceTargetPlan{ + Namespace: namespace1, + Status: TargetStatusCreate, + Values: []*RegisteredResourceValuePlan{ + { + Source: &policy.RegisteredResourceValue{Id: "rrv-1", Value: "repo-a"}, + ActionBindings: []*RegisteredResourceActionBinding{ + { + SourceActionID: "action-1", + AttributeValue: &policy.Value{Id: "attribute-value-id-1"}, }, }, }, @@ -495,10 +462,10 @@ func TestExecuteRegisteredResources(t *testing.T) { require.Error(t, err) require.Contains(t, handler.createdRegisteredResourceValues, "rrv-1") - require.NotNil(t, plan.RegisteredResources[0].Targets[0].Execution) - assert.True(t, plan.RegisteredResources[0].Targets[0].Execution.Applied) - require.NotNil(t, plan.RegisteredResources[0].Targets[0].Values[0].Execution) - assert.Equal(t, "boom", plan.RegisteredResources[0].Targets[0].Values[0].Execution.Failure) + require.NotNil(t, plan.RegisteredResources[0].Target.Execution) + assert.True(t, plan.RegisteredResources[0].Target.Execution.Applied) + require.NotNil(t, plan.RegisteredResources[0].Target.Values[0].Execution) + assert.Equal(t, "boom", plan.RegisteredResources[0].Target.Values[0].Execution.Failure) }, }, } diff --git a/otdfctl/migrations/namespacedpolicy/subject_condition_sets_execute_test.go b/otdfctl/migrations/namespacedpolicy/subject_condition_sets_execute_test.go index 74c292d24a..9fc32606a3 100644 --- a/otdfctl/migrations/namespacedpolicy/subject_condition_sets_execute_test.go +++ b/otdfctl/migrations/namespacedpolicy/subject_condition_sets_execute_test.go @@ -63,9 +63,9 @@ func TestExecuteSubjectConditionSets(t *testing.T) { Status: TargetStatusCreate, }, { - Namespace: namespace2, - Status: TargetStatusAlreadyMigrated, - Existing: &policy.SubjectConditionSet{Id: "migrated-scs-1"}, + Namespace: namespace2, + Status: TargetStatusAlreadyMigrated, + ExistingID: "migrated-scs-1", }, }, }, @@ -97,7 +97,7 @@ func TestExecuteSubjectConditionSets(t *testing.T) { createdTarget := plan.SubjectConditionSets[0].Targets[0] assert.Equal(t, TargetStatusCreate, createdTarget.Status) - assert.Nil(t, createdTarget.Existing) + assert.Empty(t, createdTarget.ExistingID) require.NotNil(t, createdTarget.Execution) assert.True(t, createdTarget.Execution.Applied) assert.Equal(t, "created-scs-1", createdTarget.Execution.CreatedTargetID) diff --git a/otdfctl/migrations/namespacedpolicy/subject_mappings_execute.go b/otdfctl/migrations/namespacedpolicy/subject_mappings_execute.go index 6bf245f3cf..a44b97a267 100644 --- a/otdfctl/migrations/namespacedpolicy/subject_mappings_execute.go +++ b/otdfctl/migrations/namespacedpolicy/subject_mappings_execute.go @@ -17,15 +17,12 @@ func (e *Executor) executeSubjectMappings(ctx context.Context, plans []*SubjectM continue } - // TODO: Need to fix this on the plan. A subject mapping plan should not have multiple targets. - for _, target := range mappingPlan.Targets { - if target == nil { - continue - } - - if err := e.executeSubjectMappingTarget(ctx, mappingPlan, target); err != nil { - return err - } + if mappingPlan.Target == nil { + continue + } + + if err := e.executeSubjectMappingTarget(ctx, mappingPlan, mappingPlan.Target); err != nil { + return err } } @@ -108,15 +105,15 @@ func (e *Executor) createSubjectMappingTarget(ctx context.Context, mappingPlan * } func (e *Executor) resolveSubjectMappingActions(mappingPlan *SubjectMappingPlan, target *SubjectMappingTargetPlan) ([]*policy.Action, error) { - actions := make([]*policy.Action, 0, len(target.Actions)) - for _, binding := range target.Actions { - if binding == nil || binding.SourceID == "" { + actions := make([]*policy.Action, 0, len(target.ActionSourceIDs)) + for _, sourceID := range target.ActionSourceIDs { + if sourceID == "" { return nil, fmt.Errorf("%w: subject mapping %q target %q", ErrMissingActionTarget, mappingPlan.Source.GetId(), namespaceLabel(target.Namespace)) } - targetID := e.cachedActionTargetID(binding.SourceID, target.Namespace) + targetID := e.cachedActionTargetID(sourceID, target.Namespace) if targetID == "" { - return nil, fmt.Errorf("%w: subject mapping %q action %q target %q", ErrMissingActionTarget, mappingPlan.Source.GetId(), binding.SourceID, namespaceLabel(target.Namespace)) + return nil, fmt.Errorf("%w: subject mapping %q action %q target %q", ErrMissingActionTarget, mappingPlan.Source.GetId(), sourceID, namespaceLabel(target.Namespace)) } actions = append(actions, &policy.Action{Id: targetID}) @@ -126,13 +123,13 @@ func (e *Executor) resolveSubjectMappingActions(mappingPlan *SubjectMappingPlan, } func (e *Executor) resolveSubjectMappingSubjectConditionSet(mappingPlan *SubjectMappingPlan, target *SubjectMappingTargetPlan) (string, error) { - if target.SubjectConditionSet == nil || target.SubjectConditionSet.SourceID == "" { + if target.SubjectConditionSetSourceID == "" { return "", fmt.Errorf("%w: subject mapping %q target %q", ErrMissingSubjectConditionSetTarget, mappingPlan.Source.GetId(), namespaceLabel(target.Namespace)) } - targetID := e.cachedScsTargetID(target.SubjectConditionSet.SourceID, target.Namespace) + targetID := e.cachedScsTargetID(target.SubjectConditionSetSourceID, target.Namespace) if targetID == "" { - return "", fmt.Errorf("%w: subject mapping %q subject condition set %q target %q", ErrMissingSubjectConditionSetTarget, mappingPlan.Source.GetId(), target.SubjectConditionSet.SourceID, namespaceLabel(target.Namespace)) + return "", fmt.Errorf("%w: subject mapping %q subject condition set %q target %q", ErrMissingSubjectConditionSetTarget, mappingPlan.Source.GetId(), target.SubjectConditionSetSourceID, namespaceLabel(target.Namespace)) } return targetID, nil diff --git a/otdfctl/migrations/namespacedpolicy/subject_mappings_execute_test.go b/otdfctl/migrations/namespacedpolicy/subject_mappings_execute_test.go index 71e9cceed9..68744fc254 100644 --- a/otdfctl/migrations/namespacedpolicy/subject_mappings_execute_test.go +++ b/otdfctl/migrations/namespacedpolicy/subject_mappings_execute_test.go @@ -66,23 +66,11 @@ func TestExecuteSubjectMappings(t *testing.T) { }, }, }, - Targets: []*SubjectMappingTargetPlan{ - { - Namespace: namespace1, - Status: TargetStatusCreate, - Actions: []*ActionBinding{ - { - SourceID: "action-1", - Namespace: namespace1, - Status: TargetStatusCreate, - }, - }, - SubjectConditionSet: &SubjectConditionSetBinding{ - SourceID: "scs-1", - Namespace: namespace1, - Status: TargetStatusCreate, - }, - }, + Target: &SubjectMappingTargetPlan{ + Namespace: namespace1, + Status: TargetStatusCreate, + ActionSourceIDs: []string{"action-1"}, + SubjectConditionSetSourceID: "scs-1", }, }, }, @@ -125,9 +113,9 @@ func TestExecuteSubjectMappings(t *testing.T) { migrationLabelRun: "run-789", }, call.Metadata.GetLabels()) - target := plan.SubjectMappings[0].Targets[0] + target := plan.SubjectMappings[0].Target assert.Equal(t, TargetStatusCreate, target.Status) - assert.Nil(t, target.Existing) + assert.Empty(t, target.ExistingID) require.NotNil(t, target.Execution) assert.True(t, target.Execution.Applied) assert.Equal(t, "mapping-target-1", target.Execution.CreatedTargetID) @@ -142,12 +130,10 @@ func TestExecuteSubjectMappings(t *testing.T) { SubjectMappings: []*SubjectMappingPlan{ { Source: &policy.SubjectMapping{Id: "mapping-1"}, - Targets: []*SubjectMappingTargetPlan{ - { - Namespace: namespace1, - Status: TargetStatusAlreadyMigrated, - Existing: &policy.SubjectMapping{Id: "mapping-target-1"}, - }, + Target: &SubjectMappingTargetPlan{ + Namespace: namespace1, + Status: TargetStatusAlreadyMigrated, + ExistingID: "mapping-target-1", }, }, }, @@ -158,8 +144,8 @@ func TestExecuteSubjectMappings(t *testing.T) { require.NoError(t, err) assert.Empty(t, handler.createdSubjectMappings) - assert.Equal(t, "mapping-target-1", plan.SubjectMappings[0].Targets[0].TargetID()) - assert.Nil(t, plan.SubjectMappings[0].Targets[0].Execution) + assert.Equal(t, "mapping-target-1", plan.SubjectMappings[0].Target.TargetID()) + assert.Nil(t, plan.SubjectMappings[0].Target.Execution) }, }, { @@ -169,12 +155,10 @@ func TestExecuteSubjectMappings(t *testing.T) { SubjectMappings: []*SubjectMappingPlan{ { Source: &policy.SubjectMapping{Id: "mapping-1"}, - Targets: []*SubjectMappingTargetPlan{ - { - Namespace: namespace1, - Status: TargetStatusUnresolved, - Reason: "missing target namespace mapping", - }, + Target: &SubjectMappingTargetPlan{ + Namespace: namespace1, + Status: TargetStatusUnresolved, + Reason: "missing target namespace mapping", }, }, }, @@ -201,11 +185,9 @@ func TestExecuteSubjectMappings(t *testing.T) { SubjectMappings: []*SubjectMappingPlan{ { Source: &policy.SubjectMapping{Id: "mapping-1"}, - Targets: []*SubjectMappingTargetPlan{ - { - Namespace: namespace1, - Status: TargetStatusAlreadyMigrated, - }, + Target: &SubjectMappingTargetPlan{ + Namespace: namespace1, + Status: TargetStatusAlreadyMigrated, }, }, }, @@ -231,23 +213,11 @@ func TestExecuteSubjectMappings(t *testing.T) { Id: "av-1", }, }, - Targets: []*SubjectMappingTargetPlan{ - { - Namespace: namespace1, - Status: TargetStatusCreate, - Actions: []*ActionBinding{ - { - SourceID: "action-1", - Namespace: namespace1, - Status: TargetStatusCreate, - }, - }, - SubjectConditionSet: &SubjectConditionSetBinding{ - SourceID: "scs-1", - Namespace: namespace1, - Status: TargetStatusAlreadyMigrated, - }, - }, + Target: &SubjectMappingTargetPlan{ + Namespace: namespace1, + Status: TargetStatusCreate, + ActionSourceIDs: []string{"action-1"}, + SubjectConditionSetSourceID: "scs-1", }, }, }, @@ -270,9 +240,9 @@ func TestExecuteSubjectMappings(t *testing.T) { Source: &policy.Action{Id: "action-1", Name: "decrypt"}, Targets: []*ActionTargetPlan{ { - Namespace: namespace1, - Status: TargetStatusAlreadyMigrated, - Existing: &policy.Action{Id: "action-target-1"}, + Namespace: namespace1, + Status: TargetStatusAlreadyMigrated, + ExistingID: "action-target-1", }, }, }, @@ -285,23 +255,11 @@ func TestExecuteSubjectMappings(t *testing.T) { Id: "av-1", }, }, - Targets: []*SubjectMappingTargetPlan{ - { - Namespace: namespace1, - Status: TargetStatusCreate, - Actions: []*ActionBinding{ - { - SourceID: "action-1", - Namespace: namespace1, - Status: TargetStatusAlreadyMigrated, - }, - }, - SubjectConditionSet: &SubjectConditionSetBinding{ - SourceID: "scs-1", - Namespace: namespace1, - Status: TargetStatusCreate, - }, - }, + Target: &SubjectMappingTargetPlan{ + Namespace: namespace1, + Status: TargetStatusCreate, + ActionSourceIDs: []string{"action-1"}, + SubjectConditionSetSourceID: "scs-1", }, }, }, @@ -327,10 +285,8 @@ func TestExecuteSubjectMappings(t *testing.T) { Id: "av-1", }, }, - Targets: []*SubjectMappingTargetPlan{ - { - Status: TargetStatusCreate, - }, + Target: &SubjectMappingTargetPlan{ + Status: TargetStatusCreate, }, }, }, @@ -353,9 +309,9 @@ func TestExecuteSubjectMappings(t *testing.T) { Source: &policy.Action{Id: "action-1", Name: "decrypt"}, Targets: []*ActionTargetPlan{ { - Namespace: namespace1, - Status: TargetStatusAlreadyMigrated, - Existing: &policy.Action{Id: "action-target-1"}, + Namespace: namespace1, + Status: TargetStatusAlreadyMigrated, + ExistingID: "action-target-1", }, }, }, @@ -365,9 +321,9 @@ func TestExecuteSubjectMappings(t *testing.T) { Source: &policy.SubjectConditionSet{Id: "scs-1"}, Targets: []*SubjectConditionSetTargetPlan{ { - Namespace: namespace1, - Status: TargetStatusAlreadyMigrated, - Existing: &policy.SubjectConditionSet{Id: "scs-target-1"}, + Namespace: namespace1, + Status: TargetStatusAlreadyMigrated, + ExistingID: "scs-target-1", }, }, }, @@ -380,23 +336,11 @@ func TestExecuteSubjectMappings(t *testing.T) { Id: "av-1", }, }, - Targets: []*SubjectMappingTargetPlan{ - { - Namespace: namespace1, - Status: TargetStatusCreate, - Actions: []*ActionBinding{ - { - SourceID: "action-1", - Namespace: namespace1, - Status: TargetStatusAlreadyMigrated, - }, - }, - SubjectConditionSet: &SubjectConditionSetBinding{ - SourceID: "scs-1", - Namespace: namespace1, - Status: TargetStatusAlreadyMigrated, - }, - }, + Target: &SubjectMappingTargetPlan{ + Namespace: namespace1, + Status: TargetStatusCreate, + ActionSourceIDs: []string{"action-1"}, + SubjectConditionSetSourceID: "scs-1", }, }, }, @@ -414,8 +358,8 @@ func TestExecuteSubjectMappings(t *testing.T) { require.Error(t, err) require.Contains(t, handler.createdSubjectMappings, "mapping-1") - require.NotNil(t, plan.SubjectMappings[0].Targets[0].Execution) - assert.Equal(t, ErrMissingCreatedTargetID.Error(), plan.SubjectMappings[0].Targets[0].Execution.Failure) + require.NotNil(t, plan.SubjectMappings[0].Target.Execution) + assert.Equal(t, ErrMissingCreatedTargetID.Error(), plan.SubjectMappings[0].Target.Execution.Failure) }, }, { @@ -425,11 +369,9 @@ func TestExecuteSubjectMappings(t *testing.T) { SubjectMappings: []*SubjectMappingPlan{ { Source: &policy.SubjectMapping{Id: "mapping-1"}, - Targets: []*SubjectMappingTargetPlan{ - { - Namespace: namespace1, - Status: TargetStatus("bogus"), - }, + Target: &SubjectMappingTargetPlan{ + Namespace: namespace1, + Status: TargetStatus("bogus"), }, }, }, @@ -458,9 +400,9 @@ func TestExecuteSubjectMappings(t *testing.T) { Source: &policy.Action{Id: "action-1", Name: "decrypt"}, Targets: []*ActionTargetPlan{ { - Namespace: namespace1, - Status: TargetStatusAlreadyMigrated, - Existing: &policy.Action{Id: "action-target-1"}, + Namespace: namespace1, + Status: TargetStatusAlreadyMigrated, + ExistingID: "action-target-1", }, }, }, @@ -470,9 +412,9 @@ func TestExecuteSubjectMappings(t *testing.T) { Source: &policy.SubjectConditionSet{Id: "scs-1"}, Targets: []*SubjectConditionSetTargetPlan{ { - Namespace: namespace1, - Status: TargetStatusAlreadyMigrated, - Existing: &policy.SubjectConditionSet{Id: "scs-target-1"}, + Namespace: namespace1, + Status: TargetStatusAlreadyMigrated, + ExistingID: "scs-target-1", }, }, }, @@ -485,23 +427,11 @@ func TestExecuteSubjectMappings(t *testing.T) { Id: "av-1", }, }, - Targets: []*SubjectMappingTargetPlan{ - { - Namespace: namespace1, - Status: TargetStatusCreate, - Actions: []*ActionBinding{ - { - SourceID: "action-1", - Namespace: namespace1, - Status: TargetStatusAlreadyMigrated, - }, - }, - SubjectConditionSet: &SubjectConditionSetBinding{ - SourceID: "scs-1", - Namespace: namespace1, - Status: TargetStatusAlreadyMigrated, - }, - }, + Target: &SubjectMappingTargetPlan{ + Namespace: namespace1, + Status: TargetStatusCreate, + ActionSourceIDs: []string{"action-1"}, + SubjectConditionSetSourceID: "scs-1", }, }, }, @@ -522,8 +452,8 @@ func TestExecuteSubjectMappings(t *testing.T) { require.Error(t, err) require.Contains(t, handler.createdSubjectMappings, "mapping-1") - require.NotNil(t, plan.SubjectMappings[0].Targets[0].Execution) - assert.Equal(t, "boom", plan.SubjectMappings[0].Targets[0].Execution.Failure) + require.NotNil(t, plan.SubjectMappings[0].Target.Execution) + assert.Equal(t, "boom", plan.SubjectMappings[0].Target.Execution.Failure) }, }, } @@ -558,8 +488,8 @@ func TestSubjectMappingTargetIDPrefersExecutionResult(t *testing.T) { t.Parallel() target := &SubjectMappingTargetPlan{ - Namespace: &policy.Namespace{Id: "ns-2", Fqn: "https://example.net"}, - Existing: &policy.SubjectMapping{Id: "existing-target"}, + Namespace: &policy.Namespace{Id: "ns-2", Fqn: "https://example.net"}, + ExistingID: "existing-target", Execution: &ExecutionResult{ CreatedTargetID: "created-target", },