Skip to content

Chrome Extension using @sentry/browser gets rejected #14010

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
3 tasks done
SpaceK33z opened this issue Oct 17, 2024 · 17 comments
Closed
3 tasks done

Chrome Extension using @sentry/browser gets rejected #14010

SpaceK33z opened this issue Oct 17, 2024 · 17 comments
Labels
Package: browser Issues related to the Sentry Browser SDK

Comments

@SpaceK33z
Copy link

SpaceK33z commented Oct 17, 2024

Is there an existing issue for this?

How do you use Sentry?

Sentry Saas (sentry.io)

Which SDK are you using?

@sentry/browser

SDK Version

8.34.0

Framework Version

No response

Link to Sentry event

No response

Reproduction Example/SDK Setup

import * as Sentry from '@sentry/browser';

Sentry.init({ dsn: sentryDsn}); // (does not matter)

Use this in a Chrome Extension in the service worker.
In the content script we setup Sentry as outlined in these official docs — but just using it in a service worker is enough to trigger this.

Steps to Reproduce

  1. Submit the extension to the Chrome Webstore
  2. Wait

Expected Result

  • Extension is approved by the reviewers

Actual Result

  • Extension is rejected by the reviewers

The given reason:

Violating Content:
Code snippet: assets/[snip].js: const o = _b(n), i = k.document.createElement("script"); i.src = o, i.crossOrigin = "anonymous", i.referrerPolicy = "origin", t && i.setAttribute("nonce", t);
function _b(e) { const t = R(), n = t && t.getOptions(), r = n && n.cdnBaseUrl || "https://browser.sentry-cdn.com/"; return new URL(`/${yt}/${e}.min.js`, r).toString()

When looking up this code, it's coming from @sentry/browser and it looks like it's being used twice;

  1. to lazy load integrations
  2. and to load the "showReportDialog" feature

We use neither of these, yet still get rejected.

Probably not coincidentally, Chrome now is finally actually phasing out MV2 extensions (source), and only with MV3 remote code is not allowed to be executed. My guess is that they only started checking now.

It might be debatable that this is a bug, but I consider it as such because browser extensions seem to be officially supported.

The current work-around that I am using is to use patch-package to remove the code that injects a script tag in the lazyLoadIntegration and showReportDialog functions.

@getsantry getsantry bot moved this to Waiting for: Product Owner in GitHub Issues with 👀 3 Oct 17, 2024
@github-actions github-actions bot added the Package: browser Issues related to the Sentry Browser SDK label Oct 17, 2024
@chargome
Copy link
Member

Hey @SpaceK33z, how are you exactly bundling your application? The lazyLoadIntegration for showReportDialog should basically be treeshakable if you're not including it.

@SpaceK33z
Copy link
Author

SpaceK33z commented Oct 21, 2024

@chargome I am bundling the application with Vite and following the official docs which has this line in it:

const integrations = getDefaultIntegrations({}).filter(
  (defaultIntegration) => {
    return !["BrowserApiErrors", "Breadcrumbs", "GlobalHandlers"].includes(
      defaultIntegration.name,
    );
  },
);

Because of that, it will always import all integrations. The docs should be changed to not teach this, but instead do this:

const integrations = [browserApiErrorsIntegration(), breadcrumbsIntegration(), globalHandlersIntegration()];

This is shorter, more readable, doesn't use "magic" strings, and most importantly enables tree-shaking which fixes this issue.

@getsantry getsantry bot moved this to Waiting for: Product Owner in GitHub Issues with 👀 3 Oct 21, 2024
@chargome
Copy link
Member

chargome commented Oct 21, 2024

@SpaceK33z The snippet you provided does the exact opposite (not filtering out the integrations that use global state). So in your case this might work because it get's rid of all integrations but these three. In the docs there is also a line that states:

As a rule of thumb, it's best to avoid using any integrations and to rely on manual capture of errors only in such scenarios.

We could update the docs in this regard by adding a comment directly in the code snippet, wdyt?

@SpaceK33z
Copy link
Author

This was definitely a "problem exists between chair and computer" situation; the whole experience was just very confusing because we suddenly got rejected from the Chrome Webstore;

In the end the real issue was that I was doing import * as Sentry from '@sentry/browser'. Doing that makes tree-shaking not work, and to be fair the docs show specific imports and don't use the *.

To prevent other users from having this issue, it could be helpful to add a warning about that to the docs; that importing * from Sentry might lead to a rejection of the webextension (it's not just Chrome, Firefox also doesn't like this).

@getsantry getsantry bot moved this to Waiting for: Product Owner in GitHub Issues with 👀 3 Oct 22, 2024
@s1gr1d
Copy link
Member

s1gr1d commented Oct 23, 2024

Bundlers should still be able to tree-shake this. Did you check the emitted build output? There should not be a place that uses lazyLoadIntegration.

@SpaceK33z
Copy link
Author

Yes I checked the build output and it's there when using import * as Sentry from '@sentry/browser', and I verified that using specific imports (import { BrowserClient, ... } from '@sentry/core') fix the issue. This is using Vite.

It also makes sense because that's the whole reason we got rejected from the store, because that piece of code is in our bundle output. We got approved again by the store after switching to specific imports.

For me it's fine if this ticket gets closed, but potentially a warning to the docs like I mention above could be helpful for others.

@getsantry getsantry bot moved this to Waiting for: Product Owner in GitHub Issues with 👀 3 Oct 23, 2024
@s1gr1d
Copy link
Member

s1gr1d commented Oct 23, 2024

I just set up a Vite project with the vanilla preset and TS, bundled it and could not find lazyLoadIntegration in the build output.

Can you please share a minimal reproduction example of your setup so we can confirm this? It's useful to warn in the docs, but I want to make sure that this is not a problem within a specific setup or Vite preset.

@SpaceK33z
Copy link
Author

SpaceK33z commented Oct 23, 2024

Can you also not find any reference of document.createElement("script") in the output? Because it's not about lazyLoadIntegration, it's about whether it tries to execute remote code

@getsantry getsantry bot moved this to Waiting for: Product Owner in GitHub Issues with 👀 3 Oct 23, 2024
@s1gr1d
Copy link
Member

s1gr1d commented Oct 23, 2024

The only occurrences I found with createElement inside the whole output are iframe, function and link. A reproduction would be very useful here.

@FedorT22
Copy link

FedorT22 commented Dec 11, 2024

For us it worked fine with @sentry/browser, when we imported all dependencies granularly, like:

import {
  BrowserClient,
  defaultStackParser,
  browserApiErrorsIntegration,
  breadcrumbsIntegration,
  globalHandlersIntegration,
  makeFetchTransport,
  Scope,
} from '@sentry/browser';

const sentryClient = new BrowserClient({
  integrations: [
    browserApiErrorsIntegration(),
    breadcrumbsIntegration(),
    globalHandlersIntegration(),
  ],
  ...
});

or

import { captureException } from '@sentry/browser';

❌ Unfortunately, this approach did not work with @sentry/react. CDN links were still included into the final bundle and it's sourcemap also. We tried to build in development and production modes. In both cases the result is the same, it did not help.
So for us, the temporary solution is to clean up the CDN links after the building process (we are using vite):

    plugins: [
      react(),
      copy({
        targets: [
          {
            src: resolve(PATHS.dist, 'APP_NAME.js'),
            dest: PATHS.dist,
            transform(content) {
              return content
                .toString()
                .replace(/https:\/\/browser\.sentry-cdn\.com/g, '');
            },
          },
          {
            src: resolve(PATHS.dist, 'APP_NAME.js.map'),
            dest: PATHS.dist,
            transform(content) {
              return content
                .toString()
                .replace(/https:\/\/browser\.sentry-cdn\.com/g, '');
            },
          },
        ],
        hook: 'writeBundle',
      }),
   ...

@getsantry getsantry bot moved this from Waiting for: Community to Waiting for: Product Owner in GitHub Issues with 👀 3 Dec 11, 2024
@Lms24
Copy link
Member

Lms24 commented Dec 12, 2024

I have a feeling this is mostly related to bundler and tree-shaking setup. All modern bundlers are able to tree-shake out unused APIs, like lazyloadIntegration. It shouldn't even matter if you're importing a namespace (import * as Sentry ...) or you only use named imports import {...} from ....

Likewise, I can't see a reason as to why @sentry/react would behave differently from @sentry/browser. The only exception is that the React SDK depends on the Browser SDK. lazyloadIntegration is defined in the Browser SDK and only re-exported from the React SDK. Meaning perhaps tree shaking isn't configured correctly for transitive dependencies?

We'd still need a minimal reproduction to investigate this further. Thanks!

@piloudu
Copy link

piloudu commented Dec 17, 2024

I've faced this same issue when importing from the @sentry/browser package. Replacing wildcard imports by more specific imports didn't work for me, but I've managed to get a review approval by following the same approach @FedorT22 suggests in #14010 (comment).

In my project we're using the Rollup bundler, so I've bounced of the input plugin rollup-plugin-modify to strip the Sentry CDN URL:

const rollup = require('rollup');
const modify = require('rollup-plugin-modify');

rollup
  .rollup({
    input: 'src/main/background/index.ts',
    plugins: modify({
      find: 'https://browser.sentry-cdn.com',
      replace: '',
    }),
  })
  .then((bundle) => {
    return bundle.write({
      // ...
    });
  })

@getsantry getsantry bot moved this to Waiting for: Product Owner in GitHub Issues with 👀 3 Dec 17, 2024
@Lms24
Copy link
Member

Lms24 commented Dec 17, 2024

Glad you found a workaround!

However, in general I'd still argue that there must be a tree-shaking related problem in build setups where lazyloadIntegration is included. That is as long as you don't use feedbackIntegration.

My comment from above still stands:

We'd still need a minimal reproduction to investigate this further. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Package: browser Issues related to the Sentry Browser SDK
Projects
Archived in project
Development

No branches or pull requests

10 participants