Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cwhub refact #2637

Merged
merged 3 commits into from
Dec 5, 2023
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
4 changes: 2 additions & 2 deletions cmd/crowdsec-cli/config_backup.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,15 @@
}

//for the local/tainted ones, we back up the full file
if v.State.Tainted || v.IsLocal() || !v.State.UpToDate {
if v.State.Tainted || v.State.IsLocal() || !v.State.UpToDate {

Check warning on line 49 in cmd/crowdsec-cli/config_backup.go

View check run for this annotation

Codecov / codecov/patch

cmd/crowdsec-cli/config_backup.go#L49

Added line #L49 was not covered by tests
//we need to backup stages for parsers
if itemType == cwhub.PARSERS || itemType == cwhub.POSTOVERFLOWS {
fstagedir := fmt.Sprintf("%s%s", itemDirectory, v.Stage)
if err = os.MkdirAll(fstagedir, os.ModePerm); err != nil {
return fmt.Errorf("error while creating stage dir %s : %s", fstagedir, err)
}
}
clog.Debugf("[%s]: backing up file (tainted:%t local:%t up-to-date:%t)", k, v.State.Tainted, v.IsLocal(), v.State.UpToDate)
clog.Debugf("[%s]: backing up file (tainted:%t local:%t up-to-date:%t)", k, v.State.Tainted, v.State.IsLocal(), v.State.UpToDate)

Check warning on line 57 in cmd/crowdsec-cli/config_backup.go

View check run for this annotation

Codecov / codecov/patch

cmd/crowdsec-cli/config_backup.go#L57

Added line #L57 was not covered by tests
tfile := fmt.Sprintf("%s%s/%s", itemDirectory, v.Stage, v.FileName)
if err = CopyFile(v.State.LocalPath, tfile); err != nil {
return fmt.Errorf("failed copy %s %s to %s : %s", itemType, v.State.LocalPath, tfile, err)
Expand Down
2 changes: 1 addition & 1 deletion cmd/crowdsec-cli/hub.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func runHubList(cmd *cobra.Command, args []string) error {
}
}

err = listItems(color.Output, cwhub.ItemTypes, items)
err = listItems(color.Output, cwhub.ItemTypes, items, true)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/crowdsec-cli/itemcommands.go
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,7 @@ func itemsListRunner(it hubItemType) func(cmd *cobra.Command, args []string) err
return err
}

if err = listItems(color.Output, []string{it.name}, items); err != nil {
if err = listItems(color.Output, []string{it.name}, items, false); err != nil {
return err
}

Expand Down
18 changes: 13 additions & 5 deletions cmd/crowdsec-cli/items.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,19 @@ func selectItems(hub *cwhub.Hub, itemType string, args []string, installedOnly b
return items, nil
}

func listItems(out io.Writer, itemTypes []string, items map[string][]*cwhub.Item) error {
func listItems(out io.Writer, itemTypes []string, items map[string][]*cwhub.Item, omitIfEmpty bool) error {
switch csConfig.Cscli.Output {
case "human":
nothingToDisplay := true
for _, itemType := range itemTypes {
if omitIfEmpty && len(items[itemType]) == 0 {
continue
}
listHubItemTable(out, "\n"+strings.ToUpper(itemType), items[itemType])
nothingToDisplay = false
}
if nothingToDisplay {
fmt.Println("No items to display")
}
case "json":
type itemHubStatus struct {
Expand All @@ -75,14 +83,15 @@ func listItems(out io.Writer, itemTypes []string, items map[string][]*cwhub.Item
hubStatus[itemType] = make([]itemHubStatus, len(items[itemType]))

for i, item := range items[itemType] {
status, emo := item.InstallStatus()
status := item.State.Text()
status_emo := item.State.Emoji()
hubStatus[itemType][i] = itemHubStatus{
Name: item.Name,
LocalVersion: item.State.LocalVersion,
LocalPath: item.State.LocalPath,
Description: item.Description,
Status: status,
UTF8Status: fmt.Sprintf("%v %s", emo, status),
UTF8Status: fmt.Sprintf("%v %s", status_emo, status),
}
}
}
Expand All @@ -107,10 +116,9 @@ func listItems(out io.Writer, itemTypes []string, items map[string][]*cwhub.Item

for _, itemType := range itemTypes {
for _, item := range items[itemType] {
status, _ := item.InstallStatus()
row := []string{
item.Name,
status,
item.State.Text(),
item.State.LocalVersion,
item.Description,
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/crowdsec-cli/support.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ func collectHubItems(hub *cwhub.Hub, itemType string) []byte {
log.Warnf("could not collect %s list: %s", itemType, err)
}

if err := listItems(out, []string{itemType}, items); err != nil {
if err := listItems(out, []string{itemType}, items, false); err != nil {
log.Warnf("could not collect %s list: %s", itemType, err)
}
return out.Bytes()
Expand Down
4 changes: 2 additions & 2 deletions cmd/crowdsec-cli/utils_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ func listHubItemTable(out io.Writer, title string, items []*cwhub.Item) {
t.SetAlignment(table.AlignLeft, table.AlignLeft, table.AlignLeft, table.AlignLeft)

for _, item := range items {
status, emo := item.InstallStatus()
t.AddRow(item.Name, fmt.Sprintf("%v %s", emo, status), item.State.LocalVersion, item.State.LocalPath)
status := fmt.Sprintf("%v %s", item.State.Emoji(), item.State.Text())
t.AddRow(item.Name, status, item.State.LocalVersion, item.State.LocalPath)
}
renderTableTitle(out, title)
t.Render()
Expand Down
4 changes: 0 additions & 4 deletions cmd/crowdsec/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,10 +262,6 @@ func LoadConfig(configFile string, disableAgent bool, disableAPI bool, quiet boo
return nil, errors.New("You must run at least the API Server or crowdsec")
}

if flags.TestMode && !cConfig.DisableAgent {
cConfig.Crowdsec.LintOnly = true
}

if flags.OneShotDSN != "" && flags.SingleFileType == "" {
return nil, errors.New("-dsn requires a -type argument")
}
Expand Down
1 change: 0 additions & 1 deletion pkg/csconfig/crowdsec_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ type CrowdsecServiceCfg struct {
BucketsRoutinesCount int `yaml:"buckets_routines"`
OutputRoutinesCount int `yaml:"output_routines"`
SimulationConfig *SimulationConfig `yaml:"-"`
LintOnly bool `yaml:"-"` // if set to true, exit after loading configs
BucketStateFile string `yaml:"state_input_file,omitempty"` // if we need to unserialize buckets at start
BucketStateDumpDir string `yaml:"state_output_dir,omitempty"` // if we need to unserialize buckets on shutdown
BucketsGCEnabled bool `yaml:"-"` // we need to garbage collect buckets when in forensic mode
Expand Down
2 changes: 1 addition & 1 deletion pkg/cwhub/hub.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ func (h *Hub) ItemStats() []string {
loaded += fmt.Sprintf("%d %s, ", len(h.GetItemMap(itemType)), itemType)

for _, item := range h.GetItemMap(itemType) {
if item.IsLocal() {
if item.State.IsLocal() {
local++
}

Expand Down
93 changes: 44 additions & 49 deletions pkg/cwhub/item.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,48 @@
BelongsToCollections []string `json:"belongs_to_collections,omitempty" yaml:"belongs_to_collections,omitempty"`
}

// IsLocal returns true if the item has been create by a user (not downloaded from the hub).
func (s *ItemState) IsLocal() bool {
return s.Installed && !s.Downloaded
}

// Text returns the status of the item as a string (eg. "enabled,update-available").
func (s *ItemState) Text() string {
ret := "disabled"

if s.Installed {
ret = "enabled"
}

if s.IsLocal() {
ret += ",local"
}

if s.Tainted {
ret += ",tainted"
} else if !s.UpToDate && !s.IsLocal() {
ret += ",update-available"
}

return ret
}

// Emoji returns the status of the item as an emoji (eg. emoji.Warning).
func (s *ItemState) Emoji() emoji.Emoji {
switch {
case s.IsLocal():
return emoji.House
case !s.Installed:
return emoji.Prohibited
case s.Tainted || (!s.UpToDate && !s.IsLocal()):
return emoji.Warning
case s.Installed:
return emoji.CheckMark
default:
return emoji.QuestionMark

Check warning on line 94 in pkg/cwhub/item.go

View check run for this annotation

Codecov / codecov/patch

pkg/cwhub/item.go#L93-L94

Added lines #L93 - L94 were not covered by tests
}
}

// Item is created from an index file and enriched with local info.
type Item struct {
hub *Hub // back pointer to the hub, to retrieve other items and call install/remove methods
Expand Down Expand Up @@ -107,11 +149,6 @@
return i.Type == COLLECTIONS
}

// IsLocal returns true if the item has been create by a user (not downloaded from the hub).
func (i *Item) IsLocal() bool {
return i.State.Installed && !i.State.Downloaded
}

// MarshalJSON is used to prepare the output for "cscli ... inspect -o json".
// It must not use a pointer receiver.
func (i Item) MarshalJSON() ([]byte, error) {
Expand Down Expand Up @@ -139,7 +176,7 @@
UpToDate: i.State.UpToDate,
Tainted: i.State.Tainted,
BelongsToCollections: i.State.BelongsToCollections,
Local: i.IsLocal(),
Local: i.State.IsLocal(),
})
}

Expand All @@ -155,7 +192,7 @@
}{
Alias: Alias(i),
State: i.State,
Local: i.IsLocal(),
Local: i.State.IsLocal(),
}, nil
}

Expand Down Expand Up @@ -290,48 +327,6 @@
return ret, nil
}

// InstallStatus returns the status of the item as a string and an emoji
// (eg. "enabled,update-available" and emoji.Warning).
func (i *Item) InstallStatus() (string, emoji.Emoji) {
status := "disabled"
ok := false

if i.State.Installed {
ok = true
status = "enabled"
}

managed := true
if i.IsLocal() {
managed = false
status += ",local"
}

warning := false
if i.State.Tainted {
warning = true
status += ",tainted"
} else if !i.State.UpToDate && !i.IsLocal() {
warning = true
status += ",update-available"
}

emo := emoji.QuestionMark

switch {
case !managed:
emo = emoji.House
case !i.State.Installed:
emo = emoji.Prohibited
case warning:
emo = emoji.Warning
case ok:
emo = emoji.CheckMark
}

return status, emo
}

// versionStatus returns the status of the item version compared to the hub version.
// semver requires the 'v' prefix.
func (i *Item) versionStatus() int {
Expand Down
4 changes: 2 additions & 2 deletions pkg/cwhub/item_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ func TestItemStatus(t *testing.T) {
item.State.Tainted = false
item.State.Downloaded = true

txt, _ := item.InstallStatus()
txt := item.State.Text()
require.Equal(t, "enabled,update-available", txt)

item.State.Installed = true
item.State.UpToDate = false
item.State.Tainted = false
item.State.Downloaded = false

txt, _ = item.InstallStatus()
txt = item.State.Text()
require.Equal(t, "enabled,local", txt)
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/cwhub/iteminstall.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func (i *Item) enable() error {
return fmt.Errorf("%s is tainted, won't enable unless --force", i.Name)
}

if i.IsLocal() {
if i.State.IsLocal() {
return fmt.Errorf("%s is local, won't enable", i.Name)
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/cwhub/itemremove.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func (i *Item) disable(purge bool, force bool) (bool, error) {

// Remove disables the item, optionally removing the downloaded content.
func (i *Item) Remove(purge bool, force bool) (bool, error) {
if i.IsLocal() {
if i.State.IsLocal() {
log.Warningf("%s is a local item, please delete manually", i.Name)
return false, nil
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/cwhub/itemupgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
func (i *Item) Upgrade(force bool) (bool, error) {
updated := false

if i.IsLocal() {
if i.State.IsLocal() {
log.Infof("not upgrading %s: local item", i.Name)
return false, nil
}
Expand Down Expand Up @@ -155,7 +155,7 @@ func (i *Item) fetch() ([]byte, error) {

// download downloads the item from the hub and writes it to the hub directory.
func (i *Item) download(overwrite bool) (string, error) {
if i.IsLocal() {
if i.State.IsLocal() {
return "", fmt.Errorf("%s is local, can't download", i.Name)
}
// if user didn't --force, don't overwrite local, tainted, up-to-date files
Expand Down
2 changes: 1 addition & 1 deletion pkg/cwhub/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ func (h *Hub) localSync() error {
case versionFuture:
warnings = append(warnings, fmt.Sprintf("collection %s is in the future (currently:%s, latest:%s)", item.Name, item.State.LocalVersion, item.Version))
case versionUnknown:
if !item.IsLocal() {
if !item.State.IsLocal() {
warnings = append(warnings, fmt.Sprintf("collection %s is tainted (latest:%s)", item.Name, item.Version))
}
}
Expand Down
8 changes: 5 additions & 3 deletions test/bats/20_hub.bats
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,19 @@ teardown() {

# no items
rune -0 cscli hub list
assert_output --regexp ".*PARSERS.*POSTOVERFLOWS.*SCENARIOS.*COLLECTIONS.*"
assert_output "No items to display"
rune -0 cscli hub list -o json
assert_json '{parsers:[],scenarios:[],collections:[],postoverflows:[]}'
rune -0 cscli hub list -o raw
assert_output 'name,status,version,description,type'

# some items
# some items: with output=human, show only non-empty tables
rune -0 cscli parsers install crowdsecurity/whitelists
rune -0 cscli scenarios install crowdsecurity/telnet-bf
rune -0 cscli hub list
assert_output --regexp ".*PARSERS.*crowdsecurity/whitelists.*POSTOVERFLOWS.*SCENARIOS.*crowdsecurity/telnet-bf.*COLLECTIONS.*"
assert_output --regexp ".*PARSERS.*crowdsecurity/whitelists.*SCENARIOS.*crowdsecurity/telnet-bf.*"
refute_output --partial 'POSTOVERFLOWS'
refute_output --partial 'COLLECTIONS'
rune -0 cscli hub list -o json
rune -0 jq -e '(.parsers | length == 1) and (.scenarios | length == 1)' <(output)
rune -0 cscli hub list -o raw
Expand Down
Loading