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 }