Skip to content

Commit

Permalink
feat(policy): subject condition sets prune service/db (#1688)
Browse files Browse the repository at this point in the history
Resolves #1178
  • Loading branch information
jakedoublev authored Nov 6, 2024
1 parent ce289a4 commit 3cdd1b2
Show file tree
Hide file tree
Showing 7 changed files with 330 additions and 188 deletions.
373 changes: 187 additions & 186 deletions protocol/go/policy/objects.pb.go

Large diffs are not rendered by default.

59 changes: 59 additions & 0 deletions service/integration/subject_mappings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ func (s *SubjectMappingsSuite) SetupSuite() {
c := *Config
c.DB.Schema = "test_opentdf_subject_mappings"
s.db = fixtures.NewDBInterface(c)
s.ctx = context.Background()
s.f = fixtures.NewFixture(s.db)
s.ctx = context.Background()
s.f.Provision()
Expand Down Expand Up @@ -637,6 +638,64 @@ func (s *SubjectMappingsSuite) TestDeleteSubjectConditionSet_WithNonExistentId_F
s.Require().ErrorIs(err, db.ErrNotFound)
}

func (s *SubjectMappingsSuite) TestDeleteAllUnmappedSubjectConditionSets() {
// create two new subject condition sets, create a subject mapping with one of them, then verify only the unmapped is deleted
newSCS := &subjectmapping.SubjectConditionSetCreate{
SubjectSets: []*policy.SubjectSet{
{
ConditionGroups: []*policy.ConditionGroup{
{
Conditions: []*policy.Condition{
{
SubjectExternalSelectorValue: ".some_selector",
},
},
},
},
},
},
}

unmapped, err := s.db.PolicyClient.CreateSubjectConditionSet(s.ctx, newSCS)
s.Require().NoError(err)
s.NotNil(unmapped)

mapped, err := s.db.PolicyClient.CreateSubjectConditionSet(s.ctx, newSCS)
s.Require().NoError(err)
s.NotNil(mapped)

sm, err := s.db.PolicyClient.CreateSubjectMapping(s.ctx, &subjectmapping.CreateSubjectMappingRequest{
AttributeValueId: s.f.GetAttributeValueKey("example.net/attr/attr1/value/value2").ID,
Actions: []*policy.Action{fixtureActions[Decrypt]},
ExistingSubjectConditionSetId: mapped.GetId(),
})
s.Require().NoError(err)
s.NotNil(sm)

deleted, err := s.db.PolicyClient.DeleteAllUnmappedSubjectConditionSets(s.ctx)
s.Require().NoError(err)
s.NotEmpty(deleted)
unmappedDeleted := true
mappedDeleted := false
for _, scs := range deleted {
deletedID := scs.GetId()
if deletedID == unmapped.GetId() {
unmappedDeleted = true
}
if deletedID == mapped.GetId() {
mappedDeleted = true
}
}
s.True(unmappedDeleted)
s.False(mappedDeleted)

// cannot get after pruning
got, err := s.db.PolicyClient.GetSubjectConditionSet(s.ctx, unmapped.GetId())
s.Nil(got)
s.Require().Error(err)
s.ErrorIs(err, db.ErrNotFound)
}

func (s *SubjectMappingsSuite) TestUpdateSubjectConditionSet_NewSubjectSets() {
// create a new one, update nothing but the subject sets, and verify the solo update
newConditionSet := &subjectmapping.SubjectConditionSetCreate{
Expand Down
5 changes: 5 additions & 0 deletions service/policy/db/query.sql
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,11 @@ WHERE id = $1;
-- name: DeleteSubjectConditionSet :execrows
DELETE FROM subject_condition_set WHERE id = $1;

-- name: DeleteAllUnmappedSubjectConditionSets :many
DELETE FROM subject_condition_set
WHERE id NOT IN (SELECT DISTINCT sm.subject_condition_set_id FROM subject_mappings sm)
RETURNING id;

----------------------------------------------------------------
-- SUBJECT MAPPINGS
----------------------------------------------------------------
Expand Down
31 changes: 31 additions & 0 deletions service/policy/db/query.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions service/policy/db/subject_mappings.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,25 @@ func (c PolicyDBClient) DeleteSubjectConditionSet(ctx context.Context, id string
}, nil
}

// Deletes/prunes all subject condition sets not referenced within a subject mapping
func (c PolicyDBClient) DeleteAllUnmappedSubjectConditionSets(ctx context.Context) ([]*policy.SubjectConditionSet, error) {
deletedIDs, err := c.Queries.DeleteAllUnmappedSubjectConditionSets(ctx)
if err != nil {
return nil, db.WrapIfKnownInvalidQueryErr(err)
}
if len(deletedIDs) == 0 {
return nil, db.ErrNotFound
}

setList := make([]*policy.SubjectConditionSet, len(deletedIDs))
for i, id := range deletedIDs {
setList[i] = &policy.SubjectConditionSet{
Id: id,
}
}
return setList, nil
}

/*
Subject Mappings
*/
Expand Down
4 changes: 2 additions & 2 deletions service/policy/objects.proto
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ message SubjectMapping {
*/
message Condition {
// a selector for a field value on a flattened Entity Representation (such as from idP/LDAP)
string subject_external_selector_value = 1;
string subject_external_selector_value = 1 [ (buf.validate.field).required = true ];

// the evaluation operator of relation
SubjectMappingOperatorEnum operator = 2 [
Expand All @@ -163,7 +163,7 @@ message Condition {
];

// list of comparison values for the result of applying the subject_external_selector_value on a flattened Entity Representation (Subject), evaluated by the operator
repeated string subject_external_values = 3;
repeated string subject_external_values = 3 [(buf.validate.field).repeated.min_items = 1];
}

// A collection of Conditions evaluated by the boolean_operator provided
Expand Down
27 changes: 27 additions & 0 deletions service/policy/subjectmapping/subject_mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,3 +293,30 @@ func (s SubjectMappingService) DeleteSubjectConditionSet(ctx context.Context,
}
return rsp, nil
}

func (s SubjectMappingService) DeleteAllUnmappedSubjectConditionSets(ctx context.Context,
_ *sm.DeleteAllUnmappedSubjectConditionSetsRequest,
) (*sm.DeleteAllUnmappedSubjectConditionSetsResponse, error) {
rsp := &sm.DeleteAllUnmappedSubjectConditionSetsResponse{}
s.logger.Debug("deleting all unmapped subject condition sets")

auditParams := audit.PolicyEventParams{
ActionType: audit.ActionTypeDelete,
ObjectType: audit.ObjectTypeConditionSet,
}

deleted, err := s.dbClient.DeleteAllUnmappedSubjectConditionSets(ctx)
if err != nil {
s.logger.Audit.PolicyCRUDFailure(ctx, auditParams)
return nil, db.StatusifyError(err, db.ErrTextDeletionFailed)
}

// Log each pruned subject condition set to audit
for _, scs := range deleted {
auditParams.ObjectID = scs.GetId()
s.logger.Audit.PolicyCRUDSuccess(ctx, auditParams)
}

rsp.SubjectConditionSets = deleted
return rsp, nil
}

0 comments on commit 3cdd1b2

Please sign in to comment.