Skip to content

Commit

Permalink
single method interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
mmetc committed Dec 27, 2024
1 parent 07165aa commit e73f3e3
Show file tree
Hide file tree
Showing 13 changed files with 116 additions and 56 deletions.
8 changes: 4 additions & 4 deletions cmd/crowdsec-cli/clihub/hub.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,9 @@ func (cli *cliHub) update(ctx context.Context, withContent bool) error {
return err
}

hubProvider := require.HubDownloader(ctx, cli.cfg())
indexProvider := require.HubDownloader(ctx, cli.cfg())

if err := hub.Update(ctx, hubProvider, withContent); err != nil {
if err := hub.Update(ctx, indexProvider, withContent); err != nil {
return fmt.Errorf("failed to update hub: %w", err)
}

Expand Down Expand Up @@ -173,11 +173,11 @@ func (cli *cliHub) upgrade(ctx context.Context, yes bool, dryRun bool, force boo

plan := hubops.NewActionPlan(hub)

hubProvider := require.HubDownloader(ctx, cfg)
contentProvider := require.HubDownloader(ctx, cfg)

for _, itemType := range cwhub.ItemTypes {
for _, item := range hub.GetInstalledByType(itemType, true) {
plan.AddCommand(hubops.NewDownloadCommand(item, hubProvider, force))
plan.AddCommand(hubops.NewDownloadCommand(item, contentProvider, force))
}
}

Expand Down
28 changes: 14 additions & 14 deletions cmd/crowdsec-cli/cliitem/item.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func (cli cliItem) install(ctx context.Context, args []string, yes bool, dryRun

plan := hubops.NewActionPlan(hub)

hubProvider := require.HubDownloader(ctx, cfg)
contentProvider := require.HubDownloader(ctx, cfg)

for _, name := range args {
item := hub.GetItem(cli.name, name)
Expand All @@ -93,7 +93,7 @@ func (cli cliItem) install(ctx context.Context, args []string, yes bool, dryRun
continue
}

if err = plan.AddCommand(hubops.NewDownloadCommand(item, hubProvider, force)); err != nil {
if err = plan.AddCommand(hubops.NewDownloadCommand(item, contentProvider, force)); err != nil {
return err
}

Expand Down Expand Up @@ -292,12 +292,12 @@ func (cli cliItem) newRemoveCmd() *cobra.Command {
return cmd
}

func (cli cliItem) upgradePlan(hub *cwhub.Hub, hubProvider cwhub.HubProvider, args []string, force bool, all bool) (*hubops.ActionPlan, error) {
func (cli cliItem) upgradePlan(hub *cwhub.Hub, contentProvider cwhub.ContentProvider, args []string, force bool, all bool) (*hubops.ActionPlan, error) {
plan := hubops.NewActionPlan(hub)

if all {
for _, item := range hub.GetInstalledByType(cli.name, true) {
if err := plan.AddCommand(hubops.NewDownloadCommand(item, hubProvider, force)); err != nil {
if err := plan.AddCommand(hubops.NewDownloadCommand(item, contentProvider, force)); err != nil {
return nil, err
}
}
Expand All @@ -315,7 +315,7 @@ func (cli cliItem) upgradePlan(hub *cwhub.Hub, hubProvider cwhub.HubProvider, ar
return nil, fmt.Errorf("can't find '%s' in %s", itemName, cli.name)
}

if err := plan.AddCommand(hubops.NewDownloadCommand(item, hubProvider, force)); err != nil {
if err := plan.AddCommand(hubops.NewDownloadCommand(item, contentProvider, force)); err != nil {
return nil, err
}
}
Expand All @@ -331,9 +331,9 @@ func (cli cliItem) upgrade(ctx context.Context, args []string, yes bool, dryRun
return err
}

hubProvider := require.HubDownloader(ctx, cfg)
contentProvider := require.HubDownloader(ctx, cfg)

plan, err := cli.upgradePlan(hub, hubProvider, args, force, all)
plan, err := cli.upgradePlan(hub, contentProvider, args, force, all)
if err != nil {
return err
}
Expand Down Expand Up @@ -394,10 +394,10 @@ func (cli cliItem) inspect(ctx context.Context, args []string, url string, diff
cfg.Cscli.PrometheusUrl = url
}

var hubProvider cwhub.HubProvider
var contentProvider cwhub.ContentProvider

if diff {
hubProvider = require.HubDownloader(ctx, cfg)
contentProvider = require.HubDownloader(ctx, cfg)

Check warning on line 400 in cmd/crowdsec-cli/cliitem/item.go

View check run for this annotation

Codecov / codecov/patch

cmd/crowdsec-cli/cliitem/item.go#L400

Added line #L400 was not covered by tests
}

hub, err := require.Hub(cfg, log.StandardLogger())
Expand All @@ -412,7 +412,7 @@ func (cli cliItem) inspect(ctx context.Context, args []string, url string, diff
}

if diff {
fmt.Println(cli.whyTainted(ctx, hub, hubProvider, item, rev))
fmt.Println(cli.whyTainted(ctx, hub, contentProvider, item, rev))

Check warning on line 415 in cmd/crowdsec-cli/cliitem/item.go

View check run for this annotation

Codecov / codecov/patch

cmd/crowdsec-cli/cliitem/item.go#L415

Added line #L415 was not covered by tests

continue
}
Expand Down Expand Up @@ -502,7 +502,7 @@ func (cli cliItem) newListCmd() *cobra.Command {
}

// return the diff between the installed version and the latest version
func (cli cliItem) itemDiff(ctx context.Context, item *cwhub.Item, hubProvider cwhub.HubProvider, reverse bool) (string, error) {
func (cli cliItem) itemDiff(ctx context.Context, item *cwhub.Item, contentProvider cwhub.ContentProvider, reverse bool) (string, error) {

Check warning on line 505 in cmd/crowdsec-cli/cliitem/item.go

View check run for this annotation

Codecov / codecov/patch

cmd/crowdsec-cli/cliitem/item.go#L505

Added line #L505 was not covered by tests
if !item.State.Installed {
return "", fmt.Errorf("'%s' is not installed", item.FQName())
}
Expand All @@ -513,7 +513,7 @@ func (cli cliItem) itemDiff(ctx context.Context, item *cwhub.Item, hubProvider c
}
defer os.Remove(dest.Name())

_, remoteURL, err := item.FetchContentTo(ctx, hubProvider, dest.Name())
_, remoteURL, err := item.FetchContentTo(ctx, contentProvider, dest.Name())

Check warning on line 516 in cmd/crowdsec-cli/cliitem/item.go

View check run for this annotation

Codecov / codecov/patch

cmd/crowdsec-cli/cliitem/item.go#L516

Added line #L516 was not covered by tests
if err != nil {
return "", err
}
Expand Down Expand Up @@ -544,7 +544,7 @@ func (cli cliItem) itemDiff(ctx context.Context, item *cwhub.Item, hubProvider c
return fmt.Sprintf("%s", diff), nil
}

func (cli cliItem) whyTainted(ctx context.Context, hub *cwhub.Hub, hubProvider cwhub.HubProvider, item *cwhub.Item, reverse bool) string {
func (cli cliItem) whyTainted(ctx context.Context, hub *cwhub.Hub, contentProvider cwhub.ContentProvider, item *cwhub.Item, reverse bool) string {

Check warning on line 547 in cmd/crowdsec-cli/cliitem/item.go

View check run for this annotation

Codecov / codecov/patch

cmd/crowdsec-cli/cliitem/item.go#L547

Added line #L547 was not covered by tests
if !item.State.Installed {
return fmt.Sprintf("# %s is not installed", item.FQName())
}
Expand All @@ -569,7 +569,7 @@ func (cli cliItem) whyTainted(ctx context.Context, hub *cwhub.Hub, hubProvider c
ret = append(ret, err.Error())
}

diff, err := cli.itemDiff(ctx, sub, hubProvider, reverse)
diff, err := cli.itemDiff(ctx, sub, contentProvider, reverse)

Check warning on line 572 in cmd/crowdsec-cli/cliitem/item.go

View check run for this annotation

Codecov / codecov/patch

cmd/crowdsec-cli/cliitem/item.go#L572

Added line #L572 was not covered by tests
if err != nil {
ret = append(ret, err.Error())
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/crowdsec-cli/clisetup/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,9 +296,9 @@ func (cli *cliSetup) install(ctx context.Context, yes bool, dryRun bool, fromFil

verbose := (cfg.Cscli.Output == "raw")

hubProvider := require.HubDownloader(ctx, cfg)
contentProvider := require.HubDownloader(ctx, cfg)

return setup.InstallHubItems(ctx, hub, hubProvider, input, yes, dryRun, verbose)
return setup.InstallHubItems(ctx, hub, contentProvider, input, yes, dryRun, verbose)
}

func (cli *cliSetup) validate(fromFile string) error {
Expand Down
4 changes: 2 additions & 2 deletions cmd/crowdsec-cli/config_restore.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func (cli *cliConfig) restoreHub(ctx context.Context, dirPath string) error {
return err
}

hubProvider := require.HubDownloader(ctx, cfg)
contentProvider := require.HubDownloader(ctx, cfg)

for _, itype := range cwhub.ItemTypes {
itemDirectory := fmt.Sprintf("%s/%s/", dirPath, itype)
Expand Down Expand Up @@ -55,7 +55,7 @@ func (cli *cliConfig) restoreHub(ctx context.Context, dirPath string) error {

plan := hubops.NewActionPlan(hub)

if err = plan.AddCommand(hubops.NewDownloadCommand(item, hubProvider, false)); err != nil {
if err = plan.AddCommand(hubops.NewDownloadCommand(item, contentProvider, false)); err != nil {

Check warning on line 58 in cmd/crowdsec-cli/config_restore.go

View check run for this annotation

Codecov / codecov/patch

cmd/crowdsec-cli/config_restore.go#L58

Added line #L58 was not covered by tests
return err
}

Expand Down
4 changes: 2 additions & 2 deletions pkg/cwhub/cwhub_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,14 @@ func testHub(t *testing.T, update bool) *Hub {
require.NoError(t, err)

if update {
hubProvider := &Downloader{
indexProvider := &Downloader{
Branch: "master",
URLTemplate: mockURLTemplate,
IndexPath: ".index.json",
}

ctx := context.Background()
err := hub.Update(ctx, hubProvider, false)
err := hub.Update(ctx, indexProvider, false)
require.NoError(t, err)
}

Expand Down
4 changes: 2 additions & 2 deletions pkg/cwhub/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
//
// Some commands require an object to provide the hub index, or contents:
//
// hubProvider := cwhub.Downloader{
// indexProvider := cwhub.Downloader{
// URLTemplate: "https://cdn-hub.crowdsec.net/crowdsecurity/%s/%s",
// Branch: "master",
// IndexPath: ".index.json",
Expand All @@ -98,7 +98,7 @@
//
// Before calling hub.Load(), you can update the index file by calling the Update() method:
//
// err := hub.Update(context.Background(), hubProvider)
// err := hub.Update(context.Background(), indexProvider)
// if err != nil {
// return fmt.Errorf("unable to update hub index: %w", err)
// }
Expand Down
21 changes: 18 additions & 3 deletions pkg/cwhub/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,24 @@ import (
"github.com/crowdsecurity/go-cs-lib/downloader"
)

// Downloader is used to retrieve index and items from a remote hub.
// Downloader is used to retrieve index and items from a remote hub, with cache control.
type Downloader struct {
Branch string
URLTemplate string
IndexPath string
}

// IndexProvider retrieves and writes .index.json
type IndexProvider interface {
FetchIndex(ctx context.Context, indexFile string, withContent bool, logger *logrus.Logger) (bool, error)
}

// ContentProvider retrieves and writes the YAML files with the item content.
type ContentProvider interface {
FetchContent(ctx context.Context, remotePath, destPath, wantHash string, logger *logrus.Logger) (bool, string, error)
}


// urlTo builds the URL to download a file from the remote hub.
func (d *Downloader) urlTo(remotePath string) (string, error) {
// the template must contain two string placeholders
Expand Down Expand Up @@ -47,7 +58,9 @@ func addURLParam(rawURL string, param string, value string) (string, error) {
return parsedURL.String(), nil
}

// FetchIndex downloads the index from the hub and returns the content.
// FetchIndex downloads the index from the hub and writes it to the filesystem.
// It uses a temporary file to avoid partial downloads, and won't overwrite the original
// if it has not changed.
func (d *Downloader) FetchIndex(ctx context.Context, destPath string, withContent bool, logger *logrus.Logger) (bool, error) {
url, err := d.urlTo(d.IndexPath)
if err != nil {
Expand Down Expand Up @@ -79,7 +92,9 @@ func (d *Downloader) FetchIndex(ctx context.Context, destPath string, withConten
return downloaded, nil
}

// FetchContent downloads the content to the specified path and checks the hash.
// FetchContent downloads the content to the specified path, through a temporary file
// to avoid partial downloads.
// If the hash does not match, it will not overwrite and log a warning.
func (d *Downloader) FetchContent(ctx context.Context, remotePath, destPath, wantHash string, logger *logrus.Logger) (bool, string, error) {
url, err := d.urlTo(remotePath)
if err != nil {
Expand Down
50 changes: 50 additions & 0 deletions pkg/cwhub/download_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package cwhub

import (
"context"
"io"
"os"
"testing"
"net/http"
"net/http/httptest"
"path/filepath"

"github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestFetchIndex(t *testing.T) {
ctx := context.Background()

mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Query().Get("with_content") == "true" {
w.WriteHeader(http.StatusOK)
w.Write([]byte(`Hi I'm an index with content`))
} else {
w.WriteHeader(http.StatusOK)
w.Write([]byte(`Hi I'm a regular index`))
}
}))
defer mockServer.Close()

downloader := &Downloader{
Branch: "main",
URLTemplate: mockServer.URL + "/%s/%s",
IndexPath: "index.txt",
}

logger := logrus.New()
logger.Out = io.Discard

destPath := filepath.Join(t.TempDir(), "index.txt")
withContent := true

downloaded, err := downloader.FetchIndex(ctx, destPath, withContent, logger)
require.NoError(t, err)
assert.True(t, downloaded)

content, err := os.ReadFile(destPath)
require.NoError(t, err)
assert.Equal(t, "Hi I'm an index with content", string(content))
}
4 changes: 2 additions & 2 deletions pkg/cwhub/fetch.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func (i *Item) writeEmbeddedContentTo(destPath, wantHash string) error {

// FetchContentTo writes the last version of the item's YAML file to the specified path.
// Returns whether the file was downloaded, and the remote url for feedback purposes.
func (i *Item) FetchContentTo(ctx context.Context, hubProvider HubProvider, destPath string) (bool, string, error) {
func (i *Item) FetchContentTo(ctx context.Context, contentProvider ContentProvider, destPath string) (bool, string, error) {
wantHash := i.latestHash()
if wantHash == "" {
return false, "", fmt.Errorf("%s: latest hash missing from index. The index file is invalid, please run 'cscli hub update' and try again", i.FQName())
Expand All @@ -65,5 +65,5 @@ func (i *Item) FetchContentTo(ctx context.Context, hubProvider HubProvider, dest
return true, fmt.Sprintf("(embedded in %s)", i.hub.local.HubIndexFile), nil
}

return hubProvider.FetchContent(ctx, i.RemotePath, destPath, wantHash, i.hub.logger)
return contentProvider.FetchContent(ctx, i.RemotePath, destPath, wantHash, i.hub.logger)

Check warning on line 68 in pkg/cwhub/fetch.go

View check run for this annotation

Codecov / codecov/patch

pkg/cwhub/fetch.go#L68

Added line #L68 was not covered by tests
}
9 changes: 2 additions & 7 deletions pkg/cwhub/hub.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,20 +153,15 @@ func (h *Hub) ItemStats() []string {
return ret
}

type HubProvider interface {
FetchIndex(ctx context.Context, indexFile string, withContent bool, logger *logrus.Logger) (bool, error)
FetchContent(ctx context.Context, remotePath, destPath, wantHash string, logger *logrus.Logger) (bool, string, error)
}

// Update downloads the latest version of the index and writes it to disk if it changed.
// It cannot be called after Load() unless the hub is completely empty.
func (h *Hub) Update(ctx context.Context, hubProvider HubProvider, withContent bool) error {
func (h *Hub) Update(ctx context.Context, indexProvider IndexProvider, withContent bool) error {
if len(h.pathIndex) > 0 {
// if this happens, it's a bug.
return errors.New("cannot update hub after items have been loaded")
}

downloaded, err := hubProvider.FetchIndex(ctx, h.local.HubIndexFile, withContent, h.logger)
downloaded, err := indexProvider.FetchIndex(ctx, h.local.HubIndexFile, withContent, h.logger)
if err != nil {
return err
}
Expand Down
Loading

0 comments on commit e73f3e3

Please sign in to comment.