Skip to content

Commit 82b96f0

Browse files
authored
feat(policy): Allow the deletion of a key. (#2575)
### Proposed Changes 1.) Add the ability to delete a key under the unsafe service. 2.) Update changelog and release-please information >[!IMPORTANT] >When deleting a key the key id and the kas uri within the request body are >case-sensitive. Meaning they must match **exactly** what you have in the database. ### Checklist - [ ] I have added or updated unit tests - [ ] I have added or updated integration tests (if appropriate) - [ ] I have added or updated documentation ### Testing Instructions
1 parent 50882e1 commit 82b96f0

File tree

14 files changed

+244
-114
lines changed

14 files changed

+244
-114
lines changed

.github/release-please/release-please-manifest.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"lib/ocrypto": "0.3.0",
44
"lib/flattening": "0.1.3",
55
"lib/identifier": "0.0.2",
6-
"protocol/go": "0.6.0",
7-
"sdk": "0.6.0",
6+
"protocol/go": "0.6.2",
7+
"sdk": "0.6.1",
88
"service": "0.7.0"
9-
}
9+
}

protocol/go/CHANGELOG.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,24 @@
11
# Changelog
22

3-
## [0.6.0](https://github.com/opentdf/platform/compare/protocol/go/v0.5.0...protocol/go/v0.6.0) (2025-07-09)
3+
## [0.6.2](https://github.com/opentdf/platform/compare/protocol/go/v0.6.1...protocol/go/v0.6.2) (2025-07-22)
4+
5+
### Features
6+
7+
* **policy:** Add validation to delete keys [backport to release/protocol/go/v0.6] ([#2577](https://github.com/opentdf/platform/issues/2577)) ([f1f5819](https://github.com/opentdf/platform/commit/f1f5819f95eda5b98cf002a43bd47a4e5b2c62d0))
8+
9+
## [0.6.1](https://github.com/opentdf/platform/compare/protocol/go/v0.6.0...protocol/go/v0.6.1) (2025-07-22)
410

11+
### Features
12+
13+
* **policy:** Change return type for delete key proto. [backport to release/protocol/go/v0.6] ([#2568](https://github.com/opentdf/platform/issues/2568)) ([bb38eca](https://github.com/opentdf/platform/commit/bb38ecaf75feee91484b1a2f8e835e2fc57633d7))
14+
15+
## [0.6.0](https://github.com/opentdf/platform/compare/protocol/go/v0.5.0...protocol/go/v0.6.0) (2025-07-09)
516

617
### Features
718

819
* **authz:** sensible request limit upper bounds ([#2526](https://github.com/opentdf/platform/issues/2526)) ([b3093cc](https://github.com/opentdf/platform/commit/b3093cce2ffd1f1cdaec884967dc96a40caa2903))
920
* **policy:** Add list key mappings rpc. ([#2533](https://github.com/opentdf/platform/issues/2533)) ([fbc2724](https://github.com/opentdf/platform/commit/fbc2724a066b5e4121838a958cb926a1ab5bdcde))
1021

11-
1222
### Bug Fixes
1323

1424
* **core:** Allow 521 curve to be used ([#2485](https://github.com/opentdf/platform/issues/2485)) ([aaf43dc](https://github.com/opentdf/platform/commit/aaf43dc368b4cabbc9affa0a6075abd335aa57e3))

sdk/CHANGELOG.md

Lines changed: 6 additions & 76 deletions
Large diffs are not rendered by default.

service/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ require (
3333
github.com/opentdf/platform/lib/flattening v0.1.3
3434
github.com/opentdf/platform/lib/identifier v0.0.2
3535
github.com/opentdf/platform/lib/ocrypto v0.3.0
36-
github.com/opentdf/platform/protocol/go v0.5.0
36+
github.com/opentdf/platform/protocol/go v0.6.2
3737
github.com/opentdf/platform/sdk v0.5.0
3838
github.com/pressly/goose/v3 v3.24.3
3939
github.com/spf13/cobra v1.9.1

service/go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,8 +251,8 @@ github.com/opentdf/platform/lib/identifier v0.0.2 h1:h3zR+IZ/4/X5UOYUp/aTA0OcX1Q
251251
github.com/opentdf/platform/lib/identifier v0.0.2/go.mod h1:/tHnLlSVOq3qmbIYSvKrtuZchQfagenv4wG5twl4oRs=
252252
github.com/opentdf/platform/lib/ocrypto v0.3.0 h1:/nHlIj6kqZ9XT9M45vAbzoMV8USeCj7GRuhFR6JH+RA=
253253
github.com/opentdf/platform/lib/ocrypto v0.3.0/go.mod h1:VuVHTye/smLiRZ5Ls4sZ14R+PtN9Egwj8D1Hv5X9iP0=
254-
github.com/opentdf/platform/protocol/go v0.5.0 h1:C/jUpg+DfG5gdznT909UXzKktQPLCe2hgaXBmmwk/Z0=
255-
github.com/opentdf/platform/protocol/go v0.5.0/go.mod h1:FwoNd0HJaxGCZf74de/yFpVP4HEjkUMoF6Br79W0TBk=
254+
github.com/opentdf/platform/protocol/go v0.6.2 h1:seLTEP4xBRF2BG1vbuWzQqNo58g3wtkzCV+Z4ExRXnM=
255+
github.com/opentdf/platform/protocol/go v0.6.2/go.mod h1:FwoNd0HJaxGCZf74de/yFpVP4HEjkUMoF6Br79W0TBk=
256256
github.com/opentdf/platform/sdk v0.5.0 h1:K4a8kWUtt5EJktFC55egicsp9537SI1+bmJPMIsYrKg=
257257
github.com/opentdf/platform/sdk v0.5.0/go.mod h1:Qxwq9zjUVkBZs3xZUOPls5gdX4d0y2nsoZvJ93hyWAU=
258258
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=

service/integration/attribute_values_test.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -870,11 +870,15 @@ func (s *AttributeValuesSuite) Test_AssignPublicKeyToAttributeValue_Returns_Erro
870870

871871
func (s *AttributeValuesSuite) Test_AssignPublicKeyToAttributeValue_NotActiveKey_Fail() {
872872
var kasID string
873-
keyIDs := make([]string, 0)
873+
keys := make([]*policy.KasKey, 0)
874874
defer func() {
875-
for _, keyID := range keyIDs {
876-
// delete the kas key
877-
_, err := s.db.PolicyClient.DeleteKey(s.ctx, keyID)
875+
for _, key := range keys {
876+
r := &unsafe.UnsafeDeleteKasKeyRequest{
877+
Id: key.GetKey().GetId(),
878+
Kid: key.GetKey().GetKeyId(),
879+
KasUri: key.GetKasUri(),
880+
}
881+
_, err := s.db.PolicyClient.UnsafeDeleteKey(s.ctx, key, r)
878882
s.Require().NoError(err)
879883
}
880884

@@ -913,7 +917,7 @@ func (s *AttributeValuesSuite) Test_AssignPublicKeyToAttributeValue_NotActiveKey
913917
toBeRotatedKey, err := s.db.PolicyClient.CreateKey(s.ctx, kasKey)
914918
s.Require().NoError(err)
915919
s.NotNil(toBeRotatedKey)
916-
keyIDs = append(keyIDs, toBeRotatedKey.GetKasKey().GetKey().GetId())
920+
keys = append(keys, toBeRotatedKey.GetKasKey())
917921

918922
// rotate the key
919923
newKey := &kasregistry.RotateKeyRequest_NewKey{
@@ -927,7 +931,7 @@ func (s *AttributeValuesSuite) Test_AssignPublicKeyToAttributeValue_NotActiveKey
927931
rotatedInKey, err := s.db.PolicyClient.RotateKey(s.ctx, toBeRotatedKey.GetKasKey(), newKey)
928932
s.Require().NoError(err)
929933
s.NotNil(rotatedInKey)
930-
keyIDs = append(keyIDs, rotatedInKey.GetKasKey().GetKey().GetId())
934+
keys = append(keys, rotatedInKey.GetKasKey())
931935

932936
// Get an attribute value
933937
attrValue := s.f.GetAttributeValueKey("example.com/attr/attr1/value/value1")

service/integration/attributes_test.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1222,11 +1222,15 @@ func (s *AttributesSuite) Test_AssociatePublicKeyToAttribute_Returns_Error_When_
12221222

12231223
func (s *AttributesSuite) Test_AssociatePublicKeyToAttribute_NotActiveKey_Fail() {
12241224
var kasID string
1225-
keyIDs := make([]string, 0)
1225+
keys := make([]*policy.KasKey, 0)
12261226
defer func() {
1227-
for _, keyID := range keyIDs {
1228-
// delete the kas key
1229-
_, err := s.db.PolicyClient.DeleteKey(s.ctx, keyID)
1227+
for _, key := range keys {
1228+
r := &unsafe.UnsafeDeleteKasKeyRequest{
1229+
Id: key.GetKey().GetId(),
1230+
Kid: key.GetKey().GetKeyId(),
1231+
KasUri: key.GetKasUri(),
1232+
}
1233+
_, err := s.db.PolicyClient.UnsafeDeleteKey(s.ctx, key, r)
12301234
s.Require().NoError(err)
12311235
}
12321236

@@ -1265,7 +1269,7 @@ func (s *AttributesSuite) Test_AssociatePublicKeyToAttribute_NotActiveKey_Fail()
12651269
toBeRotatedKey, err := s.db.PolicyClient.CreateKey(s.ctx, kasKey)
12661270
s.Require().NoError(err)
12671271
s.NotNil(toBeRotatedKey)
1268-
keyIDs = append(keyIDs, toBeRotatedKey.GetKasKey().GetKey().GetId())
1272+
keys = append(keys, toBeRotatedKey.GetKasKey())
12691273

12701274
// rotate the key
12711275
newKey := &kasregistry.RotateKeyRequest_NewKey{
@@ -1279,7 +1283,7 @@ func (s *AttributesSuite) Test_AssociatePublicKeyToAttribute_NotActiveKey_Fail()
12791283
rotatedInKey, err := s.db.PolicyClient.RotateKey(s.ctx, toBeRotatedKey.GetKasKey(), newKey)
12801284
s.Require().NoError(err)
12811285
s.NotNil(rotatedInKey)
1282-
keyIDs = append(keyIDs, rotatedInKey.GetKasKey().GetKey().GetId())
1286+
keys = append(keys, rotatedInKey.GetKasKey())
12831287

12841288
resp, err := s.db.PolicyClient.AssignPublicKeyToAttribute(s.ctx, &attributes.AttributeKey{
12851289
AttributeId: s.f.GetAttributeKey("example.com/attr/attr1").ID,

service/integration/kas_registry_key_test.go

Lines changed: 100 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/opentdf/platform/protocol/go/policy/kasregistry"
1414
"github.com/opentdf/platform/protocol/go/policy/keymanagement"
1515
"github.com/opentdf/platform/protocol/go/policy/namespaces"
16+
"github.com/opentdf/platform/protocol/go/policy/unsafe"
1617
"github.com/opentdf/platform/service/internal/fixtures"
1718
"github.com/opentdf/platform/service/pkg/db"
1819
"github.com/stretchr/testify/suite"
@@ -150,7 +151,11 @@ func (s *KasRegistryKeySuite) Test_CreateKasKey_Success() {
150151
s.Equal(validKeyID1, resp.GetKasKey().GetKey().GetPrivateKeyCtx().GetKeyId())
151152
s.Nil(resp.GetKasKey().GetKey().GetProviderConfig())
152153

153-
_, err = s.db.PolicyClient.DeleteKey(s.ctx, resp.GetKasKey().GetKey().GetId())
154+
_, err = s.db.PolicyClient.UnsafeDeleteKey(s.ctx, resp.GetKasKey(), &unsafe.UnsafeDeleteKasKeyRequest{
155+
Id: resp.GetKasKey().GetKey().GetId(),
156+
KasUri: resp.GetKasKey().GetKasUri(),
157+
Kid: resp.GetKasKey().GetKey().GetKeyId(),
158+
})
154159
s.Require().NoError(err)
155160
}
156161

@@ -1505,6 +1510,89 @@ func (s *KasRegistryKeySuite) Test_ListKeyMappings_Multiple_Mixed_Mappings() {
15051510
s.Equal(int32(0), mappedResponse.GetPagination().GetNextOffset())
15061511
}
15071512

1513+
func (s *KasRegistryKeySuite) Test_UnsafeDeleteKey_InvalidId_Fail() {
1514+
resp, err := s.db.PolicyClient.UnsafeDeleteKey(s.ctx, &policy.KasKey{}, &unsafe.UnsafeDeleteKasKeyRequest{
1515+
Id: "invalid-uuid",
1516+
})
1517+
s.Require().Error(err)
1518+
s.Nil(resp)
1519+
s.Require().ErrorContains(err, db.ErrUUIDInvalid.Error())
1520+
}
1521+
1522+
func (s *KasRegistryKeySuite) Test_DeleteKey_WrongKasUriOrKid_Fail() {
1523+
// Create a key
1524+
req := kasregistry.CreateKeyRequest{
1525+
KasId: s.kasKeys[0].KeyAccessServerID,
1526+
KeyId: uuid.NewString(),
1527+
KeyAlgorithm: policy.Algorithm_ALGORITHM_EC_P256,
1528+
KeyMode: policy.KeyMode_KEY_MODE_CONFIG_ROOT_KEY,
1529+
PublicKeyCtx: &policy.PublicKeyCtx{Pem: keyCtx},
1530+
PrivateKeyCtx: &policy.PrivateKeyCtx{
1531+
WrappedKey: keyCtx,
1532+
KeyId: validKeyID1,
1533+
},
1534+
}
1535+
resp, err := s.db.PolicyClient.CreateKey(s.ctx, &req)
1536+
s.Require().NoError(err)
1537+
s.NotNil(resp)
1538+
1539+
defer func() {
1540+
r := unsafe.UnsafeDeleteKasKeyRequest{
1541+
Id: resp.GetKasKey().GetKey().GetId(),
1542+
KasUri: resp.GetKasKey().GetKasUri(),
1543+
Kid: resp.GetKasKey().GetKey().GetKeyId(),
1544+
}
1545+
_, err := s.db.PolicyClient.UnsafeDeleteKey(s.ctx, resp.GetKasKey(), &r)
1546+
s.Require().NoError(err)
1547+
}()
1548+
1549+
// Attempt to delete with incorrect Kid
1550+
deleteResp, err := s.db.PolicyClient.UnsafeDeleteKey(s.ctx, resp.GetKasKey(), &unsafe.UnsafeDeleteKasKeyRequest{Id: resp.GetKasKey().GetKey().GetId(), KasUri: resp.GetKasKey().GetKasUri(), Kid: "wrong-KID"})
1551+
s.Require().Error(err)
1552+
s.Nil(deleteResp)
1553+
s.Require().ErrorIs(err, db.ErrKIDMismatch)
1554+
1555+
deleteResp, err = s.db.PolicyClient.UnsafeDeleteKey(s.ctx, resp.GetKasKey(), &unsafe.UnsafeDeleteKasKeyRequest{Id: resp.GetKasKey().GetKey().GetId(), KasUri: "wrong-kas-uri", Kid: resp.GetKasKey().GetKey().GetKeyId()})
1556+
s.Require().Error(err)
1557+
s.Nil(deleteResp)
1558+
s.Require().ErrorIs(err, db.ErrKasURIMismatch)
1559+
}
1560+
1561+
func (s *KasRegistryKeySuite) Test_DeleteKey_Success() {
1562+
// Create KAS server
1563+
req := kasregistry.CreateKeyRequest{
1564+
KasId: s.kasKeys[0].KeyAccessServerID,
1565+
KeyId: uuid.NewString(),
1566+
KeyAlgorithm: policy.Algorithm_ALGORITHM_EC_P256,
1567+
KeyMode: policy.KeyMode_KEY_MODE_CONFIG_ROOT_KEY,
1568+
PublicKeyCtx: &policy.PublicKeyCtx{Pem: keyCtx},
1569+
PrivateKeyCtx: &policy.PrivateKeyCtx{
1570+
WrappedKey: keyCtx,
1571+
KeyId: validKeyID1,
1572+
},
1573+
}
1574+
resp, err := s.db.PolicyClient.CreateKey(s.ctx, &req)
1575+
s.Require().NoError(err)
1576+
s.NotNil(resp)
1577+
1578+
deleteResp, err := s.db.PolicyClient.UnsafeDeleteKey(s.ctx, resp.GetKasKey(), &unsafe.UnsafeDeleteKasKeyRequest{
1579+
Id: resp.GetKasKey().GetKey().GetId(),
1580+
Kid: resp.GetKasKey().GetKey().GetKeyId(),
1581+
KasUri: resp.GetKasKey().GetKasUri(),
1582+
})
1583+
s.Require().NoError(err)
1584+
s.NotNil(deleteResp)
1585+
s.Equal(resp.GetKasKey().GetKey().GetId(), deleteResp.GetId())
1586+
1587+
// Verify it's deleted
1588+
getResp, err := s.db.PolicyClient.GetKey(s.ctx, &kasregistry.GetKeyRequest_Id{
1589+
Id: resp.GetKasKey().GetKey().GetId(),
1590+
})
1591+
s.Require().Error(err)
1592+
s.Nil(getResp)
1593+
s.Require().ErrorContains(err, db.ErrNotFound.Error())
1594+
}
1595+
15081596
func (s *KasRegistryKeySuite) validateKeyMapping(mapping *kasregistry.KeyMapping, expectedKey *policy.KasKey, expectedNamespace []*policy.Namespace, expectedAttrDef []*policy.Attribute, expectedValue []*policy.Value) {
15091597
s.Equal(expectedKey.GetKey().GetKeyId(), mapping.GetKid())
15101598
s.Equal(expectedKey.GetKasUri(), mapping.GetKasUri())
@@ -1745,7 +1833,17 @@ func (s *KasRegistryKeySuite) cleanupKeys(keyIDs []string, keyAccessServerIDs []
17451833
s.Require().NoError(err)
17461834

17471835
for _, id := range keyIDs {
1748-
_, err := s.db.PolicyClient.DeleteKey(s.ctx, id)
1836+
key, err := s.db.PolicyClient.GetKey(s.ctx, &kasregistry.GetKeyRequest_Id{
1837+
Id: id,
1838+
})
1839+
s.Require().NoError(err)
1840+
s.NotNil(key)
1841+
r := unsafe.UnsafeDeleteKasKeyRequest{
1842+
Id: key.GetKey().GetId(),
1843+
KasUri: key.GetKasUri(),
1844+
Kid: key.GetKey().GetKeyId(),
1845+
}
1846+
_, err = s.db.PolicyClient.UnsafeDeleteKey(s.ctx, key, &r)
17491847
s.Require().NoError(err)
17501848
}
17511849
for _, id := range keyAccessServerIDs {

service/integration/kas_registry_test.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/opentdf/platform/protocol/go/common"
1010
"github.com/opentdf/platform/protocol/go/policy"
1111
"github.com/opentdf/platform/protocol/go/policy/kasregistry"
12+
"github.com/opentdf/platform/protocol/go/policy/unsafe"
1213

1314
"github.com/opentdf/platform/service/internal/fixtures"
1415
"github.com/opentdf/platform/service/pkg/db"
@@ -789,7 +790,11 @@ func (s *KasRegistrySuite) Test_DeleteKeyAccessServer_WithChildKeys_Fails() {
789790
s.Nil(deleted)
790791

791792
// Remove key to clean up
792-
_, err = s.db.PolicyClient.DeleteKey(s.ctx, createdKey.GetKasKey().GetKey().GetId())
793+
_, err = s.db.PolicyClient.UnsafeDeleteKey(s.ctx, createdKey.GetKasKey(), &unsafe.UnsafeDeleteKasKeyRequest{
794+
Id: createdKey.GetKasKey().GetKey().GetId(),
795+
Kid: createdKey.GetKasKey().GetKey().GetKeyId(),
796+
KasUri: createdKey.GetKasKey().GetKasUri(),
797+
})
793798
s.Require().NoError(err)
794799

795800
// Delete the KAS

service/integration/keymanagement_test.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/opentdf/platform/protocol/go/policy"
1212
"github.com/opentdf/platform/protocol/go/policy/kasregistry"
1313
"github.com/opentdf/platform/protocol/go/policy/keymanagement"
14+
"github.com/opentdf/platform/protocol/go/policy/unsafe"
1415
"github.com/opentdf/platform/service/internal/fixtures"
1516
"github.com/opentdf/platform/service/pkg/db"
1617
"github.com/stretchr/testify/suite"
@@ -389,10 +390,14 @@ func (s *KeyManagementSuite) Test_DeleteProviderConfig_InUse_Fails() {
389390
// Create a provider config
390391
pcIDs := make([]string, 0)
391392
var kasID string
392-
var keyID string
393+
var kasKey *policy.KasKey
393394
defer func() {
394-
if keyID != "" {
395-
_, err := s.db.PolicyClient.DeleteKey(s.ctx, keyID)
395+
if kasKey != nil {
396+
_, err := s.db.PolicyClient.UnsafeDeleteKey(s.ctx, kasKey, &unsafe.UnsafeDeleteKasKeyRequest{
397+
Id: kasKey.GetKey().GetId(),
398+
Kid: kasKey.GetKey().GetKeyId(),
399+
KasUri: kasKey.GetKasUri(),
400+
})
396401
s.Require().NoError(err)
397402
}
398403
if kasID != "" {
@@ -441,7 +446,7 @@ func (s *KeyManagementSuite) Test_DeleteProviderConfig_InUse_Fails() {
441446
})
442447
s.Require().NoError(err)
443448
s.NotNil(key)
444-
keyID = key.GetKasKey().GetKey().GetId()
449+
kasKey = key.GetKasKey()
445450

446451
_, err = s.db.PolicyClient.DeleteProviderConfig(s.ctx, pc.GetId())
447452
s.Require().Error(err)

0 commit comments

Comments
 (0)