@zappie/check 0.2.1 → 0.2.3

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # @zappie/check
2
2
 
3
+ ## 0.2.3
4
+
5
+ ### Patch Changes
6
+
7
+ - 9b25eb7: The packages now live in zappie/storefront-packages, and each package's repository, homepage and issues links point there. This release is the first one published from that repository.
8
+ - Updated dependencies [9b25eb7]
9
+ - @zappie/sdk@0.1.13
10
+ - @zappie/tokens@0.1.2
11
+ - eslint-plugin-zappie@0.3.1
12
+
13
+ ## 0.2.2
14
+
15
+ ### Patch Changes
16
+
17
+ - afb46d4: Add storefront security lint rules, pass outbound hosts from `zappie.config.ts` to ESLint, and provide `safeRedirect` from `@zappie/sdk/redirect` for untrusted navigation targets.
18
+ - Updated dependencies [2b672c9]
19
+ - Updated dependencies [9b5b412]
20
+ - Updated dependencies [32ecccf]
21
+ - Updated dependencies [afb46d4]
22
+ - Updated dependencies [6a8e227]
23
+ - Updated dependencies [c0171ae]
24
+ - Updated dependencies [0cbc4da]
25
+ - @zappie/sdk@0.1.12
26
+ - eslint-plugin-zappie@0.3.0
27
+
3
28
  ## 0.2.1
4
29
 
5
30
  ### Patch Changes
package/dist/index.js CHANGED
@@ -67,7 +67,7 @@ var globallyAllowed = (value) => GLOBAL_PACKAGE_ALLOWLIST.some(
67
67
  function hostname(value) {
68
68
  const wildcard = value.startsWith("*.");
69
69
  const host = wildcard ? value.slice(2) : value;
70
- if (!host.includes(".") || /^\d+(?:\.\d+){3}$/.test(host) || host.length > 253 || host.includes("..")) {
70
+ if (!host.includes(".") || /^\d+(?:\.\d+){3}$/.test(host) || host.length > 253 || host.includes("..") || wildcard && /^(?:ac|co|com|edu|gov|net|org)\.[^.]+$/i.test(host)) {
71
71
  return false;
72
72
  }
73
73
  return host.split(".").every(
@@ -183,6 +183,7 @@ var rootKeys = [
183
183
  "packages",
184
184
  "audit",
185
185
  "outbound",
186
+ "security",
186
187
  "budgets",
187
188
  "readiness",
188
189
  "analytics"
@@ -236,16 +237,20 @@ function validateConfig(input) {
236
237
  });
237
238
  });
238
239
  nested(input.outbound, "outbound", ["allow"], issue, (value) => {
239
- const allow = stringList(value.allow, "outbound.allow", error);
240
- allow?.forEach((host, index) => {
241
- if (!hostname(host)) {
242
- error(
243
- `outbound.allow[${index}]`,
244
- "invalid_format",
245
- "Expected a hostname or leading *. subdomain pattern without a scheme, path, port or IP. Use a value such as api.example.com."
246
- );
240
+ hostList(value.allow, "outbound.allow", error);
241
+ });
242
+ nested(input.security, "security", ["csp"], issue, (security) => {
243
+ nested(
244
+ security.csp,
245
+ "security.csp",
246
+ ["imgSrc", "connectSrc", "fontSrc", "styleSrc", "frameSrc"],
247
+ issue,
248
+ (csp) => {
249
+ for (const [name, value] of Object.entries(csp)) {
250
+ hostList(value, `security.csp.${name}`, error);
251
+ }
247
252
  }
248
- });
253
+ );
249
254
  });
250
255
  budgets(input.budgets, issue, error);
251
256
  nested(
@@ -346,6 +351,17 @@ function stringList(value, path15, error, options = {}) {
346
351
  }
347
352
  return value;
348
353
  }
354
+ function hostList(value, path15, error) {
355
+ stringList(value, path15, error)?.forEach((host, index) => {
356
+ if (!hostname(host)) {
357
+ error(
358
+ `${path15}[${index}]`,
359
+ "invalid_format",
360
+ "Expected a hostname or leading *. subdomain pattern without a scheme, path, port or IP. Use a value such as api.example.com."
361
+ );
362
+ }
363
+ });
364
+ }
349
365
  function paths(value, error) {
350
366
  const values = stringList(value, "prerender", error, { unique: true });
351
367
  values?.forEach((path15, index) => {
@@ -2784,7 +2800,12 @@ async function checkLint({
2784
2800
  ]);
2785
2801
  }
2786
2802
  try {
2787
- const eslint = new ESLint({ cwd });
2803
+ const eslint = new ESLint({
2804
+ cwd,
2805
+ overrideConfig: {
2806
+ settings: { zappie: { outboundAllow: await outboundAllow(cwd) } }
2807
+ }
2808
+ });
2788
2809
  const source = await sourceFile(cwd);
2789
2810
  const config = await eslint.calculateConfigForFile(source);
2790
2811
  const problems = recommendedProblems(config?.rules ?? {});
@@ -2818,6 +2839,23 @@ async function checkLint({
2818
2839
  ]);
2819
2840
  }
2820
2841
  }
2842
+ async function outboundAllow(cwd) {
2843
+ try {
2844
+ const value = (await loadConfig(cwd)).value;
2845
+ if (!value || typeof value !== "object" || !("outbound" in value)) {
2846
+ return [];
2847
+ }
2848
+ const outbound = value.outbound;
2849
+ if (!outbound || typeof outbound !== "object" || !("allow" in outbound)) {
2850
+ return [];
2851
+ }
2852
+ return Array.isArray(outbound.allow) ? outbound.allow.filter(
2853
+ (entry) => typeof entry === "string"
2854
+ ) : [];
2855
+ } catch {
2856
+ return [];
2857
+ }
2858
+ }
2821
2859
  function recommendedProblems(applied) {
2822
2860
  const expected = recommendedRules();
2823
2861
  return Object.entries(expected).flatMap(([rule, severity]) => {