Skip to content

feat(dsn): add monorepo support with multi-DSN detection - #27

Merged
betegon merged 15 commits into
mainfrom
feat/monorepo-dsn-detection
Jan 21, 2026
Merged

feat(dsn): add monorepo support with multi-DSN detection#27
betegon merged 15 commits into
mainfrom
feat/monorepo-dsn-detection

Conversation

@betegon

@betegon betegon commented Jan 21, 2026

Copy link
Copy Markdown
Member

Summary

Adds monorepo support so the CLI can detect and work with multiple Sentry projects in a single repository. Previously, finding multiple DSNs was treated as a "conflict" - now it's properly supported for monorepo workflows.

Changes

DSN Detection:

  • Scans packages/, apps/, libs/, services/, modules/ for .env files
  • Tracks packagePath to identify which package a DSN belongs to
  • detectAllDsns() returns all found DSNs (deduplicated)
  • Changed conflict flag to hasMultiple (multiple DSNs is now valid)

Commands:

  • project get - shows details for all detected projects in monorepos
  • project list - fetches from all detected orgs in monorepos
  • Both show a footer listing detected projects when multiple found

Code Quality:

  • Added scanner.ts with shared file scanning utilities
  • Added ARCHITECTURE.md documenting the DSN module for contributors
  • Consolidated naming (extractDsnFromEnvContent as canonical)

Test Plan

# Unit tests pass
bun test test/lib/dsn

# E2E tests pass (requires .env.local with auth)
bun test --env-file=../../.env.local

# Manual test in a monorepo
cd your-monorepo
sentry project get  # Should show all detected projects

- Add detectAllDsns() to find all DSNs in a project (vs first-only)
- Add packagePath inference for monorepo structures (packages/*, apps/*, etc.)
- Add resolveAllTargets() for commands to resolve multiple DSNs in parallel
- Update project list/get commands to use monorepo-aware resolution
- Add formatMultipleProjectsFooter() for user-friendly multi-project output
- Scan monorepo directories for .env files (packages/*, apps/*, libs/*, etc.)

Supports monorepos where different packages have different Sentry projects.
- Add scanner.ts with shared file scanning utilities for env-file detection
- Add ARCHITECTURE.md documenting module structure for contributors
- Consolidate naming: extractDsnFromEnvContent as canonical function name
- Export getDetectorForFile from languages for cache verification
- Simplify env-file.ts to use shared scanner utilities
- Improve JSDoc and inline documentation throughout
@github-actions

github-actions Bot commented Jan 21, 2026

Copy link
Copy Markdown
Contributor

Codecov Results 📊

❌ Patch coverage is 79.51%. Project has 676 uncovered lines.
✅ Project coverage is 63.73%. Comparing base (base) to head (head).

Files with missing lines (14)
File Patch % Lines
api-client.ts 12.20% ⚠️ 180 Missing
resolver.ts 3.77% ⚠️ 102 Missing
errors.ts 5.94% ⚠️ 95 Missing
errors.ts 33.87% ⚠️ 82 Missing
fixture.ts 28.74% ⚠️ 62 Missing
api.ts 66.30% ⚠️ 61 Missing
config.ts 75.45% ⚠️ 27 Missing
preload.ts 39.02% ⚠️ 25 Missing
detector.ts 87.79% ⚠️ 16 Missing
cache.ts 76.27% ⚠️ 14 Missing
index.ts 95.06% ⚠️ 4 Missing
parser.ts 93.75% ⚠️ 4 Missing
env-file.ts 97.17% ⚠️ 3 Missing
java.ts 97.22% ⚠️ 1 Missing
Coverage diff
@@            Coverage Diff             @@
##          main       #PR       +/-##
==========================================
+ Coverage    62.65%    63.73%    +1.08%
==========================================
  Files           26        27        +1
  Lines         1751      1864      +113
  Branches         0         0         —
==========================================
+ Hits          1097      1188       +91
- Misses         654       676       +22
- Partials         0         0         —

Generated by Codecov Action

@betegon
betegon marked this pull request as ready for review January 21, 2026 15:59
cursor[bot]

This comment was marked as outdated.

Comment thread src/lib/resolve-target.ts
Self-hosted Sentry DSNs don't have an orgId, so they can't be resolved
via the API. Previously these were silently filtered out. Now we:
- Track how many self-hosted DSNs were detected but couldn't be resolved
- Show a helpful note explaining that --org/--project flags are needed
Comment thread src/lib/resolve-target.ts
cursor[bot]

This comment was marked as outdated.

When resolving DSNs, AuthError should not be swallowed - if the user
is not authenticated, they need to know immediately. Other errors
(API failures, network issues) can still be silently skipped since
in monorepos some projects might be inaccessible.
cursor[bot]

This comment was marked as outdated.

The glob scan with onlyFiles: false returns both files and directories.
Now we explicitly check if each entry is a directory before processing,
matching what the comment says: 'Scan for subdirectories'.
cursor[bot]

This comment was marked as outdated.

- Add usageHint parameter to ResolveOptions for context-specific error messages
- Update ContextError to include full formatted message (Stricli compatibility)
- Update issue list to use resolveAllTargets for monorepo detection
- Merge issues from all projects into single sorted table (by lastSeen)
- Apply limit per-project (10 per project = 30 total for 3 projects)
- Add stricter Zod datetime validation for firstSeen/lastSeen fields
- Fix misleading error when all API fetches fail
Comment thread packages/cli/src/lib/resolve-target.ts Outdated
cursor[bot]

This comment was marked as outdated.

Multiple DSNs with different public keys can point to the same Sentry
project (e.g., rotated keys, browser vs server keys). Previously this
caused duplicate API calls and duplicate output.

Now deduplicates resolved targets by org+project combination, keeping
the first match (highest priority source: code > env files > env var).
Use writeJson directly instead of writeOutput with incorrect type cast.
When multiple projects are returned, jsonOutput is SentryProject[] not
SentryProject, making the 'as SentryProject' assertion incorrect.
The bare catch block was swallowing all errors including AuthError,
causing users to see an empty project list instead of a 'please log in'
message when not authenticated. Now re-throws AuthError to match the
intent in resolveDsnToTarget.
cursor[bot]

This comment was marked as outdated.

Added fetchOrgProjectsSafe helper that re-throws AuthError while
swallowing other errors (e.g., permission errors on individual orgs).

Fixes two locations:
1. Explicit --org flag: was using .catch(() => []) which swallowed auth
2. fetchAllOrgProjects loop: bare catch was swallowing all errors

Now users see 'please log in' instead of 'No projects found' when
not authenticated.
cursor[bot]

This comment was marked as outdated.

Previously, merged multi-project results were always sorted by lastSeen
(date) regardless of the --sort flag. Now uses the user's sort preference:

- date: sort by lastSeen (default)
- new: sort by firstSeen
- freq: sort by event count
- user: sort by affected user count
- priority: falls back to date (field not available client-side)
@github-actions

github-actions Bot commented Jan 21, 2026

Copy link
Copy Markdown
Contributor

Semver Impact of This PR

🟡 Minor (new features)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


New Features ✨

  • (dsn) Add monorepo support with multi-DSN detection by betegon in #27

🤖 This preview updates automatically when you update the PR.

Resolve conflicts from directory restructure (packages/cli/ -> root)
- Remove 'priority' from issue list sort options (no priority field available for client-side sorting)
- Fix lint: add braces to if statement in env-file.ts
- Fix lint: remove unnecessary async in detectAllFromCode
- Fix lint: extract processCodeFile to reduce cognitive complexity

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

Comment thread src/commands/issue/list.ts
@betegon
betegon merged commit cf0a2ce into main Jan 21, 2026
14 checks passed
@betegon
betegon deleted the feat/monorepo-dsn-detection branch January 21, 2026 21:59
BYK added a commit that referenced this pull request Aug 1, 2026
…s lockfile (#1332)

## Summary

Fixes all 13 open Dependabot alerts. No GitHub security advisories are
open.

Bumps the published package minimum to **Node.js 20+** (from 18+) so the
declared `engines.node` matches what the new transitive overrides
(`@hono/node-server@2.0.12`, `brace-expansion@5.0.9`) actually install.

## Background

Post-merge of PR #1254 ("chore: pre-shape repo into pnpm-workspace
monorepo layout"), the docs workspace moved from `docs/` to
`apps/cli-docs/`. The old `docs/package.json` was deleted, but
`docs/pnpm-lock.yaml` was left tracked — referencing the obsolete Astro
6.x / Starlight 0.39 layout. This stale lockfile is the source of 9 of
the 13 open alerts.

The remaining 4 alerts are transitive vulnerabilities in the active root
`pnpm-lock.yaml`:
- `shell-quote@1.8.4` via `react-devtools-core`
- `@hono/node-server@1.19.17` via `@modelcontextprotocol/sdk@1.29.0` →
`@hono/mcp` → `@mastra/client-js`
- `fast-uri@3.1.3` via `ajv` → MCP SDK chain
- `brace-expansion@5.0.7` via `minimatch` → `glob` (via ultracite and
@sentry/bundler-plugins)

## Changes

1. **Delete `docs/pnpm-lock.yaml`** — orphaned lockfile from
pre-monorepo layout; closes alerts #25, #27, #29, #31, #33, #34, #35,
#41, #54.

2. **`pnpm.overrides` in root `package.json`** for the 4 transitive
alerts:

```diff
-"shell-quote@<1.8.4": "1.8.4",
+"shell-quote@<1.9.0": "1.9.0",
 `qs@>=6.11.1 <=6.15.1`: "6.15.2",
 `form-data@<4.0.6`: "4.0.6",
 `vite@>=8.0.0 <8.0.16`: "8.0.16`,
+"@hono/node-server@<2.0.5": "2.0.12",
+"fast-uri@<=3.1.3": "3.1.5",
+"brace-expansion@<5.0.8": "5.0.9"
```

The previous `shell-quote@<1.8.4 → 1.8.4` override was itself vulnerable
(alert #36: `shell-quote <= 1.8.4` is the vulnerable range, patched in
1.9.0), so it is bumped to `<1.9.0 → 1.9.0`.

3. **`engines.node` bump 18 → 20** in root `package.json` and
`packages/cli/package.json`, plus doc updates in:
   - `apps/cli-docs/src/content/docs/library-usage.md`
   - `apps/cli-docs/src/content/docs/migrating-from-v3.md`
- `packages/cli/README.md` (the auto-generated `library-prereq` block
reads from `engines.node` via `generateLibraryPrereq()` in
`generate-docs-sections.ts`, so it picked up the new floor
automatically).

The dev floor (`devEngines.runtime >=22.15`) is unchanged — Node 22.15+
remains the development minimum. The standalone binary continues to
bundle its own Node 22.15+ runtime.

## Verification

- `pnpm audit --prod` → no known vulnerabilities
- `pnpm run check:deps` ✓
- `pnpm run lint` ✓ (951 files)
- `pnpm run typecheck` ✓
- `pnpm test:unit` → 416 files, 8760 tests passing, 13 skipped
- Resolved versions match or exceed each patched minimum:
  - shell-quote 1.9.0 (patched 1.9.0)
  - @hono/node-server 2.0.12 (patched 2.0.5)
  - fast-uri 3.1.5 (patched 3.1.4)
  - brace-expansion 5.0.9 (patched 5.0.8)

## Reviewer notes

**Pin rationale for `@hono/node-server@2.0.12`** — the patched minimum
is 2.0.5, but `packages/cli/package.json` already declares
`"@hono/node-server": "^2.0.6"` as a direct devDependency. Pinning to
2.0.12 (the latest 2.x available at PR time) keeps the override and the
direct declaration in the same major line and avoids a near-term minor
bump. `2.0.5–2.0.11` had no further advisories at the time of writing.

**Lockfile dedupe side effect** — `shell-quote@1.10.0` (already
non-vulnerable, used by `launch-editor`) is consolidated to `1.9.0`
because the override forces single-version resolution. No security
regression; `launch-editor` does not pin a shell-quote range narrower
than what 1.9.0 satisfies.

**Node 18 deprecation** — addresses the F1 SHOULD-FIX from the initial
review. The `>=18.0` floor had become inconsistent with the lockfile
once the overrides pulled in `@hono/node-server@2.0.12` (engines `>=20`)
and `brace-expansion@5.0.9` (engines `20 || >=22`). Both packages are
dev-only transitive deps, so the only users impacted are source-install
users who run the CLI via `node` instead of the standalone binary.
`devEngines.runtime` already required `>=22.15`, so development
environments are unaffected.

## Note

`pnpm audit` (non-prod-only) flags one additional low-severity advisory
— `@ai-sdk/provider-utils@2.2.8` (GHSA-866g-f22w-33x8, CVE-2026-8769,
via @mastra/client-js) — that is not yet in Dependabot. Addressing it
requires bumping @mastra/client-js to a newer major; left out of this PR
to keep scope focused on the explicit GitHub security report.

<sub>Comment `@sentry <feedback>` on this PR to have Autofix iterate on
the changes.</sub>
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