Skip to content

Commit 153ea5c

Browse files
committed
improved
1 parent 4871656 commit 153ea5c

3 files changed

Lines changed: 46 additions & 10 deletions

File tree

cmd/root.go

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,15 +95,28 @@ By BoostSecurity.io - https://github.com/boostsecurityio/poutine `,
9595
},
9696
}
9797

98+
// versionCheckSkipCommands lists subcommands that must not trigger the
99+
// version check: "mcp-server" speaks JSON-RPC over stdio (no point delaying
100+
// its handshake), and "completion" is invoked by shells for tab-completion
101+
// lookups. Other subcommands (including "version" and "help") still pay the
102+
// once-per-day check, since the 24h cache means at most one network call.
103+
var versionCheckSkipCommands = map[string]struct{}{
104+
"mcp-server": {},
105+
"completion": {},
106+
}
107+
98108
// runVersionCheck performs the once-per-day update check unless disabled by
99-
// flag, env var, or config. The "version" subcommand is excluded so users can
100-
// inspect the binary without triggering a network call.
109+
// flag, env var, or config. Commands listed in versionCheckSkipCommands and
110+
// any subcommand under them are excluded so users can inspect the binary or
111+
// run the MCP server without triggering a network call.
101112
func runVersionCheck(cmd *cobra.Command) {
102-
if cmd != nil && cmd.Name() == "version" {
103-
return
113+
for c := cmd; c != nil; c = c.Parent() {
114+
if _, skip := versionCheckSkipCommands[c.Name()]; skip {
115+
return
116+
}
104117
}
105118
disabled := disableVersionCheck || (config != nil && config.DisableVersionCheck)
106-
result := versioncheck.Run(Version, disabled)
119+
result := versioncheck.Run(cmd.Context(), Version, disabled)
107120
if result == nil || !result.UpdateAvailable {
108121
return
109122
}

versioncheck/versioncheck.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,9 @@ type options struct {
5353

5454
// Run records a CLI start and, at most once every 24 hours, reports anonymous
5555
// telemetry to the configured endpoint and returns the latest release info.
56-
// The whole operation is bounded by checkTimeout so it never noticeably
57-
// slows down poutine startup.
58-
func Run(version string, disabled bool) *Result {
56+
// The HTTP call is bounded by checkTimeout (derived from ctx) so it never
57+
// noticeably slows down poutine startup.
58+
func Run(ctx context.Context, version string, disabled bool) *Result {
5959
if disabled || isDisabledByEnv(os.Getenv(DisableEnv)) {
6060
return nil
6161
}
@@ -67,10 +67,10 @@ func Run(version string, disabled bool) *Result {
6767
recordStart(cfg, uuid.NewString)
6868
_ = SaveConfig(cfg)
6969

70-
ctx, cancel := context.WithTimeout(context.Background(), checkTimeout)
70+
timeoutCtx, cancel := context.WithTimeout(ctx, checkTimeout)
7171
defer cancel()
7272

73-
result, _ := run(ctx, options{
73+
result, _ := run(timeoutCtx, options{
7474
Config: cfg,
7575
Version: version,
7676
URL: VersionCheckURL,

versioncheck/versioncheck_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"errors"
66
"io"
77
"net/http"
8+
"os"
9+
"path/filepath"
810
"strings"
911
"testing"
1012
"time"
@@ -306,6 +308,27 @@ func TestLoadConfig_RoundTrip(t *testing.T) {
306308
assert.True(t, cfg.LastVersionCheckAt.Equal(loaded.LastVersionCheckAt))
307309
}
308310

311+
func TestRun_DisabledShortCircuitsBeforeAnyDiskWrite(t *testing.T) {
312+
dir := t.TempDir()
313+
t.Setenv("POUTINE_CONFIG_DIR", dir)
314+
t.Setenv(DisableEnv, "")
315+
316+
// Disabled via the option (CLI flag / config path).
317+
result := Run(context.Background(), "v0.18.0", true)
318+
assert.Nil(t, result)
319+
320+
_, err := os.Stat(filepath.Join(dir, "config.yaml"))
321+
assert.True(t, os.IsNotExist(err), "no state file should be written when disabled")
322+
323+
// Disabled via env var, even if the option is false.
324+
t.Setenv(DisableEnv, "1")
325+
result = Run(context.Background(), "v0.18.0", false)
326+
assert.Nil(t, result)
327+
328+
_, err = os.Stat(filepath.Join(dir, "config.yaml"))
329+
assert.True(t, os.IsNotExist(err), "no state file should be written when disabled by env")
330+
}
331+
309332
func TestIsDisabledByEnv(t *testing.T) {
310333
for _, value := range []string{"1", "true", "TRUE", "yes", "on"} {
311334
assert.True(t, isDisabledByEnv(value), value)

0 commit comments

Comments
 (0)