Skip to content

Commit cf90d50

Browse files
chore(mdm): resolve conflict & address copilot comments
1 parent 9478f12 commit cf90d50

11 files changed

Lines changed: 62 additions & 56 deletions

File tree

internal/detector/aicli.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,10 @@ var cliToolDefinitions = []cliToolSpec{
5454
},
5555
},
5656
{
57-
Name: "github-copilot-cli",
58-
Vendor: "Microsoft",
59-
Binaries: []string{"copilot", "gh-copilot"},
60-
ConfigDirs: []string{"~/.config/github-copilot"},
57+
Name: "github-copilot-cli",
58+
Vendor: "Microsoft",
59+
Binaries: []string{"copilot", "gh-copilot"},
60+
ConfigDirs: []string{"~/.config/github-copilot"},
6161
},
6262
{
6363
Name: "microsoft-ai-shell",

internal/detector/ide.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,12 @@ var ideDefinitions = []ideSpec{
5353
},
5454
{
5555
AppName: "Claude", IDEType: "claude_desktop", Vendor: "Anthropic",
56-
AppPath: "/Applications/Claude.app",
56+
AppPath: "/Applications/Claude.app",
5757
WinPaths: []string{`%LOCALAPPDATA%\Programs\Claude`},
5858
},
5959
{
6060
AppName: "Microsoft Copilot", IDEType: "microsoft_copilot_desktop", Vendor: "Microsoft",
61-
AppPath: "/Applications/Copilot.app",
61+
AppPath: "/Applications/Copilot.app",
6262
WinPaths: []string{`%LOCALAPPDATA%\Programs\Copilot`},
6363
},
6464
}

internal/detector/nodescan.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ func NewNodeScanner(exec executor.Executor, log *progress.Logger, loggedInUser s
4141
}
4242

4343
// shouldRunAsUser returns true when commands should be delegated to the logged-in user.
44+
// Only applies on Unix — RunAsUser uses sudo which is not available on Windows.
4445
func (s *NodeScanner) shouldRunAsUser() bool {
45-
return s.exec.IsRoot() && s.loggedInUser != ""
46+
return s.exec.GOOS() != "windows" && s.exec.IsRoot() && s.loggedInUser != ""
4647
}
4748

4849
// runCmd runs a command, delegating to the logged-in user when running as root.
@@ -68,6 +69,7 @@ func (s *NodeScanner) runCmd(ctx context.Context, timeout time.Duration, name st
6869
}
6970

7071
// runShellCmd runs a shell command string, delegating to the logged-in user when running as root.
72+
// Falls through to the platform-aware free function for the normal (non-delegation) path.
7173
func (s *NodeScanner) runShellCmd(ctx context.Context, timeout time.Duration, shellCmd string) (string, string, int, error) {
7274
if s.shouldRunAsUser() {
7375
ctx, cancel := context.WithTimeout(ctx, timeout)
@@ -81,7 +83,7 @@ func (s *NodeScanner) runShellCmd(ctx context.Context, timeout time.Duration, sh
8183
}
8284
return stdout, "", 0, nil
8385
}
84-
return s.exec.RunWithTimeout(ctx, timeout, "bash", "-c", shellCmd)
86+
return runShellCmd(ctx, s.exec, timeout, shellCmd)
8587
}
8688

8789
// checkPath checks if a binary is available, using the logged-in user's PATH when running as root.
@@ -165,7 +167,7 @@ func (s *NodeScanner) scanYarnGlobal(ctx context.Context) (model.NodeScanResult,
165167

166168
start := time.Now()
167169
shellCmd := "cd " + platformShellQuote(s.exec, globalDir) + " && yarn list --json --depth=0"
168-
stdout, stderr, exitCode, _ := runShellCmd(ctx, s.exec, 60*time.Second, shellCmd)
170+
stdout, stderr, exitCode, _ := s.runShellCmd(ctx, 60*time.Second, shellCmd)
169171
duration := time.Since(start).Milliseconds()
170172

171173
errMsg := ""
@@ -345,7 +347,7 @@ func (s *NodeScanner) scanProject(ctx context.Context, projectDir string) model.
345347
for _, a := range args {
346348
cmdStr += " " + a
347349
}
348-
stdout, stderr, exitCode, _ := runShellCmd(ctx, s.exec, 30*time.Second, cmdStr)
350+
stdout, stderr, exitCode, _ := s.runShellCmd(ctx, 30*time.Second, cmdStr)
349351
duration := time.Since(start).Milliseconds()
350352

351353
errMsg := ""

internal/detector/nodescan_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212

1313
func newTestScanner(exec *executor.Mock) *NodeScanner {
1414
log := progress.NewLogger(false)
15-
return NewNodeScanner(exec, log)
15+
return NewNodeScanner(exec, log, "")
1616
}
1717

1818
func TestNodeScanner_ScanNPMGlobal(t *testing.T) {

internal/executor/executor.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"os/user"
1010
"path/filepath"
1111
"runtime"
12+
"strings"
1213
"time"
1314
)
1415

internal/executor/mock.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -290,9 +290,9 @@ type mockFileInfo struct {
290290
dir bool
291291
}
292292

293-
func (fi *mockFileInfo) Name() string { return fi.name }
294-
func (fi *mockFileInfo) Size() int64 { return fi.size }
295-
func (fi *mockFileInfo) IsDir() bool { return fi.dir }
293+
func (fi *mockFileInfo) Name() string { return fi.name }
294+
func (fi *mockFileInfo) Size() int64 { return fi.size }
295+
func (fi *mockFileInfo) IsDir() bool { return fi.dir }
296296
func (fi *mockFileInfo) ModTime() time.Time { return time.Time{} }
297297
func (fi *mockFileInfo) Mode() os.FileMode { return 0o644 }
298298
func (fi *mockFileInfo) Sys() any { return nil }

internal/lock/lock.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,3 @@ func (l *Lock) Release() {
5757
_ = os.Remove(l.path)
5858
}
5959
}
60-

internal/model/model.go

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@ package model
22

33
// ScanResult is the community-mode JSON output structure.
44
type ScanResult struct {
5-
AgentVersion string `json:"agent_version"`
6-
AgentURL string `json:"agent_url"`
7-
ScanTimestamp int64 `json:"scan_timestamp"`
8-
ScanTimestampISO string `json:"scan_timestamp_iso"`
9-
Device Device `json:"device"`
10-
AIAgentsAndTools []AITool `json:"ai_agents_and_tools"`
11-
IDEInstallations []IDE `json:"ide_installations"`
12-
IDEExtensions []Extension `json:"ide_extensions"`
13-
MCPConfigs []MCPConfig `json:"mcp_configs"`
14-
NodePkgManagers []PkgManager `json:"node_package_managers"`
15-
NodePackages []any `json:"node_packages"`
16-
Summary Summary `json:"summary"`
5+
AgentVersion string `json:"agent_version"`
6+
AgentURL string `json:"agent_url"`
7+
ScanTimestamp int64 `json:"scan_timestamp"`
8+
ScanTimestampISO string `json:"scan_timestamp_iso"`
9+
Device Device `json:"device"`
10+
AIAgentsAndTools []AITool `json:"ai_agents_and_tools"`
11+
IDEInstallations []IDE `json:"ide_installations"`
12+
IDEExtensions []Extension `json:"ide_extensions"`
13+
MCPConfigs []MCPConfig `json:"mcp_configs"`
14+
NodePkgManagers []PkgManager `json:"node_package_managers"`
15+
NodePackages []any `json:"node_packages"`
16+
Summary Summary `json:"summary"`
1717
}
1818

1919
type Device struct {
@@ -63,9 +63,9 @@ type MCPConfig struct {
6363

6464
// MCPConfigEnterprise includes base64-encoded content for enterprise mode.
6565
type MCPConfigEnterprise struct {
66-
ConfigSource string `json:"config_source"`
67-
ConfigPath string `json:"config_path"`
68-
Vendor string `json:"vendor"`
66+
ConfigSource string `json:"config_source"`
67+
ConfigPath string `json:"config_path"`
68+
Vendor string `json:"vendor"`
6969
ConfigContentBase64 string `json:"config_content_base64,omitempty"`
7070
}
7171

@@ -86,13 +86,13 @@ type Summary struct {
8686
// NodeScanResult holds raw scan output for enterprise telemetry.
8787
// Used for both global packages and per-project scans.
8888
type NodeScanResult struct {
89-
ProjectPath string `json:"project_path"`
90-
PackageManager string `json:"package_manager"`
91-
PMVersion string `json:"package_manager_version"`
92-
WorkingDirectory string `json:"working_directory"`
93-
RawStdoutBase64 string `json:"raw_stdout_base64"`
94-
RawStderrBase64 string `json:"raw_stderr_base64"`
95-
Error string `json:"error"`
96-
ExitCode int `json:"exit_code"`
97-
ScanDurationMs int64 `json:"scan_duration_ms"`
89+
ProjectPath string `json:"project_path"`
90+
PackageManager string `json:"package_manager"`
91+
PMVersion string `json:"package_manager_version"`
92+
WorkingDirectory string `json:"working_directory"`
93+
RawStdoutBase64 string `json:"raw_stdout_base64"`
94+
RawStderrBase64 string `json:"raw_stderr_base64"`
95+
Error string `json:"error"`
96+
ExitCode int `json:"exit_code"`
97+
ScanDurationMs int64 `json:"scan_duration_ms"`
9898
}

internal/output/pretty.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ import (
1111
"github.com/step-security/dev-machine-guard/internal/model"
1212
)
1313

14-
//nolint:errcheck // fmt.Fprint* to io.Writer; errors surface through the writer
1514
// Pretty writes human-readable formatted output.
15+
//
16+
//nolint:errcheck // fmt.Fprint* to io.Writer; errors surface through the writer
1617
func Pretty(w io.Writer, result *model.ScanResult, colorMode string) error {
1718
c := setupColors(colorMode)
1819

internal/progress/progress.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ import (
88
)
99

1010
// Logger handles progress output to stderr.
11-
// Logging format matches the shell script:
12-
// [scanning] message — progress (suppressed in quiet mode)
13-
// [error] message — errors (never suppressed)
14-
// ⠋ label... (Xms) — spinner animation
15-
// ✓ label (Xms) — step done
16-
// ○ label (skipped) — step skipped
11+
// Logging format:
12+
//
13+
// 2006-01-02 15:04:05 [scanning] message — progress (suppressed in quiet mode)
14+
// 2006-01-02 15:04:05 [error] message — errors (never suppressed)
15+
// ⠋ label... (Xms) — spinner animation
16+
// ✓ label (Xms) — step done
17+
// ○ label (skipped) — step skipped
1718
type Logger struct {
1819
quiet bool
1920
spinner *spinner
@@ -82,18 +83,18 @@ type spinner struct {
8283
}
8384

8485
type stopMsg struct {
85-
kind string // "done" or "skip"
86-
reason string
86+
kind string // "done" or "skip"
87+
reason string
8788
elapsed time.Duration
8889
}
8990

9091
var spinnerFrames = []string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"}
9192

9293
func newSpinner(label string) *spinner {
9394
return &spinner{
94-
label: label,
95+
label: label,
9596
startedAt: time.Now(),
96-
stopCh: make(chan stopMsg, 1),
97+
stopCh: make(chan stopMsg, 1),
9798
}
9899
}
99100

0 commit comments

Comments
 (0)