Skip to content

feat(windows): eclipse plugin detection#32

Merged
ashishkurmi merged 10 commits intostep-security:mainfrom
swarit-stepsecurity:swarit/feat/windows-eclipse-plugins
Apr 21, 2026
Merged

feat(windows): eclipse plugin detection#32
ashishkurmi merged 10 commits intostep-security:mainfrom
swarit-stepsecurity:swarit/feat/windows-eclipse-plugins

Conversation

@swarit-stepsecurity
Copy link
Copy Markdown
Member

What does this PR do?

Type of change

  • Bug fix
  • Enhancement
  • Documentation

Testing

  • Tested on macOS (version: ___)
  • Binary runs without errors: ./stepsecurity-dev-machine-guard --verbose
  • JSON output is valid: ./stepsecurity-dev-machine-guard --json | python3 -m json.tool
  • No secrets or credentials included
  • Lint passes: make lint
  • Tests pass: make test

Related Issues

eclipseFeatureDirs was macOS-only (/Applications/Eclipse.app/...).
On Windows, Eclipse installs to variable paths. Now dynamically
resolves features/dropins directories from common Windows locations:
- %PROGRAMFILES%\eclipse
- C:\eclipse
- %USERPROFILE%\eclipse\<variant>\eclipse (Oomph installer)
Eclipse plugin detection now receives the detected IDEs list and uses
the actual Eclipse install path (which may have been discovered via
registry) instead of hardcoded candidates. This ensures plugins are
found even when Eclipse is installed at a custom path.

Also parses bundles.info on Windows (modern Eclipse uses p2 provisioning)
instead of scanning features/ directory which may not exist.
Rewrites Eclipse plugin detection with a comprehensive pipeline:

- Stage 1: Uses detected IDE install paths (registry-aware)
- Stage 2: Well-known path probes including Oomph installer paths,
  vendor variants (STS, MyEclipse), and D:-Z: drive letter scanning
- Stage 4: Install validation (eclipse.ini + plugins/ + configuration/)
  before reporting — eliminates false positives
- Stage 6: bundles.info parsing (primary) + dropins/ scanning (secondary)
  with dedup by symbolicName@version

Also expands bundled prefix list to correctly classify Eclipse platform
bundles (491 bundled vs 45 user-installed on a typical install).
…tplace plugins

Expanded eclipseBundledPrefixes to cover all standard Eclipse platform
dependencies (JUnit, JaCoCo, Gradle tooling, crypto libs, etc.).
This reduces false positives from 45 to 4 — only truly marketplace-
installed plugins (Claude Code, Putman) are now classified as
user_installed.
…in detection

Instead of heuristic prefix-matching on bundles.info, use Eclipse's own
p2 director (eclipsec.exe -listInstalledRoots) to get the authoritative
list of installed root features. Marketplace-installed features are those
not prefixed with org.eclipse.* or epp.*.

The p2 director output also enriches bundles.info — bundles belonging
to marketplace features are tagged as 'marketplace' source.

Falls back to bundles.info-only parsing if eclipsec.exe is unavailable.
…s flag

By default, only user-installed and marketplace plugins are included in
scan output and telemetry. Bundled/platform plugins (e.g., Eclipse's 500+
OSGi bundles) are filtered out to reduce noise and payload size.

Use --include-bundled-plugins to include them if needed.

Payload reduction: 124KB → 21KB for a typical Eclipse install.
macOS detection doesn't produce bundled plugins in the same volume,
so the filter is unnecessary there. Gate on exec.GOOS() == windows.
Signed-off-by: Swarit Pandey <swarit@stepsecurity.io>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds improved Eclipse plugin detection on Windows and reduces noisy “bundled/platform” plugin output by default, with an opt-in flag to include bundled plugins.

Changes:

  • Extend ExtensionDetector.Detect to accept detected IDEs and use them for Eclipse plugin discovery.
  • Implement a multi-stage Windows Eclipse plugin discovery pipeline (candidate collection, validation, p2 roots, bundles.info, dropins).
  • Add a --include-bundled-plugins flag and Windows-only filtering of bundled plugins in scan + telemetry flows.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
internal/telemetry/telemetry.go Pass IDEs into extension detection and filter bundled plugins on Windows (unless opted in).
internal/scan/scanner.go Same Windows bundled-plugin filtering behavior for community scans.
internal/detector/jetbrains_plugins_test.go Update test to new ExtensionDetector.Detect signature.
internal/detector/ide.go Use .cmd wrappers for certain Windows IDE binaries to avoid launching GUI executables.
internal/detector/extension.go Update extension detection API and route Eclipse detection through detected IDE install paths.
internal/detector/eclipse_plugins.go Replace simple Eclipse scanning with Windows-specific validated discovery + parsing pipeline.
internal/cli/cli.go Add IncludeBundledPlugins config and parse --include-bundled-plugins.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/telemetry/telemetry.go Outdated
Comment on lines +620 to +629
// filterUserInstalledExtensions removes bundled/platform extensions,
// keeping only user-installed and marketplace extensions.
func filterUserInstalledExtensions(exts []model.Extension) []model.Extension {
var filtered []model.Extension
for _, ext := range exts {
if ext.Source != "bundled" {
filtered = append(filtered, ext)
}
}
return filtered
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filterUserInstalledExtensions is duplicated here and in internal/scan/scanner.go. Consider moving it to a shared location (e.g., an internal helper package) to avoid divergence if the filtering criteria changes (e.g., additional bundled sources besides "bundled").

Copilot uses AI. Check for mistakes.
Comment thread internal/scan/scanner.go Outdated
Comment on lines +265 to +274
// filterUserInstalledExtensions removes bundled/platform extensions,
// keeping only user-installed and marketplace extensions.
func filterUserInstalledExtensions(exts []model.Extension) []model.Extension {
var filtered []model.Extension
for _, ext := range exts {
if ext.Source != "bundled" {
filtered = append(filtered, ext)
}
}
return filtered
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filterUserInstalledExtensions is duplicated here and in internal/telemetry/telemetry.go. Consider centralizing this filtering logic to keep behavior consistent across scan and telemetry paths.

Copilot uses AI. Check for mistakes.
Comment thread internal/detector/eclipse_plugins.go Outdated
Comment on lines +350 to +354
ctx := context.Background()
stdout, _, exitCode, err := d.exec.RunWithTimeout(ctx, 30*time.Second,
eclipsec, "-nosplash",
"-application", "org.eclipse.equinox.p2.director",
"-listInstalledRoots")
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

queryP2InstalledRoots creates a new context.Background() instead of using the caller’s ctx. This prevents cancellation/timeout propagation from the scan/telemetry run and can leave the process waiting up to the full RunWithTimeout duration even if the overall operation was canceled. Consider threading the caller context through the Eclipse detection pipeline and using it here.

Copilot uses AI. Check for mistakes.
Comment thread internal/detector/eclipse_plugins.go Outdated
Comment on lines +203 to +207
// Drive letter probe: D:\eclipse through Z:\eclipse (fixed drives only)
for drive := 'D'; drive <= 'Z'; drive++ {
driveRoot := string(drive) + `:\eclipse`
candidates = append(candidates, driveRoot)
}
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The drive-letter probe loop adds D:\eclipse through Z:\eclipse unconditionally, but the comment says “fixed drives only”. As implemented, DirExists/FileExists checks against mapped network drives can be slow or hang, which may significantly impact scan time on Windows. Either adjust the comment, or restrict probing to local/fixed drives (or only drives that are known to exist).

Copilot uses AI. Check for mistakes.
Comment thread internal/detector/eclipse_plugins.go Outdated
Comment on lines +15 to +16
// platform or are standard dependencies. Everything NOT matching is classified
// as "marketplace" (user-installed from Eclipse Marketplace or update sites).
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The header comment for eclipseBundledPrefixes says “Everything NOT matching is classified as "marketplace"”, but the implementation uses multiple non-bundled sources (e.g., "user_installed", "dropins", and sometimes "marketplace"). Please align the comment with the actual Source values used, or standardize the non-bundled classification to avoid confusing downstream consumers.

Suggested change
// platform or are standard dependencies. Everything NOT matching is classified
// as "marketplace" (user-installed from Eclipse Marketplace or update sites).
// platform or are standard dependencies. Bundles that do not match these
// prefixes are treated as non-bundled and may be classified into source
// categories such as "marketplace", "user_installed", or "dropins".

Copilot uses AI. Check for mistakes.
Comment thread internal/detector/eclipse_plugins.go Outdated
Comment on lines +114 to +149
func (d *ExtensionDetector) detectEclipsePluginsWindows(ides []model.IDE) []model.Extension {
// Stage 1+2: Collect candidate paths from detected IDEs + well-known locations
candidates := d.gatherEclipseCandidates(ides)

// Stage 4: Validate each candidate
seen := make(map[string]bool)
var validInstalls []string
for _, path := range candidates {
key := strings.ToLower(filepath.Clean(path))
if seen[key] {
continue
}
seen[key] = true

if d.validateEclipseInstall(path) {
validInstalls = append(validInstalls, path)
}
}

// Stage 6: Enumerate plugins from each validated install
pluginSeen := make(map[string]bool)
var results []model.Extension
for _, installDir := range validInstalls {
plugins := d.enumerateEclipsePlugins(installDir)
for _, p := range plugins {
dedupKey := p.ID + "@" + p.Version
if pluginSeen[dedupKey] {
continue
}
pluginSeen[dedupKey] = true
results = append(results, p)
}
}

return results
}
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR introduces a fairly complex Windows Eclipse detection pipeline (candidate gathering, validation, p2 director parsing, bundles.info parsing, dropins scanning), but there are no new unit tests covering it. Since internal/detector already has extensive test coverage, please add focused tests for the key behaviors (candidate validation, p2 output parsing/classification, bundles.info parsing, and dropins handling) to prevent regressions.

Copilot uses AI. Check for mistakes.
Comment thread internal/cli/cli.go
Comment on lines +87 to +88
case arg == "--include-bundled-plugins":
cfg.IncludeBundledPlugins = true
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new --include-bundled-plugins flag is parsed, but it isn’t shown in printHelp() under Options. This makes the flag hard to discover and can lead to confusion when users run --help.

Copilot uses AI. Check for mistakes.
- Move filterUserInstalledExtensions to model package (was duplicated)
- Thread context.Context through Eclipse detection pipeline (was using
  context.Background())
- Drive letter probes check if drive exists before probing (avoids
  network drive timeouts)
- Fix eclipseBundledPrefixes comment to match actual Source values
- Add --include-bundled-plugins to help text
- Add 14 unit tests for Eclipse detection pipeline (validation,
  bundles.info parsing, p2 director output parsing, dropins, etc.)
@ashishkurmi ashishkurmi merged commit 8a029a0 into step-security:main Apr 21, 2026
5 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.

3 participants