Skip to content

feat(detector): add Conda package inventory and configuration audit - #262

Open
raysubham wants to merge 6 commits into
step-security:mainfrom
raysubham:feat/conda-inventory
Open

raysubham wants to merge 6 commits into
step-security:mainfrom
raysubham:feat/conda-inventory

Conversation

@raysubham

@raysubham raysubham commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds passive Conda package inventory and configuration audit to enterprise telemetry through optional conda_inventory and conda_config_audit sections, collected in a new conda_scan phase.

  • Collects installed packages from conda-meta/*.json receipts, cached packages from extracted pkgs/<dist>/info metadata (repodata_record.json, falling back to index.json), declared requirements from environment.yml/environment.yaml/env.yml/env.yaml/environment.json, and locked packages from @EXPLICIT files, conda-lock v1 and rattler/pixi v6 locks.
  • Discovers standard installation roots (Miniconda, Anaconda, Miniforge, Mambaforge, Micromamba, ~/.conda, macOS Homebrew casks and /opt prefixes, Windows %LOCALAPPDATA%\conda\conda), verified CONDA_PREFIX/CONDA_ROOT/MAMBA_ROOT_PREFIX, envs_dirs and pkgs_dirs leads from configuration, the ~/.conda/environments.txt registry and project search roots. Pixi and project-local prefixes are found by their conda-meta directory.
  • Audits the allowlisted .condarc/condarc/condarc.d settings across system, installation, user, environment and process scopes, plus saved conda-meta/state variables and project manifest channels, and reports ambient, per-environment and per-project precedence chains. Emits findings conda-001 through conda-004. ~/.netrc, ~/_netrc and the anaconda-client token directory are checked for existence only.
  • Removes credentials, query strings, fragments and /t/<token> path components from every channel, proxy, artifact and requested-spec URL before emission or identity generation. Environment-variable references are not treated as literal credentials.
  • Sources carry discovery parents so a later scan of a surviving ancestor can prove removal of an installation, cache or environment. Unreadable, cancelled, protected, oversized or budget-limited inputs leave their sources partial so prior evidence is never retired on unproven absence. Admitted records are kept when collection stops.
  • Reuses the Go/Cargo/Composer/NuGet/Ruby guarded filesystem access, developer selection, source coverage and collection limits. No executor, dependency, Python collector, Agent API or version changes.
  • Adds the shared producer/backend golden fixture (internal/model/testdata/conda_inventory_v1_golden.json, sha256 c1f8ecfe26760e3d92dd5210557fb14441ce7152e02fcbb62ad742b4cd22c491) and parser, scanner, configuration, limit, cancellation, removal and redaction regressions, plus a FuzzCondaMetadata target.

The collector never executes conda, mamba, micromamba, pixi, Python or shells, never runs activation scripts or plugins, never makes network calls and never solves dependencies. Conda packages are reported without language labels. Community output and existing Python discovery remain unchanged. Updates README and scan-coverage documentation.

Known limitations: archive-only cache entries are reported as unsupported rather than identified; wheel rows in locks and caches are reported as unsupported; rattler caches, .mambarc, MAMBARC and Pixi configuration are not read; manifests with selectors or sel() are partial.

Type of change

  • Bug fix
  • Enhancement
  • Documentation

Testing

  • gofmt, go vet, go mod tidy without drift, golangci-lint (0 issues), git diff --check.
  • go test ./... -race -count=1; Conda detector, configaudit, model and telemetry packages at -race -count=3.
  • FuzzCondaMetadata 5 minutes at 4 workers after the first CI fuzz run found a requested spec with a fragment passing through; the fix redacts query/fragment requests and the crasher inputs are kept as seeds. make smoke (45/45); gosec with no findings in the changed files.
  • CGO-disabled linux/amd64, darwin/arm64 and windows/amd64 builds.
  • No secrets or credentials included; fixture canaries asserted absent from emitted JSON and stderr.
  • Native macOS, Linux and Windows scans against Conda installations and deployed backend acceptance: not yet run.

Related Issues

Stacks on the Ruby scanner from #258 (open); rebase after it merges. Builds on the NuGet scanner from #239 and the Composer configuration helpers from #238.

…g audit

Adds passive Ruby inventory and RubyGems/Bundler configuration audit to
enterprise telemetry as optional ruby_inventory and ruby_config_audit
sections, collected in a new ruby_scan phase.

Declared, locked, installed and cached evidence stay separate. Sources
that are shared, unreadable, cancelled or budget-limited are partial so
prior evidence is never retired on unproven absence. The collector never
executes Ruby, Bundler, gemspecs or Gemfiles, never extracts archives,
and reports credentials as configured only.
Add optional conda_inventory and conda_config_audit telemetry sections
collected in a new conda_scan phase. The scanner passively reads
conda-meta receipts, extracted package caches, environment manifests,
explicit, conda-lock and rattler locks, and the .condarc family plus
saved environment state and process variables. It never executes conda,
mamba, pixi or Python, never activates environments, never reads
credential contents and never resolves dependencies.

Discovery covers standard installation roots, verified CONDA_PREFIX,
CONDA_ROOT, envs_dirs and pkgs_dirs leads, the environments.txt
registry and project search roots. Sources carry discovery parents so a
later scan of a surviving ancestor can prove removal; unreadable,
cancelled, protected or budget-limited inputs leave their sources
partial instead of retiring prior evidence.

Channel, proxy and artifact URLs are emitted without credentials, query
strings, fragments or Conda token path components. Findings conda-001
through conda-004 report unencrypted channels, disabled TLS
verification, embedded credentials and disabled safety checks.
Existing Python discovery and output are unchanged.
A requested spec with ? or # is a URL-like request rather than a match
spec, so it is redacted whole like one with userinfo or a token path.
The fuzz oracle now looks for token components only inside a URL path:
a host or local directory named "t" is not a token. Keep the three
crasher inputs as regression seeds.

This branch has not been deployed

No deployments
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.

1 participant