Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion app/client/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
const CLOUD_HOSTING = parseConfig('{{env "APPSMITH_CLOUD_HOSTING"}}');
const AIRGAPPED = parseConfig('{{env "APPSMITH_AIRGAP_ENABLED"}}');
const REO_CLIENT_ID = parseConfig('{{env "APPSMITH_REO_CLIENT_ID"}}');
const DISABLE_BETTERBUGS = parseConfig('{{env "APPSMITH_DISABLE_BETTERBUGS"}}');
</script>
<script>
window.__APPSMITH_CHUNKS_TO_PRELOAD =
Expand Down Expand Up @@ -71,6 +72,28 @@
}
</script>
<!-- End of Reo Javascript -->

<!-- Start of BetterBugs Recording Links (logs + recorder; only when BetterBugs enabled and not airgapped) -->
<script type="text/javascript">
if (!DISABLE_BETTERBUGS && !AIRGAPPED) {
window.__BetterbugsRecordingLinkConfig = {
styles: { theme: "light", primaryColor: "#E15615", primaryTextColor: "#ffffff" },
successMessageHeaderText: "Information received",
successMessageSubHeaderText: "Our support team will use it to review the issue",
};
(function () {
var s1 = document.createElement("script");
s1.src = "https://cdn.betterbugs.io/scripts/latest/logs-capture.js";
s1.async = true;
document.head.appendChild(s1);
var s2 = document.createElement("script");
s2.src = "https://cdn.betterbugs.io/scripts/latest/recorder.js";
s2.async = true;
document.head.appendChild(s2);
})();
}
</script>
<!-- End of BetterBugs Recording Links -->
Comment on lines +76 to +96
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

BetterBugs CDN logs-capture.js recorder.js version pinned URLs SRI

💡 Result:

BetterBugs’ own docs currently instruct loading these mutable (“latest”) CDN assets (so you can’t safely “pin” + SRI them unless BetterBugs also offers immutable, versioned file URLs):

  • https://cdn.betterbugs.io/scripts/latest/logs-capture.js
  • https://cdn.betterbugs.io/scripts/latest/recorder.js [1]

What that means for “version-pinned URLs + SRI”

  • SRI only makes sense with an immutable URL (a URL whose content won’t change). If the path contains latest, the bytes can change at any time, so an SRI hash will either break unexpectedly (when BetterBugs updates) or you’ll be forced to constantly update the hash. This is why vendors that support SRI typically document version-specific URLs (e.g., /…/3.10.4/…) and then provide (or let you compute) an integrity hash for that exact version. [2]

Practical options

  1. Ask BetterBugs support whether they have versioned/immutable URLs like:
    https://cdn.betterbugs.io/scripts/<version>/logs-capture.js and …/recorder.js
    (and whether they publish SRI hashes for each release).
  2. If they don’t offer versioned URLs, use one of these approaches:
    • Self-host the exact JS files you’ve vetted (then you can pin via your own deploy process).
    • Or keep using latest without SRI, accepting vendor-driven updates (their documented default). [1]

If you tell me your deployment preference (self-host vs CDN) and whether BetterBugs provides any versioned script paths in your dashboard/UI, I can give you the exact snippet format to use (including integrity/crossorigin) for your chosen setup.

Sources: [1] BetterBugs “Recording Links” docs (shows the latest CDN script URLs). [2] TrackJS SRI guidance (explains using version-specific URLs for SRI).


🌐 Web query:

BetterBugs official documentation CDN scripts versioning

💡 Result:

BetterBugs’ official Web SDK CDN install snippet uses a “moving” alias (no pinned version in the URL):

  • <script src="https://cdn.betterbugs.io/scripts/latest/index.js"></script> (loads the latest build). [1]

In the official docs, there isn’t any documented alternative CDN URL format for pinning a specific version (e.g., /scripts/1.2.3/...)—only the /latest/ path is shown. [1]

If you need explicit versioning / reproducible builds, the docs recommend installing the SDK via npm/yarn, where you can pin a semver version in package.json:

  • npm install @betterbugs/web-sdk / `yarn add `@betterbugs/web-sdk [2]
  • The package is published on npm (e.g., jsDelivr shows version 0.0.40 at the time it was crawled). [3]

Sources: [1] BetterBugs Doc – “Start widget with CDN Script” • [2] BetterBugs Doc – “Start widget with npm or yarn” • [3] jsDelivr – @betterbugs/web-sdk package page


Use npm/yarn to pin BetterBugs SDK version instead of mutable CDN /latest/ paths.

Lines 86 and 90 load third-party scripts from https://cdn.betterbugs.io/scripts/latest/..., which are non-deterministic and weaken supply-chain control. BetterBugs' official CDN does not offer versioned URLs (e.g., /scripts/1.2.3/...). For reproducible builds, migrate to the npm package (@betterbugs/web-sdk) and pin the version in package.json, or self-host the vetted scripts from your own infrastructure.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/client/public/index.html` around lines 76 - 96, The BetterBugs snippet
uses mutable CDN "/latest/" URLs (s1.src and s2.src) which makes builds
non-deterministic; replace the dynamic <script> injection by installing and
importing the pinned npm package `@betterbugs/web-sdk` (or using self-hosted
vetted copies) and initialize it using the existing
window.__BetterbugsRecordingLinkConfig settings (the same config object name)
instead of loading "https://cdn.betterbugs.io/scripts/latest/logs-capture.js"
and "recorder.js"; update package.json to pin the version, remove the runtime
creation of s1/s2, and call the SDK init/start functions from your bundled
client bootstrap code where window.__BetterbugsRecordingLinkConfig is still
applied.

</head>

<body class="appsmith-light-theme">
Expand Down Expand Up @@ -160,7 +183,6 @@
parseConfig("%REACT_APP_INTERCOM_APP_ID%") ||
parseConfig('{{env "APPSMITH_INTERCOM_APP_ID"}}');
const DISABLE_INTERCOM = parseConfig('{{env "APPSMITH_DISABLE_INTERCOM"}}');
const DISABLE_BETTERBUGS = parseConfig('{{env "APPSMITH_DISABLE_BETTERBUGS"}}');

// Initialize the Intercom library
if (INTERCOM_APP_ID.length && !DISABLE_INTERCOM) {
Expand Down
4 changes: 4 additions & 0 deletions app/client/src/utils/Analytics/betterbugs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import log from "loglevel";
import { APPSMITH_BRAND_PRIMARY_COLOR } from "utils/BrandingUtils";
import { isAirgapped } from "ee/utils/airgapHelpers";

/**
* BetterBugs in-app widget (init/show/hide below). Recording-link scripts (logs-capture.js, recorder.js)
* are loaded in index.html when BetterBugs is enabled and not airgapped; they activate when users open a recording URL.
*/
export interface BetterbugsMetadata {
instanceId: string;
tenantId: string | undefined;
Expand Down
Loading