From c66c6a7c2ac48077e1a0a977c25dc3d577d6391a Mon Sep 17 00:00:00 2001 From: Silke Hofstra Date: Fri, 1 Sep 2023 20:17:38 +0200 Subject: [PATCH 01/19] Add golangci-lint config and GitHub workflow --- .github/workflows/golangci-lint.yml | 29 +++++++ .golangci.yaml | 130 ++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 .github/workflows/golangci-lint.yml create mode 100644 .golangci.yaml diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml new file mode 100644 index 0000000..993d2f7 --- /dev/null +++ b/.github/workflows/golangci-lint.yml @@ -0,0 +1,29 @@ +name: golangci-lint +on: + push: + branches: + - master + - main + pull_request: + +permissions: + contents: read + +jobs: + golangci: + name: lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-go@v4 + with: + go-version: '1.21' + cache: false + # Install libgit2-dev 1.5 for git2go + - run: sudo apt-get install -qqy wget + - run: wget http://archive.ubuntu.com/ubuntu/pool/universe/libg/libgit2/libgit2-{1.5,dev}_1.5.1+ds-1ubuntu1_amd64.deb + - run: sudo apt-get install -qqy ./*.deb + - name: golangci-lint + uses: golangci/golangci-lint-action@v3 + with: + version: v1.54 diff --git a/.golangci.yaml b/.golangci.yaml new file mode 100644 index 0000000..0f0f523 --- /dev/null +++ b/.golangci.yaml @@ -0,0 +1,130 @@ +--- +linters: + enable-all: true + disable: + # Disabled to get codebase to pass the linter. + # We can enable these one at a time. + - cyclop + - errcheck + - forcetypeassert + - funlen + - forbidigo + - gci + - gochecknoglobals + - gochecknoinits + - gocritic + - godot + - godox + - goerr113 + - gofumpt + - gomnd + - gosec + - govet + - lll + - musttag + - nakedret + - prealloc + - revive + - staticcheck + - stylecheck + - tagalign + - wrapcheck + - wsl + # Disabled permanently + - exhaustruct # structs may be uninitialized + - nlreturn # covered by wsl cuddle rules + - paralleltest # tests are acceptable in sequence + - goimports # conflicts with GCI + - depguard # manage using go.mod for now + - nonamedreturns # named returns are acceptable in short functions + # Deprecated + - exhaustivestruct + - scopelint + - interfacer + - maligned + - golint + - structcheck + - varcheck + - deadcode + - nosnakecase + - ifshort + +severity: + default-severity: major + +issues: + fast: false + max-issues-per-linter: 0 + max-same-issues: 0 + exclude-use-default: false + exclude-case-sensitive: true + exclude-rules: + - path: _test\.go + linters: + - gochecknoglobals + - errcheck + - wrapcheck + - gosec + - goerr113 + +linters-settings: + exhaustive: + default-signifies-exhaustive: true + + gci: + sections: + - standard + - default + - prefix(github.com/getsolus/usysconf) + + gomnd: + ignored-numbers: ['2', '4', '8', '16', '32', '64', '10'] + + gosec: + excludes: [] + + govet: + enable-all: true + disable: + - fieldalignment # misalignment is accepted + + revive: + enable-all-rules: false + rules: # see https://github.com/mgechev/revive#recommended-configuration + - name: blank-imports + - name: context-as-argument + - name: context-keys-type + - name: dot-imports + - name: error-return + - name: error-strings + - name: error-naming + - name: exported + - name: if-return + - name: increment-decrement + - name: var-naming + - name: var-declaration + - name: package-comments + - name: range + - name: receiver-naming + - name: time-naming + - name: unexported-return + - name: indent-error-flow + - name: errorf + - name: empty-block + - name: superfluous-else + - name: unused-parameter + - name: unreachable-code + - name: redefines-builtin-id + + stylecheck: + checks: [all] + + tagalign: + order: + - zero + - short + - long + - desc + + varnamelen: + min-name-length: 1 From 64d6453fc8ca9a4053572460e05acf6150c3ca4a Mon Sep 17 00:00:00 2001 From: Silke Hofstra Date: Fri, 1 Sep 2023 20:18:13 +0200 Subject: [PATCH 02/19] Enable and appease the gofumpt linter --- .golangci.yaml | 1 - state/map.go | 2 +- triggers/config.go | 3 ++- triggers/map.go | 1 - triggers/skip.go | 1 + util/live.go | 2 +- 6 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index 0f0f523..94dbc41 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -16,7 +16,6 @@ linters: - godot - godox - goerr113 - - gofumpt - gomnd - gosec - govet diff --git a/state/map.go b/state/map.go index 8122205..7ad88b8 100644 --- a/state/map.go +++ b/state/map.go @@ -60,7 +60,7 @@ func Load() (Map, error) { // Save writes out the current state for future runs func (m Map) Save() error { - if err := os.MkdirAll(filepath.Dir(Path), 0750); err != nil { + if err := os.MkdirAll(filepath.Dir(Path), 0o750); err != nil { return err } sFile, err := os.Create(filepath.Clean(Path)) diff --git a/triggers/config.go b/triggers/config.go index 5cb9f81..1c27b09 100644 --- a/triggers/config.go +++ b/triggers/config.go @@ -16,10 +16,11 @@ package triggers import ( "fmt" - "github.com/BurntSushi/toml" "io/ioutil" "os" "path/filepath" + + "github.com/BurntSushi/toml" ) // Load reads a Trigger configuration from a file and parses it diff --git a/triggers/map.go b/triggers/map.go index 3802fc5..804b5c6 100644 --- a/triggers/map.go +++ b/triggers/map.go @@ -80,7 +80,6 @@ func (tm Map) Graph(chroot, live bool) (g deps.Graph) { // Run executes a list of triggers, where available func (tm Map) Run(s Scope, names []string) { prev, err := state.Load() - if err != nil { slog.Error("Failed to read state file", "reason", err) return diff --git a/triggers/skip.go b/triggers/skip.go index 3096849..c7deb60 100644 --- a/triggers/skip.go +++ b/triggers/skip.go @@ -16,6 +16,7 @@ package triggers import ( "fmt" + "github.com/getsolus/usysconf/state" ) diff --git a/util/live.go b/util/live.go index 6674b03..7cfb7f5 100644 --- a/util/live.go +++ b/util/live.go @@ -32,5 +32,5 @@ func IsLive() bool { slog.Error("Could not check for live session", "reason", err) // TODO: Return error instead of panicking. panic("Could not check for live session") - //return false + // return false } From 5c5cde2add20cbf9c3ced605016b720ade9c9dff Mon Sep 17 00:00:00 2001 From: Silke Hofstra Date: Fri, 1 Sep 2023 20:18:30 +0200 Subject: [PATCH 03/19] Enable and appease the gci linter --- .golangci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.golangci.yaml b/.golangci.yaml index 94dbc41..e80a4f0 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -9,7 +9,6 @@ linters: - forcetypeassert - funlen - forbidigo - - gci - gochecknoglobals - gochecknoinits - gocritic From 2089443fffe25581193cc60e0e61b5824bd6e6bd Mon Sep 17 00:00:00 2001 From: Silke Hofstra Date: Fri, 1 Sep 2023 20:18:53 +0200 Subject: [PATCH 04/19] Enable and appease the wsl linter --- .golangci.yaml | 1 - cli/cli.go | 1 + cli/graph.go | 2 ++ cli/list.go | 2 ++ cli/run.go | 3 +++ config/load.go | 16 ++++++++++++++++ deps/graph.go | 25 +++++++++++++++++++++++++ main.go | 1 + state/map.go | 27 +++++++++++++++++++++++++++ triggers/bin.go | 10 ++++++++++ triggers/check.go | 4 ++++ triggers/config.go | 2 ++ triggers/map.go | 16 ++++++++++++++++ triggers/remove.go | 9 +++++++++ triggers/skip.go | 3 +++ triggers/trigger.go | 1 + util/chroot.go | 11 +++++++++++ util/filter_paths.go | 4 ++++ util/live.go | 3 ++- 19 files changed, 139 insertions(+), 2 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index e80a4f0..6579ec9 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -27,7 +27,6 @@ linters: - stylecheck - tagalign - wrapcheck - - wsl # Disabled permanently - exhaustruct # structs may be uninitialized - nlreturn # covered by wsl cuddle rules diff --git a/cli/cli.go b/cli/cli.go index 3c3cc6d..adf5c9a 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -40,5 +40,6 @@ type arguments struct { func Parse() (*kong.Context, GlobalFlags) { var args arguments ctx := kong.Parse(&args, kong.Vars{"version": Version}) + return ctx, args.GlobalFlags } diff --git a/cli/graph.go b/cli/graph.go index d7ff48c..208b02f 100644 --- a/cli/graph.go +++ b/cli/graph.go @@ -28,6 +28,8 @@ func (g graph) Run(flags GlobalFlags) error { if err != nil { return fmt.Errorf("failed to load triggers: %w", err) } + tm.Graph(flags.Chroot, flags.Live).Print() + return nil } diff --git a/cli/list.go b/cli/list.go index fc81632..9a41a9c 100644 --- a/cli/list.go +++ b/cli/list.go @@ -28,7 +28,9 @@ func (l list) Run(flags GlobalFlags) error { if err != nil { return fmt.Errorf("failed to load triggers: %w", err) } + slog.Info("Available triggers:") tm.Print(flags.Chroot, flags.Live) + return nil } diff --git a/cli/run.go b/cli/run.go index 4efe3ce..c9bd709 100644 --- a/cli/run.go +++ b/cli/run.go @@ -35,9 +35,11 @@ func (r run) Run(flags GlobalFlags) error { if os.Geteuid() != 0 { return errors.New("you must have root privileges to run triggers") } + if util.IsChroot() { flags.Chroot = true } + if util.IsLive() { flags.Live = true } @@ -64,5 +66,6 @@ func (r run) Run(flags GlobalFlags) error { } // Run triggers. tm.Run(s, n) + return nil } diff --git a/config/load.go b/config/load.go index 1c5d48b..dd7cc1e 100644 --- a/config/load.go +++ b/config/load.go @@ -35,36 +35,47 @@ func Load(path string) (triggers.Map, error) { logger.Debug("Directory not found") return nil, nil } + return nil, fmt.Errorf("failed to read triggers: %w", err) } + tm := make(triggers.Map, len(entries)) + logger.Debug("Scanning directory") + for _, entry := range entries { if entry.IsDir() { continue } + name := entry.Name() if !strings.HasSuffix(name, ".toml") { continue } + t := triggers.Trigger{ Name: strings.TrimSuffix(name, ".toml"), Path: filepath.Clean(filepath.Join(path, name)), } logger.Debug("Trigger found", "name", t.Name) + err = t.Load(t.Path) if err != nil { return nil, err } + err = t.Validate() if err != nil { return nil, fmt.Errorf("failed to read %s from %s: %w", name, path, err) } + tm[t.Name] = t } + if len(tm) == 0 { logger.Debug("No triggers found") } + return tm, nil } @@ -76,6 +87,7 @@ func LoadAll() (triggers.Map, error) { if p, err := os.UserHomeDir(); err != nil { paths = append(paths, p) } + if os.Getuid() == 0 { uname := os.Getenv("SUDO_USER") if uname != "" && uname != "root" { @@ -89,13 +101,17 @@ func LoadAll() (triggers.Map, error) { } tm := make(triggers.Map) + for _, path := range paths { trig, err := Load(path) if err != nil { return nil, err } + tm.Merge(trig) } + slog.Info("Total triggers", "count", len(tm)) + return tm, nil } diff --git a/deps/graph.go b/deps/graph.go index 50737f9..b8253cf 100644 --- a/deps/graph.go +++ b/deps/graph.go @@ -40,12 +40,14 @@ func (g Graph) CheckMissing(triggers []string) { for name, deps := range g { for _, dep := range deps { found := false + for _, trigger := range triggers { if dep == trigger { found = true break } } + if !found { slog.Warn("Dependency does not exist", "parent", name, "child", dep) } @@ -63,6 +65,7 @@ func (g Graph) CheckCircular() { if next == last { break } + found = found[1:] } // TODO: Return an error instead of panicking. @@ -81,6 +84,7 @@ func (g Graph) circular(name string, visited []string) (found []string) { return } } + if len(found) == 0 { found = g.circular(dep, visited) if len(found) != 0 { @@ -88,6 +92,7 @@ func (g Graph) circular(name string, visited []string) (found []string) { } } } + return } @@ -95,30 +100,37 @@ func (g Graph) circular(name string, visited []string) (found []string) { func (g Graph) prune(names []string) { for k := range g { found := false + for _, name := range names { if k == name { found = true break } } + if !found { delete(g, k) } } + for k, deps := range g { var next []string + for _, dep := range deps { found := false + for _, name := range names { if dep == name { found = true break } } + if found { next = append(next, dep) } } + g[k] = next } } @@ -133,34 +145,43 @@ func (g Graph) traverse(todo []string) (order, remaining []string) { remaining = append(remaining, name) } } + for _, name := range remaining { var next []string + for _, dep := range g[name] { found := false + for _, prev := range order { if dep == prev { found = true break } } + if !found { next = append(next, dep) } } + g[name] = next } + sort.Strings(order) + return } // Resolve finds the ideal ordering for a list of triggers func (g Graph) Resolve(todo []string) (order []string) { g.prune(todo) + var partial []string for len(todo) > 0 { partial, todo = g.traverse(todo) order = append(order, partial...) } + return } @@ -170,14 +191,18 @@ func (g Graph) Print() { for name := range g { names = append(names, name) } + sort.Strings(names) fmt.Println("digraph {") + for _, name := range names { deps := g[name] sort.Strings(deps) + for _, dep := range deps { fmt.Printf("\t\"%s\" -> \"%s\";\n", name, dep) } } + fmt.Println("}") } diff --git a/main.go b/main.go index f33fbae..cb70cc0 100644 --- a/main.go +++ b/main.go @@ -28,6 +28,7 @@ func main() { if flags.Debug { logOpt.Level = slog.LevelDebug } + slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, logOpt))) err := ctx.Run(flags) diff --git a/state/map.go b/state/map.go index 7ad88b8..952f615 100644 --- a/state/map.go +++ b/state/map.go @@ -63,13 +63,16 @@ func (m Map) Save() error { if err := os.MkdirAll(filepath.Dir(Path), 0o750); err != nil { return err } + sFile, err := os.Create(filepath.Clean(Path)) if err != nil { return err } + enc := cbor.NewEncoder(sFile) err = enc.Encode(m) _ = sFile.Close() + return err } @@ -86,39 +89,48 @@ func (m Map) Diff(curr Map) Map { // Check for new or newer for currKey, currVal := range curr { found := false + for prevKey, prevVal := range m { if currKey == prevKey { found = true + if currVal.After(prevVal) { diff[currKey] = currVal } + break } } + if !found { diff[currKey] = currVal } } + return diff } // Search finds all of the matching files in a Map func (m Map) Search(paths []string) Map { match := make(Map) + for _, path := range paths { search := strings.ReplaceAll(path, "*", ".*") search = "^" + strings.ReplaceAll(search, string(filepath.Separator), "\\"+string(filepath.Separator)) + regex, err := regexp.Compile(search) if err != nil { slog.Warn("Could not convert to regex", "path", path) continue } + for k, v := range m { if regex.MatchString(k) { match[k] = v } } } + return match } @@ -128,16 +140,21 @@ func (m Map) Exclude(patterns []string) Map { for k, v := range m { match[k] = v } + var regexes []*regexp.Regexp + for _, pattern := range patterns { exclude := strings.ReplaceAll(pattern, "*", ".*") + regex, err := regexp.Compile(exclude) if err != nil { slog.Warn("Could not convert to regex", "pattern", pattern) continue } + regexes = append(regexes, regex) } + for k := range m { for _, regex := range regexes { if regex.MatchString(k) { @@ -146,6 +163,7 @@ func (m Map) Exclude(patterns []string) Map { } } } + return match } @@ -159,28 +177,35 @@ func (m Map) Strings() (strs []string) { for k := range m { strs = append(strs, k) } + return } // Scan goes over a set of paths and imports them and their contents to the map func Scan(filters []string) (m Map, err error) { m = make(Map) + var matches []string + for _, filter := range filters { if matches, err = filepath.Glob(filter); err != nil { err = fmt.Errorf("unable to glob path: %s", filter) return } + if len(matches) == 0 { continue } + for _, match := range matches { err = filepath.Walk(filepath.Clean(match), func(path string, info os.FileInfo, err error) error { if err != nil { err = fmt.Errorf("failed to check path: %s", path) return err } + m[filepath.Join(path, info.Name())] = info.ModTime() + return nil }) if err != nil { @@ -188,9 +213,11 @@ func Scan(filters []string) (m Map, err error) { err = nil continue } + return } } } + return } diff --git a/triggers/bin.go b/triggers/bin.go index f7432ee..fb22fdf 100644 --- a/triggers/bin.go +++ b/triggers/bin.go @@ -34,6 +34,7 @@ type Bin struct { // ExecuteBins generates and runs all of the necesarry Bin commands func (t *Trigger) ExecuteBins(s Scope) { var bins []Bin + var outputs []Output // Generate for _, b := range t.Bins { @@ -47,6 +48,7 @@ func (t *Trigger) ExecuteBins(s Scope) { outputs[i].Status = out.Status outputs[i].Message = out.Message } + t.Output = append(t.Output, outputs...) } @@ -73,6 +75,7 @@ func (b *Bin) Execute(s Scope, env map[string]string) Output { out.Status = Failure out.Message = fmt.Sprintf("error executing '%s %v': %s\n%s", b.Bin, b.Args, err.Error(), buff.String()) } + return out } @@ -80,23 +83,29 @@ func (b *Bin) Execute(s Scope, env map[string]string) Output { // in the arguments and creating separate binaries to be executed. func (b Bin) FanOut() (nbins []Bin, outputs []Output) { phIndex := -1 + for i, arg := range b.Args { if arg == "***" { phIndex = i break } } + if phIndex == -1 { nbins = append(nbins, b) out := Output{Name: b.Task} outputs = append(outputs, out) + return } + if b.Replace == nil { slog.Error("Placeholder found, but [bins.replaces] is missing") return } + slog.Debug("Replace string exists", "argument", phIndex) + paths := util.FilterPaths(b.Replace.Paths, b.Replace.Exclude) for _, path := range paths { out := Output{ @@ -107,5 +116,6 @@ func (b Bin) FanOut() (nbins []Bin, outputs []Output) { nbins = append(nbins, b) outputs = append(outputs, out) } + return } diff --git a/triggers/check.go b/triggers/check.go index 6289efd..13f1b61 100644 --- a/triggers/check.go +++ b/triggers/check.go @@ -30,10 +30,12 @@ type Check struct { // CheckMatch will glob the paths and if the path does not exist in the system, an error is returned func (t *Trigger) CheckMatch() (m state.Map, ok bool) { ok = true + if t.Check == nil { slog.Debug("No check paths for trigger", "name", t.Name) return } + m, err := state.Scan(t.Check.Paths) if err != nil { out := Output{ @@ -42,7 +44,9 @@ func (t *Trigger) CheckMatch() (m state.Map, ok bool) { } t.Output = append(t.Output, out) ok = false + return } + return } diff --git a/triggers/config.go b/triggers/config.go index 1c27b09..08f3c57 100644 --- a/triggers/config.go +++ b/triggers/config.go @@ -38,6 +38,7 @@ func (t *Trigger) Load(path string) error { if err := toml.Unmarshal(cfg, t); err != nil { return fmt.Errorf("unable to read config file located at %s due to %s", path, err.Error()) } + return nil } @@ -48,5 +49,6 @@ func (t *Trigger) Validate() error { if len(t.Bins) == 0 { return fmt.Errorf("triggers must contain at least one [[bin]]") } + return nil } diff --git a/triggers/map.go b/triggers/map.go index 804b5c6..1bcb45a 100644 --- a/triggers/map.go +++ b/triggers/map.go @@ -36,16 +36,23 @@ func (tm Map) Merge(tm2 Map) { // Print renders a Map in a human-readable format func (tm Map) Print(chroot, live bool) { var keys []string + max := 0 + for k := range tm { keys = append(keys, k) + if len(k) > max { max = len(k) } } + max += 4 + sort.Strings(keys) + f := fmt.Sprintf("%%%ds - %%s\n", max) + for _, key := range keys { t := tm[key] if t.Skip != nil { @@ -53,27 +60,35 @@ func (tm Map) Print(chroot, live bool) { continue } } + fmt.Printf(f, t.Name, t.Description) } + fmt.Println() } // Graph generates a dependency graph func (tm Map) Graph(chroot, live bool) (g deps.Graph) { g = make(deps.Graph) + var names []string + for _, t := range tm { if t.Skip != nil { if (t.Skip.Chroot && chroot) || (t.Skip.Live && live) { continue } } + if t.Deps != nil { g.Insert(t.Name, t.Deps.After) } + names = append(names, t.Name) } + g.Validate(names) + return } @@ -100,6 +115,7 @@ func (tm Map) Run(s Scope, names []string) { // Run Trigger t.Run(s, prev, next) } + if !s.DryRun { // Save new State for next run if err := next.Save(); err != nil { diff --git a/triggers/remove.go b/triggers/remove.go index 7ca65f6..8aabda4 100644 --- a/triggers/remove.go +++ b/triggers/remove.go @@ -33,15 +33,18 @@ func (t *Trigger) Remove(s Scope) bool { if s.DryRun { slog.Debug("No Paths will be removed during a dry-run") } + if len(t.Removals) == 0 { slog.Debug("No Paths to remove") return true } + for _, remove := range t.Removals { if !t.removeOne(s, remove) { return false } } + return true } @@ -54,22 +57,28 @@ func (t *Trigger) removeOne(s Scope, remove Remove) bool { Message: fmt.Sprintf("Failed to remove paths for '%s', reason: %s\n", t.Name, err), } t.Output = append(t.Output, out) + return false } + matches = matches.Exclude(remove.Exclude) for path := range matches { slog.Debug("Removing", "path", path) + if s.DryRun { continue } + if err := os.Remove(path); err != nil { out := Output{ Status: Failure, Message: fmt.Sprintf("Failed to remove path '%s', reason: %s\n", path, err), } t.Output = append(t.Output, out) + return false } } + return true } diff --git a/triggers/skip.go b/triggers/skip.go index c7deb60..6159aff 100644 --- a/triggers/skip.go +++ b/triggers/skip.go @@ -42,6 +42,7 @@ func (t *Trigger) ShouldSkip(s Scope, check, diff state.Map) bool { if s.Forced { return false } + if t.Skip == nil { return false } @@ -60,7 +61,9 @@ func (t *Trigger) ShouldSkip(s Scope, check, diff state.Map) bool { for k := range matches { out.Message = fmt.Sprintf("path '%s' found", k) t.Output = append(t.Output, out) + return true } + return false } diff --git a/triggers/trigger.go b/triggers/trigger.go index 2193334..2929ec3 100644 --- a/triggers/trigger.go +++ b/triggers/trigger.go @@ -58,6 +58,7 @@ func (t *Trigger) Run(s Scope, prev, next state.Map) (ok bool) { t.ExecuteBins(s) FINISH: t.Finish(s) + return } diff --git a/util/chroot.go b/util/chroot.go index 5703236..268890a 100644 --- a/util/chroot.go +++ b/util/chroot.go @@ -27,8 +27,11 @@ import ( // IsChroot detects if the current process is running in a chroot environment func IsChroot() bool { var raw []byte + var root, chroot *syscall.Stat_t + var rootDir, chrootDir os.FileInfo + var pid int // Try to check for access to the root partition of PID1 (shell?) if _, err := os.Stat("/proc/1/root"); err != nil { @@ -41,32 +44,40 @@ func IsChroot() bool { slog.Warn("Failed to access", "path", "/proc/mounts", "reason", err) goto FALLBACK } + raw, err = io.ReadAll(mounts) if err != nil { slog.Warn("Failed to read", "path", "/proc/mounts", "reason", err) goto FALLBACK } + _ = mounts.Close() + if strings.Contains(string(raw), "overlay / overlay") { slog.Debug("Overlayfs for '/' found, assuming chroot") return true } FALLBACK: slog.Debug("Falling back to rigorous check for chroot") + rootDir, err = os.Stat("/") if err != nil { slog.Error("Failed to access", "path", "/", "reason", err) // TODO: Return error instead of panicking. panic("Failed to access") } + pid = os.Getpid() + chrootDir, err = os.Stat(filepath.Join("/", "proc", strconv.Itoa(pid), "root")) if err != nil { slog.Error("Failed to access", "path", "/", "reason", err) // TODO: Return error instead of panicking. panic("Failed to access") } + root = rootDir.Sys().(*syscall.Stat_t) chroot = chrootDir.Sys().(*syscall.Stat_t) + return root.Dev != chroot.Dev || root.Ino != chroot.Ino } diff --git a/util/filter_paths.go b/util/filter_paths.go index 3ea08f1..c840f25 100644 --- a/util/filter_paths.go +++ b/util/filter_paths.go @@ -25,8 +25,10 @@ func match(filters []string) (matches []string) { if err != nil { continue } + matches = append(matches, partial...) } + return } @@ -39,7 +41,9 @@ func FilterPaths(includes []string, excludes []string) (paths []string) { break } } + paths = append(paths, includePath) } + return } diff --git a/util/live.go b/util/live.go index 7cfb7f5..f3139ec 100644 --- a/util/live.go +++ b/util/live.go @@ -26,11 +26,12 @@ func IsLive() bool { slog.Debug("Live session detected") return true } + if os.IsNotExist(err) { return false } + slog.Error("Could not check for live session", "reason", err) // TODO: Return error instead of panicking. panic("Could not check for live session") - // return false } From d36032360174fb912f728f33b2b25e4d584836c5 Mon Sep 17 00:00:00 2001 From: Silke Hofstra Date: Fri, 1 Sep 2023 20:22:41 +0200 Subject: [PATCH 05/19] Enable and appease the gocritic linter --- .golangci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.golangci.yaml b/.golangci.yaml index 6579ec9..94eb4f0 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -11,7 +11,6 @@ linters: - forbidigo - gochecknoglobals - gochecknoinits - - gocritic - godot - godox - goerr113 From 5e1611b94ce312c546a02ef1eb2f1eaf0ae1b4dd Mon Sep 17 00:00:00 2001 From: Silke Hofstra Date: Fri, 1 Sep 2023 20:24:34 +0200 Subject: [PATCH 06/19] Enable and appease the godot linter --- .golangci.yaml | 1 - cli/graph.go | 2 +- config/paths.go | 4 ++-- deps/graph.go | 18 +++++++++--------- state/map.go | 22 +++++++++++----------- triggers/bin.go | 4 ++-- triggers/check.go | 2 +- triggers/config.go | 4 ++-- triggers/deps.go | 2 +- triggers/map.go | 10 +++++----- triggers/remove.go | 4 ++-- triggers/scope.go | 2 +- util/chroot.go | 2 +- util/filter_paths.go | 2 +- util/live.go | 2 +- 15 files changed, 40 insertions(+), 41 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index 94eb4f0..5208ae6 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -11,7 +11,6 @@ linters: - forbidigo - gochecknoglobals - gochecknoinits - - godot - godox - goerr113 - gomnd diff --git a/cli/graph.go b/cli/graph.go index 208b02f..edbd205 100644 --- a/cli/graph.go +++ b/cli/graph.go @@ -22,7 +22,7 @@ import ( type graph struct{} -// GraphDepsRun prints the usage for the requested command +// GraphDepsRun prints the usage for the requested command. func (g graph) Run(flags GlobalFlags) error { tm, err := config.LoadAll() if err != nil { diff --git a/config/paths.go b/config/paths.go index b109a5f..1ee2325 100644 --- a/config/paths.go +++ b/config/paths.go @@ -15,8 +15,8 @@ package config var ( - // UsrDir is the path defined during build (Makefile) i.e. /usr/share/defaults/usysconf.d + // UsrDir is the path defined during build (Makefile) i.e. `/usr/share/defaults/usysconf.d`. UsrDir string - // SysDir is the path defined during build (Makefile) i.e. /etc/usysconf.d + // SysDir is the path defined during build (Makefile) i.e. `/etc/usysconf.d`. SysDir string ) diff --git a/deps/graph.go b/deps/graph.go index b8253cf..676017e 100644 --- a/deps/graph.go +++ b/deps/graph.go @@ -21,21 +21,21 @@ import ( "strings" ) -// Graph represents the dependencies shared between triggers +// Graph represents the dependencies shared between triggers. type Graph map[string][]string -// Insert sets the dependencies for a given trigger +// Insert sets the dependencies for a given trigger. func (g Graph) Insert(name string, deps []string) { g[name] = append(g[name], deps...) } -// Validate checks the graph for any potential issues +// Validate checks the graph for any potential issues. func (g Graph) Validate(triggers []string) { g.CheckCircular() g.CheckMissing(triggers) } -// CheckMissing checks for any missign triggers and prints warnings +// CheckMissing checks for any missign triggers and prints warnings. func (g Graph) CheckMissing(triggers []string) { for name, deps := range g { for _, dep := range deps { @@ -55,7 +55,7 @@ func (g Graph) CheckMissing(triggers []string) { } } -// CheckCircular checks for circular dependencies +// CheckCircular checks for circular dependencies. func (g Graph) CheckCircular() { var visited []string for name := range g { @@ -96,7 +96,7 @@ func (g Graph) circular(name string, visited []string) (found []string) { return } -// prune all references to things not in the list +// prune all references to things not in the list. func (g Graph) prune(names []string) { for k := range g { found := false @@ -135,7 +135,7 @@ func (g Graph) prune(names []string) { } } -// traverse performs a breadth-first traversal of a graph +// traverse performs a breadth-first traversal of a graph. func (g Graph) traverse(todo []string) (order, remaining []string) { for _, name := range todo { deps := g[name] @@ -172,7 +172,7 @@ func (g Graph) traverse(todo []string) (order, remaining []string) { return } -// Resolve finds the ideal ordering for a list of triggers +// Resolve finds the ideal ordering for a list of triggers. func (g Graph) Resolve(todo []string) (order []string) { g.prune(todo) @@ -185,7 +185,7 @@ func (g Graph) Resolve(todo []string) (order []string) { return } -// Print renders this graph to a "dot" format +// Print renders this graph to a "dot" format. func (g Graph) Print() { var names []string for name := range g { diff --git a/state/map.go b/state/map.go index 952f615..2623361 100644 --- a/state/map.go +++ b/state/map.go @@ -26,13 +26,13 @@ import ( "github.com/fxamacker/cbor/v2" ) -// Path is the location of the serialized system state directory +// Path is the location of the serialized system state directory. var Path string -// Map contains a list files and their modification times +// Map contains a list files and their modification times. type Map map[string]time.Time -// Load reads in the state if it exists and deserializes it +// Load reads in the state if it exists and deserializes it. func Load() (Map, error) { m := make(Map) sFile, err := os.Open(filepath.Clean(Path)) @@ -58,7 +58,7 @@ func Load() (Map, error) { return m, nil } -// Save writes out the current state for future runs +// Save writes out the current state for future runs. func (m Map) Save() error { if err := os.MkdirAll(filepath.Dir(Path), 0o750); err != nil { return err @@ -76,14 +76,14 @@ func (m Map) Save() error { return err } -// Merge combines two Maps into one +// Merge combines two Maps into one. func (m Map) Merge(other Map) { for k, v := range other { m[k] = v } } -// Diff finds all of the Files which were modified or deleted between states +// Diff finds all of the Files which were modified or deleted between states. func (m Map) Diff(curr Map) Map { diff := make(Map) // Check for new or newer @@ -110,7 +110,7 @@ func (m Map) Diff(curr Map) Map { return diff } -// Search finds all of the matching files in a Map +// Search finds all of the matching files in a Map. func (m Map) Search(paths []string) Map { match := make(Map) @@ -134,7 +134,7 @@ func (m Map) Search(paths []string) Map { return match } -// Exclude removes keys from the Map if they match certain patterns +// Exclude removes keys from the Map if they match certain patterns. func (m Map) Exclude(patterns []string) Map { match := make(Map) for k, v := range m { @@ -167,12 +167,12 @@ func (m Map) Exclude(patterns []string) Map { return match } -// IsEmpty checkes if the Map has nothing in it +// IsEmpty checkes if the Map has nothing in it. func (m Map) IsEmpty() bool { return len(m) == 0 } -// Strings gets a list of files from the keys +// Strings gets a list of files from the keys. func (m Map) Strings() (strs []string) { for k := range m { strs = append(strs, k) @@ -181,7 +181,7 @@ func (m Map) Strings() (strs []string) { return } -// Scan goes over a set of paths and imports them and their contents to the map +// Scan goes over a set of paths and imports them and their contents to the map. func Scan(filters []string) (m Map, err error) { m = make(Map) diff --git a/triggers/bin.go b/triggers/bin.go index fb22fdf..3f05c78 100644 --- a/triggers/bin.go +++ b/triggers/bin.go @@ -31,7 +31,7 @@ type Bin struct { Replace *Replace `toml:"replace"` } -// ExecuteBins generates and runs all of the necesarry Bin commands +// ExecuteBins generates and runs all of the necesarry Bin commands. func (t *Trigger) ExecuteBins(s Scope) { var bins []Bin @@ -52,7 +52,7 @@ func (t *Trigger) ExecuteBins(s Scope) { t.Output = append(t.Output, outputs...) } -// Execute the binary from the confuration +// Execute the binary from the confuration. func (b *Bin) Execute(s Scope, env map[string]string) Output { out := Output{Status: Success} // if the norun flag is present do not execute the configuration diff --git a/triggers/check.go b/triggers/check.go index 13f1b61..a33f457 100644 --- a/triggers/check.go +++ b/triggers/check.go @@ -27,7 +27,7 @@ type Check struct { Paths []string `toml:"paths"` } -// CheckMatch will glob the paths and if the path does not exist in the system, an error is returned +// CheckMatch will glob the paths and if the path does not exist in the system, an error is returned. func (t *Trigger) CheckMatch() (m state.Map, ok bool) { ok = true diff --git a/triggers/config.go b/triggers/config.go index 08f3c57..f6feca9 100644 --- a/triggers/config.go +++ b/triggers/config.go @@ -23,7 +23,7 @@ import ( "github.com/BurntSushi/toml" ) -// Load reads a Trigger configuration from a file and parses it +// Load reads a Trigger configuration from a file and parses it. func (t *Trigger) Load(path string) error { // Check if this is a valid file path if _, err := os.Stat(path); os.IsNotExist(err) { @@ -42,7 +42,7 @@ func (t *Trigger) Load(path string) error { return nil } -// Validate checks for errors in a Trigger configuration +// Validate checks for errors in a Trigger configuration. func (t *Trigger) Validate() error { // Verify that there is at least one binary to execute, otherwise there // is no need to continue diff --git a/triggers/deps.go b/triggers/deps.go index e9187e1..14abcf6 100644 --- a/triggers/deps.go +++ b/triggers/deps.go @@ -14,7 +14,7 @@ package triggers -// Deps contains a description of the dependencies between triggers +// Deps contains a description of the dependencies between triggers. type Deps struct { After []string `toml:"after"` } diff --git a/triggers/map.go b/triggers/map.go index 1bcb45a..58c9dee 100644 --- a/triggers/map.go +++ b/triggers/map.go @@ -23,17 +23,17 @@ import ( "github.com/getsolus/usysconf/state" ) -// Map relates the name of trigger to its definition +// Map relates the name of trigger to its definition. type Map map[string]Trigger -// Merge combines two Maps by copying from right to left +// Merge combines two Maps by copying from right to left. func (tm Map) Merge(tm2 Map) { for k, v := range tm2 { tm[k] = v } } -// Print renders a Map in a human-readable format +// Print renders a Map in a human-readable format. func (tm Map) Print(chroot, live bool) { var keys []string @@ -67,7 +67,7 @@ func (tm Map) Print(chroot, live bool) { fmt.Println() } -// Graph generates a dependency graph +// Graph generates a dependency graph. func (tm Map) Graph(chroot, live bool) (g deps.Graph) { g = make(deps.Graph) @@ -92,7 +92,7 @@ func (tm Map) Graph(chroot, live bool) (g deps.Graph) { return } -// Run executes a list of triggers, where available +// Run executes a list of triggers, where available. func (tm Map) Run(s Scope, names []string) { prev, err := state.Load() if err != nil { diff --git a/triggers/remove.go b/triggers/remove.go index 8aabda4..eb68233 100644 --- a/triggers/remove.go +++ b/triggers/remove.go @@ -28,7 +28,7 @@ type Remove struct { Exclude []string `toml:"exclude"` } -// Remove glob the paths and if it exists it will remove it from the system +// Remove glob the paths and if it exists it will remove it from the system. func (t *Trigger) Remove(s Scope) bool { if s.DryRun { slog.Debug("No Paths will be removed during a dry-run") @@ -48,7 +48,7 @@ func (t *Trigger) Remove(s Scope) bool { return true } -// removeOne carries out removals for a single Remove entry +// removeOne carries out removals for a single Remove entry. func (t *Trigger) removeOne(s Scope, remove Remove) bool { matches, err := state.Scan(remove.Paths) if err != nil { diff --git a/triggers/scope.go b/triggers/scope.go index c37f2f1..0410115 100644 --- a/triggers/scope.go +++ b/triggers/scope.go @@ -14,7 +14,7 @@ package triggers -// Scope sets limits of execution for a trigger +// Scope sets limits of execution for a trigger. type Scope struct { Chroot bool Debug bool diff --git a/util/chroot.go b/util/chroot.go index 268890a..03cf5b7 100644 --- a/util/chroot.go +++ b/util/chroot.go @@ -24,7 +24,7 @@ import ( "syscall" ) -// IsChroot detects if the current process is running in a chroot environment +// IsChroot detects if the current process is running in a chroot environment. func IsChroot() bool { var raw []byte diff --git a/util/filter_paths.go b/util/filter_paths.go index c840f25..72983fd 100644 --- a/util/filter_paths.go +++ b/util/filter_paths.go @@ -18,7 +18,7 @@ import ( "path/filepath" ) -// get a list of files that match the provided filters +// get a list of files that match the provided filters. func match(filters []string) (matches []string) { for _, filter := range filters { partial, err := filepath.Glob(filter) diff --git a/util/live.go b/util/live.go index f3139ec..5f553f3 100644 --- a/util/live.go +++ b/util/live.go @@ -19,7 +19,7 @@ import ( "os" ) -// IsLive checks is this process is running in a Live install +// IsLive checks is this process is running in a Live install. func IsLive() bool { var err error if _, err = os.Stat("/run/initramfs/livedev"); err == nil { From 7025b98dff2324400facedfbe5f9ecfaab2dc3e3 Mon Sep 17 00:00:00 2001 From: Silke Hofstra Date: Fri, 1 Sep 2023 20:27:12 +0200 Subject: [PATCH 07/19] Enable and appease the goerr113 linter --- .golangci.yaml | 1 - cli/run.go | 4 +++- state/map.go | 4 ++-- triggers/config.go | 10 +++++++--- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index 5208ae6..afe064e 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -12,7 +12,6 @@ linters: - gochecknoglobals - gochecknoinits - godox - - goerr113 - gomnd - gosec - govet diff --git a/cli/run.go b/cli/run.go index c9bd709..d8162c4 100644 --- a/cli/run.go +++ b/cli/run.go @@ -31,9 +31,11 @@ type run struct { Triggers []string `arg:"" help:"Names of the triggers to run." optional:""` } +var errNeedRoot = errors.New("you must have root privileges to run triggers") + func (r run) Run(flags GlobalFlags) error { if os.Geteuid() != 0 { - return errors.New("you must have root privileges to run triggers") + return errNeedRoot } if util.IsChroot() { diff --git a/state/map.go b/state/map.go index 2623361..4c52168 100644 --- a/state/map.go +++ b/state/map.go @@ -189,7 +189,7 @@ func Scan(filters []string) (m Map, err error) { for _, filter := range filters { if matches, err = filepath.Glob(filter); err != nil { - err = fmt.Errorf("unable to glob path: %s", filter) + err = fmt.Errorf("unable to glob path %q: %w", filter, err) return } @@ -200,7 +200,7 @@ func Scan(filters []string) (m Map, err error) { for _, match := range matches { err = filepath.Walk(filepath.Clean(match), func(path string, info os.FileInfo, err error) error { if err != nil { - err = fmt.Errorf("failed to check path: %s", path) + err = fmt.Errorf("failed to check path %q: %w", path, err) return err } diff --git a/triggers/config.go b/triggers/config.go index f6feca9..1e61549 100644 --- a/triggers/config.go +++ b/triggers/config.go @@ -15,6 +15,7 @@ package triggers import ( + "errors" "fmt" "io/ioutil" "os" @@ -32,22 +33,25 @@ func (t *Trigger) Load(path string) error { // Read the configuration into the program cfg, err := ioutil.ReadFile(filepath.Clean(path)) if err != nil { - return fmt.Errorf("unable to read config file located at %s", path) + return fmt.Errorf("unable to read config file located at %q: %w", path, err) } // Save the configuration into the content structure if err := toml.Unmarshal(cfg, t); err != nil { - return fmt.Errorf("unable to read config file located at %s due to %s", path, err.Error()) + return fmt.Errorf("unable to read config file located at %q: %w", path, err) } return nil } +// ErrNoBin is returned when a trigger does not contain a binary to execute. +var ErrNoBin = errors.New("triggers must contain at least one [[bin]]") + // Validate checks for errors in a Trigger configuration. func (t *Trigger) Validate() error { // Verify that there is at least one binary to execute, otherwise there // is no need to continue if len(t.Bins) == 0 { - return fmt.Errorf("triggers must contain at least one [[bin]]") + return ErrNoBin } return nil From 1c26c8c59b66833963b801854487c50144e9284a Mon Sep 17 00:00:00 2001 From: Silke Hofstra Date: Fri, 1 Sep 2023 20:28:12 +0200 Subject: [PATCH 08/19] Enable and appease the gomnd linter --- .golangci.yaml | 1 - state/map.go | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index afe064e..359dd89 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -12,7 +12,6 @@ linters: - gochecknoglobals - gochecknoinits - godox - - gomnd - gosec - govet - lll diff --git a/state/map.go b/state/map.go index 4c52168..8fed2e9 100644 --- a/state/map.go +++ b/state/map.go @@ -26,6 +26,8 @@ import ( "github.com/fxamacker/cbor/v2" ) +const stateDirPermissions = 0o750 + // Path is the location of the serialized system state directory. var Path string @@ -60,7 +62,7 @@ func Load() (Map, error) { // Save writes out the current state for future runs. func (m Map) Save() error { - if err := os.MkdirAll(filepath.Dir(Path), 0o750); err != nil { + if err := os.MkdirAll(filepath.Dir(Path), stateDirPermissions); err != nil { return err } From e807b38924ce79b04c98f76c4b2efc15d6e8f3ce Mon Sep 17 00:00:00 2001 From: Silke Hofstra Date: Fri, 1 Sep 2023 20:29:31 +0200 Subject: [PATCH 09/19] Enable and appease the gosec linter --- .golangci.yaml | 1 - triggers/bin.go | 6 ++++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index 359dd89..d0623a6 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -12,7 +12,6 @@ linters: - gochecknoglobals - gochecknoinits - godox - - gosec - govet - lll - musttag diff --git a/triggers/bin.go b/triggers/bin.go index 3f05c78..6ba6b20 100644 --- a/triggers/bin.go +++ b/triggers/bin.go @@ -52,7 +52,7 @@ func (t *Trigger) ExecuteBins(s Scope) { t.Output = append(t.Output, outputs...) } -// Execute the binary from the confuration. +// Execute the binary from the configuration. func (b *Bin) Execute(s Scope, env map[string]string) Output { out := Output{Status: Success} // if the norun flag is present do not execute the configuration @@ -60,8 +60,10 @@ func (b *Bin) Execute(s Scope, env map[string]string) Output { out.Status = Success return out } + // Create command - cmd := exec.Command(b.Bin, b.Args...) + cmd := exec.Command(b.Bin, b.Args...) //#nosec:G204 // the command from the config is tainted + // Setup environment for k, v := range env { cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", k, v)) From 47089b65c998c8b6d26230056411f097c02ed5bb Mon Sep 17 00:00:00 2001 From: Silke Hofstra Date: Fri, 1 Sep 2023 20:30:03 +0200 Subject: [PATCH 10/19] Enable and appease the govet linter --- .golangci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.golangci.yaml b/.golangci.yaml index d0623a6..3d248f4 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -12,7 +12,6 @@ linters: - gochecknoglobals - gochecknoinits - godox - - govet - lll - musttag - nakedret From 56c4e5b89588f41b4f2506746e8adcce251086fb Mon Sep 17 00:00:00 2001 From: Silke Hofstra Date: Fri, 1 Sep 2023 20:31:21 +0200 Subject: [PATCH 11/19] Enable and appease the lll linter --- .golangci.yaml | 1 - cli/cli.go | 2 +- cli/run.go | 2 +- triggers/skip.go | 7 ++++--- util/filter_paths.go | 3 ++- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index 3d248f4..f1df798 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -12,7 +12,6 @@ linters: - gochecknoglobals - gochecknoinits - godox - - lll - musttag - nakedret - prealloc diff --git a/cli/cli.go b/cli/cli.go index adf5c9a..bba3f86 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -24,7 +24,7 @@ var Version string = "unknown" // GlobalFlags contains the flags for all commands. type GlobalFlags struct { Debug bool `short:"d" long:"debug" help:"Run in debug mode."` - Chroot bool `short:"c" long:"chroot" help:"Specify that command is being run from a chrooted environment."` + Chroot bool `short:"c" long:"chroot" help:"Specify that command is being run from a chrooted environment."` //nolint:lll Live bool `short:"l" long:"live" help:"Specify that command is being run from a live medium."` Version kong.VersionFlag `short:"v" long:"version" help:"Print version and exit."` } diff --git a/cli/run.go b/cli/run.go index d8162c4..b51cd8a 100644 --- a/cli/run.go +++ b/cli/run.go @@ -26,7 +26,7 @@ import ( type run struct { Force bool `short:"f" long:"force" help:"Force run the configuration regardless if it should be skipped."` - DryRun bool `short:"n" long:"dry-run" help:"Test the configuration files without executing the specified binaries and arguments."` + DryRun bool `short:"n" long:"dry-run" help:"Test the configuration files without executing the specified binaries and arguments."` //nolint:lll Triggers []string `arg:"" help:"Names of the triggers to run." optional:""` } diff --git a/triggers/skip.go b/triggers/skip.go index 6159aff..8a576a8 100644 --- a/triggers/skip.go +++ b/triggers/skip.go @@ -20,15 +20,16 @@ import ( "github.com/getsolus/usysconf/state" ) -// Skip contains details for when the configuration will not be executed, due to existing paths, or possible flags passed. -// This supports globbing. +// Skip contains details for when the configuration will not be executed due to existing paths, +// or possible flags passed. This supports globbing. type Skip struct { Chroot bool `toml:"chroot,omitempty"` Live bool `toml:"live,omitempty"` Paths []string `toml:"paths"` } -// ShouldSkip will process the skip and check elements of the configuration and see if it should not be executed. +// ShouldSkip will process the skip and check elements of the configuration and see if +// it should not be executed. func (t *Trigger) ShouldSkip(s Scope, check, diff state.Map) bool { out := Output{ Status: Skipped, diff --git a/util/filter_paths.go b/util/filter_paths.go index 72983fd..129ac6e 100644 --- a/util/filter_paths.go +++ b/util/filter_paths.go @@ -32,7 +32,8 @@ func match(filters []string) (matches []string) { return } -// FilterPaths will process through globbed paths and remove any paths from the resulting slice if they are present in the excludes slice. +// FilterPaths will process through globbed paths and remove any paths from the resulting slice +// if they are present in the excludes slice. func FilterPaths(includes []string, excludes []string) (paths []string) { excludePaths := match(excludes) for _, includePath := range match(includes) { From b8d6d8dfd105d0369241bba5a053fcc9c2afb1fa Mon Sep 17 00:00:00 2001 From: Silke Hofstra Date: Fri, 1 Sep 2023 20:33:15 +0200 Subject: [PATCH 12/19] Enable and appease the musttag linter --- .golangci.yaml | 1 - triggers/trigger.go | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index f1df798..61f4f55 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -12,7 +12,6 @@ linters: - gochecknoglobals - gochecknoinits - godox - - musttag - nakedret - prealloc - revive diff --git a/triggers/trigger.go b/triggers/trigger.go index 2929ec3..8310016 100644 --- a/triggers/trigger.go +++ b/triggers/trigger.go @@ -22,9 +22,9 @@ import ( // Trigger contains all the information for a configuration to be executed and output to the user. type Trigger struct { - Name string - Path string - Output []Output + Name string `toml:"-"` + Path string `toml:"-"` + Output []Output `toml:"-"` Description string `toml:"description"` Check *Check `toml:"check,omitempty"` From ecae72e6e71347bdc0ad00eaf3da9040ed899cd2 Mon Sep 17 00:00:00 2001 From: Silke Hofstra Date: Fri, 1 Sep 2023 20:36:07 +0200 Subject: [PATCH 13/19] Enable and appease the nakedret linter --- .golangci.yaml | 1 - deps/graph.go | 2 +- state/map.go | 10 ++++------ triggers/bin.go | 10 +++------- 4 files changed, 8 insertions(+), 15 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index 61f4f55..dd2cffb 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -12,7 +12,6 @@ linters: - gochecknoglobals - gochecknoinits - godox - - nakedret - prealloc - revive - staticcheck diff --git a/deps/graph.go b/deps/graph.go index 676017e..00512a9 100644 --- a/deps/graph.go +++ b/deps/graph.go @@ -169,7 +169,7 @@ func (g Graph) traverse(todo []string) (order, remaining []string) { sort.Strings(order) - return + return order, remaining } // Resolve finds the ideal ordering for a list of triggers. diff --git a/state/map.go b/state/map.go index 8fed2e9..8d02633 100644 --- a/state/map.go +++ b/state/map.go @@ -191,8 +191,7 @@ func Scan(filters []string) (m Map, err error) { for _, filter := range filters { if matches, err = filepath.Glob(filter); err != nil { - err = fmt.Errorf("unable to glob path %q: %w", filter, err) - return + return m, fmt.Errorf("unable to glob path %q: %w", filter, err) } if len(matches) == 0 { @@ -202,8 +201,7 @@ func Scan(filters []string) (m Map, err error) { for _, match := range matches { err = filepath.Walk(filepath.Clean(match), func(path string, info os.FileInfo, err error) error { if err != nil { - err = fmt.Errorf("failed to check path %q: %w", path, err) - return err + return fmt.Errorf("failed to check path %q: %w", path, err) } m[filepath.Join(path, info.Name())] = info.ModTime() @@ -216,10 +214,10 @@ func Scan(filters []string) (m Map, err error) { continue } - return + return m, err } } } - return + return m, err } diff --git a/triggers/bin.go b/triggers/bin.go index 6ba6b20..aa43569 100644 --- a/triggers/bin.go +++ b/triggers/bin.go @@ -94,16 +94,12 @@ func (b Bin) FanOut() (nbins []Bin, outputs []Output) { } if phIndex == -1 { - nbins = append(nbins, b) - out := Output{Name: b.Task} - outputs = append(outputs, out) - - return + return append(nbins, b), append(outputs, Output{Name: b.Task}) } if b.Replace == nil { slog.Error("Placeholder found, but [bins.replaces] is missing") - return + return nil, nil } slog.Debug("Replace string exists", "argument", phIndex) @@ -119,5 +115,5 @@ func (b Bin) FanOut() (nbins []Bin, outputs []Output) { outputs = append(outputs, out) } - return + return nbins, outputs } From 8a6e0316cd890744e1296272f34bd0315965dd02 Mon Sep 17 00:00:00 2001 From: Silke Hofstra Date: Fri, 1 Sep 2023 20:38:03 +0200 Subject: [PATCH 14/19] Enable and appease the prealloc linter --- .golangci.yaml | 1 - deps/graph.go | 3 ++- state/map.go | 2 +- triggers/map.go | 6 ++---- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index dd2cffb..fbfa319 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -12,7 +12,6 @@ linters: - gochecknoglobals - gochecknoinits - godox - - prealloc - revive - staticcheck - stylecheck diff --git a/deps/graph.go b/deps/graph.go index 00512a9..c6bdcd3 100644 --- a/deps/graph.go +++ b/deps/graph.go @@ -187,7 +187,8 @@ func (g Graph) Resolve(todo []string) (order []string) { // Print renders this graph to a "dot" format. func (g Graph) Print() { - var names []string + names := make([]string, 0, len(g)) + for name := range g { names = append(names, name) } diff --git a/state/map.go b/state/map.go index 8d02633..3a2b5fa 100644 --- a/state/map.go +++ b/state/map.go @@ -143,7 +143,7 @@ func (m Map) Exclude(patterns []string) Map { match[k] = v } - var regexes []*regexp.Regexp + regexes := make([]*regexp.Regexp, 0, len(patterns)) for _, pattern := range patterns { exclude := strings.ReplaceAll(pattern, "*", ".*") diff --git a/triggers/map.go b/triggers/map.go index 58c9dee..d65166d 100644 --- a/triggers/map.go +++ b/triggers/map.go @@ -35,8 +35,7 @@ func (tm Map) Merge(tm2 Map) { // Print renders a Map in a human-readable format. func (tm Map) Print(chroot, live bool) { - var keys []string - + keys := make([]string, 0, len(tm)) max := 0 for k := range tm { @@ -70,8 +69,7 @@ func (tm Map) Print(chroot, live bool) { // Graph generates a dependency graph. func (tm Map) Graph(chroot, live bool) (g deps.Graph) { g = make(deps.Graph) - - var names []string + names := make([]string, 0, len(tm)) for _, t := range tm { if t.Skip != nil { From d06fc925eb0f9068c637f14d77d7650b2bd79f90 Mon Sep 17 00:00:00 2001 From: Silke Hofstra Date: Fri, 1 Sep 2023 20:38:55 +0200 Subject: [PATCH 15/19] Enable and appease the staticcheck linter --- .golangci.yaml | 1 - triggers/config.go | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index fbfa319..9ed66f7 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -13,7 +13,6 @@ linters: - gochecknoinits - godox - revive - - staticcheck - stylecheck - tagalign - wrapcheck diff --git a/triggers/config.go b/triggers/config.go index 1e61549..415bef3 100644 --- a/triggers/config.go +++ b/triggers/config.go @@ -17,7 +17,6 @@ package triggers import ( "errors" "fmt" - "io/ioutil" "os" "path/filepath" @@ -31,7 +30,7 @@ func (t *Trigger) Load(path string) error { return err } // Read the configuration into the program - cfg, err := ioutil.ReadFile(filepath.Clean(path)) + cfg, err := os.ReadFile(filepath.Clean(path)) if err != nil { return fmt.Errorf("unable to read config file located at %q: %w", path, err) } From 3e60e0527cffff9ec41738b98e5b9bedb3daa9d7 Mon Sep 17 00:00:00 2001 From: Silke Hofstra Date: Fri, 1 Sep 2023 20:48:16 +0200 Subject: [PATCH 16/19] Update Make `check` target with golangci-lint --- Makefile | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 19d1379..f67cbce 100644 --- a/Makefile +++ b/Makefile @@ -54,16 +54,7 @@ uninstall: $(RMDIR_IF_EMPTY) $(BINDIR) check: - $(GO) get -u golang.org/x/lint/golint - $(GO) get -u github.com/securego/gosec/cmd/gosec - $(GO) get -u honnef.co/go/tools/cmd/staticcheck - $(GO) get -u gitlab.com/opennota/check/cmd/aligncheck - $(GO) fmt -x ./... - $(GO) vet ./... - golint -set_exit_status `go list ./... | grep -v vendor` - gosec -exclude=G204 ./... - staticcheck ./... - aligncheck ./... + $(shell $(GO) env GOPATH)/bin/golangci-lint run $(GO) test -cover ./... vendor: check clean From d115fd7c515abc1900ff758fa67d38dba3dceec3 Mon Sep 17 00:00:00 2001 From: Silke Hofstra Date: Mon, 11 Sep 2023 19:57:15 +0200 Subject: [PATCH 17/19] Enable and configure the errcheck linter --- .golangci.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.golangci.yaml b/.golangci.yaml index 9ed66f7..d9f9008 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -5,7 +5,6 @@ linters: # Disabled to get codebase to pass the linter. # We can enable these one at a time. - cyclop - - errcheck - forcetypeassert - funlen - forbidigo @@ -57,6 +56,10 @@ linters-settings: exhaustive: default-signifies-exhaustive: true + errcheck: + exclude-functions: + - (*os.File).Close + gci: sections: - standard From 58e16730fc9de04c7f5904c611cd2c7c9de40f90 Mon Sep 17 00:00:00 2001 From: Silke Hofstra Date: Mon, 11 Sep 2023 19:58:26 +0200 Subject: [PATCH 18/19] Enable and appease the forbidigo linter --- .golangci.yaml | 1 - deps/graph.go | 2 ++ triggers/map.go | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.golangci.yaml b/.golangci.yaml index d9f9008..8fa67ad 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -7,7 +7,6 @@ linters: - cyclop - forcetypeassert - funlen - - forbidigo - gochecknoglobals - gochecknoinits - godox diff --git a/deps/graph.go b/deps/graph.go index c6bdcd3..dace1cf 100644 --- a/deps/graph.go +++ b/deps/graph.go @@ -186,6 +186,8 @@ func (g Graph) Resolve(todo []string) (order []string) { } // Print renders this graph to a "dot" format. +// +//nolint:forbidigo func (g Graph) Print() { names := make([]string, 0, len(g)) diff --git a/triggers/map.go b/triggers/map.go index d65166d..ef5cc9a 100644 --- a/triggers/map.go +++ b/triggers/map.go @@ -34,6 +34,8 @@ func (tm Map) Merge(tm2 Map) { } // Print renders a Map in a human-readable format. +// +//nolint:forbidigo func (tm Map) Print(chroot, live bool) { keys := make([]string, 0, len(tm)) max := 0 From 865d34fde1c1444505ebe8716c2b4d27e946e6a2 Mon Sep 17 00:00:00 2001 From: Silke Hofstra Date: Mon, 11 Sep 2023 20:00:45 +0200 Subject: [PATCH 19/19] Enable and appease the tagalign linter --- .golangci.yaml | 5 ++++- cli/cli.go | 12 ++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index 8fa67ad..c7666d9 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -12,7 +12,6 @@ linters: - godox - revive - stylecheck - - tagalign - wrapcheck # Disabled permanently - exhaustruct # structs may be uninitialized @@ -113,6 +112,10 @@ linters-settings: - short - long - desc + - cmd + - arg + - aliases + - help varnamelen: min-name-length: 1 diff --git a/cli/cli.go b/cli/cli.go index bba3f86..9ed5a66 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -23,18 +23,18 @@ var Version string = "unknown" // GlobalFlags contains the flags for all commands. type GlobalFlags struct { - Debug bool `short:"d" long:"debug" help:"Run in debug mode."` - Chroot bool `short:"c" long:"chroot" help:"Specify that command is being run from a chrooted environment."` //nolint:lll - Live bool `short:"l" long:"live" help:"Specify that command is being run from a live medium."` - Version kong.VersionFlag `short:"v" long:"version" help:"Print version and exit."` + Debug bool `short:"d" long:"debug" help:"Run in debug mode."` + Chroot bool `short:"c" long:"chroot" help:"Specify that command is being run from a chrooted environment."` //nolint:lll + Live bool `short:"l" long:"live" help:"Specify that command is being run from a live medium."` + Version kong.VersionFlag `short:"v" long:"version" help:"Print version and exit."` } type arguments struct { GlobalFlags - Run run `cmd:"" aliases:"r" help:"Run specified trigger(s) to update the system configuration."` + Run run `cmd:"" aliases:"r" help:"Run specified trigger(s) to update the system configuration."` List list `cmd:"" aliases:"ls" help:"List available triggers to run (user-specific)."` - Graph graph `cmd:"" aliases:"g" help:"Print the dependencies for all available triggers."` + Graph graph `cmd:"" aliases:"g" help:"Print the dependencies for all available triggers."` } func Parse() (*kong.Context, GlobalFlags) {