## Overview `dibble` is a one-stop CLI for seeding a Fleet server with test data — users, teams, policies, reports, labels, scripts, MDM profiles, software, secrets, CAs, and vulns — replacing ~8 ad-hoc seeding tools with a single binary. It makes it easy to: - **Spin up a populated dev/test server in one command** — `dibble all` plants everything with sensible, idempotent defaults. - **Skip the flag-memorization** — running `dibble` with no args launches an interactive wizard that prompts for Fleet URL, API token, theme, and which entities to seed, and offers to save the config to `~/.dibble.yaml`. - **Seed individual entity types** — `dibble users`, `dibble teams`, `dibble policies`, etc., when you only need one slice. - **Get themed, recognizable test data** — pick a theme (hitchhikers, tng, lotr, ghibli, parksrec, …) so seeded names are easy to eyeball in the UI. Hosts are intentionally out of scope — `cmd/osquery-perf` still owns that. `dibble hosts` is a thin convenience wrapper that picks a fleet, fetches its enroll secret, and prints/runs the osquery-perf invocation for you. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Dibble: a CLI tool to seed realistic test data, including an interactive wizard and subcommands for teams/users/software/policies/scripts/reports/profiles/labels/activities/enroll-secrets/hosts/vulns, plus theme-driven “cas” and “ping”. * Theme system: multiple curated themes to generate consistent seeded identities, policies, software, labels, and scripts. * **Chores** * Ignored the built dibble binary and added a Makefile build target to compile the dibble tool. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
76 lines
2.4 KiB
Go
76 lines
2.4 KiB
Go
// Package seed contains the per-entity seeding logic that backs both the
|
|
// dibble subcommands and the interactive wizard. Keeping the logic here
|
|
// (instead of in the cmd_*.go cobra wrappers) makes it possible for the
|
|
// wizard to call the same functions and guarantees the two paths can't drift.
|
|
package seed
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
// MultipartFile is one file part of a multipart upload. The FieldName is the
|
|
// form field (e.g. "script", "profile"); the Filename is what the server sees
|
|
// when it inspects the upload's name — important because Fleet uses extensions
|
|
// like .mobileconfig / .xml to detect MDM profile platforms.
|
|
type MultipartFile struct {
|
|
FieldName string
|
|
Filename string
|
|
Content []byte
|
|
}
|
|
|
|
// Client is the subset of the dibble HTTP client that seeders need. Defined
|
|
// as an interface so tests can swap in a fake.
|
|
type Client interface {
|
|
Get(path string, out any) error
|
|
Post(path string, body any, out any) error
|
|
Patch(path string, body any, out any) error
|
|
Delete(path string) error
|
|
PostMultipart(path string, fields map[string]string, files []MultipartFile, out any) error
|
|
}
|
|
|
|
// AlreadyExists is the sentinel returned by Client when the server reports a
|
|
// conflict. Seeders treat this as soft success.
|
|
type AlreadyExistsError interface {
|
|
error
|
|
IsAlreadyExists() bool
|
|
}
|
|
|
|
// IsAlreadyExists reports whether err is an "already exists"-shaped error.
|
|
// Decoupled from the concrete client type via duck typing on Error() text so
|
|
// the seed package doesn't import the main package.
|
|
func IsAlreadyExists(err error) bool {
|
|
if err == nil {
|
|
return false
|
|
}
|
|
type ae interface{ IsAlreadyExists() bool }
|
|
var x ae
|
|
if errors.As(err, &x) {
|
|
return x.IsAlreadyExists()
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Result is what each seeder reports back so cmd_all and the wizard can
|
|
// print a tidy summary.
|
|
type Result struct {
|
|
Entity string
|
|
Created int
|
|
Skipped int // already-exists
|
|
Errors []error
|
|
}
|
|
|
|
// Summary turns a Result into a one-line printable status.
|
|
func (r Result) Summary() string {
|
|
if len(r.Errors) > 0 {
|
|
return fmt.Sprintf("%s: %d created, %d skipped, %d errors", r.Entity, r.Created, r.Skipped, len(r.Errors))
|
|
}
|
|
return fmt.Sprintf("%s: %d created, %d skipped", r.Entity, r.Created, r.Skipped)
|
|
}
|
|
|
|
// Logger is a minimal writer interface so seeders can print progress lines
|
|
// without coupling to the main package.
|
|
type Logger interface {
|
|
Printf(format string, a ...any)
|
|
}
|