function update
This commit is contained in:
+77
-13
@@ -268,6 +268,16 @@ func (c *CLIClient) ListPostoverflows(ctx context.Context) ([]HubItem, error) {
|
||||
return c.listHubItems(ctx, "postoverflows")
|
||||
}
|
||||
|
||||
// InstallPostoverflow installs a postoverflow.
|
||||
func (c *CLIClient) InstallPostoverflow(ctx context.Context, name string) error {
|
||||
return c.hubAction(ctx, "postoverflows", "install", name)
|
||||
}
|
||||
|
||||
// RemovePostoverflow removes a postoverflow.
|
||||
func (c *CLIClient) RemovePostoverflow(ctx context.Context, name string) error {
|
||||
return c.hubAction(ctx, "postoverflows", "remove", name)
|
||||
}
|
||||
|
||||
// HubUpdate runs cscli hub update && cscli hub upgrade.
|
||||
func (c *CLIClient) HubUpdate(ctx context.Context) error {
|
||||
if _, err := c.run(ctx, "hub", "update"); err != nil {
|
||||
@@ -352,15 +362,55 @@ func (c *CLIClient) InspectAllowlist(ctx context.Context, name string) (*Allowli
|
||||
return &al, nil
|
||||
}
|
||||
|
||||
// AddAllowlistEntry adds a value to a named allowlist.
|
||||
func (c *CLIClient) AddAllowlistEntry(ctx context.Context, listName, value string) error {
|
||||
// CreateAllowlist creates a new allowlist. Ignores "already exists" errors.
|
||||
// cscli v1.7 requires the -d (description) flag.
|
||||
func (c *CLIClient) CreateAllowlist(ctx context.Context, name string) error {
|
||||
if !safeArg.MatchString(name) {
|
||||
return fmt.Errorf("invalid allowlist name: %q", name)
|
||||
}
|
||||
_, err := c.run(ctx, "allowlists", "create", name, "-d", "crowdsec-dashy")
|
||||
if err != nil {
|
||||
msg := err.Error()
|
||||
if strings.Contains(msg, "already exists") || strings.Contains(msg, "already exist") {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddAllowlistEntries adds one or more values to a named allowlist in a single call.
|
||||
// comment is optional; if non-empty it is passed as -d to cscli.
|
||||
func (c *CLIClient) AddAllowlistEntries(ctx context.Context, listName, comment string, values []string) error {
|
||||
if !safeArg.MatchString(listName) {
|
||||
return fmt.Errorf("invalid allowlist name: %q", listName)
|
||||
}
|
||||
if !safeArg.MatchString(value) {
|
||||
return fmt.Errorf("invalid allowlist value: %q", value)
|
||||
if len(values) == 0 {
|
||||
return fmt.Errorf("no values provided")
|
||||
}
|
||||
_, err := c.run(ctx, "allowlists", "items", "add", listName, value)
|
||||
args := []string{"allowlists", "add", listName}
|
||||
for _, v := range values {
|
||||
if !safeArg.MatchString(v) {
|
||||
return fmt.Errorf("invalid allowlist value: %q", v)
|
||||
}
|
||||
args = append(args, v)
|
||||
}
|
||||
if comment != "" {
|
||||
if !safeFlagValue.MatchString(comment) {
|
||||
return fmt.Errorf("invalid comment: only letters, digits, spaces, and common punctuation allowed")
|
||||
}
|
||||
args = append(args, "-d", comment)
|
||||
}
|
||||
_, err := c.run(ctx, args...)
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteAllowlist removes an entire allowlist.
|
||||
func (c *CLIClient) DeleteAllowlist(ctx context.Context, name string) error {
|
||||
if !safeArg.MatchString(name) {
|
||||
return fmt.Errorf("invalid allowlist name: %q", name)
|
||||
}
|
||||
_, err := c.run(ctx, "allowlists", "delete", name)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -372,7 +422,7 @@ func (c *CLIClient) RemoveAllowlistEntry(ctx context.Context, listName, value st
|
||||
if !safeArg.MatchString(value) {
|
||||
return fmt.Errorf("invalid allowlist value: %q", value)
|
||||
}
|
||||
_, err := c.run(ctx, "allowlists", "items", "del", listName, value)
|
||||
_, err := c.run(ctx, "allowlists", "remove", listName, value)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -430,13 +480,16 @@ var allowedActions = map[string]bool{
|
||||
"validate": true,
|
||||
"create": true,
|
||||
"inspect": true,
|
||||
"items": true,
|
||||
"del": true,
|
||||
}
|
||||
|
||||
// safeArg matches strings that are safe to pass as arguments (no shell metacharacters).
|
||||
// safeArg matches strings that are safe to pass as positional cscli arguments.
|
||||
var safeArg = regexp.MustCompile(`^[a-zA-Z0-9_./:@\-]+$`)
|
||||
|
||||
// safeFlagValue matches flag values (after --flag). More permissive: allows spaces and
|
||||
// common punctuation, but blocks null bytes, control chars, and shell metacharacters.
|
||||
var safeFlagValue = regexp.MustCompile(`^[a-zA-Z0-9 _./:@\-,!?()']+$`)
|
||||
|
||||
func validateArgs(args []string) error {
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("no subcommand provided")
|
||||
@@ -444,19 +497,30 @@ func validateArgs(args []string) error {
|
||||
if !allowedSubcommands[args[0]] {
|
||||
return fmt.Errorf("disallowed cscli subcommand: %q", args[0])
|
||||
}
|
||||
// Skip flag-value pairs like "-o json" and "--machine-id <id>" — validate values
|
||||
// Iterate remaining args. Flag names (start with -) are allowed as-is.
|
||||
// The arg immediately after a flag is treated as its value and validated with
|
||||
// the more permissive safeFlagValue rather than safeArg.
|
||||
prevWasFlag := false
|
||||
for i := 1; i < len(args); i++ {
|
||||
arg := args[i]
|
||||
if strings.HasPrefix(arg, "-") {
|
||||
continue // flags are fine
|
||||
prevWasFlag = true
|
||||
continue
|
||||
}
|
||||
if prevWasFlag {
|
||||
prevWasFlag = false
|
||||
if !safeFlagValue.MatchString(arg) {
|
||||
return fmt.Errorf("unsafe cscli flag value: %q", arg)
|
||||
}
|
||||
continue
|
||||
}
|
||||
prevWasFlag = false
|
||||
if allowedActions[arg] {
|
||||
continue // known action words
|
||||
continue
|
||||
}
|
||||
if arg == "raw" || arg == "json" || arg == "human" {
|
||||
continue // output format values
|
||||
continue
|
||||
}
|
||||
// Everything else (names, IDs) must match safe pattern
|
||||
if !safeArg.MatchString(arg) {
|
||||
return fmt.Errorf("unsafe cscli argument: %q", arg)
|
||||
}
|
||||
|
||||
+13
-12
@@ -116,18 +116,19 @@ type Machine struct {
|
||||
}
|
||||
|
||||
type HubItem struct {
|
||||
Author string `json:"author"`
|
||||
Description string `json:"description"`
|
||||
Downloaded bool `json:"downloaded"`
|
||||
Installed bool `json:"installed"`
|
||||
Local bool `json:"local"`
|
||||
Name string `json:"name"`
|
||||
Path string `json:"path"`
|
||||
Stage string `json:"stage"`
|
||||
Status string `json:"status"`
|
||||
Tainted bool `json:"tainted"`
|
||||
UpToDate bool `json:"up_to_date"`
|
||||
Version string `json:"version"`
|
||||
Author string `json:"author"`
|
||||
Description string `json:"description"`
|
||||
Downloaded bool `json:"downloaded"`
|
||||
Installed bool `json:"installed"`
|
||||
Local bool `json:"local"`
|
||||
LocalVersion string `json:"local_version"`
|
||||
Name string `json:"name"`
|
||||
Path string `json:"path"`
|
||||
Stage string `json:"stage"`
|
||||
Status string `json:"status"`
|
||||
Tainted bool `json:"tainted"`
|
||||
UpToDate bool `json:"up_to_date"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
type MetricsSection struct {
|
||||
|
||||
Reference in New Issue
Block a user