Discover Augment Code (Auggie CLI + VS Code + JetBrains) — WEB-4950#213
Conversation
…rains
Add Augment Code (label "augment") to the coding-discovery scanner as a
single cross-surface detector returning per-surface rows (Auggie CLI,
Augment (VS Code), Augment (<JetBrains IDE>)) that share one ~/.augment
config. Mirrors the GitHub Copilot cross-surface pattern.
Extraction parity with claude_code/copilot_cli:
- settings/permissions: toolPermissions -> allow/deny/ask; hooks preserved
in raw_settings (user/managed/project/local scopes)
- MCP servers: top-level mcpServers + augment.advanced.mcpServers + flat form
- rules/guidelines: .augment-guidelines, .augment/rules/*.{md,mdx},
~/.augment/rules, ~/.augment/user-guidelines.md, hierarchical AGENTS.md/CLAUDE.md
- skills/commands: ~/.augment/skills/<name>/SKILL.md, .augment/commands/*.md
Shared ~/.augment config is attached to a single canonical surface
(Auggie CLI > VS Code > JetBrains) to avoid duplication; non-canonical
surfaces emit bare detection rows. macOS holds the logic; Windows/Linux
are thin OS-seam subclasses.
Part of WEB-4950 (discovery half).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…settings scope) - Owner-key user-scope skills by file_path so a user's skill content can't leak onto another user's row under a root all-users scan (mirrors _copilot_skill_owner_home) - Guard the rules project walk against re-collecting ~/.augment/rules as project scope, matching the settings/skills extractors' user-dir guards - Settings: extract user + managed only; drop the unsurfaceable project/local filesystem walk; include managed scope in the permissions filter - Skip symlinked dirs before the .augment branch in the rules walk - Memo parity for _get_augment_mcp; settings docstring fix - Add regression tests for the cross-user skills leak and rules duplication Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🛡️ Automated Security Review (consensus)2 findings — 1 high-confidence, 1 to triage. Reviewers: Cursor, Claude, Semgrep, Gitleaks. 🔴 Privileged scan executes user-writable
|
…ndows
The rules/skills project-walk tests instantiate the macOS extractor and
patched only _iter_top_level_dirs, leaving _filesystem_root at "/". On
Windows the walk's item.relative_to("/") raises ValueError for a C:\ temp
path, so every subdirectory was skipped and project rules/skills were never
collected (8 Windows-only unittest failures, all in the rules/skills suites).
Pin _filesystem_root to the temp ancestor so relative_to works cross-platform.
Production is unaffected: real Windows uses the Windows*AugmentExtractor with
the correct filesystem root.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🛡️ Automated Security Review (consensus)4 findings — 2 high-confidence, 2 to triage. Reviewers: Cursor, Claude, Semgrep, Gitleaks. 🔴 Privileged scan executes user-writable
|
| "publisher": "Augment Computer", | ||
| "install_path": binary, | ||
| "_config_path": str(_resolve_augment_dir(user_home)), | ||
| } |
There was a problem hiding this comment.
Root scan runs user auggie
High Severity
During privileged multi-user scans, the detector resolves the auggie CLI binary from user-writable paths (e.g., ~/.local/bin). Running auggie --version on these untrusted binaries can execute arbitrary code with the scanner's elevated privileges.
Reviewed by Cursor Bugbot for commit 45eae7b. Configure here.
There was a problem hiding this comment.
Deferring this as a separate, repo-wide hardening rather than fixing Augment in isolation. The same pattern — resolving a per-user CLI binary from user-writable paths (~/.local/bin, ~/.bun/bin, nvm) and running --version under a root/MDM scan — already ships in the Copilot CLI detector (macos/copilot_cli/copilot_cli.py _detect_for_user → get_version) and the Claude binary detector. Hardening only Augment would leave the siblings exposed and diverge the detector family, so this should be one repo-wide change (under root: only exec root-owned, non-world-writable binaries, else report version "unknown"). Will track separately.
|
|
||
| def _extract_user_configs_for_user(self, user_home: Path) -> List[Dict]: | ||
| """Read the User-scope MCP config(s) for a single user's ``~/.augment``.""" | ||
| augment_dir = _resolve_augment_dir(user_home) |
There was a problem hiding this comment.
🔒 Agentic Security Review
Severity: HIGH
User-scope Augment extraction trusts ~/.augment as-is and then reads files beneath it without resolving/containing symlinks. In privileged all-users scans, a low-privilege user can symlink their ~/.augment to another user-readable location and cause cross-user MCP/settings/rules/skills ingestion under the wrong identity.
Impact: cross-user data exposure and misattribution during root/admin discovery runs.
Reviewed by Cursor Security Reviewer for commit 45eae7b. Configure here.
| bucket["mcpServers"] = self._union_mcp_servers( | ||
| bucket.get("mcpServers", []), project.get("mcpServers", []) | ||
| ) | ||
| log_mcp_details(projects_dict, tool_name) |
There was a problem hiding this comment.
🔒 Agentic Security Review
Severity: MEDIUM
The new Augment path now emits MCP details via log_mcp_details, which logs full command/arg strings at info level. MCP server args frequently carry tokens/keys (--api-key, bearer values), so this can leak sensitive material into operational logs.
Impact: credential or secret disclosure through log aggregation/retention.
Reviewed by Cursor Security Reviewer for commit 45eae7b. Configure here.
…dedup, symlink, ownership) Cursor + Greptile inline review follow-ups: - G: canonical Augment surface is now chosen PER USER (keyed by _config_path), not a single global name. A root multi-user scan picks a winner for each user's ~/.augment independently, so a VS Code-only user no longer gets a bare row that drops their config when another user has the CLI. - F: managed-scope-only permissions (org-wide /etc/augment) no longer manufacture a phantom Augment row for a non-owner under root scans (_augment_owned_by_user no longer counts managed permissions as user-owned data). - B: MCP accessor memoization uses a distinct UNSET sentinel so a legitimate cached None (no MCP configured) short-circuits instead of re-running the full MCP walk on every surface. - C: emit at most one "Augment (VS Code)" row per user (prefer stable over nightly) so stable+nightly installs don't create duplicate canonical rows. - A: skills walk skips symlinked dirs before the .augment handling (mirrors the rules/mcp/settings walks) so a symlinked .augment can't be followed. - E: Windows skills walk also skips other-tool config dirs (parity with the macOS base + Windows rules walk). D (Linux rules per-user error guard) was already covered by the macOS base _extract_user_rules try/except that the Linux subclass inherits. Adds per-user-canonical, managed-ownership, MCP-memo, dual-extension, and symlink regression tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ans (H2) Under a root MDM all-users scan, MacOSJetBrainsDetector returns every user's IDEs, but the Augment JetBrains row stamped _config_path from the outer scan home — so an IDE owned by user B could be attributed to user A's ~/.augment (wrong permissions/config). Run JetBrains detection once and derive each IDE's owning user from the IDE's own config path (longest-prefix match against the scanned homes), falling back to the scoped/current home. This also removes the prior N-times-redundant rescan. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🛡️ Automated Security Review (consensus)2 findings — 1 high-confidence, 1 to triage. Reviewers: Cursor, Claude, Semgrep, Gitleaks. 🔴 HIGH — User-scope
|
The new H2 regression test hardcoded "/Users/bob/.augment", but production stringifies a Path, so on Windows _config_path is "\\Users\\bob\\.augment" and the literal-POSIX assertion failed (Windows CI). Build the expected value via Path so the separator matches the host OS. Test-only; production is correct. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🛡️ Automated Security Review (consensus)2 findings — 1 high-confidence, 1 to triage. Reviewers: Cursor, Claude, Semgrep, Gitleaks. 🔴 HIGH — User-scope
|
| "_config_path": str(_resolve_augment_dir(user_home)), | ||
| } | ||
|
|
||
| def _resolve_binary(self, user_home: Path) -> Optional[str]: |
There was a problem hiding this comment.
🔒 Agentic Security Review
Severity: HIGH
_detect_auggie_cli_for_user() resolves auggie from user-writable home paths and immediately executes it via get_version(binary) during all-users scanning. In privileged discovery runs, this lets a low-privilege local user plant a malicious auggie binary and get execution under the scanner's elevated identity.
Impact: local privilege escalation to the discovery process account (root/admin) and host compromise.
Reviewed by Cursor Security Reviewer for commit d75e591. Configure here.
…eptile) Parity with LinuxAugmentSkillsExtractor: wrap each per-user extract_for_user in try/except (PermissionError, OSError) so one unreadable home can't abort the whole multi-user rules scan. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🛡️ Automated Security Review (consensus)3 findings — 2 high-confidence, 1 to triage. Reviewers: Cursor, Claude, Semgrep, Gitleaks. 🔴 HIGH — Symlinked rule/guideline files read without containment
🔴 HIGH — User-scope
|
…ptile) The MCP workspace walk descended into user homes and re-read ~/.augment/settings.json as PROJECT scope — the same servers already collected as USER scope — emitting duplicate MCP servers under two project paths (~/.augment as "user" + the home dir as "project"). Record each user-home ~/.augment collected as user scope and skip it in the workspace walk, matching the rules/settings/skills user-dir guards. Genuine project .augment dirs are still collected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🛡️ Automated Security Review (consensus)2 findings — 2 high-confidence, 0 to triage. Reviewers: Cursor, Claude, Semgrep, Gitleaks. 🔴 HIGH — Symlinked rule/guideline files read without containment
🔴 HIGH — User-scope
|
| return None | ||
|
|
||
| mcp_servers_obj = _extract_servers_obj(config_data) | ||
| mcp_servers_array = transform_mcp_servers_to_array(mcp_servers_obj) |
There was a problem hiding this comment.
🔒 Agentic Security Review
Severity: HIGH
Workspace .<augment>/settings.json data is treated as trusted enough to invoke transform_mcp_servers_to_array, which actively scans MCP servers and can spawn configured stdio commands. Because this workspace file is attacker-controlled project content, a privileged all-users scan can be coerced into executing arbitrary commands from untrusted config.
Impact: privilege-boundary command execution during discovery (especially under root/admin scans), with potential host compromise or unauthorized outbound actions.
Reviewed by Cursor Security Reviewer for commit a6bf47d. Configure here.
…onfig dir Two follow-ups from dogfooding the Auggie CLI: 1. Auggie loads skills/commands from .augment, .claude AND .agents (per docs.augmentcode.com/cli/skills, in both workspace and home) and honors .claude/commands for Claude compatibility. The Augment skills extractor now sources all three marker dirs (user + project). The same .claude/.agents item is reported under Claude Code / Copilot CLI AND Augment by design — each tool reports what it loads; the backend dedups per (tool, home_user). 2. Group user-scope skills under their CONFIG DIR (~/.augment, ~/.claude, ~/.agents) instead of the bare home. The backend keys an AIToolProject per project path, so the old bare-home key surfaced a spurious "~" project separate from the ~/.augment rules/MCP project; now ~/.augment skills coalesce with that row's rules/MCP, while ~/.claude/~/.agents skills group under their own dir. Still owner-scoped (home is in the path) so the per-user filter prevents cross-user skill leakage under root scans. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| and Path(str(s["settings_path"])).parent == Path(config_dir) | ||
| ) | ||
| ] | ||
| permissions_payload = transform_settings_to_backend_format(own) if own else None |
There was a problem hiding this comment.
User hooks dropped when managed exists
Medium Severity
_process_augment_tool passes both managed and user settings into transform_settings_to_backend_format, which keeps only the highest-precedence record. When org managed settings.json exists, user hooks in raw_settings are omitted from the payload even though this PR relies on those hooks for risk classification.
Reviewed by Cursor Bugbot for commit 5333ad8. Configure here.
vigneshsubbiah16
left a comment
There was a problem hiding this comment.
🛡️ Automated Security Review (consensus)
1 finding — 1 high-confidence, 0 to triage. Reviewers: Cursor, Claude, Semgrep, Gitleaks.
🔴 HIGH — Symlinked rule/config files read without path containment
scripts/coding_discovery_tools/macos/augment/augment_rules_extractor.py:298 (also augment_settings_extractor.py:57, augment_mcp_config_extractor.py:218)
Impact: Project walks skip symlinked directories, but file reads gate only on is_file() (which follows symlinks); under root/MDM scans a planted symlink (e.g. ~/.augment/rules/x.md, AGENTS.md, settings.json) can pull arbitrary host files into the discovery payload.
Fix: Before reading, reject path.is_symlink() and/or verify path.resolve() stays under the intended user/project root; apply uniformly in _add_rule_file, _parse_jsonc, and _read_mcp_config (and the shared skills file-read path).
Reviewers: Claude, Cursor, Lead
Previously acknowledged (not re-flagged)
- Privileged scan executes user-writable
auggiebinaries — deferred as repo-wide hardening tracked separately; same pattern already ships in Copilot/Claude CLI detectors (@thatcatfromspace). - MCP cache sentinel / empty-result memoization — fixed with
_AUGMENT_CACHE_UNSET(@thatcatfromspace). - MCP workspace walk duplicating user-home
~/.augment— fixed via_scanned_user_augment_dirsskip set (@thatcatfromspace). - Linux rules extractor missing per-user error guard — fixed with
try/except (PermissionError, OSError)(@thatcatfromspace). - VS Code stable+nightly duplicate rows — fixed; at most one row emitted, stable preferred.
- Symlinked
.augmentdirectories in project walks — fixed; symlink check runs before.augmentdispatch in rules/MCP/skills walkers. - Managed permissions bypassing ownership gate — fixed;
_augment_owned_by_userexcludes managed-only scope from counting as user-owned data. - JetBrains
_config_pathmis-attribution under root scans — fixed via IDE-owner home derivation. log_mcp_detailsmay log MCP arg secrets — pre-existing shared helper used by sibling tools; not introduced by this diff (Claude).
🤖 consensus review · reviewers: Cursor,Claude,Semgrep,Gitleaks · head 5333ad8e · 2026-06-26T06:23Z
vigneshsubbiah16
left a comment
There was a problem hiding this comment.
🛡️ Automated Security Review (consensus)
5 findings — 3 high-confidence, 2 to triage. Reviewers: Cursor, Claude, Semgrep, Gitleaks.
🔴 HIGH — MCP config reads lack symlink containment
scripts/coding_discovery_tools/macos/augment/augment_mcp_config_extractor.py:223
Impact: _read_mcp_config reads ~/.augment/settings.json and mcp*.json (user + project scope) with only is_file() — no symlinked_file_escapes_home — so a privileged all-users scan can follow out-of-home symlinks and emit arbitrary file contents as MCP config.
Fix: Reject paths where symlinked_file_escapes_home(config_path) before read_text(), matching augment_settings_extractor._parse_jsonc.
Reviewers: Claude, Cursor
🔴 HIGH — Symlinked ~/.augment parent bypasses leaf-only guard
scripts/coding_discovery_tools/constants.py:104 (and direct user-scope read sites: settings, rules, MCP)
Impact: symlinked_file_escapes_home returns safe when the leaf file is not a symlink; if ~/.augment itself is ln -s /Users/victim/.augment, reads of settings.json follow the dir symlink and ingest another user's config under the attacker's identity during root scans.
Fix: Resolve the full path (or walk ancestors) and verify the real target stays within the owning user's home, not only when the leaf is a symlink.
Reviewers: Claude, Lead
🔴 HIGH — Workspace MCP transform may execute attacker-controlled commands
scripts/coding_discovery_tools/macos/augment/augment_mcp_config_extractor.py:231
Impact: Project .augment/settings.json is attacker-controlled; parsing flows into transform_mcp_servers_to_array, which can actively probe/spawn configured stdio MCP commands — a coercion vector during privileged discovery runs.
Fix: Confirm whether transform_mcp_servers_to_array executes commands; if yes, disable active probing for workspace/project scope or restrict to metadata-only collection during discovery.
Reviewers: Cursor
🟡 TRIAGE — MCP details logged at info level may leak secrets
scripts/coding_discovery_tools/ai_tools_discovery.py:1880
Impact: _process_augment_tool calls log_mcp_details; MCP server args often carry tokens/keys (--api-key, bearer values) that may end up in operational logs.
Fix: Redact or omit sensitive MCP args in log_mcp_details, or gate Augment logging behind a debug flag.
Reviewers: Cursor
🟡 TRIAGE — User hooks dropped when managed settings win precedence
scripts/coding_discovery_tools/ai_tools_discovery.py:1939
Impact: transform_settings_to_backend_format keeps only the highest-precedence scope; when org managed settings.json exists, user hooks in raw_settings are omitted from the payload despite being needed for risk classification.
Fix: When managed wins for toolPermissions, still merge user-scope hooks into the emitted raw_settings (or attach a separate user-hooks field).
Reviewers: Cursor
Previously acknowledged (not re-flagged)
- Privileged scan executes user-writable
auggiebinaries — maintainer deferred as repo-wide hardening (parity with Copilot CLI / Claude detectors), not an Augment-only fix. - MCP cache sentinel / empty-
Nonememoization — fixed with_AUGMENT_CACHE_UNSET; regression test added. - MCP workspace walk re-collecting
~/.augmentas project scope — fixed by tracking scanned user-home.augmentdirs; regression test added. - Linux rules extractor missing per-user
try/except— fixed to match skills extractor. - Managed-only permissions bypassing ownership gate — fixed in
_augment_owned_by_user(managed scope does not count as user-owned data). - VS Code-only / per-user canonical surface dropping user settings — fixed with
_canonical_augment_surface_by_configkeyed per_config_path. - Dual stable+nightly VS Code duplicate rows — fixed (prefer stable extension, emit one row).
- JetBrains
_config_pathmis-attribution under root scans — fixed via_augment_owner_home_for_path. - Windows skills walk missing
traverses_other_tool_config_dir— fixed; parity test added. - Symlinked
.augmentdirs in skills walk — fixed (symlink check before name dispatch, matching rules/MCP ordering).
🤖 consensus review · reviewers: Cursor,Claude,Semgrep,Gitleaks · head 9e004cd3 · 2026-06-26T06:53Z
🛡️ Automated Security Review (consensus)3 findings — 1 high-confidence, 2 to triage. Reviewers: Cursor, Claude, Semgrep, Gitleaks. 🔴 HIGH — MCP config reads lack symlink containment
🟡 TRIAGE — MCP server commands/args logged at info level
🟡 TRIAGE — Workspace MCP transform may execute untrusted stdio commands
Previously acknowledged (not re-flagged)
🤖 consensus review · reviewers: Cursor,Claude,Semgrep,Gitleaks · head |
cbafbba to
5333ad8
Compare
🛡️ Automated Security Review (consensus)3 findings — 1 high-confidence, 2 to triage. Reviewers: Cursor, Claude, Semgrep, Gitleaks. 🔴 HIGH — User-scope
|
| for mcp_file in sorted(augment_dir.glob(_MCP_FILE_GLOB)): | ||
| config = self._read_mcp_config(mcp_file, str(augment_dir), "user") | ||
| if config: | ||
| configs.append(config) |
There was a problem hiding this comment.
Symlinked user augment dir read
High Severity
User-scope extraction opens ~/.augment via _resolve_augment_dir without rejecting a symlinked config directory. Under privileged all-users scans, a profile can point .augment at another user’s tree so MCP, rules, and settings reads follow the link and emit that user’s policy and content under the wrong home label.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit a3ff12c. Configure here.
a3ff12c to
5333ad8
Compare
The skills project walk symlink-checks the parent .augment dir but then used type_dir.is_dir() on the skills/commands subdir, which follows symlinks — so under a root MDM scan a user could point .augment/skills at an arbitrary dir and have the scanner traverse it. Add the matching `not type_dir.is_symlink()` guard (mirrors the parent-dir guard in the same method). All OSes via the inherited macOS walk. Adds a regression test (symlinked .augment/skills not traversed; real one still collected). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
There are 4 total unresolved issues (including 3 from previous reviews).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 8f2aeb1. Configure here.
| if size > _MAX_SETTINGS_BYTES: | ||
| logger.warning(f"Skipping oversize Augment settings file {path} ({size} bytes)") | ||
| return None | ||
| raw = path.read_text(encoding="utf-8", errors="replace") |
There was a problem hiding this comment.
Symlinked config reads lack containment
High Severity
Augment's settings and MCP config file readers (e.g., for settings.json, mcp*.json) follow symlinks. This allows users, particularly during root-aware scans, to link to files outside their expected directories, leading to the collection of unintended host content. Directory walks correctly skip symlinked folders, but not symlinked files.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 8f2aeb1. Configure here.
vigneshsubbiah16
left a comment
There was a problem hiding this comment.
🛡️ Automated Security Review (consensus)
7 findings — 5 high-confidence, 2 to triage. Reviewers: Cursor, Claude, Semgrep, Gitleaks.
🔴 HIGH — MCP config reader follows symlinks without containment
scripts/coding_discovery_tools/macos/augment/augment_mcp_config_extractor.py:218
Impact: In root/MDM all-users scans, a user can symlink ~/.augment/settings.json or mcp*.json to another readable file and have its MCP config parsed and attributed under the attacker's home.
Fix: Before read_text() in _read_mcp_config, reject paths where symlinked_file_escapes_home (same guard as sibling extractors).
Reviewers: Cursor, Claude, Greptile
🔴 HIGH — Symlinked ~/.augment directory enables cross-user ingestion
scripts/coding_discovery_tools/macos/augment/augment_rules_extractor.py:115 (also augment_settings_extractor.py:151, augment_mcp_config_extractor.py:98)
Impact: If ~/.augment is a directory symlink to another user's config, regular files inside are read without escaping the owning home; rules/settings/MCP from the target are emitted under the symlink owner's identity.
Fix: After _resolve_augment_dir, verify the resolved path stays under user_home (reject directory symlinks that escape the home boundary) before any user-scope walk/read.
Reviewers: Cursor
🔴 HIGH — Settings JSON read follows symlinks
scripts/coding_discovery_tools/macos/augment/augment_settings_extractor.py:59
Impact: _parse_jsonc uses is_file() then read_text() with no symlink check, so a symlinked ~/.augment/settings.json can disclose arbitrary root-readable JSON into raw_settings during privileged scans.
Fix: Reject symlinked settings paths that escape the owning user's home before stat()/read_text().
Reviewers: Cursor
🔴 HIGH — Rule/guideline files follow symlinks outside tree
scripts/coding_discovery_tools/macos/augment/augment_rules_extractor.py:304
Impact: _add_rule_file accepts symlinked .md/.mdx (and repo-root AGENTS.md/CLAUDE.md/.augment-guidelines), letting a crafted symlink read arbitrary host files into discovery payloads.
Fix: Skip item.is_symlink() (and apply symlinked_file_escapes against the project/home root) before calling extract_single_rule_file.
Reviewers: Cursor
🔴 HIGH — Workspace MCP transform may execute untrusted stdio commands
scripts/coding_discovery_tools/macos/augment/augment_mcp_config_extractor.py:231
Impact: Project .augment/settings.json is attacker-controlled; transform_mcp_servers_to_array can probe/spawn configured MCP stdio commands during discovery, including under elevated scans.
Fix: Treat workspace MCP configs as untrusted metadata only (parse without execution), or gate execution behind the same trust model used for other tools' MCP scanners.
Reviewers: Cursor
🟡 TRIAGE — MCP args may leak into operational logs
scripts/coding_discovery_tools/ai_tools_discovery.py:1880
Impact: _process_augment_tool calls log_mcp_details at info level; MCP command/args often carry API keys or tokens into log aggregation.
Fix: Redact sensitive args in log_mcp_details, downgrade to debug, or omit arg values for Augment (match any existing redaction used elsewhere).
Reviewers: Cursor
🟡 TRIAGE — Symlinked skill/command files not rejected at read time
scripts/coding_discovery_tools/macos/augment/augment_skills_extractor.py:129
Impact: Directory symlink guards were added, but shared skill/command helpers still accept is_file() entries that can be symlinks, enabling out-of-tree reads of markdown content.
Fix: Reject symlinked skill/command files (and apply containment vs. project/home root) before content extraction in the Augment skills path.
Reviewers: Cursor
Previously acknowledged (not re-flagged)
- Privileged scan executes user-writable
auggiebinary (macos/augment/augment.py:202-216) — @thatcatfromspace: deferred as separate repo-wide hardening (parity with Copilot CLI / Claude detectors); fix only Augment would leave siblings exposed. Tracked separately. - MCP cache sentinel / workspace
~/.augmentre-collection — @thatcatfromspace: fixed (_AUGMENT_CACHE_UNSET+ skip already-scanned user~/.augmentin workspace walk). - Linux rules scan abort on per-user OS errors — @thatcatfromspace: fixed (
try/exceptper home, parity with skills extractor).
🤖 consensus review · reviewers: Cursor,Claude,Semgrep,Gitleaks · head 8f2aeb1c · 2026-06-26T09:55Z


Summary
Adds Augment Code to the discovery scanner as a single cross-surface detector (mirroring the GitHub Copilot pattern) that emits a per-surface row for each of Auggie CLI, Augment (VS Code), and Augment (<JetBrains IDE>) — all three share one
~/.augmentconfig, which is attached to a single canonical surface so it is never duplicated across rows. Discovery half of WEB-4950 (the hooks half shipped separately in setup#184).Footprint detected (verified against a live 0.30.0 install)
auggiebinary on PATH (auggie --version); VS Code extaugment.vscode-augment(+-nightly); JetBrains plugin (id 24072, name contains "Augment").toolPermissions→ allow/deny/ask (withshellInputRegexretained),hookspreserved verbatim inraw_settings; user + managed scopes (~/.augment/settings.json,/etc/augment/settings.json, WindowsC:\ProgramData\augment).mcpServerstop-level andaugment.advanced.mcpServers(+ flat form), user + workspace scope..augment-guidelines,.augment/rules/*.{md,mdx},~/.augment/rules/,~/.augment/user-guidelines.md, plus hierarchicalAGENTS.md/CLAUDE.md(Augment reads these).~/.augment/skills/<name>/SKILL.md,.augment/commands/*.md.Changes
scripts/coding_discovery_tools/{macos,linux,windows}/augment/(detector + settings/MCP/rules/skills extractors; macOS holds logic, Win/Linux are thin OS-seam subclasses) +augment_skills_helpers.py.coding_tool_base.py;create_augment_detector+ 4 extractor factories incoding_tool_factory.py; orchestration (memoized accessors, canonical-surface picker,_process_augment_tool, routing, per-user ownership gate) inai_tools_discovery.py;linux/__init__.pyre-exports..mdx+ AGENTS.md/CLAUDE.md + user/project dedup), skills (+linux), over-collection/canonical dedup, cross-user skills attribution, and a discovery-flow fail-safe injection.Review & validation
file_path), a rules user/project duplication, and an extract-then-silently-drop of project/local settings (settings reduced to user+managed); architect validated the fix set as sound.~/.augment0.30.0 install: detector found Auggie CLI 0.30.0 + Augment (VS Code) 0.859.7; settings extractor parsed the realtoolPermissionsask-rules and preserved all 5 hook events inraw_settings.Test plan
test_copilot_cli_*binary-gate tests fail, and only on this dev machine because it has a real Homebrewcopilotbinary — unrelated to this change; zero copilot files touched)stagingKnown follow-ups (non-blocking)
_deduplicate_project_items(pre-existing pattern shared with the Copilot path); parity follow-up if desired.🤖 Generated with Claude Code
Note
Medium Risk
Runs bounded filesystem walks and reads user settings/permissions on customer machines under root scans; risk is mitigated by mirroring the hardened Copilot CLI pattern, per-user canonical/ownership logic, and broad test coverage rather than changes to auth or backend APIs.
Overview
Adds Augment Code to the coding-tools discovery scanner (WEB-4950), following the same multi-surface pattern as GitHub Copilot CLI: separate inventory rows for Auggie CLI, Augment (VS Code), and Augment (<JetBrains IDE>), all backed by one per-user
~/.augmentconfig.New macOS detector and MCP, rules, settings, and skills extractors are wired through factories and base classes; Linux and Windows reuse that logic via thin OS-seam subclasses. Orchestration in
ai_tools_discovery.pymemoizes shared extractions (with an unset sentinel so legitimate empty MCP results do not re-trigger walks), picks a canonical surface per_config_path(CLI > VS Code > JetBrains), attaches MCP/rules/skills/permissions only on that row, routes Augment before the generic JetBrains handler, and applies an ownership gate for root multi-user scans so non-owners do not get phantom rows or cross-user skill leakage.Settings cover user and managed scopes with
toolPermissionsand hooks inraw_settings; rules and skills include.augmentpaths plus compatible.claude/.agentshome content where applicable. 68 new tests cover detection, routing, deduplication, and fail-safe behavior in the discovery flow.Reviewed by Cursor Bugbot for commit 8f2aeb1. Bugbot is set up for automated code reviews on this repo. Configure here.
Greptile Summary
Adds Augment Code to the coding-tool discovery scanner, emitting separate inventory rows for Auggie CLI, Augment (VS Code), and Augment (JetBrains IDEs), all sharing one
~/.augmentconfig directory attached to a single canonical surface per user.macos/,linux/, andwindows/augment/seams follow the established Copilot CLI pattern: memoized whole-disk walks, bounded depth, symlink guards on dirs and subdirs, user-augment-dir skipping to prevent double-collection as project scope.ai_tools_discovery.pyuses a_AUGMENT_CACHE_UNSETsentinel to distinguish "not yet run" from "ran and found nothing," picks one canonical surface per user keyed by_config_path, and gates non-owners with_augment_owned_by_userto suppress phantom rows under root multi-user scans.Confidence Score: 4/5
Safe to merge with the missing observability gap addressed; the core scanning, ownership, and dedup logic is well-tested and sound.
The Augment discovery flow — detection, MCP, rules, settings, and skills extraction — ships with zero flow-specific instrumentation. The shared time_step('process_single_tool') aggregates all tools together, so Augment extraction latency and per-phase success/failure rates cannot be isolated when diagnosing customer-machine failures. Engineering standards require per-flow metrics for every new flow.
scripts/coding_discovery_tools/ai_tools_discovery.py — the memoized accessor methods and the main() processing loop need Augment-specific time_step entries and success/failure counters.
Important Files Changed
Sequence Diagram
%%{init: {'theme': 'neutral'}}%% sequenceDiagram participant Main as main() participant Det as AIToolsDetector participant AugDet as MacOSAugmentDetector participant MCP as AugmentMCPExtractor participant Rules as AugmentRulesExtractor participant Sett as AugmentSettingsExtractor participant Skills as AugmentSkillsExtractor Main->>Det: detect_all_tools() Det->>AugDet: detect() AugDet-->>Det: [AuggCLI, VSCode, JetBrains] rows (each with _config_path) Main->>Det: _set_canonical_augment_surface(tools) Note over Det: Groups by _config_path → picks CLI > VSCode > JB per user loop for each tool Main->>Det: process_single_tool(tool) Det->>Det: _process_augment_tool(tool) alt canonical surface Det->>MCP: extract_mcp_config() [memoized] MCP-->>Det: "{projects: [{path, mcpServers}]}" Det->>Rules: extract_all_augment_rules() [memoized] Rules-->>Det: "[{project_root, rules[]}]" Det->>Skills: extract_all_skills() [memoized] Skills-->>Det: "{user_skills[], project_skills[]}" Det->>Sett: extract_settings() [memoized] Sett-->>Det: "[{scope, settings_path, permissions}]" Det-->>Main: tool with projects[] + permissions else non-canonical surface Det-->>Main: "bare row (projects=[])" end Main->>Main: filter_tool_projects_by_user() Main->>Main: _augment_owned_by_user() gate end%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% sequenceDiagram participant Main as main() participant Det as AIToolsDetector participant AugDet as MacOSAugmentDetector participant MCP as AugmentMCPExtractor participant Rules as AugmentRulesExtractor participant Sett as AugmentSettingsExtractor participant Skills as AugmentSkillsExtractor Main->>Det: detect_all_tools() Det->>AugDet: detect() AugDet-->>Det: [AuggCLI, VSCode, JetBrains] rows (each with _config_path) Main->>Det: _set_canonical_augment_surface(tools) Note over Det: Groups by _config_path → picks CLI > VSCode > JB per user loop for each tool Main->>Det: process_single_tool(tool) Det->>Det: _process_augment_tool(tool) alt canonical surface Det->>MCP: extract_mcp_config() [memoized] MCP-->>Det: "{projects: [{path, mcpServers}]}" Det->>Rules: extract_all_augment_rules() [memoized] Rules-->>Det: "[{project_root, rules[]}]" Det->>Skills: extract_all_skills() [memoized] Skills-->>Det: "{user_skills[], project_skills[]}" Det->>Sett: extract_settings() [memoized] Sett-->>Det: "[{scope, settings_path, permissions}]" Det-->>Main: tool with projects[] + permissions else non-canonical surface Det-->>Main: "bare row (projects=[])" end Main->>Main: filter_tool_projects_by_user() Main->>Main: _augment_owned_by_user() gate endReviews (12): Last reviewed commit: "fix(augment): guard symlinked skills/com..." | Re-trigger Greptile
Context used:
Django / Backend ... (source)