Skip to content

Commit 7dade1e

Browse files
committed
fix(sandbox): satisfy lint rules in Herdr setup
1 parent 4afa26d commit 7dade1e

2 files changed

Lines changed: 42 additions & 25 deletions

File tree

cmd/sandbox/herdr.go

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package sandbox
22

33
import (
4+
"context"
45
"encoding/json"
56
"fmt"
67
"os"
@@ -148,7 +149,7 @@ func runHerdrSetup(c *cli.Context, doctorOnly bool) error {
148149
if err != nil {
149150
return fmt.Errorf("herdr is not on PATH — install it from https://herdr.dev")
150151
}
151-
version, err := herdrVersion(herdrBin)
152+
version, err := herdrVersion(c.Context, herdrBin)
152153
if err != nil {
153154
return err
154155
}
@@ -157,12 +158,12 @@ func runHerdrSetup(c *cli.Context, doctorOnly bool) error {
157158
}
158159
fmt.Printf("herdr %s found at %s\n", version, herdrBin)
159160

160-
if _, err := exec.LookPath("bun"); err != nil {
161+
if _, lookErr := exec.LookPath("bun"); lookErr != nil {
161162
return fmt.Errorf("bun is not on PATH — the plugin runs on it; install it from https://bun.sh")
162163
}
163164
fmt.Println("bun found on PATH")
164165

165-
if _, err := exec.LookPath("git"); err != nil {
166+
if _, lookErr := exec.LookPath("git"); lookErr != nil {
166167
return fmt.Errorf("git is not on PATH; the plugin uploads what git tracks")
167168
}
168169
fmt.Println("git found on PATH")
@@ -175,21 +176,21 @@ func runHerdrSetup(c *cli.Context, doctorOnly bool) error {
175176
// ---- install -----------------------------------------------------------
176177

177178
if local := strings.TrimSpace(c.String("local")); local != "" {
178-
if err := herdrLink(herdrBin, local); err != nil {
179-
return err
179+
if linkErr := herdrLink(c.Context, herdrBin, local); linkErr != nil {
180+
return linkErr
180181
}
181182
} else {
182183
source := herdrPluginRepo + "/" + herdrPluginPkgPath
183184
fmt.Printf("installing %s from %s\n", herdrPluginID, source)
184-
if out, err := herdrRun(herdrBin, "plugin", "install", source, "--yes"); err != nil {
185-
return fmt.Errorf("herdr plugin install failed: %w\n%s", err, out)
185+
if out, runErr := herdrRun(c.Context, herdrBin, "plugin", "install", source, "--yes"); runErr != nil {
186+
return fmt.Errorf("herdr plugin install failed: %w\n%s", runErr, out)
186187
}
187188
fmt.Println("plugin installed")
188189
}
189190

190191
// ---- plugin config -----------------------------------------------------
191192

192-
configDir, err := herdrRun(herdrBin, "plugin", "config-dir", herdrPluginID)
193+
configDir, err := herdrRun(c.Context, herdrBin, "plugin", "config-dir", herdrPluginID)
193194
if err != nil {
194195
return fmt.Errorf("could not find the plugin config directory: %w", err)
195196
}
@@ -216,17 +217,16 @@ func runHerdrSetup(c *cli.Context, doctorOnly bool) error {
216217
if err != nil {
217218
return err
218219
}
219-
switch {
220-
case added == 0:
220+
if added == 0 {
221221
fmt.Printf("keybindings already present in %s\n", path)
222-
default:
222+
} else {
223223
fmt.Printf("added %d keybindings to %s (undo with 'herdr config reset-keys')\n", added, path)
224224
}
225-
if out, err := herdrRun(herdrBin, "config", "check"); err != nil {
225+
if out, err := herdrRun(c.Context, herdrBin, "config", "check"); err != nil {
226226
return fmt.Errorf("herdr rejected the updated config: %w\n%s", err, out)
227227
}
228228
// Only a running server can reload; a failure here is not a setup failure.
229-
if _, err := herdrRun(herdrBin, "server", "reload-config"); err != nil {
229+
if _, err := herdrRun(c.Context, herdrBin, "server", "reload-config"); err != nil {
230230
fmt.Println("no running Herdr server to reload — the keys apply next time you start one")
231231
} else {
232232
fmt.Println("reloaded the running Herdr server")
@@ -242,7 +242,7 @@ func runHerdrSetup(c *cli.Context, doctorOnly bool) error {
242242
return nil
243243
}
244244

245-
func herdrLink(herdrBin, local string) error {
245+
func herdrLink(ctx context.Context, herdrBin, local string) error {
246246
dir, err := filepath.Abs(local)
247247
if err != nil {
248248
return fmt.Errorf("could not resolve %q: %w", local, err)
@@ -251,7 +251,7 @@ func herdrLink(herdrBin, local string) error {
251251
return fmt.Errorf("%s does not look like the plugin: no herdr-plugin.toml", dir)
252252
}
253253
fmt.Printf("linking %s\n", dir)
254-
if out, err := herdrRun(herdrBin, "plugin", "link", dir); err != nil {
254+
if out, err := herdrRun(ctx, herdrBin, "plugin", "link", dir); err != nil {
255255
return fmt.Errorf("herdr plugin link failed: %w\n%s", err, out)
256256
}
257257
// `plugin link` deliberately does not run build commands, so the generated
@@ -261,7 +261,9 @@ func herdrLink(herdrBin, local string) error {
261261
return fmt.Errorf("%s is missing; the plugin cannot generate its launcher", build)
262262
}
263263
fmt.Println("running the plugin build step")
264-
cmd := exec.Command("sh", build)
264+
// #nosec G204 -- build is filepath.Join of an --local path the user chose
265+
// and the literal "build.sh"; it is one argv element, never a shell string.
266+
cmd := exec.CommandContext(ctx, "sh", build)
265267
cmd.Dir = dir
266268
cmd.Stdout = os.Stderr
267269
cmd.Stderr = os.Stderr
@@ -292,7 +294,7 @@ func herdrWritePluginConfig(c *cli.Context, configDir, agent string) (bool, erro
292294
if err != nil {
293295
return false, fmt.Errorf("could not build the plugin config: %w", err)
294296
}
295-
if err := os.MkdirAll(configDir, 0o755); err != nil {
297+
if err := os.MkdirAll(configDir, 0o750); err != nil {
296298
return false, fmt.Errorf("could not create %s: %w", configDir, err)
297299
}
298300
if err := os.WriteFile(path, append(body, '\n'), 0o600); err != nil {
@@ -332,32 +334,37 @@ func herdrWriteKeys(pluginConfigDir string) (int, string, error) {
332334

333335
if len(existing) > 0 {
334336
backup := path + ".before-createos"
337+
// #nosec G703 -- path is derived from `herdr plugin config-dir`, not user input.
335338
if err := os.WriteFile(backup, existing, 0o600); err != nil {
336339
return 0, path, fmt.Errorf("could not back up %s: %w", path, err)
337340
}
338341
fmt.Printf("backed up your config to %s\n", backup)
339342
}
340-
if err := os.MkdirAll(root, 0o755); err != nil {
343+
if err := os.MkdirAll(root, 0o750); err != nil {
341344
return 0, path, fmt.Errorf("could not create %s: %w", root, err)
342345
}
343346
updated := current
344347
if updated != "" && !strings.HasSuffix(updated, "\n") {
345348
updated += "\n"
346349
}
347350
updated += "\n# Added by 'createos sandbox setup herdr'.\n" + strings.TrimPrefix(block.String(), "\n")
351+
// #nosec G703 -- path is derived from `herdr plugin config-dir`, not user input.
348352
if err := os.WriteFile(path, []byte(updated), 0o600); err != nil {
349353
return 0, path, fmt.Errorf("could not write %s: %w", path, err)
350354
}
351355
return added, path, nil
352356
}
353357

354-
func herdrRun(bin string, args ...string) (string, error) {
355-
out, err := exec.Command(bin, args...).CombinedOutput()
358+
func herdrRun(ctx context.Context, bin string, args ...string) (string, error) {
359+
// #nosec G204 -- bin is the exec.LookPath("herdr") result and every arg is
360+
// a literal from this file; nothing here comes from a sandbox or the network.
361+
out, err := exec.CommandContext(ctx, bin, args...).CombinedOutput()
356362
return string(out), err
357363
}
358364

359-
func herdrVersion(bin string) (string, error) {
360-
out, err := exec.Command(bin, "--version").Output()
365+
func herdrVersion(ctx context.Context, bin string) (string, error) {
366+
// #nosec G204 -- bin is the exec.LookPath("herdr") result; the arg is a literal.
367+
out, err := exec.CommandContext(ctx, bin, "--version").Output()
361368
if err != nil {
362369
return "", fmt.Errorf("could not run 'herdr --version': %w", err)
363370
}
@@ -377,12 +384,22 @@ func herdrVersionLess(have, want string) bool {
377384
for i := 0; i < len(wantParts); i++ {
378385
var h int
379386
if i < len(haveParts) {
380-
h, _ = strconv.Atoi(haveParts[i])
387+
h = herdrVersionPart(haveParts[i])
381388
}
382-
w, _ := strconv.Atoi(wantParts[i])
389+
w := herdrVersionPart(wantParts[i])
383390
if h != w {
384391
return h < w
385392
}
386393
}
387394
return false
388395
}
396+
397+
// herdrVersionPart reads one dotted version part. Anything that is not a
398+
// number counts as 0, so a suffix never reads as newer than a release.
399+
func herdrVersionPart(s string) int {
400+
n, err := strconv.Atoi(s)
401+
if err != nil {
402+
return 0
403+
}
404+
return n
405+
}

cmd/sandbox/herdr_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func TestHerdrVersionLess(t *testing.T) {
2929
func TestHerdrWriteKeysIsIdempotentAndBacksUp(t *testing.T) {
3030
root := t.TempDir()
3131
pluginConfigDir := filepath.Join(root, "plugins", "config", herdrPluginID)
32-
if err := os.MkdirAll(pluginConfigDir, 0o755); err != nil {
32+
if err := os.MkdirAll(pluginConfigDir, 0o750); err != nil {
3333
t.Fatal(err)
3434
}
3535
configPath := filepath.Join(root, "config.toml")

0 commit comments

Comments
 (0)