@tokenoftrust/storefront-runner 2.0.23 → 2.0.25

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.
Files changed (27) hide show
  1. package/apps/storefront/astro.config.mjs +5 -0
  2. package/apps/storefront/integrations/lifecycle-host-asset.mjs +125 -0
  3. package/apps/storefront/src/layouts/Layout.astro +8 -10
  4. package/apps/storefront/src/lib/integration/bakedManagedInstalls.ts +56 -0
  5. package/apps/storefront/src/lib/integration/managedInstallDeclarations.ts +11 -3
  6. package/apps/storefront/src/lib/integration/stageDestinationIds.ts +103 -0
  7. package/apps/storefront/src/middleware/renderChain.ts +15 -1
  8. package/package.json +1 -1
  9. package/packages/public-runtime/package.json +2 -1
  10. package/packages/public-runtime/schemas/managed-analytics/v1/adapter-definition.schema.json +2 -1
  11. package/packages/public-runtime/schemas/managed-analytics/v1/create-integration-install-request.schema.json +79 -0
  12. package/packages/public-runtime/schemas/managed-analytics/v1/create-migration-draft-request.schema.json +79 -0
  13. package/packages/public-runtime/schemas/managed-analytics/v1/integration-revision.schema.json +79 -0
  14. package/packages/public-runtime/schemas/managed-analytics/v1/migration-draft.schema.json +79 -0
  15. package/packages/public-runtime/schemas/managed-analytics/v1/revise-integration-install-request.schema.json +79 -0
  16. package/packages/public-runtime/schemas/managed-analytics/v1/update-migration-draft-request.schema.json +79 -0
  17. package/packages/public-runtime/src/gtm-migration/draft-generator.ts +5 -2
  18. package/packages/public-runtime/src/integration/baked-managed-installs.ts +188 -0
  19. package/packages/public-runtime/src/integration/index.ts +1 -0
  20. package/packages/public-runtime/src/integration/lifecycle-boot.ts +72 -0
  21. package/packages/public-runtime/src/integration/lifecycle-host-asset.d.mts +3 -0
  22. package/packages/public-runtime/src/integration/lifecycle-host-asset.mjs +17 -0
  23. package/packages/public-runtime/src/integration/lifecycle-host-entry.ts +16 -0
  24. package/packages/public-runtime/src/integration/lifecycle-runtime.ts +59 -0
  25. package/packages/public-runtime/src/integration/managed-analytics-api-v1.schemas.ts +18 -1
  26. package/packages/public-runtime/src/integration/managed-analytics-api-v1.ts +48 -3
  27. package/packages/public-runtime/src/integration/render-phases.ts +30 -2
@@ -58,6 +58,7 @@ import preact from "@astrojs/preact";
58
58
  import tailwindcss from "@tailwindcss/vite";
59
59
  import { tenantHotReload } from "./dev-plugins/tenant-hot-reload.mjs";
60
60
  import { materializeGuard } from "./integrations/materialize-guard.mjs";
61
+ import { lifecycleHostAsset } from "./integrations/lifecycle-host-asset.mjs";
61
62
 
62
63
  // SSR on Cloudflare Workers. `output: 'server'` because every response is
63
64
  // tenant-resolved at the edge from the Host header (see src/middleware).
@@ -94,6 +95,10 @@ export default defineConfig({
94
95
  // resolves from KV/R2 at request time. The same integration becomes strict
95
96
  // only when TOT_BUILD_TENANTS names a per-tenant static publish input.
96
97
  materializeGuard(),
98
+ // The document.deferred lifecycle host, emitted as one self-contained module at a
99
+ // stable same-origin URL so BOTH document mounts load the same boot — the raw
100
+ // marketing mount has no bundler to hoist a module import through.
101
+ lifecycleHostAsset(),
97
102
  preact({ compat: true }),
98
103
  // Astro's file-based router ignores ANY path segment starting with "_" (see
99
104
  // `astro/dist/core/routing/create-manifest.js`), so a page literally named
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Emit the document.deferred lifecycle host as ONE self-contained module at a stable
3
+ * same-origin URL, so both document mounts can load the same host.
4
+ *
5
+ * WHY NOT A ROLLUP CHUNK. `Layout.astro` gets its client code through Astro's bundler,
6
+ * which hashes filenames and splits shared modules into sibling chunks. The raw marketing
7
+ * mount can use neither: it serves a tenant's own document verbatim, so it needs a URL it
8
+ * can hardcode. And a SPLIT bundle is actively unsafe here — a published static bundle
9
+ * (`scripts/publish/materialize-tenant.mjs`) copies only what the rendered HTML references
10
+ * and follows CSS `url()` but NOT JavaScript imports, so a sibling chunk would resolve on
11
+ * the Cloudflare plane and 404 on the S3/CloudFront one. That asymmetry is exactly the
12
+ * both-CDNs failure this repo treats as an invariant, and nothing downstream would report
13
+ * it: validate-bundle only checks HTML-referenced paths.
14
+ *
15
+ * So the host is bundled ONCE by esbuild with no code splitting, and this REFUSES to emit
16
+ * anything carrying an import. A single import-free file behaves identically on both
17
+ * providers by construction.
18
+ *
19
+ * It is an Astro INTEGRATION rather than a bare Vite plugin because Astro is the only
20
+ * thing that knows where the client output actually goes: every one of Astro's build
21
+ * passes — the client pass included — runs with `build.ssr === true`, so a Vite plugin
22
+ * cannot tell them apart, while `config.build.client` says it outright.
23
+ */
24
+ import { mkdir, writeFile } from "node:fs/promises";
25
+ import { createRequire } from "node:module";
26
+ import { dirname } from "node:path";
27
+ import { fileURLToPath } from "node:url";
28
+ import { LIFECYCLE_HOST_ASSET_PATH } from "@tot/public-runtime/integration/lifecycle-host-asset";
29
+
30
+ const HOST_ENTRY = fileURLToPath(
31
+ new URL(
32
+ "../../../packages/public-runtime/src/integration/lifecycle-host-entry.ts",
33
+ import.meta.url,
34
+ ),
35
+ );
36
+
37
+ /**
38
+ * Bundle the host to a single self-contained ES module.
39
+ *
40
+ * esbuild is resolved through `astro` (a direct dependency of this app, always present
41
+ * whenever this integration runs) rather than declared again here, so its version cannot
42
+ * drift from the one the build already uses.
43
+ * @returns {Promise<string>}
44
+ */
45
+ export async function bundleLifecycleHost() {
46
+ const require = createRequire(import.meta.url);
47
+ const esbuild = createRequire(require.resolve("astro/package.json"))("esbuild");
48
+ const result = await esbuild.build({
49
+ entryPoints: [HOST_ENTRY],
50
+ bundle: true,
51
+ write: false,
52
+ metafile: true,
53
+ format: "esm",
54
+ platform: "browser",
55
+ target: "es2022",
56
+ minify: true,
57
+ treeShaking: true,
58
+ legalComments: "none",
59
+ sourcemap: false,
60
+ logLevel: "silent",
61
+ });
62
+ if (result.outputFiles.length !== 1) {
63
+ throw new Error(
64
+ `The lifecycle host bundled to ${result.outputFiles.length} files; it must be one ` +
65
+ `self-contained module (a sibling chunk 404s on the S3/CloudFront plane).`,
66
+ );
67
+ }
68
+ // The metafile is authoritative about imports in a way a regex over minified code is
69
+ // not: any entry here is a file the browser would have to fetch separately.
70
+ for (const output of Object.values(result.metafile.outputs)) {
71
+ const external = (output.imports ?? []).filter((i) => i.kind !== "file-loader");
72
+ if (external.length > 0) {
73
+ throw new Error(
74
+ `The lifecycle host bundle imports ${external.map((i) => i.path).join(", ")}; it ` +
75
+ `must carry no imports, because the static publish pipeline does not follow them.`,
76
+ );
77
+ }
78
+ }
79
+ return result.outputFiles[0].text;
80
+ }
81
+
82
+ /**
83
+ * @returns {import("astro").AstroIntegration}
84
+ */
85
+ export function lifecycleHostAsset() {
86
+ /** @type {URL | null} */
87
+ let clientDir = null;
88
+
89
+ return {
90
+ name: "tot-lifecycle-host-asset",
91
+ hooks: {
92
+ "astro:config:done": ({ config }) => {
93
+ clientDir = config.build.client;
94
+ },
95
+
96
+ // Dev serves it from memory: the raw marketing mount bypasses Astro's pipeline
97
+ // entirely, so without this the host 404s in `astro dev` and `tot dev` on exactly
98
+ // the pages this asset exists to cover. Rebundled per request (esbuild is fast) so
99
+ // an edit to the runtime shows up on reload rather than being pinned to server boot.
100
+ "astro:server:setup": ({ server }) => {
101
+ server.middlewares.use((req, res, next) => {
102
+ const path = (req.url ?? "").split("?")[0];
103
+ if (path !== `/${LIFECYCLE_HOST_ASSET_PATH}`) return next();
104
+ bundleLifecycleHost().then(
105
+ (code) => {
106
+ res.setHeader("content-type", "text/javascript; charset=utf-8");
107
+ res.setHeader("cache-control", "no-store");
108
+ res.end(code);
109
+ },
110
+ (error) => next(error),
111
+ );
112
+ });
113
+ },
114
+
115
+ "astro:build:done": async ({ logger }) => {
116
+ if (!clientDir) throw new Error("the lifecycle host has no resolved client output dir");
117
+ const code = await bundleLifecycleHost();
118
+ const target = fileURLToPath(new URL(LIFECYCLE_HOST_ASSET_PATH, clientDir));
119
+ await mkdir(dirname(target), { recursive: true });
120
+ await writeFile(target, code, "utf8");
121
+ logger.info(`lifecycle host → /${LIFECYCLE_HOST_ASSET_PATH} (${code.length} bytes)`);
122
+ },
123
+ },
124
+ };
125
+ }
@@ -618,16 +618,14 @@ const footerWidgets = await renderWidgetSlot(
618
618
  entry in lib/cspStaticHashes.ts. */}
619
619
  <script is:inline nonce={cspNonce} set:html={INTERACTION_TRACKING_BOOT_JS}></script>
620
620
 
621
- {/* document.deferred global-entry boundary (ext-kernel-04) — the last phase,
622
- the renderer-owned mount point for the deferred integration entry. */}
621
+ {/* document.deferred global-entry boundary (ext-kernel-04) — the last phase, the
622
+ renderer-owned mount point for the deferred integration entry. This region also
623
+ CARRIES the lifecycle host tag (ext-kernel-05), which initializes the plan's
624
+ integrations exactly once per document, emits the governed page view, wires the
625
+ reserved completed-navigation event, and disposes on teardown; a no-op for an
626
+ empty plan. It ships with the phase markup rather than as a per-mount addition,
627
+ so the same bytes reach the raw marketing mount — which serves a tenant's
628
+ document verbatim and has no bundler to hoist a module import through. */}
623
629
  <Fragment set:html={integrationPhases.bodyDeferred} />
624
-
625
- {/* document.deferred lifecycle boot (ext-kernel-05) — initializes the plan's
626
- integrations exactly once per document, wires the reserved completed-
627
- navigation event, and disposes on teardown; a no-op for an empty plan. */}
628
- <script>
629
- import { bootIntegrationLifecycleFromDocument } from "@tot/public-runtime";
630
- bootIntegrationLifecycleFromDocument();
631
- </script>
632
630
  </body>
633
631
  </html>
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Read a tenant's BAKED managed installs off the materialize-only signed header.
3
+ *
4
+ * This is the read half of the wire documented in
5
+ * `packages/public-runtime/src/integration/baked-managed-installs.ts`. It exists because
6
+ * ADR 0013 gives a public page no per-request access to admin-installed state — the
7
+ * static bake has no D1 binding at all — so an active install can only reach a published
8
+ * bundle by being resolved and signed once, by the Worker, at go-live.
9
+ *
10
+ * Fail-safe at every step: not in materialize mode, no header, no secret, a signature
11
+ * that does not verify, or a payload that does not parse all yield an EMPTY list, and the
12
+ * render then resolves the environment-only plan exactly as it would for a tenant with no
13
+ * integrations. Nothing here can widen what a public request may inject, because gate one
14
+ * is a binding the deployed Worker never has.
15
+ */
16
+ import {
17
+ MANAGED_INSTALLS_INPUT_HEADER,
18
+ MANAGED_INSTALLS_SIG_HEADER,
19
+ parseManagedInstalls,
20
+ verifyManagedInstallsSig,
21
+ MATERIALIZE_MODE_BINDING,
22
+ CONSENT_SNAPSHOT_HMAC_SECRET_BINDING,
23
+ type IntegrationDeclarationInput,
24
+ } from "@tot/public-runtime";
25
+
26
+ /** Reads a runtime binding; injected so this is testable without a Worker env. */
27
+ export type ReadEnv = (key: string) => Promise<string | undefined>;
28
+
29
+ /**
30
+ * The signed, materialize-only managed installs for `tenantPublicId`, or `[]`.
31
+ *
32
+ * The signature is TENANT-BOUND, so a payload signed for one tenant cannot be replayed
33
+ * into another tenant's bundle even by something that legitimately holds a signed header
34
+ * — which matters because one publish job builds one tenant at a time from a shared
35
+ * pipeline.
36
+ */
37
+ export async function readBakedManagedInstalls(
38
+ request: Request,
39
+ tenantPublicId: string,
40
+ readEnv: ReadEnv,
41
+ ): Promise<IntegrationDeclarationInput[]> {
42
+ // Gate 1: the materialize-mode binding. The deployed Worker never declares it, so this
43
+ // header is unreadable on any public request and can never enter a cache key.
44
+ if ((await readEnv(MATERIALIZE_MODE_BINDING)) !== "1") return [];
45
+
46
+ const payload = request.headers.get(MANAGED_INSTALLS_INPUT_HEADER);
47
+ if (!payload) return [];
48
+
49
+ // Gate 2: the tenant-bound HMAC, verified constant-time against the go-live secret.
50
+ const secret = await readEnv(CONSENT_SNAPSHOT_HMAC_SECRET_BINDING);
51
+ if (!secret) return [];
52
+ const signature = request.headers.get(MANAGED_INSTALLS_SIG_HEADER);
53
+ if (!(await verifyManagedInstallsSig(secret, tenantPublicId, payload, signature))) return [];
54
+
55
+ return parseManagedInstalls(payload) ?? [];
56
+ }
@@ -6,11 +6,13 @@
6
6
  import {
7
7
  ENVIRONMENT_SCHEMA_VERSION,
8
8
  buildPlatformAdapterDeclaration,
9
+ getPlatformAdapter,
9
10
  validateIntegrationManifest,
10
11
  type IntegrationDeclarationInput,
11
12
  } from "@tot/public-runtime";
12
13
  import { AppVersionStore } from "../apps/appVersionStore.js";
13
14
  import type { Queryable } from "../d1/catalog.js";
15
+ import { parseStageDestinationIds } from "./stageDestinationIds.js";
14
16
 
15
17
  const MANAGED_KIND = "managed-analytics-v1";
16
18
 
@@ -47,11 +49,17 @@ export async function loadActiveManagedInstallDeclarations(
47
49
  if (!manifest.ok || !current || current.tenantId !== tenantPublicId) continue;
48
50
  if (current.appVersion !== row.app_version || current.facets.appVersion !== row.app_version) continue;
49
51
  if (current.facets.digest !== manifest.value.app.digest || manifest.value.app.id !== row.app_id) continue;
50
- const destinationId = current.facets.publicConfig["destinationId"];
51
- if (typeof destinationId !== "string") continue;
52
+ // The stored per-stage map, re-parsed through the SAME validator the API used, so a
53
+ // row that no longer satisfies the contract disables its install rather than
54
+ // resolving a partial or stale destination set.
55
+ const ids = parseStageDestinationIds(
56
+ current.facets.publicConfig["destinationIds"],
57
+ getPlatformAdapter(row.app_id),
58
+ );
59
+ if (!ids.ok) continue;
52
60
  const built = buildPlatformAdapterDeclaration({
53
61
  adapterId: row.app_id,
54
- ids: { live: destinationId },
62
+ ids: ids.value,
55
63
  tenantPublicId,
56
64
  environment: {
57
65
  schemaVersion: ENVIRONMENT_SCHEMA_VERSION,
@@ -0,0 +1,103 @@
1
+ /**
2
+ * The per-stage destination map, parsed once for both callers that need it: the
3
+ * managed-analytics API (validating what a merchant submits) and the render plane
4
+ * (rebuilding a stored install's declaration). One parser, so what the console accepts
5
+ * and what actually fires can never disagree.
6
+ *
7
+ * WHY PER STAGE. `resolveAdapterDestinationId` reads only the CURRENT stage's id, and
8
+ * `buildPlatformAdapterDeclaration` refuses a non-live stage that reuses the live one. So
9
+ * with a single id the runtime is already correct — a non-live stage resolves nothing and
10
+ * dispatches nothing — but the merchant has no way to measure anything off live either.
11
+ * A per-stage map is what makes non-live verification possible without pointing preview
12
+ * traffic at the property that carries real reporting.
13
+ */
14
+ import {
15
+ ADAPTER_CONFIG_STAGES,
16
+ type AdapterConfigStage,
17
+ type DestinationIdsByEnvironment,
18
+ type PlatformAdapterDefinition,
19
+ } from "@tot/public-runtime";
20
+
21
+ export interface StageDestinationIdsOk {
22
+ ok: true;
23
+ value: DestinationIdsByEnvironment;
24
+ }
25
+
26
+ export interface StageDestinationIdsError {
27
+ ok: false;
28
+ details: { path: string; code: string; message: string }[];
29
+ }
30
+
31
+ export type StageDestinationIdsResult = StageDestinationIdsOk | StageDestinationIdsError;
32
+
33
+ /**
34
+ * Parse and validate a submitted per-stage map fail-closed.
35
+ *
36
+ * `live` is required because it is the stage that publishes; a non-live stage is optional
37
+ * and simply resolves nothing when absent. Every id is checked against the ADAPTER's own
38
+ * format validator, so a Meta pixel id cannot be accepted where a GA4 measurement id
39
+ * belongs. Reusing the live id on a non-live stage is refused HERE with a field-level
40
+ * message rather than left to the declaration builder, so the console can point at the
41
+ * offending stage instead of failing the whole submission opaquely.
42
+ */
43
+ export function parseStageDestinationIds(
44
+ input: unknown,
45
+ platform: PlatformAdapterDefinition | undefined,
46
+ ): StageDestinationIdsResult {
47
+ const base = "body.configuration.destinationIds";
48
+ if (typeof input !== "object" || input === null || Array.isArray(input)) {
49
+ return {
50
+ ok: false,
51
+ details: [{ path: base, code: "type", message: "Expected a map of stage to destination identifier." }],
52
+ };
53
+ }
54
+ if (!platform) {
55
+ return { ok: false, details: [{ path: "body.adapterId", code: "unknown_adapter", message: "Unknown adapter." }] };
56
+ }
57
+
58
+ const entries = Object.entries(input as Record<string, unknown>);
59
+ const details: StageDestinationIdsError["details"] = [];
60
+ const value: DestinationIdsByEnvironment = {};
61
+
62
+ for (const [stage, id] of entries) {
63
+ const path = `${base}.${stage}`;
64
+ if (!(ADAPTER_CONFIG_STAGES as readonly string[]).includes(stage)) {
65
+ details.push({
66
+ path,
67
+ code: "unknown_enum",
68
+ message: `Stage must be one of: ${ADAPTER_CONFIG_STAGES.join(", ")}.`,
69
+ });
70
+ continue;
71
+ }
72
+ if (typeof id !== "string" || !platform.validateId(id)) {
73
+ details.push({ path, code: "format", message: "Destination identifier has an invalid format." });
74
+ continue;
75
+ }
76
+ value[stage as AdapterConfigStage] = id;
77
+ }
78
+
79
+ if (!value.live) {
80
+ details.push({
81
+ path: `${base}.live`,
82
+ code: "required",
83
+ message: "A live destination identifier is required.",
84
+ });
85
+ } else {
86
+ for (const stage of ADAPTER_CONFIG_STAGES) {
87
+ if (stage === "live") continue;
88
+ if (value[stage] === value.live) {
89
+ details.push({
90
+ path: `${base}.${stage}`,
91
+ code: "live_destination_reused",
92
+ message:
93
+ "A non-live stage must use its own TEST destination, never the live one — " +
94
+ "otherwise preview and candidate traffic lands in the property that carries " +
95
+ "real reporting.",
96
+ });
97
+ }
98
+ }
99
+ }
100
+
101
+ if (details.length > 0) return { ok: false, details };
102
+ return { ok: true, value };
103
+ }
@@ -62,6 +62,7 @@ import {
62
62
  MATERIALIZE_MODE_BINDING,
63
63
  verifyConsentSnapshotSig,
64
64
  } from "@tot/public-runtime";
65
+ import { readBakedManagedInstalls } from "@/lib/integration/bakedManagedInstalls";
65
66
  import type {
66
67
  CapabilityConfig,
67
68
  ConsentSnapshot,
@@ -219,7 +220,20 @@ export async function runRenderChain(input: RenderChainInput): Promise<Response>
219
220
  ? publicationSource.publicationTimestamp
220
221
  : exactPublicationTimestamp(await readEnv("TOT_PUBLICATION_TIMESTAMP"));
221
222
 
222
- const managedIntegrationDeclarations = input.managedIntegrationDeclarations;
223
+ // Managed installs reach this render one of two ways, never both. The control plane
224
+ // reads them from D1 per request (`controlPlane.ts`). A PUBLIC render supplies none by
225
+ // design (ADR 0013: "baked at publish, never read per request on a public page") — so
226
+ // on the materialize render, which is a public render with no D1 at all, they arrive
227
+ // BAKED: resolved and signed once by the go-live Worker, carried in a materialize-only
228
+ // signed header. Without this the bundle serves a plan whose `integrations` is empty
229
+ // for a tenant that has an active install, and nothing anywhere reports the difference.
230
+ //
231
+ // Read here, before declarations are assembled below, because the resolved plan and its
232
+ // compiled CSP both depend on the full declaration set.
233
+ const managedIntegrationDeclarations =
234
+ input.managedIntegrationDeclarations.length > 0
235
+ ? input.managedIntegrationDeclarations
236
+ : await readBakedManagedInstalls(request, tenant.tenant_id, readEnv);
223
237
 
224
238
  // Digest-addressed static-bundle serving. Deliberately before the edge page
225
239
  // cache/catalog/theme machinery. A selected publication bypasses this legacy
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tokenoftrust/storefront-runner",
3
- "version": "2.0.23",
3
+ "version": "2.0.25",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "description": "World-shareable storefront runner: multi-tenant renderer on Astro/Cloudflare. No control plane.",
6
6
  "packageManager": "pnpm@11.9.0",
@@ -9,7 +9,8 @@
9
9
  "types": "./src/index.ts",
10
10
  "exports": {
11
11
  ".": "./src/index.ts",
12
- "./blog-visibility": "./src/blog-visibility.mjs"
12
+ "./blog-visibility": "./src/blog-visibility.mjs",
13
+ "./integration/lifecycle-host-asset": "./src/integration/lifecycle-host-asset.mjs"
13
14
  },
14
15
  "scripts": {
15
16
  "typecheck": "tsc --noEmit",
@@ -202,7 +202,8 @@
202
202
  "enum": [
203
203
  "string",
204
204
  "boolean",
205
- "integer"
205
+ "integer",
206
+ "stageMap"
206
207
  ]
207
208
  },
208
209
  "required": {
@@ -147,6 +147,85 @@
147
147
  },
148
148
  {
149
149
  "type": "integer"
150
+ },
151
+ {
152
+ "type": "object",
153
+ "additionalProperties": false,
154
+ "minProperties": 1,
155
+ "properties": {
156
+ "candidate": {
157
+ "type": "string",
158
+ "not": {
159
+ "anyOf": [
160
+ {
161
+ "type": "string",
162
+ "pattern": "(?:[Gg][Tt][Mm]-[A-Za-z0-9]+|[Uu][Aa]-[0-9]+-[0-9]+)"
163
+ },
164
+ {
165
+ "type": "string",
166
+ "pattern": "(?:-----BEGIN(?: [A-Z]+)? PRIVATE KEY-----|\\bAKIA[0-9A-Z]{16}\\b|\\bsk-proj-[A-Za-z0-9_-]{8,}\\b|\\bsk-[A-Za-z0-9_-]{20,}\\b|\\b(?:sk|rk)_(?:live|test|prod)_[A-Za-z0-9_-]{8,}\\b|\\b(?:gh[pousr]_|github_pat_)[A-Za-z0-9_]{20,}\\b|\\b(?:npm_|glpat-)[A-Za-z0-9_.-]{8,}\\b|\\bxox[baprs]-[A-Za-z0-9-]{10,}\\b|\\bAIza[A-Za-z0-9_-]{20,}\\b|\\bSG\\.[A-Za-z0-9_.-]{8,}\\b|\\b(?:[Ss]ecret|[Pp]assword|[Cc]redential)[_-][A-Za-z0-9_-]{4,}\\b|\\b[Bb]earer\\s+[A-Za-z0-9._~+/-]{12,}={0,2}\\b|\\beyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]+\\b|\\b(?:api[_ -]?[Kk]ey|client[_ -]?[Ss]ecret|[Pp]assword|[Cc]redential|private[_ -]?[Kk]ey)\\s*[:=]\\s*\\S+)"
167
+ },
168
+ {
169
+ "type": "string",
170
+ "pattern": "(?:[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}|\\b[0-9]{3}-[0-9]{2}-[0-9]{4}\\b|\\b(?:[0-9][ -]?){13,19}\\b|(?:^|[^0-9])(?:\\+?1[ .-]?)?(?:\\([2-9][0-9]{2}\\)|[2-9][0-9]{2})[ .-]?[0-9]{3}[ .-]?[0-9]{4}(?=$|[^0-9]))"
171
+ },
172
+ {
173
+ "type": "string",
174
+ "pattern": "(?:</?[A-Za-z][^>]*>|[Jj][Aa][Vv][Aa][Ss][Cc][Rr][Ii][Pp][Tt]\\s*:|[Ee][Vv][Aa][Ll]\\s*\\(|(?:[Aa][Ll][Ee][Rr][Tt]|[Ff][Ee][Tt][Cc][Hh])\\s*\\(|\\{\\{|\\}\\}|\\$\\{|#[A-Za-z_][A-Za-z0-9_-]*|(?:^|[\\s,>+~])\\.[A-Za-z_-][A-Za-z0-9_-]*(?:$|[\\s,>+~.#[\\:])|\\[[A-Za-z_:][-A-Za-z0-9_:.]*(?:[~|^$*]?=[^\\]]+)?\\]|(?:[Ll][Oo][Cc][Aa][Ll]|[Ss][Ee][Ss][Ss][Ii][Oo][Nn])[Ss][Tt][Oo][Rr][Aa][Gg][Ee]|[Ii][Nn][Dd][Ee][Xx][Ee][Dd][Dd][Bb]|[Qq][Uu][Ee][Rr][Yy][Ss][Ee][Ll][Ee][Cc][Tt][Oo][Rr]|(?:[Ww][Ii][Nn][Dd][Oo][Ww]|[Dd][Oo][Cc][Uu][Mm][Ee][Nn][Tt]|[Gg][Ll][Oo][Bb][Aa][Ll][Tt][Hh][Ii][Ss]|[Cc][Oo][Nn][Ss][Oo][Ll][Ee])\\s*(?:\\.|\\[)|[A-Za-z_$][A-Za-z0-9_$]*\\s*\\.\\s*[A-Za-z_$][A-Za-z0-9_$]*\\s*\\(|[A-Za-z_$][A-Za-z0-9_$]*\\s*\\([^)]*\\)\\s*;|[Rr][Ee][Tt][Uu][Rr][Nn][^;{}]*;|[Ff][Uu][Nn][Cc][Tt][Ii][Oo][Nn]|=>|(?:[Vv][Aa][Rr]|[Ll][Ee][Tt]|[Cc][Oo][Nn][Ss][Tt])\\s+[A-Za-z_$])"
175
+ }
176
+ ]
177
+ },
178
+ "minLength": 1
179
+ },
180
+ "staged": {
181
+ "type": "string",
182
+ "not": {
183
+ "anyOf": [
184
+ {
185
+ "type": "string",
186
+ "pattern": "(?:[Gg][Tt][Mm]-[A-Za-z0-9]+|[Uu][Aa]-[0-9]+-[0-9]+)"
187
+ },
188
+ {
189
+ "type": "string",
190
+ "pattern": "(?:-----BEGIN(?: [A-Z]+)? PRIVATE KEY-----|\\bAKIA[0-9A-Z]{16}\\b|\\bsk-proj-[A-Za-z0-9_-]{8,}\\b|\\bsk-[A-Za-z0-9_-]{20,}\\b|\\b(?:sk|rk)_(?:live|test|prod)_[A-Za-z0-9_-]{8,}\\b|\\b(?:gh[pousr]_|github_pat_)[A-Za-z0-9_]{20,}\\b|\\b(?:npm_|glpat-)[A-Za-z0-9_.-]{8,}\\b|\\bxox[baprs]-[A-Za-z0-9-]{10,}\\b|\\bAIza[A-Za-z0-9_-]{20,}\\b|\\bSG\\.[A-Za-z0-9_.-]{8,}\\b|\\b(?:[Ss]ecret|[Pp]assword|[Cc]redential)[_-][A-Za-z0-9_-]{4,}\\b|\\b[Bb]earer\\s+[A-Za-z0-9._~+/-]{12,}={0,2}\\b|\\beyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]+\\b|\\b(?:api[_ -]?[Kk]ey|client[_ -]?[Ss]ecret|[Pp]assword|[Cc]redential|private[_ -]?[Kk]ey)\\s*[:=]\\s*\\S+)"
191
+ },
192
+ {
193
+ "type": "string",
194
+ "pattern": "(?:[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}|\\b[0-9]{3}-[0-9]{2}-[0-9]{4}\\b|\\b(?:[0-9][ -]?){13,19}\\b|(?:^|[^0-9])(?:\\+?1[ .-]?)?(?:\\([2-9][0-9]{2}\\)|[2-9][0-9]{2})[ .-]?[0-9]{3}[ .-]?[0-9]{4}(?=$|[^0-9]))"
195
+ },
196
+ {
197
+ "type": "string",
198
+ "pattern": "(?:</?[A-Za-z][^>]*>|[Jj][Aa][Vv][Aa][Ss][Cc][Rr][Ii][Pp][Tt]\\s*:|[Ee][Vv][Aa][Ll]\\s*\\(|(?:[Aa][Ll][Ee][Rr][Tt]|[Ff][Ee][Tt][Cc][Hh])\\s*\\(|\\{\\{|\\}\\}|\\$\\{|#[A-Za-z_][A-Za-z0-9_-]*|(?:^|[\\s,>+~])\\.[A-Za-z_-][A-Za-z0-9_-]*(?:$|[\\s,>+~.#[\\:])|\\[[A-Za-z_:][-A-Za-z0-9_:.]*(?:[~|^$*]?=[^\\]]+)?\\]|(?:[Ll][Oo][Cc][Aa][Ll]|[Ss][Ee][Ss][Ss][Ii][Oo][Nn])[Ss][Tt][Oo][Rr][Aa][Gg][Ee]|[Ii][Nn][Dd][Ee][Xx][Ee][Dd][Dd][Bb]|[Qq][Uu][Ee][Rr][Yy][Ss][Ee][Ll][Ee][Cc][Tt][Oo][Rr]|(?:[Ww][Ii][Nn][Dd][Oo][Ww]|[Dd][Oo][Cc][Uu][Mm][Ee][Nn][Tt]|[Gg][Ll][Oo][Bb][Aa][Ll][Tt][Hh][Ii][Ss]|[Cc][Oo][Nn][Ss][Oo][Ll][Ee])\\s*(?:\\.|\\[)|[A-Za-z_$][A-Za-z0-9_$]*\\s*\\.\\s*[A-Za-z_$][A-Za-z0-9_$]*\\s*\\(|[A-Za-z_$][A-Za-z0-9_$]*\\s*\\([^)]*\\)\\s*;|[Rr][Ee][Tt][Uu][Rr][Nn][^;{}]*;|[Ff][Uu][Nn][Cc][Tt][Ii][Oo][Nn]|=>|(?:[Vv][Aa][Rr]|[Ll][Ee][Tt]|[Cc][Oo][Nn][Ss][Tt])\\s+[A-Za-z_$])"
199
+ }
200
+ ]
201
+ },
202
+ "minLength": 1
203
+ },
204
+ "live": {
205
+ "type": "string",
206
+ "not": {
207
+ "anyOf": [
208
+ {
209
+ "type": "string",
210
+ "pattern": "(?:[Gg][Tt][Mm]-[A-Za-z0-9]+|[Uu][Aa]-[0-9]+-[0-9]+)"
211
+ },
212
+ {
213
+ "type": "string",
214
+ "pattern": "(?:-----BEGIN(?: [A-Z]+)? PRIVATE KEY-----|\\bAKIA[0-9A-Z]{16}\\b|\\bsk-proj-[A-Za-z0-9_-]{8,}\\b|\\bsk-[A-Za-z0-9_-]{20,}\\b|\\b(?:sk|rk)_(?:live|test|prod)_[A-Za-z0-9_-]{8,}\\b|\\b(?:gh[pousr]_|github_pat_)[A-Za-z0-9_]{20,}\\b|\\b(?:npm_|glpat-)[A-Za-z0-9_.-]{8,}\\b|\\bxox[baprs]-[A-Za-z0-9-]{10,}\\b|\\bAIza[A-Za-z0-9_-]{20,}\\b|\\bSG\\.[A-Za-z0-9_.-]{8,}\\b|\\b(?:[Ss]ecret|[Pp]assword|[Cc]redential)[_-][A-Za-z0-9_-]{4,}\\b|\\b[Bb]earer\\s+[A-Za-z0-9._~+/-]{12,}={0,2}\\b|\\beyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]+\\b|\\b(?:api[_ -]?[Kk]ey|client[_ -]?[Ss]ecret|[Pp]assword|[Cc]redential|private[_ -]?[Kk]ey)\\s*[:=]\\s*\\S+)"
215
+ },
216
+ {
217
+ "type": "string",
218
+ "pattern": "(?:[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}|\\b[0-9]{3}-[0-9]{2}-[0-9]{4}\\b|\\b(?:[0-9][ -]?){13,19}\\b|(?:^|[^0-9])(?:\\+?1[ .-]?)?(?:\\([2-9][0-9]{2}\\)|[2-9][0-9]{2})[ .-]?[0-9]{3}[ .-]?[0-9]{4}(?=$|[^0-9]))"
219
+ },
220
+ {
221
+ "type": "string",
222
+ "pattern": "(?:</?[A-Za-z][^>]*>|[Jj][Aa][Vv][Aa][Ss][Cc][Rr][Ii][Pp][Tt]\\s*:|[Ee][Vv][Aa][Ll]\\s*\\(|(?:[Aa][Ll][Ee][Rr][Tt]|[Ff][Ee][Tt][Cc][Hh])\\s*\\(|\\{\\{|\\}\\}|\\$\\{|#[A-Za-z_][A-Za-z0-9_-]*|(?:^|[\\s,>+~])\\.[A-Za-z_-][A-Za-z0-9_-]*(?:$|[\\s,>+~.#[\\:])|\\[[A-Za-z_:][-A-Za-z0-9_:.]*(?:[~|^$*]?=[^\\]]+)?\\]|(?:[Ll][Oo][Cc][Aa][Ll]|[Ss][Ee][Ss][Ss][Ii][Oo][Nn])[Ss][Tt][Oo][Rr][Aa][Gg][Ee]|[Ii][Nn][Dd][Ee][Xx][Ee][Dd][Dd][Bb]|[Qq][Uu][Ee][Rr][Yy][Ss][Ee][Ll][Ee][Cc][Tt][Oo][Rr]|(?:[Ww][Ii][Nn][Dd][Oo][Ww]|[Dd][Oo][Cc][Uu][Mm][Ee][Nn][Tt]|[Gg][Ll][Oo][Bb][Aa][Ll][Tt][Hh][Ii][Ss]|[Cc][Oo][Nn][Ss][Oo][Ll][Ee])\\s*(?:\\.|\\[)|[A-Za-z_$][A-Za-z0-9_$]*\\s*\\.\\s*[A-Za-z_$][A-Za-z0-9_$]*\\s*\\(|[A-Za-z_$][A-Za-z0-9_$]*\\s*\\([^)]*\\)\\s*;|[Rr][Ee][Tt][Uu][Rr][Nn][^;{}]*;|[Ff][Uu][Nn][Cc][Tt][Ii][Oo][Nn]|=>|(?:[Vv][Aa][Rr]|[Ll][Ee][Tt]|[Cc][Oo][Nn][Ss][Tt])\\s+[A-Za-z_$])"
223
+ }
224
+ ]
225
+ },
226
+ "minLength": 1
227
+ }
228
+ }
150
229
  }
151
230
  ]
152
231
  }
@@ -120,6 +120,85 @@
120
120
  },
121
121
  {
122
122
  "type": "integer"
123
+ },
124
+ {
125
+ "type": "object",
126
+ "additionalProperties": false,
127
+ "minProperties": 1,
128
+ "properties": {
129
+ "candidate": {
130
+ "type": "string",
131
+ "not": {
132
+ "anyOf": [
133
+ {
134
+ "type": "string",
135
+ "pattern": "(?:[Gg][Tt][Mm]-[A-Za-z0-9]+|[Uu][Aa]-[0-9]+-[0-9]+)"
136
+ },
137
+ {
138
+ "type": "string",
139
+ "pattern": "(?:-----BEGIN(?: [A-Z]+)? PRIVATE KEY-----|\\bAKIA[0-9A-Z]{16}\\b|\\bsk-proj-[A-Za-z0-9_-]{8,}\\b|\\bsk-[A-Za-z0-9_-]{20,}\\b|\\b(?:sk|rk)_(?:live|test|prod)_[A-Za-z0-9_-]{8,}\\b|\\b(?:gh[pousr]_|github_pat_)[A-Za-z0-9_]{20,}\\b|\\b(?:npm_|glpat-)[A-Za-z0-9_.-]{8,}\\b|\\bxox[baprs]-[A-Za-z0-9-]{10,}\\b|\\bAIza[A-Za-z0-9_-]{20,}\\b|\\bSG\\.[A-Za-z0-9_.-]{8,}\\b|\\b(?:[Ss]ecret|[Pp]assword|[Cc]redential)[_-][A-Za-z0-9_-]{4,}\\b|\\b[Bb]earer\\s+[A-Za-z0-9._~+/-]{12,}={0,2}\\b|\\beyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]+\\b|\\b(?:api[_ -]?[Kk]ey|client[_ -]?[Ss]ecret|[Pp]assword|[Cc]redential|private[_ -]?[Kk]ey)\\s*[:=]\\s*\\S+)"
140
+ },
141
+ {
142
+ "type": "string",
143
+ "pattern": "(?:[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}|\\b[0-9]{3}-[0-9]{2}-[0-9]{4}\\b|\\b(?:[0-9][ -]?){13,19}\\b|(?:^|[^0-9])(?:\\+?1[ .-]?)?(?:\\([2-9][0-9]{2}\\)|[2-9][0-9]{2})[ .-]?[0-9]{3}[ .-]?[0-9]{4}(?=$|[^0-9]))"
144
+ },
145
+ {
146
+ "type": "string",
147
+ "pattern": "(?:</?[A-Za-z][^>]*>|[Jj][Aa][Vv][Aa][Ss][Cc][Rr][Ii][Pp][Tt]\\s*:|[Ee][Vv][Aa][Ll]\\s*\\(|(?:[Aa][Ll][Ee][Rr][Tt]|[Ff][Ee][Tt][Cc][Hh])\\s*\\(|\\{\\{|\\}\\}|\\$\\{|#[A-Za-z_][A-Za-z0-9_-]*|(?:^|[\\s,>+~])\\.[A-Za-z_-][A-Za-z0-9_-]*(?:$|[\\s,>+~.#[\\:])|\\[[A-Za-z_:][-A-Za-z0-9_:.]*(?:[~|^$*]?=[^\\]]+)?\\]|(?:[Ll][Oo][Cc][Aa][Ll]|[Ss][Ee][Ss][Ss][Ii][Oo][Nn])[Ss][Tt][Oo][Rr][Aa][Gg][Ee]|[Ii][Nn][Dd][Ee][Xx][Ee][Dd][Dd][Bb]|[Qq][Uu][Ee][Rr][Yy][Ss][Ee][Ll][Ee][Cc][Tt][Oo][Rr]|(?:[Ww][Ii][Nn][Dd][Oo][Ww]|[Dd][Oo][Cc][Uu][Mm][Ee][Nn][Tt]|[Gg][Ll][Oo][Bb][Aa][Ll][Tt][Hh][Ii][Ss]|[Cc][Oo][Nn][Ss][Oo][Ll][Ee])\\s*(?:\\.|\\[)|[A-Za-z_$][A-Za-z0-9_$]*\\s*\\.\\s*[A-Za-z_$][A-Za-z0-9_$]*\\s*\\(|[A-Za-z_$][A-Za-z0-9_$]*\\s*\\([^)]*\\)\\s*;|[Rr][Ee][Tt][Uu][Rr][Nn][^;{}]*;|[Ff][Uu][Nn][Cc][Tt][Ii][Oo][Nn]|=>|(?:[Vv][Aa][Rr]|[Ll][Ee][Tt]|[Cc][Oo][Nn][Ss][Tt])\\s+[A-Za-z_$])"
148
+ }
149
+ ]
150
+ },
151
+ "minLength": 1
152
+ },
153
+ "staged": {
154
+ "type": "string",
155
+ "not": {
156
+ "anyOf": [
157
+ {
158
+ "type": "string",
159
+ "pattern": "(?:[Gg][Tt][Mm]-[A-Za-z0-9]+|[Uu][Aa]-[0-9]+-[0-9]+)"
160
+ },
161
+ {
162
+ "type": "string",
163
+ "pattern": "(?:-----BEGIN(?: [A-Z]+)? PRIVATE KEY-----|\\bAKIA[0-9A-Z]{16}\\b|\\bsk-proj-[A-Za-z0-9_-]{8,}\\b|\\bsk-[A-Za-z0-9_-]{20,}\\b|\\b(?:sk|rk)_(?:live|test|prod)_[A-Za-z0-9_-]{8,}\\b|\\b(?:gh[pousr]_|github_pat_)[A-Za-z0-9_]{20,}\\b|\\b(?:npm_|glpat-)[A-Za-z0-9_.-]{8,}\\b|\\bxox[baprs]-[A-Za-z0-9-]{10,}\\b|\\bAIza[A-Za-z0-9_-]{20,}\\b|\\bSG\\.[A-Za-z0-9_.-]{8,}\\b|\\b(?:[Ss]ecret|[Pp]assword|[Cc]redential)[_-][A-Za-z0-9_-]{4,}\\b|\\b[Bb]earer\\s+[A-Za-z0-9._~+/-]{12,}={0,2}\\b|\\beyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]+\\b|\\b(?:api[_ -]?[Kk]ey|client[_ -]?[Ss]ecret|[Pp]assword|[Cc]redential|private[_ -]?[Kk]ey)\\s*[:=]\\s*\\S+)"
164
+ },
165
+ {
166
+ "type": "string",
167
+ "pattern": "(?:[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}|\\b[0-9]{3}-[0-9]{2}-[0-9]{4}\\b|\\b(?:[0-9][ -]?){13,19}\\b|(?:^|[^0-9])(?:\\+?1[ .-]?)?(?:\\([2-9][0-9]{2}\\)|[2-9][0-9]{2})[ .-]?[0-9]{3}[ .-]?[0-9]{4}(?=$|[^0-9]))"
168
+ },
169
+ {
170
+ "type": "string",
171
+ "pattern": "(?:</?[A-Za-z][^>]*>|[Jj][Aa][Vv][Aa][Ss][Cc][Rr][Ii][Pp][Tt]\\s*:|[Ee][Vv][Aa][Ll]\\s*\\(|(?:[Aa][Ll][Ee][Rr][Tt]|[Ff][Ee][Tt][Cc][Hh])\\s*\\(|\\{\\{|\\}\\}|\\$\\{|#[A-Za-z_][A-Za-z0-9_-]*|(?:^|[\\s,>+~])\\.[A-Za-z_-][A-Za-z0-9_-]*(?:$|[\\s,>+~.#[\\:])|\\[[A-Za-z_:][-A-Za-z0-9_:.]*(?:[~|^$*]?=[^\\]]+)?\\]|(?:[Ll][Oo][Cc][Aa][Ll]|[Ss][Ee][Ss][Ss][Ii][Oo][Nn])[Ss][Tt][Oo][Rr][Aa][Gg][Ee]|[Ii][Nn][Dd][Ee][Xx][Ee][Dd][Dd][Bb]|[Qq][Uu][Ee][Rr][Yy][Ss][Ee][Ll][Ee][Cc][Tt][Oo][Rr]|(?:[Ww][Ii][Nn][Dd][Oo][Ww]|[Dd][Oo][Cc][Uu][Mm][Ee][Nn][Tt]|[Gg][Ll][Oo][Bb][Aa][Ll][Tt][Hh][Ii][Ss]|[Cc][Oo][Nn][Ss][Oo][Ll][Ee])\\s*(?:\\.|\\[)|[A-Za-z_$][A-Za-z0-9_$]*\\s*\\.\\s*[A-Za-z_$][A-Za-z0-9_$]*\\s*\\(|[A-Za-z_$][A-Za-z0-9_$]*\\s*\\([^)]*\\)\\s*;|[Rr][Ee][Tt][Uu][Rr][Nn][^;{}]*;|[Ff][Uu][Nn][Cc][Tt][Ii][Oo][Nn]|=>|(?:[Vv][Aa][Rr]|[Ll][Ee][Tt]|[Cc][Oo][Nn][Ss][Tt])\\s+[A-Za-z_$])"
172
+ }
173
+ ]
174
+ },
175
+ "minLength": 1
176
+ },
177
+ "live": {
178
+ "type": "string",
179
+ "not": {
180
+ "anyOf": [
181
+ {
182
+ "type": "string",
183
+ "pattern": "(?:[Gg][Tt][Mm]-[A-Za-z0-9]+|[Uu][Aa]-[0-9]+-[0-9]+)"
184
+ },
185
+ {
186
+ "type": "string",
187
+ "pattern": "(?:-----BEGIN(?: [A-Z]+)? PRIVATE KEY-----|\\bAKIA[0-9A-Z]{16}\\b|\\bsk-proj-[A-Za-z0-9_-]{8,}\\b|\\bsk-[A-Za-z0-9_-]{20,}\\b|\\b(?:sk|rk)_(?:live|test|prod)_[A-Za-z0-9_-]{8,}\\b|\\b(?:gh[pousr]_|github_pat_)[A-Za-z0-9_]{20,}\\b|\\b(?:npm_|glpat-)[A-Za-z0-9_.-]{8,}\\b|\\bxox[baprs]-[A-Za-z0-9-]{10,}\\b|\\bAIza[A-Za-z0-9_-]{20,}\\b|\\bSG\\.[A-Za-z0-9_.-]{8,}\\b|\\b(?:[Ss]ecret|[Pp]assword|[Cc]redential)[_-][A-Za-z0-9_-]{4,}\\b|\\b[Bb]earer\\s+[A-Za-z0-9._~+/-]{12,}={0,2}\\b|\\beyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]+\\b|\\b(?:api[_ -]?[Kk]ey|client[_ -]?[Ss]ecret|[Pp]assword|[Cc]redential|private[_ -]?[Kk]ey)\\s*[:=]\\s*\\S+)"
188
+ },
189
+ {
190
+ "type": "string",
191
+ "pattern": "(?:[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}|\\b[0-9]{3}-[0-9]{2}-[0-9]{4}\\b|\\b(?:[0-9][ -]?){13,19}\\b|(?:^|[^0-9])(?:\\+?1[ .-]?)?(?:\\([2-9][0-9]{2}\\)|[2-9][0-9]{2})[ .-]?[0-9]{3}[ .-]?[0-9]{4}(?=$|[^0-9]))"
192
+ },
193
+ {
194
+ "type": "string",
195
+ "pattern": "(?:</?[A-Za-z][^>]*>|[Jj][Aa][Vv][Aa][Ss][Cc][Rr][Ii][Pp][Tt]\\s*:|[Ee][Vv][Aa][Ll]\\s*\\(|(?:[Aa][Ll][Ee][Rr][Tt]|[Ff][Ee][Tt][Cc][Hh])\\s*\\(|\\{\\{|\\}\\}|\\$\\{|#[A-Za-z_][A-Za-z0-9_-]*|(?:^|[\\s,>+~])\\.[A-Za-z_-][A-Za-z0-9_-]*(?:$|[\\s,>+~.#[\\:])|\\[[A-Za-z_:][-A-Za-z0-9_:.]*(?:[~|^$*]?=[^\\]]+)?\\]|(?:[Ll][Oo][Cc][Aa][Ll]|[Ss][Ee][Ss][Ss][Ii][Oo][Nn])[Ss][Tt][Oo][Rr][Aa][Gg][Ee]|[Ii][Nn][Dd][Ee][Xx][Ee][Dd][Dd][Bb]|[Qq][Uu][Ee][Rr][Yy][Ss][Ee][Ll][Ee][Cc][Tt][Oo][Rr]|(?:[Ww][Ii][Nn][Dd][Oo][Ww]|[Dd][Oo][Cc][Uu][Mm][Ee][Nn][Tt]|[Gg][Ll][Oo][Bb][Aa][Ll][Tt][Hh][Ii][Ss]|[Cc][Oo][Nn][Ss][Oo][Ll][Ee])\\s*(?:\\.|\\[)|[A-Za-z_$][A-Za-z0-9_$]*\\s*\\.\\s*[A-Za-z_$][A-Za-z0-9_$]*\\s*\\(|[A-Za-z_$][A-Za-z0-9_$]*\\s*\\([^)]*\\)\\s*;|[Rr][Ee][Tt][Uu][Rr][Nn][^;{}]*;|[Ff][Uu][Nn][Cc][Tt][Ii][Oo][Nn]|=>|(?:[Vv][Aa][Rr]|[Ll][Ee][Tt]|[Cc][Oo][Nn][Ss][Tt])\\s+[A-Za-z_$])"
196
+ }
197
+ ]
198
+ },
199
+ "minLength": 1
200
+ }
201
+ }
123
202
  }
124
203
  ]
125
204
  }