github.com/crowdsecurity/crowdsec@v1.6.1/pkg/cwhub/itemremove.go (about)

     1  package cwhub
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"slices"
     7  )
     8  
     9  // purge removes the actual config file that was downloaded.
    10  func (i *Item) purge() (bool, error) {
    11  	if !i.State.Downloaded {
    12  		i.hub.logger.Debugf("removing %s: not downloaded -- no need to remove", i.Name)
    13  		return false, nil
    14  	}
    15  
    16  	src, err := i.downloadPath()
    17  	if err != nil {
    18  		return false, err
    19  	}
    20  
    21  	if err := os.Remove(src); err != nil {
    22  		if os.IsNotExist(err) {
    23  			i.hub.logger.Debugf("%s doesn't exist, no need to remove", src)
    24  			return false, nil
    25  		}
    26  
    27  		return false, fmt.Errorf("while removing file: %w", err)
    28  	}
    29  
    30  	i.State.Downloaded = false
    31  	i.hub.logger.Infof("Removed source file [%s]: %s", i.Name, src)
    32  
    33  	return true, nil
    34  }
    35  
    36  // disable removes the install link, and optionally the downloaded content.
    37  func (i *Item) disable(purge bool, force bool) (bool, error) {
    38  	didRemove := true
    39  
    40  	err := i.removeInstallLink()
    41  	if os.IsNotExist(err) {
    42  		if !purge && !force {
    43  			link, _ := i.installPath()
    44  			return false, fmt.Errorf("link %s does not exist (override with --force or --purge)", link)
    45  		}
    46  
    47  		didRemove = false
    48  	} else if err != nil {
    49  		return false, err
    50  	}
    51  
    52  	i.State.Installed = false
    53  	didPurge := false
    54  
    55  	if purge {
    56  		if didPurge, err = i.purge(); err != nil {
    57  			return didRemove, err
    58  		}
    59  	}
    60  
    61  	ret := didRemove || didPurge
    62  
    63  	return ret, nil
    64  }
    65  
    66  // Remove disables the item, optionally removing the downloaded content.
    67  func (i *Item) Remove(purge bool, force bool) (bool, error) {
    68  	if i.State.IsLocal() {
    69  		i.hub.logger.Warningf("%s is a local item, please delete manually", i.Name)
    70  		return false, nil
    71  	}
    72  
    73  	if i.State.Tainted && !force {
    74  		return false, fmt.Errorf("%s is tainted, use '--force' to remove", i.Name)
    75  	}
    76  
    77  	if !i.State.Installed && !purge {
    78  		i.hub.logger.Infof("removing %s: not installed -- no need to remove", i.Name)
    79  		return false, nil
    80  	}
    81  
    82  	removed := false
    83  
    84  	descendants, err := i.descendants()
    85  	if err != nil {
    86  		return false, err
    87  	}
    88  
    89  	ancestors := i.Ancestors()
    90  
    91  	for _, sub := range i.SubItems() {
    92  		if !sub.State.Installed {
    93  			continue
    94  		}
    95  
    96  		// if the sub depends on a collection that is not a direct or indirect dependency
    97  		// of the current item, it is not removed
    98  		for _, subParent := range sub.Ancestors() {
    99  			if !purge && !subParent.State.Installed {
   100  				continue
   101  			}
   102  
   103  			// the ancestor that would block the removal of the sub item is also an ancestor
   104  			// of the item we are removing, so we don't want false warnings
   105  			// (e.g. crowdsecurity/sshd-logs was not removed because it also belongs to crowdsecurity/linux,
   106  			// while we are removing crowdsecurity/sshd)
   107  			if slices.Contains(ancestors, subParent) {
   108  				continue
   109  			}
   110  
   111  			// the sub-item belongs to the item we are removing, but we already knew that
   112  			if subParent == i {
   113  				continue
   114  			}
   115  
   116  			if !slices.Contains(descendants, subParent) {
   117  				i.hub.logger.Infof("%s was not removed because it also belongs to %s", sub.Name, subParent.Name)
   118  				continue
   119  			}
   120  		}
   121  
   122  		subRemoved, err := sub.Remove(purge, force)
   123  		if err != nil {
   124  			return false, fmt.Errorf("unable to disable %s: %w", i.Name, err)
   125  		}
   126  
   127  		removed = removed || subRemoved
   128  	}
   129  
   130  	didDisable, err := i.disable(purge, force)
   131  	if err != nil {
   132  		return false, fmt.Errorf("while removing %s: %w", i.Name, err)
   133  	}
   134  
   135  	removed = removed || didDisable
   136  
   137  	return removed, nil
   138  }