Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions server/datastore/mysql/host_certificate_templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,18 @@ func (ds *Datastore) DeleteHostCertificateTemplates(ctx context.Context, hostCer
return nil
}

// DeleteHostCertificateTemplate deletes a single host_certificate_template record
// identified by host_uuid and certificate_template_id.
func (ds *Datastore) DeleteHostCertificateTemplate(ctx context.Context, hostUUID string, certificateTemplateID uint) error {
const stmt = `DELETE FROM host_certificate_templates WHERE host_uuid = ? AND certificate_template_id = ?`

if _, err := ds.writer(ctx).ExecContext(ctx, stmt, hostUUID, certificateTemplateID); err != nil {
return ctxerr.Wrap(ctx, err, "delete host_certificate_template")
}

return nil
}

func (ds *Datastore) UpsertCertificateStatus(
ctx context.Context,
hostUUID string,
Expand Down
58 changes: 58 additions & 0 deletions server/datastore/mysql/host_certificate_templates_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func TestHostCertificateTemplates(t *testing.T) {
{"ListCertificateTemplatesForHosts", testListCertificateTemplatesForHosts},
{"GetCertificateTemplateForHostNoTeam", testGetCertificateTemplateForHostNoTeam},
{"BulkInsertAndDeleteHostCertificateTemplates", testBulkInsertAndDeleteHostCertificateTemplates},
{"DeleteHostCertificateTemplate", testDeleteHostCertificateTemplate},
{"UpsertHostCertificateTemplateStatus", testUpsertHostCertificateTemplateStatus},
{"CreatePendingCertificateTemplatesForExistingHosts", testCreatePendingCertificateTemplatesForExistingHosts},
{"CreatePendingCertificateTemplatesForNewHost", testCreatePendingCertificateTemplatesForNewHost},
Expand Down Expand Up @@ -474,6 +475,63 @@ func testBulkInsertAndDeleteHostCertificateTemplates(t *testing.T, ds *Datastore
})
}

func testDeleteHostCertificateTemplate(t *testing.T, ds *Datastore) {
ctx := t.Context()

t.Run("no error when deleting non-existent record", func(t *testing.T) {
defer TruncateTables(t, ds)

err := ds.DeleteHostCertificateTemplate(ctx, "non-existent-host", 999)
require.NoError(t, err)
})

t.Run("only deletes specified record", func(t *testing.T) {
defer TruncateTables(t, ds)
setup := createCertTemplateTestSetup(t, ctx, ds, "")

templateTwo, err := ds.CreateCertificateTemplate(ctx, &fleet.CertificateTemplate{
Name: "Cert2",
TeamID: setup.team.ID,
CertificateAuthorityID: setup.ca.ID,
SubjectName: "CN=Test Subject 2",
})
require.NoError(t, err)

// Insert multiple host certificate template records
hostCerts := []fleet.HostCertificateTemplate{
{HostUUID: "host-1", CertificateTemplateID: setup.template.ID, FleetChallenge: ptr.String("challenge-1"), Status: fleet.CertificateTemplateVerified, OperationType: fleet.MDMOperationTypeRemove, Name: setup.template.Name},
{HostUUID: "host-1", CertificateTemplateID: templateTwo.ID, FleetChallenge: ptr.String("challenge-2"), Status: fleet.CertificateTemplateVerified, OperationType: fleet.MDMOperationTypeInstall, Name: templateTwo.Name},
{HostUUID: "host-2", CertificateTemplateID: setup.template.ID, FleetChallenge: ptr.String("challenge-3"), Status: fleet.CertificateTemplateVerified, OperationType: fleet.MDMOperationTypeRemove, Name: setup.template.Name},
}
err = ds.BulkInsertHostCertificateTemplates(ctx, hostCerts)
require.NoError(t, err)

// Delete only host-1's first certificate
err = ds.DeleteHostCertificateTemplate(ctx, "host-1", setup.template.ID)
require.NoError(t, err)

// Verify only 2 records remain
var count int
err = ds.writer(ctx).GetContext(ctx, &count, "SELECT COUNT(*) FROM host_certificate_templates")
require.NoError(t, err)
require.Equal(t, 2, count)

// Verify the correct records remain
var remaining []struct {
HostUUID string `db:"host_uuid"`
CertificateTemplateID uint `db:"certificate_template_id"`
}
err = ds.writer(ctx).SelectContext(ctx, &remaining,
"SELECT host_uuid, certificate_template_id FROM host_certificate_templates ORDER BY host_uuid, certificate_template_id")
require.NoError(t, err)
require.Len(t, remaining, 2)
require.Equal(t, "host-1", remaining[0].HostUUID)
require.Equal(t, templateTwo.ID, remaining[0].CertificateTemplateID)
require.Equal(t, "host-2", remaining[1].HostUUID)
require.Equal(t, setup.template.ID, remaining[1].CertificateTemplateID)
})
}

func testUpsertHostCertificateTemplateStatus(t *testing.T, ds *Datastore) {
ctx := t.Context()

Expand Down
3 changes: 3 additions & 0 deletions server/fleet/datastore.go
Original file line number Diff line number Diff line change
Expand Up @@ -2573,6 +2573,9 @@ type Datastore interface {
// DeleteHostCertificateTemplates deletes specific host_certificate_templates records
// identified by (host_uuid, certificate_template_id) pairs.
DeleteHostCertificateTemplates(ctx context.Context, hostCertTemplates []HostCertificateTemplate) error
// DeleteHostCertificateTemplate deletes a single host_certificate_template record
// identified by host_uuid and certificate_template_id.
DeleteHostCertificateTemplate(ctx context.Context, hostUUID string, certificateTemplateID uint) error

// ListAndroidHostUUIDsWithPendingCertificateTemplates returns hosts that have
// certificate templates in 'pending' status ready for delivery.
Expand Down
12 changes: 12 additions & 0 deletions server/mock/datastore_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -1685,6 +1685,8 @@ type BulkInsertHostCertificateTemplatesFunc func(ctx context.Context, hostCertTe

type DeleteHostCertificateTemplatesFunc func(ctx context.Context, hostCertTemplates []fleet.HostCertificateTemplate) error

type DeleteHostCertificateTemplateFunc func(ctx context.Context, hostUUID string, certificateTemplateID uint) error

type ListAndroidHostUUIDsWithPendingCertificateTemplatesFunc func(ctx context.Context, offset int, limit int) ([]string, error)

type GetAndTransitionCertificateTemplatesToDeliveringFunc func(ctx context.Context, hostUUID string) (*fleet.HostCertificateTemplatesForDelivery, error)
Expand Down Expand Up @@ -4195,6 +4197,9 @@ type DataStore struct {
DeleteHostCertificateTemplatesFunc DeleteHostCertificateTemplatesFunc
DeleteHostCertificateTemplatesFuncInvoked bool

DeleteHostCertificateTemplateFunc DeleteHostCertificateTemplateFunc
DeleteHostCertificateTemplateFuncInvoked bool

ListAndroidHostUUIDsWithPendingCertificateTemplatesFunc ListAndroidHostUUIDsWithPendingCertificateTemplatesFunc
ListAndroidHostUUIDsWithPendingCertificateTemplatesFuncInvoked bool

Expand Down Expand Up @@ -10039,6 +10044,13 @@ func (s *DataStore) DeleteHostCertificateTemplates(ctx context.Context, hostCert
return s.DeleteHostCertificateTemplatesFunc(ctx, hostCertTemplates)
}

func (s *DataStore) DeleteHostCertificateTemplate(ctx context.Context, hostUUID string, certificateTemplateID uint) error {
s.mu.Lock()
s.DeleteHostCertificateTemplateFuncInvoked = true
s.mu.Unlock()
return s.DeleteHostCertificateTemplateFunc(ctx, hostUUID, certificateTemplateID)
}

func (s *DataStore) ListAndroidHostUUIDsWithPendingCertificateTemplates(ctx context.Context, offset int, limit int) ([]string, error) {
s.mu.Lock()
s.ListAndroidHostUUIDsWithPendingCertificateTemplatesFuncInvoked = true
Expand Down
5 changes: 5 additions & 0 deletions server/service/certificates.go
Original file line number Diff line number Diff line change
Expand Up @@ -586,5 +586,10 @@ func (svc *Service) UpdateCertificateStatus(
return nil
}

// If operation_type is "remove" and status is "verified", delete the host_certificate_template row
if opType == fleet.MDMOperationTypeRemove && status == fleet.MDMDeliveryVerified {
return svc.ds.DeleteHostCertificateTemplate(ctx, host.UUID, certificateTemplateID)
}

return svc.ds.UpsertCertificateStatus(ctx, host.UUID, certificateTemplateID, status, detail, opType)
}
Loading