Skip to content

feat(windows): add Windows support - #1

Merged
Niicolaa merged 4 commits into
mainfrom
claude/windows-support-planning-tb6ae
Aug 4, 2026
Merged

feat(windows): add Windows support#1
Niicolaa merged 4 commits into
mainfrom
claude/windows-support-planning-tb6ae

Conversation

@Niicolaa

@Niicolaa Niicolaa commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Adds Windows to the supported endpoint set, so baseline and project scans work on Windows developer machines the same way they do on macOS and Linux.

This is PR 1 of 2. claude/ecosystem-sources-tb6ae (new ecosystem coverage) is stacked on top of this branch and should be merged after it.

What's covered

Root discoverycmd/bumblebee/roots.go gains a case "windows" in each of the four switch runtime.GOOS blocks:

  • MCP configs: %APPDATA%\Claude, %APPDATA%\Continue. Cursor, Windsurf and Claude Code already resolve through the existing cross-platform dotfile roots.
  • Chromium-family browsers under %LOCALAPPDATA%: Chrome, Edge, Brave, Chromium, Vivaldi, Arc.
  • Firefox-family profiles under %APPDATA%: Firefox, LibreWolf, Waterfox.
  • System roots: machine-wide Python under %ProgramFiles%\PythonNN\Lib\site-packages, plus per-user Python under %LOCALAPPDATA%\Programs\Python\*.

%APPDATA% / %LOCALAPPDATA% are read from the environment first (so enterprise folder redirection is honoured) and fall back to <home>\AppData\....

Safety contractisBroadHomeRoot now recognises Windows drive roots and bare homes: <drive>:\, <drive>:\Users, and <drive>:\Users\<name>. Comparisons are case-insensitive, since Windows filesystems are. baseline and project refuse these exactly as they refuse $HOME and /Users/<name> today.

Walker excludeswalk.DefaultExcludes gains AppData/Local/{Temp,Microsoft,Packages,CrashDumps} and AppData/LocalLow. These are the Windows analogue of the macOS Library subtrees already excluded: large, OS-managed, and holding no inventory. Without them a deep sweep of %USERPROFILE% descends into all of them.

Native project paths — npm and pnpm derived project_path by slash-joining segments after an internal filepath.ToSlash, so a Windows record carried C:/src/app instead of C:\src\app. Both now convert back with filepath.FromSlash, with regression tests. This is upstream issue #1; upstream PR #3 was closed with the note that it would be folded into the broader Windows work, and it then wasn't.

Endpoint metadataos.Getuid() returns -1 on Windows, so that fallback is now Unix-only and uid is left empty rather than emitting a misleading sentinel. When user.Current() succeeds, Go returns the user's SID on Windows, which is kept as-is.

Build and CIwindows-latest added to the test matrix; goreleaser builds windows amd64 + arm64 as .zip. The selftest step now pins shell: bash: windows-latest defaults to PowerShell, where invoking the extensionless build output doesn't work as it does in a POSIX shell.

Tests — a setHomeDir helper sets HOME, USERPROFILE, APPDATA and LOCALAPPDATA together so the existing home-based tests are hermetic on all three platforms. scanner_test.go asserted on literal "/proj/" and "/dup/" substrings of source_file — a native path — so TestEndToEndScan could only ever have passed on Unix; those are now normalized before matching. --all-users stays macOS-only and its darwin-only test guards are unchanged.

Verification

  • go test -race ./... — green
  • gofmt -l . and go vet ./... — clean
  • GOOS=windows amd64 and arm64 — build and vet clean
  • bumblebee selftest — OK

The one thing this can't demonstrate from a Linux host is a green run on Windows. Every path assumption I could find has been fixed by inspection and cross-compilation, but the real signal is the windows-latest job on this PR.

Includes one unrelated commit: cmd/threatintel-fetch/datadog.go has a stray trailing newline that fails the repo-wide gofmt -l . gate on every branch. Whitespace only — drop that commit if you'd rather fix it separately.

Prior art

Reviewed against the four earlier upstream Windows attempts (#3, #4, perplexityai#16, perplexityai#30). None were rejected on merit — #3 was closed by a collaborator as "we're going to handle native Windows paths as part of the broader experimental Windows support work", and the others are open and unreviewed. Where they had coverage this lacked (AppData excludes, the CI shell, Windows Python roots), it's incorporated here.

🤖 Generated with Claude Code

https://claude.ai/code/session_01H9erz849YcDcunP7sWteMu


Generated by Claude Code

claude added 4 commits August 4, 2026 14:30
Adds Windows to the supported endpoint set so baseline/project scans
discover MCP configs (%APPDATA%\Claude, Continue), Chromium-family
extensions (Chrome/Edge/Brave/Chromium/Vivaldi/Arc under
%LOCALAPPDATA%), and Firefox-family profiles (%APPDATA%\Mozilla\...).
isBroadHomeRoot now recognises Windows drive roots and bare
<drive>:\Users[\<name>] homes. Endpoint UID stays empty on Windows
rather than emitting "-1" when user.Current fails. setHomeDir test
helper sets HOME/USERPROFILE/APPDATA/LOCALAPPDATA together so existing
home-based tests run on all three platforms. CI matrix gains
windows-latest and goreleaser builds windows amd64/arm64 zip archives.

Tracks perplexityai#2; implemented from scratch rather than
adopting any of the open upstream PRs (#4, perplexityai#16, perplexityai#30).
Follow-up to the initial Windows support, from reviewing the earlier
upstream Windows attempts (#3, #4, perplexityai#16, perplexityai#30). Two of these would have
made CI red on the windows-latest runner the previous commit added.

CI-breaking:

  - The selftest step had no `shell: bash`. windows-latest defaults to
    PowerShell, where invoking the extensionless build output does not
    work as it does in a POSIX shell. The gofmt step already pinned
    bash; this one did not.
  - scanner_test.go asserted on literal "/proj/" and "/dup/" substrings
    of source_file, which is a native path, so TestEndToEndScan could
    only have passed on Unix. Now normalized before matching.

Correctness:

  - npm and pnpm derived project_path by slash-joining segments after an
    internal filepath.ToSlash, so a Windows record carried C:/src/app
    instead of C:\src\app. This is issue #1 ("Windows package records
    should preserve native project paths"); PR #3 was closed with the
    note that it would be folded into the broader Windows work, and it
    then was not. Both now convert back with filepath.FromSlash, with
    regression tests.
  - DefaultExcludes had no Windows entries, so a deep sweep of
    %USERPROFILE% descended into AppData/Local/{Temp,Microsoft,Packages}
    and AppData/LocalLow — the Windows analogue of the macOS Library
    subtrees already excluded there.
  - systemRoots returned nil on Windows, missing machine-wide Python
    under %ProgramFiles%\PythonNN\Lib\site-packages, and per-user Python
    under %LOCALAPPDATA%\Programs\Python\* was missing as well.
The windows-latest job added in the preceding commits fails on the gofmt
step, listing every .go file in the repository — including files no
branch here touches. It is not a formatting problem: actions/checkout on
Windows inherits git's default core.autocrlf=true and rewrites the tree
to CRLF, and gofmt reports a CRLF file as unformatted.

A .gitattributes pinning LF for Go sources fixes the checkout, so the
repo-wide `gofmt -l .` check stays meaningful on all three runners
rather than having to be skipped on Windows. It also matches what gofmt
writes when a contributor runs it on Windows locally.
TestIsPnpmStorePackageJSON hardcoded proj == "/x/proj". That assertion
encoded the bug this branch fixes: IsPnpmStorePackageJSON now returns a
native path, so on Windows it correctly yields `\x\proj` and the literal
comparison failed.

Converting the expectation with filepath.FromSlash keeps the test
correct on every platform. The input paths stay slash-written, since the
matcher normalizes internally and accepts either form.

Caught by the windows-latest runner, which reached the test step for the
first time now that the CRLF checkout issue is fixed.
@Niicolaa
Niicolaa force-pushed the claude/windows-support-planning-tb6ae branch from 3f055c4 to e62c2c6 Compare August 4, 2026 14:31
@Niicolaa
Niicolaa merged commit 6dba4c8 into main Aug 4, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants