Skip to content

SCAL-338938: allowlist runtimeFilters and runtimeParameters before they reach Mixpanel - #677

Open
sastaachar wants to merge 2 commits into
mainfrom
SCAL-338938-mixpanel-runtime-allowlist
Open

sastaachar wants to merge 2 commits into
mainfrom
SCAL-338938-mixpanel-runtime-allowlist

Conversation

@sastaachar

@sastaachar sastaachar commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

The problem

TsEmbed's constructor spreads the entire viewConfig into a Mixpanel event on every embed construction — src/embed/ts-embed.ts:254 on main:

uploadMixpanelEvent(MIXPANEL_EVENT.VISUAL_SDK_EMBED_CREATE, {
    ...viewConfig,
});

runtimeFilters and runtimeParameters ride along in that spread, and both carry customer data:

  • RuntimeFilter.columnName — a column name from the customer's worksheet
  • RuntimeFilter.values — the actual operands being filtered on
  • RuntimeParameter.name / RuntimeParameter.value — likewise

Captured from a real LiveboardEmbed construction, with this PR's fix reverted:

{"liveboardId":"lb-guid",
 "runtimeFilters":[{"columnName":"Patient SSN","operator":"EQ","values":["123-45-6789"]}],
 "runtimeParameters":[{"name":"Sales Region","value":"EMEA"}],
 "embedComponentType":"LiveboardEmbed"}

Every value in there reaches Mixpanel today.

This is the only telemetry path on main carrying runtime filters or parameters: it is the sole ...viewConfig spread into uploadMixpanelEvent (the other spreads in src/ are functional), and visual-sdk-trigger-<HostEvent> uploads no properties at all on main.

The fix

Both arrays are replaced by an allowlisted summary before upload. Every other viewConfig property is untouched.

Field Uploaded as
runtimeFilters { count, operators }
runtimeParameters { count, applicabilityLevels }

So the payload above becomes:

{"liveboardId":"lb-guid",
 "runtimeFilters":{"count":1,"operators":["EQ"]},
 "runtimeParameters":{"count":1,"applicabilityLevels":[]},
 "embedComponentType":"LiveboardEmbed"}

Two things worth calling out in the implementation:

  • operators and applicabilityLevels are membership-checked, not key-allowlisted. A value is kept only if it is actually a member of RuntimeFilterOp / ApplicabilityLevel. A bare key allowlist would pass an arbitrary string sitting under operator straight through to Mixpanel — which is the exact leak this PR exists to close.
  • A non-array value under either key is dropped entirely rather than forwarded, so an unexpected shape can't slip past the summariser.

This follows the privacy rule already agreed on SCAL-333657: store the shape, not the value, except enum members — and only once membership is verified.

Scope

The helper lives in src/utils/runtimeTelemetry.ts and is not exported from index.ts, so there is no public API change and no @version annotation is needed. No behaviour changes outside the one telemetry call.

File
src/embed/ts-embed.ts +5/−3 — one call site
src/utils/runtimeTelemetry.ts new, internal
src/utils/runtimeTelemetry.spec.ts new (14 tests)
src/embed/ts-embed.spec.ts +79 (3 tests)

Verification

  • A/B'd. With only the ts-embed.ts call site reverted, the two privacy assertions fail — Expected substring: not "Patient SSN" — and the third still passes. The tests have real diagnostic power.
  • Full SDK suite: 49/49 suites, 1917 passed, 4 skipped, 0 failed
  • One caveat, checked rather than assumed: ts-embed.spec.ts's 'should trigger Navigate only after UpdateEmbedParams has settled' is order-dependent and fails intermittently with a 5003 ms timeout. It is pre-existing and unrelated to this PR — I reverted to pristine origin/main sources in the same worktree and reproduced the identical failure there, and it passes in 480 ms in isolation either way.
  • tsc --noEmit clean
  • eslint 0 errors on all touched files (the warnings in ts-embed.ts are pre-existing comment-length on lines this PR doesn't touch)
  • check-size 31.97 kB against the 34 kB budget

One test-hygiene note: the new spec in ts-embed.spec.ts creates its Mixpanel spy in beforeEach rather than in the describe body, because an earlier suite in that file calls jest.restoreAllMocks() and would otherwise unwire it.

Deliberately out of scope

The same spread also uploads searchQuery and searchOptions.searchTokenString (raw customer search strings) and content GUIDs (liveboardId, vizId, answerId). I've left those alone and flagged them on the ticket rather than widening this PR — whether search text and GUIDs are acceptable in Mixpanel is a product call, not a mechanical one.

Background

Found and empirically confirmed during SCAL-333657 (a browser harness observed it live against a recording Mixpanel stub), deliberately left out of scope there, and never filed until now.

Jira: https://thoughtspot.atlassian.net/browse/SCAL-338938

… Mixpanel

SCAL-338938

TsEmbed's constructor spread the entire viewConfig into the
visual-sdk-embed-create Mixpanel event, so runtimeFilters and
runtimeParameters went up verbatim on every embed construction --
columnName (a customer worksheet column), values (the operands being
filtered on), and a parameter's name and value.

Both arrays are now replaced by an allowlisted summary before upload:

  runtimeFilters    -> { count, operators }
  runtimeParameters -> { count, applicabilityLevels }

operators and applicabilityLevels are checked for membership in
RuntimeFilterOp / ApplicabilityLevel before being kept, so an arbitrary
string sitting under an enum-valued key is dropped rather than passed
through. A non-array value under either key is dropped entirely. Every
other viewConfig property is untouched.

The helper is internal and is not exported from index.ts, so there is no
public API change.

Verified by reverting only the call site: the two privacy assertions fail
without the fix.
@sastaachar
sastaachar requested a review from a team as a code owner September 17, 2026 07:37

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces telemetry filtering to prevent sensitive customer data (such as runtime filters and parameters) from being uploaded to Mixpanel. It adds utility functions to replace these arrays with safe, allowlisted summaries (counts, operators, and applicability levels) and integrates them into the embed creation event. Comprehensive unit tests are also added to verify that no sensitive data is leaked. The review feedback highlights style guide violations in the JSDoc comments, specifically the use of deprecated terminology ('worksheet' instead of 'Model') and British English spelling ('Summarises' instead of 'Summarizes').

Comment thread src/utils/runtimeTelemetry.ts Outdated

/**
* `runtimeFilters` and `runtimeParameters` carry customer data: the column and
* parameter names come from the customer's worksheet, and the operands are the

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.

medium

According to the repository style guide (Rule 13: Deprecated Terminology Detection and Flagging), the term worksheet is deprecated. Please replace it with Model or LogicalModel.

Suggested change
* parameter names come from the customer's worksheet, and the operands are the
* parameter names come from the customer's Model, and the operands are the
References
  1. Deprecated terms in documentation must be flagged for the developer to update to the current equivalent. Worksheet should be replaced with Model or LogicalModel. (link)

Comment thread src/utils/runtimeTelemetry.ts Outdated
): string[] => Array.from(new Set(values.filter((v) => isEnumMember(enumObject, v)))) as string[];

/**
* Summarises the runtime filters on a view config for telemetry.

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.

medium

According to the repository style guide (Rule 9: Language and Locale), all written work must be in American English (en-US) format. Please use Summarizes instead of Summarises.

Suggested change
* Summarises the runtime filters on a view config for telemetry.
* Summarizes the runtime filters on a view config for telemetry.
References
  1. All written work must be in American English (en-US) format. Use American English spelling (e.g., 'summarizes' instead of 'summarises'). (link)

Comment thread src/utils/runtimeTelemetry.ts Outdated
),
});

/**

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.

medium

According to the repository style guide (Rule 9: Language and Locale), all written work must be in American English (en-US) format. Please use Summarizes instead of Summarises.

 * Summarizes the runtime parameters on a view config for telemetry.
References
  1. All written work must be in American English (en-US) format. Use American English spelling (e.g., 'summarizes' instead of 'summarises'). (link)

@pkg-pr-new

pkg-pr-new Bot commented Sep 17, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@thoughtspot/visual-embed-sdk@677

commit: b1552af

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