Add soft delete for revoked devices
Admins could only revoke devices, so never-enrolled and revoked inventory rows piled up with no way to remove them. Soft-delete is limited to REVOKED devices (revoke first), and ITAM GC now hard-deletes PENDING/REVOKED orphans with no API key, postures, or valid enrollment token—including user tombstones without history. Signed-off-by: Ludovic Vielle <ludovic@probo.com>
This commit is contained in:
@@ -31,6 +31,7 @@ const (
|
||||
ActionDeviceCreate = "itam:device:create"
|
||||
ActionDeviceEnroll = "itam:device:enroll"
|
||||
ActionDeviceRevoke = "itam:device:revoke"
|
||||
ActionDeviceDelete = "itam:device:delete"
|
||||
ActionDeviceAssignOwner = "itam:device:assign"
|
||||
|
||||
// DevicePosture actions
|
||||
|
||||
@@ -100,10 +100,18 @@ func (h *gcHandler) cleanup(ctx context.Context) error {
|
||||
return fmt.Errorf("cannot delete expired device enrollment tokens: %w", err)
|
||||
}
|
||||
|
||||
var device coredata.Device
|
||||
|
||||
devicesDeleted, err := device.DeleteOrphans(ctx, tx, now)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot delete orphan devices: %w", err)
|
||||
}
|
||||
|
||||
h.logger.InfoCtx(
|
||||
ctx,
|
||||
"itam garbage collector cleaned up",
|
||||
log.Int64("device_enrollment_tokens_deleted", tokensDeleted),
|
||||
log.Int64("orphan_devices_deleted", devicesDeleted),
|
||||
)
|
||||
|
||||
return nil
|
||||
|
||||
@@ -37,7 +37,7 @@ var FullAccessPolicy = policy.NewPolicy(
|
||||
"ITAM Full Access",
|
||||
policy.Allow(
|
||||
ActionDeviceList, ActionEmployeeDeviceList, ActionDeviceGet, ActionDeviceCreate,
|
||||
ActionDeviceEnroll, ActionDeviceRevoke, ActionDeviceAssignOwner,
|
||||
ActionDeviceEnroll, ActionDeviceRevoke, ActionDeviceDelete, ActionDeviceAssignOwner,
|
||||
ActionDevicePostureList,
|
||||
).WithSID("itam-full-access").When(organizationCondition),
|
||||
policy.Allow(ActionEmployeeDeviceGet).
|
||||
|
||||
@@ -58,6 +58,10 @@ var (
|
||||
// cannot be exchanged for the device.
|
||||
ErrEnrollmentTokenInvalid = errors.New("enrollment token invalid")
|
||||
|
||||
// ErrDeviceNotDeletable is returned when a device cannot be soft-deleted
|
||||
// because it is not REVOKED.
|
||||
ErrDeviceNotDeletable = errors.New("device cannot be deleted")
|
||||
|
||||
// ErrCorrelationIDRequired is returned when a posture result is
|
||||
// missing a correlation ID.
|
||||
ErrCorrelationIDRequired = errors.New("correlation_id is required")
|
||||
@@ -553,6 +557,43 @@ func (s *Service) RevokeDevice(
|
||||
return device, nil
|
||||
}
|
||||
|
||||
func (s *Service) DeleteDevice(
|
||||
ctx context.Context,
|
||||
scope coredata.Scoper,
|
||||
deviceID gid.GID,
|
||||
) (*coredata.Device, error) {
|
||||
device := &coredata.Device{}
|
||||
|
||||
err := s.pg.WithTx(
|
||||
ctx,
|
||||
func(ctx context.Context, conn pg.Tx) error {
|
||||
if err := device.LoadByIDForUpdate(ctx, conn, scope, deviceID); err != nil {
|
||||
return fmt.Errorf("cannot load device: %w", err)
|
||||
}
|
||||
|
||||
if device.State != coredata.DeviceStateRevoked {
|
||||
return ErrDeviceNotDeletable
|
||||
}
|
||||
|
||||
if err := device.SoftDelete(ctx, conn, scope); err != nil {
|
||||
return fmt.Errorf("cannot soft delete device: %w", err)
|
||||
}
|
||||
|
||||
var token coredata.DeviceEnrollmentToken
|
||||
if err := token.DeleteByDeviceID(ctx, conn, scope, device.ID); err != nil {
|
||||
return fmt.Errorf("cannot delete device enrollment tokens: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return device, nil
|
||||
}
|
||||
|
||||
func (s *Service) SetDeviceOwner(
|
||||
ctx context.Context,
|
||||
scope coredata.Scoper,
|
||||
|
||||
Reference in New Issue
Block a user