You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ru...@apache.org on 2023/12/14 18:55:58 UTC

(superset) branch master updated: feat(telemetry): Adding Scarf based telemetry to Superset (#26011)

This is an automated email from the ASF dual-hosted git repository.

rusackas pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/master by this push:
     new 8437a235c9 feat(telemetry): Adding Scarf based telemetry to Superset (#26011)
8437a235c9 is described below

commit 8437a235c9bdaa3f2f82921f5f0ea294e6c1520b
Author: Evan Rusackas <ev...@preset.io>
AuthorDate: Thu Dec 14 11:55:51 2023 -0700

    feat(telemetry): Adding Scarf based telemetry to Superset (#26011)
    
    Co-authored-by: Michael S. Molina <70...@users.noreply.github.com>
---
 CONTRIBUTING.md                                    |  2 +-
 docker-compose.yml                                 |  2 +
 docs/docs/frequently-asked-questions.mdx           |  6 ++-
 .../installing-superset-using-docker-compose.mdx   |  4 +-
 superset-frontend/package-lock.json                | 42 +++++++++++----
 superset-frontend/package.json                     |  2 +-
 superset-frontend/spec/helpers/shim.tsx            | 16 +++---
 .../TelemetryPixel/TelemetryPixel.test.tsx         | 49 ++++++++++++++++++
 .../src/components/TelemetryPixel/index.tsx        | 59 ++++++++++++++++++++++
 superset-frontend/src/features/home/RightMenu.tsx  |  6 +++
 superset-frontend/webpack.config.js                |  1 +
 superset/config.py                                 | 16 +++++-
 12 files changed, 181 insertions(+), 24 deletions(-)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 25b0e02edb..de40865edc 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -622,7 +622,7 @@ cd superset-frontend
 npm ci
 ```
 
-Note that Superset uses [Scarf](https://docs.scarf.sh) to capture telemetry/analytics about versions being installed, including the `scarf-js` npm package. As noted elsewhere in this documentation, Scarf gathers aggregated stats for the sake of security/release strategy, and does not capture/retain PII. [You can read here](https://docs.scarf.sh/package-analytics/) about the package, and various means to opt out of it, but one easy way to opt out is to add this setting in `superset-fronte [...]
+Note that Superset uses [Scarf](https://docs.scarf.sh) to capture telemetry/analytics about versions being installed, including the `scarf-js` npm package and an analytics pixel. As noted elsewhere in this documentation, Scarf gathers aggregated stats for the sake of security/release strategy, and does not capture/retain PII. [You can read here](https://docs.scarf.sh/package-analytics/) about the `scarf-js` package, and various means to opt out of it, but you can opt out of the npm packa [...]
 
 ```json
 // your-package/package.json
diff --git a/docker-compose.yml b/docker-compose.yml
index b2c9196b00..a2dfc26dba 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -124,6 +124,8 @@ services:
     command: ["/app/docker/docker-frontend.sh"]
     env_file: docker/.env
     depends_on: *superset-depends-on
+    environment:
+      SCARF_ANALYTICS: "${SCARF_ANALYTICS}"
     volumes: *superset-volumes
 
   superset-worker:
diff --git a/docs/docs/frequently-asked-questions.mdx b/docs/docs/frequently-asked-questions.mdx
index 11682136d7..3007584ab1 100644
--- a/docs/docs/frequently-asked-questions.mdx
+++ b/docs/docs/frequently-asked-questions.mdx
@@ -268,8 +268,10 @@ This can be used, for example, to convert UTC time to local time.
 ### Does Superset collect any telemetry data?
 
 Superset uses [Scarf](https://about.scarf.sh/) by default to collect basic telemetry data upon installing and/or running Superset. This data helps the maintainers of Superset better understand which versions of Superset are being used, in order to prioritize patch/minor releases and security fixes.
-We use the [Scarf Gateway](https://docs.scarf.sh/gateway/) to sit in front of container registries, and the [scarf-js](https://about.scarf.sh/package-sdks) package to track `npm` installations.
-Scarf purges PII and provides aggregated statistics. Superset users can easily opt out of analytics in various ways documented [here](https://docs.scarf.sh/gateway/#do-not-track) and [here](https://docs.scarf.sh/package-analytics/#as-a-user-of-a-package-using-scarf-js-how-can-i-opt-out-of-analytics). Additional opt-out instructions for Docker users are available on the [Docker Installation](https://superset.apache.org/docs/installation/installing-superset-using-docker-compose) page.
+We use the [Scarf Gateway](https://docs.scarf.sh/gateway/) to sit in front of container registries, the [scarf-js](https://about.scarf.sh/package-sdks) package to track `npm` installations, and a Scarf pixel to gather anonymous analytics on Superset page views.
+Scarf purges PII and provides aggregated statistics. Superset users can easily opt out of analytics in various ways documented [here](https://docs.scarf.sh/gateway/#do-not-track) and [here](https://docs.scarf.sh/package-analytics/#as-a-user-of-a-package-using-scarf-js-how-can-i-opt-out-of-analytics).
+Superset maintainers can also opt out of telemetry data collection by setting the `SCARF_ANALYTICS` environment variable to `false` in the Superset container (or anywhere Superset/webpack are run).
+Additional opt-out instructions for Docker users are available on the [Docker Installation](https://superset.apache.org/docs/installation/installing-superset-using-docker-compose) page.
 
 ### Does Superset have an archive panel or trash bin from which a user can recover deleted assets?
 
diff --git a/docs/docs/installation/installing-superset-using-docker-compose.mdx b/docs/docs/installation/installing-superset-using-docker-compose.mdx
index 4611466ca3..7b6d975739 100644
--- a/docs/docs/installation/installing-superset-using-docker-compose.mdx
+++ b/docs/docs/installation/installing-superset-using-docker-compose.mdx
@@ -124,7 +124,9 @@ Users often want to connect to other databases from Superset. Currently, the eas
 :::note
 Superset uses [Scarf Gateway](https://about.scarf.sh/scarf-gateway) to collect telemetry data. Knowing the installation counts for different Superset versions informs the project's decisions about patching and long-term support. Scarf purges personally identifiable information (PII) and provides only aggregated statistics.
 
-To opt-out of this data collection in your docker compose based installation, edit the `x-superset-image:` line in your `docker-compose.yml` and `docker-compose-non-dev.yml` files, replacing `apachesuperset.docker.scarf.sh/apache/superset` with `apache/superset` to pull the image directly from Docker Hub.
+To opt-out of this data collection for packages downloaded through the Scarf Gateway by your docker compose based installation, edit the `x-superset-image:` line in your `docker-compose.yml` and `docker-compose-non-dev.yml` files, replacing `apachesuperset.docker.scarf.sh/apache/superset` with `apache/superset` to pull the image directly from Docker Hub.
+
+To disable the Scarf telemetry pixel, set the `SCARF_ANALYTICS` environment variable to `False` in your terminal and/or in your `docker/.env` and `docker/.env-non-dev` files.
 :::
 
 ### 4. Log in to Superset
diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json
index a747d9a78e..4794218b36 100644
--- a/superset-frontend/package-lock.json
+++ b/superset-frontend/package-lock.json
@@ -194,7 +194,7 @@
         "@types/js-levenshtein": "^1.1.0",
         "@types/json-bigint": "^1.0.1",
         "@types/mousetrap": "^1.6.11",
-        "@types/react": "^16.9.43",
+        "@types/react": "^16.9.53",
         "@types/react-dom": "^16.9.8",
         "@types/react-gravatar": "^2.6.8",
         "@types/react-json-tree": "^0.6.11",
@@ -19628,12 +19628,13 @@
       "devOptional": true
     },
     "node_modules/@types/react": {
-      "version": "16.9.43",
-      "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.43.tgz",
-      "integrity": "sha512-PxshAFcnJqIWYpJbLPriClH53Z2WlJcVZE+NP2etUtWQs2s7yIMj3/LDKZT/5CHJ/F62iyjVCDu2H3jHEXIxSg==",
+      "version": "16.14.51",
+      "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.51.tgz",
+      "integrity": "sha512-4T/wsDXStA5OUGTj6w2INze3ZCz22IwQiWcApgqqNRU2A6vNUIPXpNkjAMUFxx6diYPVkvz+d7gEtU7AZ+0Xqg==",
       "dependencies": {
         "@types/prop-types": "*",
-        "csstype": "^2.2.0"
+        "@types/scheduler": "*",
+        "csstype": "^3.0.2"
       }
     },
     "node_modules/@types/react-dom": {
@@ -19775,6 +19776,11 @@
         "@types/react": "*"
       }
     },
+    "node_modules/@types/react/node_modules/csstype": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
+      "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
+    },
     "node_modules/@types/redux-localstorage": {
       "version": "1.0.8",
       "resolved": "https://registry.npmjs.org/@types/redux-localstorage/-/redux-localstorage-1.0.8.tgz",
@@ -19816,6 +19822,11 @@
       "resolved": "https://registry.npmjs.org/@types/rison/-/rison-0.0.6.tgz",
       "integrity": "sha512-mE3eRK0fpTN/GnNBOIg2tGq2cFhchQXF6fCbrLxus75TgnoOECbdHikr948FGO/UAml7/ZhLMa5FbGkF5PKvmw=="
     },
+    "node_modules/@types/scheduler": {
+      "version": "0.16.6",
+      "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.6.tgz",
+      "integrity": "sha512-Vlktnchmkylvc9SnwwwozTv04L/e1NykF5vgoQ0XTmI8DD+wxfjQuHuvHS3p0r2jz2x2ghPs2h1FVeDirIteWA=="
+    },
     "node_modules/@types/seedrandom": {
       "version": "2.4.30",
       "resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-2.4.30.tgz",
@@ -79599,12 +79610,20 @@
       "devOptional": true
     },
     "@types/react": {
-      "version": "16.9.43",
-      "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.43.tgz",
-      "integrity": "sha512-PxshAFcnJqIWYpJbLPriClH53Z2WlJcVZE+NP2etUtWQs2s7yIMj3/LDKZT/5CHJ/F62iyjVCDu2H3jHEXIxSg==",
+      "version": "16.14.51",
+      "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.51.tgz",
+      "integrity": "sha512-4T/wsDXStA5OUGTj6w2INze3ZCz22IwQiWcApgqqNRU2A6vNUIPXpNkjAMUFxx6diYPVkvz+d7gEtU7AZ+0Xqg==",
       "requires": {
         "@types/prop-types": "*",
-        "csstype": "^2.2.0"
+        "@types/scheduler": "*",
+        "csstype": "^3.0.2"
+      },
+      "dependencies": {
+        "csstype": {
+          "version": "3.1.2",
+          "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
+          "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
+        }
       }
     },
     "@types/react-dom": {
@@ -79789,6 +79808,11 @@
       "resolved": "https://registry.npmjs.org/@types/rison/-/rison-0.0.6.tgz",
       "integrity": "sha512-mE3eRK0fpTN/GnNBOIg2tGq2cFhchQXF6fCbrLxus75TgnoOECbdHikr948FGO/UAml7/ZhLMa5FbGkF5PKvmw=="
     },
+    "@types/scheduler": {
+      "version": "0.16.6",
+      "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.6.tgz",
+      "integrity": "sha512-Vlktnchmkylvc9SnwwwozTv04L/e1NykF5vgoQ0XTmI8DD+wxfjQuHuvHS3p0r2jz2x2ghPs2h1FVeDirIteWA=="
+    },
     "@types/seedrandom": {
       "version": "2.4.30",
       "resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-2.4.30.tgz",
diff --git a/superset-frontend/package.json b/superset-frontend/package.json
index 083b83c69e..d8ed6f62e8 100644
--- a/superset-frontend/package.json
+++ b/superset-frontend/package.json
@@ -259,7 +259,7 @@
     "@types/js-levenshtein": "^1.1.0",
     "@types/json-bigint": "^1.0.1",
     "@types/mousetrap": "^1.6.11",
-    "@types/react": "^16.9.43",
+    "@types/react": "^16.9.53",
     "@types/react-dom": "^16.9.8",
     "@types/react-gravatar": "^2.6.8",
     "@types/react-json-tree": "^0.6.11",
diff --git a/superset-frontend/spec/helpers/shim.tsx b/superset-frontend/spec/helpers/shim.tsx
index 152fcc370c..8270c56317 100644
--- a/superset-frontend/spec/helpers/shim.tsx
+++ b/superset-frontend/spec/helpers/shim.tsx
@@ -48,14 +48,14 @@ if (defaultView != null) {
 }
 
 const g = global as any;
-g.window = g.window || {};
-g.window.location = { href: 'about:blank' };
-g.window.performance = { now: () => new Date().getTime() };
-g.window.Worker = Worker;
-g.window.IntersectionObserver = IntersectionObserver;
-g.window.ResizeObserver = ResizeObserver;
-g.window.featureFlags = {};
-g.URL.createObjectURL = () => '';
+g.window ??= Object.create(window);
+g.window.location ??= { href: 'about:blank' };
+g.window.performance ??= { now: () => new Date().getTime() };
+g.window.Worker ??= Worker;
+g.window.IntersectionObserver ??= IntersectionObserver;
+g.window.ResizeObserver ??= ResizeObserver;
+g.window.featureFlags ??= {};
+g.URL.createObjectURL ??= () => '';
 g.caches = new CacheStorage();
 
 Object.defineProperty(window, 'matchMedia', {
diff --git a/superset-frontend/src/components/TelemetryPixel/TelemetryPixel.test.tsx b/superset-frontend/src/components/TelemetryPixel/TelemetryPixel.test.tsx
new file mode 100644
index 0000000000..4e3b3c9332
--- /dev/null
+++ b/superset-frontend/src/components/TelemetryPixel/TelemetryPixel.test.tsx
@@ -0,0 +1,49 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import React from 'react';
+import { render } from 'spec/helpers/testing-library';
+import TelemetryPixel from '.';
+
+const OLD_ENV = process.env;
+
+// restor the process after messing with it!
+afterAll(() => {
+  process.env = OLD_ENV;
+});
+
+test('should render', () => {
+  const { container } = render(<TelemetryPixel />);
+  expect(container).toBeInTheDocument();
+});
+
+test('should render the pixel link when FF is on', () => {
+  process.env.SCARF_ANALYTICS = 'true';
+  render(<TelemetryPixel />);
+
+  const image = document.querySelector('img[src*="scarf.sh"]');
+  expect(image).toBeInTheDocument();
+});
+
+test('should NOT render the pixel link when FF is off', () => {
+  process.env.SCARF_ANALYTICS = 'false';
+  render(<TelemetryPixel />);
+
+  const image = document.querySelector('img[src*="scarf.sh"]');
+  expect(image).not.toBeInTheDocument();
+});
diff --git a/superset-frontend/src/components/TelemetryPixel/index.tsx b/superset-frontend/src/components/TelemetryPixel/index.tsx
new file mode 100644
index 0000000000..6bfe1d20b9
--- /dev/null
+++ b/superset-frontend/src/components/TelemetryPixel/index.tsx
@@ -0,0 +1,59 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import React from 'react';
+
+interface TelemetryPixelProps {
+  version?: string;
+  sha?: string;
+  build?: string;
+}
+
+/**
+ * Renders a telemetry pixel component to capture anonymous, aggregated telemetry via Scarf.
+ * This can be disabled by setting the SCARF_ANALYTICS environment variable to false.
+ *
+ * @component
+ * @param {TelemetryPixelProps} props - The props for the TelemetryPixel component.
+ * @param {string} props.version - The version of  Superset that's currently in use.
+ * @param {string} props.sha - The SHA of Superset that's currently in use.
+ * @param {string} props.build - The build of Superset that's currently in use.
+ * @returns {JSX.Element | null} The rendered TelemetryPixel component.
+ */
+
+const PIXEL_ID = '0d3461e1-abb1-4691-a0aa-5ed50de66af0';
+
+const TelemetryPixel = ({
+  version = 'unknownVersion',
+  sha = 'unknownSHA',
+  build = 'unknownBuild',
+}: TelemetryPixelProps): React.ReactElement | null => {
+  const pixelPath = `https://apachesuperset.gateway.scarf.sh/pixel/${PIXEL_ID}/${version}/${sha}/${build}`;
+  return process.env.SCARF_ANALYTICS === 'false' ||
+    process.env.SCARF_ANALYTICS === 'false' ? null : (
+    <img
+      referrerPolicy="no-referrer-when-downgrade"
+      src={pixelPath}
+      width={0}
+      height={0}
+      alt=""
+    />
+  );
+};
+export default TelemetryPixel;
diff --git a/superset-frontend/src/features/home/RightMenu.tsx b/superset-frontend/src/features/home/RightMenu.tsx
index b79ebb65f8..a37214b66b 100644
--- a/superset-frontend/src/features/home/RightMenu.tsx
+++ b/superset-frontend/src/features/home/RightMenu.tsx
@@ -46,6 +46,7 @@ import {
 import { RootState } from 'src/dashboard/types';
 import DatabaseModal from 'src/features/databases/DatabaseModal';
 import { uploadUserPerms } from 'src/views/CRUD/utils';
+import TelemetryPixel from 'src/components/TelemetryPixel';
 import LanguagePicker from './LanguagePicker';
 import {
   ExtensionConfigs,
@@ -562,6 +563,11 @@ const RightMenu = ({
           {t('Login')}
         </StyledAnchor>
       )}
+      <TelemetryPixel
+        version={navbarRight.version_string}
+        sha={navbarRight.version_sha}
+        build={navbarRight.build_number}
+      />
     </StyledDiv>
   );
 };
diff --git a/superset-frontend/webpack.config.js b/superset-frontend/webpack.config.js
index dea99be2cf..6b1753009a 100644
--- a/superset-frontend/webpack.config.js
+++ b/superset-frontend/webpack.config.js
@@ -117,6 +117,7 @@ const plugins = [
     'process.env.WEBPACK_MODE': JSON.stringify(mode),
     'process.env.REDUX_DEFAULT_MIDDLEWARE':
       process.env.REDUX_DEFAULT_MIDDLEWARE,
+    'process.env.SCARF_ANALYTICS': process.env.SCARF_ANALYTICS,
   }),
 
   new CopyPlugin({
diff --git a/superset/config.py b/superset/config.py
index ca801442d9..348baef545 100644
--- a/superset/config.py
+++ b/superset/config.py
@@ -1427,7 +1427,13 @@ TALISMAN_CONFIG = {
     "content_security_policy": {
         "base-uri": ["'self'"],
         "default-src": ["'self'"],
-        "img-src": ["'self'", "blob:", "data:"],
+        "img-src": [
+            "'self'",
+            "blob:",
+            "data:",
+            "https://apachesuperset.gateway.scarf.sh",
+            "https://static.scarf.sh/",
+        ],
         "worker-src": ["'self'", "blob:"],
         "connect-src": [
             "'self'",
@@ -1450,7 +1456,13 @@ TALISMAN_DEV_CONFIG = {
     "content_security_policy": {
         "base-uri": ["'self'"],
         "default-src": ["'self'"],
-        "img-src": ["'self'", "blob:", "data:"],
+        "img-src": [
+            "'self'",
+            "blob:",
+            "data:",
+            "https://apachesuperset.gateway.scarf.sh",
+            "https://static.scarf.sh/",
+        ],
         "worker-src": ["'self'", "blob:"],
         "connect-src": [
             "'self'",