@sequenceholdings/pipeline-spec 0.1.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.
Files changed (126) hide show
  1. package/README.md +114 -0
  2. package/dist/authoring/per-table-ingestion.d.ts +74 -0
  3. package/dist/authoring/per-table-ingestion.d.ts.map +1 -0
  4. package/dist/authoring/per-table-ingestion.js +122 -0
  5. package/dist/authoring/per-table-ingestion.js.map +1 -0
  6. package/dist/authoring/yaml.d.ts +6 -0
  7. package/dist/authoring/yaml.d.ts.map +1 -0
  8. package/dist/authoring/yaml.js +15 -0
  9. package/dist/authoring/yaml.js.map +1 -0
  10. package/dist/binding-gaps.d.ts +21 -0
  11. package/dist/binding-gaps.d.ts.map +1 -0
  12. package/dist/binding-gaps.js +74 -0
  13. package/dist/binding-gaps.js.map +1 -0
  14. package/dist/bodies/ingestion.d.ts +359 -0
  15. package/dist/bodies/ingestion.d.ts.map +1 -0
  16. package/dist/bodies/ingestion.js +446 -0
  17. package/dist/bodies/ingestion.js.map +1 -0
  18. package/dist/bodies/serving.d.ts +316 -0
  19. package/dist/bodies/serving.d.ts.map +1 -0
  20. package/dist/bodies/serving.js +290 -0
  21. package/dist/bodies/serving.js.map +1 -0
  22. package/dist/bodies/transformation.d.ts +397 -0
  23. package/dist/bodies/transformation.d.ts.map +1 -0
  24. package/dist/bodies/transformation.js +278 -0
  25. package/dist/bodies/transformation.js.map +1 -0
  26. package/dist/catalog-binding.d.ts +15 -0
  27. package/dist/catalog-binding.d.ts.map +1 -0
  28. package/dist/catalog-binding.js +15 -0
  29. package/dist/catalog-binding.js.map +1 -0
  30. package/dist/columns.d.ts +177 -0
  31. package/dist/columns.d.ts.map +1 -0
  32. package/dist/columns.js +89 -0
  33. package/dist/columns.js.map +1 -0
  34. package/dist/compatibility.d.ts +25 -0
  35. package/dist/compatibility.d.ts.map +1 -0
  36. package/dist/compatibility.js +108 -0
  37. package/dist/compatibility.js.map +1 -0
  38. package/dist/constants.d.ts +95 -0
  39. package/dist/constants.d.ts.map +1 -0
  40. package/dist/constants.js +105 -0
  41. package/dist/constants.js.map +1 -0
  42. package/dist/diff.d.ts +36 -0
  43. package/dist/diff.d.ts.map +1 -0
  44. package/dist/diff.js +300 -0
  45. package/dist/diff.js.map +1 -0
  46. package/dist/documentation.d.ts +22 -0
  47. package/dist/documentation.d.ts.map +1 -0
  48. package/dist/documentation.js +43 -0
  49. package/dist/documentation.js.map +1 -0
  50. package/dist/envelope.d.ts +1241 -0
  51. package/dist/envelope.d.ts.map +1 -0
  52. package/dist/envelope.js +163 -0
  53. package/dist/envelope.js.map +1 -0
  54. package/dist/errors.d.ts +30 -0
  55. package/dist/errors.d.ts.map +1 -0
  56. package/dist/errors.js +47 -0
  57. package/dist/errors.js.map +1 -0
  58. package/dist/graph-references.d.ts +34 -0
  59. package/dist/graph-references.d.ts.map +1 -0
  60. package/dist/graph-references.js +81 -0
  61. package/dist/graph-references.js.map +1 -0
  62. package/dist/graph.d.ts +112 -0
  63. package/dist/graph.d.ts.map +1 -0
  64. package/dist/graph.js +546 -0
  65. package/dist/graph.js.map +1 -0
  66. package/dist/hash.d.ts +28 -0
  67. package/dist/hash.d.ts.map +1 -0
  68. package/dist/hash.js +91 -0
  69. package/dist/hash.js.map +1 -0
  70. package/dist/index.d.ts +27 -0
  71. package/dist/index.d.ts.map +1 -0
  72. package/dist/index.js +27 -0
  73. package/dist/index.js.map +1 -0
  74. package/dist/issues.d.ts +14 -0
  75. package/dist/issues.d.ts.map +1 -0
  76. package/dist/issues.js +27 -0
  77. package/dist/issues.js.map +1 -0
  78. package/dist/loader.d.ts +50 -0
  79. package/dist/loader.d.ts.map +1 -0
  80. package/dist/loader.js +241 -0
  81. package/dist/loader.js.map +1 -0
  82. package/dist/migrations/contracts.d.ts +38 -0
  83. package/dist/migrations/contracts.d.ts.map +1 -0
  84. package/dist/migrations/contracts.js +175 -0
  85. package/dist/migrations/contracts.js.map +1 -0
  86. package/dist/migrations/manifest.d.ts +137 -0
  87. package/dist/migrations/manifest.d.ts.map +1 -0
  88. package/dist/migrations/manifest.js +137 -0
  89. package/dist/migrations/manifest.js.map +1 -0
  90. package/dist/operations.d.ts +214 -0
  91. package/dist/operations.d.ts.map +1 -0
  92. package/dist/operations.js +275 -0
  93. package/dist/operations.js.map +1 -0
  94. package/dist/orm-satisfies.d.ts +132 -0
  95. package/dist/orm-satisfies.d.ts.map +1 -0
  96. package/dist/orm-satisfies.js +119 -0
  97. package/dist/orm-satisfies.js.map +1 -0
  98. package/dist/primitives.d.ts +11 -0
  99. package/dist/primitives.d.ts.map +1 -0
  100. package/dist/primitives.js +20 -0
  101. package/dist/primitives.js.map +1 -0
  102. package/dist/resolve.d.ts +124 -0
  103. package/dist/resolve.d.ts.map +1 -0
  104. package/dist/resolve.js +194 -0
  105. package/dist/resolve.js.map +1 -0
  106. package/dist/secret-scan.d.ts +34 -0
  107. package/dist/secret-scan.d.ts.map +1 -0
  108. package/dist/secret-scan.js +98 -0
  109. package/dist/secret-scan.js.map +1 -0
  110. package/dist/serving-compatibility.d.ts +14 -0
  111. package/dist/serving-compatibility.d.ts.map +1 -0
  112. package/dist/serving-compatibility.js +19 -0
  113. package/dist/serving-compatibility.js.map +1 -0
  114. package/dist/snapshot-transport.d.ts +83 -0
  115. package/dist/snapshot-transport.d.ts.map +1 -0
  116. package/dist/snapshot-transport.js +42 -0
  117. package/dist/snapshot-transport.js.map +1 -0
  118. package/dist/suggestions.d.ts +3 -0
  119. package/dist/suggestions.d.ts.map +1 -0
  120. package/dist/suggestions.js +26 -0
  121. package/dist/suggestions.js.map +1 -0
  122. package/dist/types.d.ts +72 -0
  123. package/dist/types.d.ts.map +1 -0
  124. package/dist/types.js +119 -0
  125. package/dist/types.js.map +1 -0
  126. package/package.json +52 -0
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Serving `satisfies:` enforcement against an ORM synced-table contract
3
+ * (SEQ-2499). Pure — callers (offline `validateSpecGraph`, provision plan)
4
+ * supply the active contract catalog; this module never fetches ORM state.
5
+ *
6
+ * Compatibility posture:
7
+ * - Projection is the **producer**; ORM contract columns are the **consumer
8
+ * requirement** (`checkCompatibility`).
9
+ * - Extra projection columns are allowed (additive pipeline supersets).
10
+ * - Primary keys must match exactly (same set + order).
11
+ * - `content_hash` on `satisfies` must equal the active contract hash.
12
+ */
13
+ import { z } from 'zod';
14
+ import { checkCompatibility } from './compatibility.js';
15
+ import { columnIdentifierSchema, columnMapSchema, identifierSchema } from './columns.js';
16
+ export const ORM_SATISFIES_FINDING_CODES = [
17
+ 'orm_contract_unavailable',
18
+ 'orm_contract_hash_mismatch',
19
+ 'orm_contract_pk_mismatch',
20
+ 'missing_column',
21
+ 'type_incompatible',
22
+ 'nullability_violation',
23
+ 'domain_violation',
24
+ 'domain_shrunk',
25
+ ];
26
+ /** One ORM synced-table contract entry for offline `satisfies` validation. */
27
+ export const ormSyncedContractRequirementSchema = z.strictObject({
28
+ namespace: z
29
+ .string()
30
+ .regex(/^[a-z][a-z0-9_]{0,40}$/, 'must be an ORM namespace (lowercase, ≤41 chars)'),
31
+ table: identifierSchema,
32
+ columns: columnMapSchema,
33
+ primary_key: z.array(columnIdentifierSchema).min(1),
34
+ content_hash: z
35
+ .string()
36
+ .regex(/^[a-f0-9]{64}$/, 'must be a sha256 hex digest (64 hex chars)'),
37
+ });
38
+ /**
39
+ * Offline ORM contract catalog for `seq-studio pipeline validate --orm-contracts`
40
+ * or `<pipeline-dir>/orm-contracts.json`. Keys must be `namespace.table`.
41
+ */
42
+ export const ormContractCatalogSchema = z
43
+ .record(z.string().min(1), ormSyncedContractRequirementSchema)
44
+ .superRefine((catalog, ctx) => {
45
+ for (const [key, value] of Object.entries(catalog)) {
46
+ const expected = `${value.namespace}.${value.table}`;
47
+ if (key !== expected) {
48
+ ctx.addIssue({
49
+ code: z.ZodIssueCode.custom,
50
+ path: [key],
51
+ message: `catalog key '${key}' must equal '${expected}' (namespace.table)`,
52
+ });
53
+ }
54
+ }
55
+ });
56
+ export function ormContractCatalogKey({ namespace, table, }) {
57
+ return `${namespace}.${table}`;
58
+ }
59
+ function primaryKeysEqual(left, right) {
60
+ if (left.length !== right.length)
61
+ return false;
62
+ return left.every((value, index) => value === right[index]);
63
+ }
64
+ /**
65
+ * Does this serving projection satisfy the declared ORM contract binding?
66
+ * Returns findings (empty = ok). Hash + PK mismatches are always errors;
67
+ * column findings reuse `checkCompatibility` severities.
68
+ */
69
+ export function checkServingSatisfiesOrmContract({ projection, satisfies, contract, }) {
70
+ const target = `${satisfies.namespace}.${satisfies.table}`;
71
+ if (!contract) {
72
+ return [
73
+ {
74
+ code: 'orm_contract_unavailable',
75
+ severity: 'error',
76
+ message: `satisfies references ORM contract '${target}' but no active synced-table contract was provided to validation`,
77
+ },
78
+ ];
79
+ }
80
+ if (contract.namespace !== satisfies.namespace || contract.table !== satisfies.table) {
81
+ return [
82
+ {
83
+ code: 'orm_contract_unavailable',
84
+ severity: 'error',
85
+ message: `satisfies references '${target}' but the supplied contract is '${contract.namespace}.${contract.table}'`,
86
+ },
87
+ ];
88
+ }
89
+ const findings = [];
90
+ if (contract.content_hash !== satisfies.content_hash) {
91
+ findings.push({
92
+ code: 'orm_contract_hash_mismatch',
93
+ severity: 'error',
94
+ message: `satisfies.content_hash does not match the active ORM contract for '${target}' ` +
95
+ `(declared '${satisfies.content_hash.slice(0, 12)}…', active '${contract.content_hash.slice(0, 12)}…')`,
96
+ });
97
+ }
98
+ if (!primaryKeysEqual(projection.primary_key, contract.primary_key)) {
99
+ findings.push({
100
+ code: 'orm_contract_pk_mismatch',
101
+ severity: 'error',
102
+ message: `projection.primary_key [${projection.primary_key.join(', ')}] must exactly match ` +
103
+ `ORM contract primary_key [${contract.primary_key.join(', ')}] for '${target}'`,
104
+ });
105
+ }
106
+ for (const finding of checkCompatibility(projection.columns, contract.columns)) {
107
+ findings.push(toOrmSatisfiesFinding(finding, target));
108
+ }
109
+ return findings;
110
+ }
111
+ function toOrmSatisfiesFinding(finding, target) {
112
+ return {
113
+ code: finding.code,
114
+ severity: finding.severity,
115
+ column: finding.column,
116
+ message: `ORM contract '${target}': ${finding.message}`,
117
+ };
118
+ }
119
+ //# sourceMappingURL=orm-satisfies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orm-satisfies.js","sourceRoot":"","sources":["../src/orm-satisfies.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Grammar primitives shared across the envelope, bodies, and operations —
4
+ * kept dependency-free (constants only) so any schema module can import them
5
+ * without cycles.
6
+ */
7
+ export declare const isoDurationSchema: z.ZodString;
8
+ export declare const symbolicRefSchema: z.ZodString;
9
+ /** Repo-relative code path (entrypoints, decoders). Never absolute, never escaping the repo. */
10
+ export declare const repoRelativePathSchema: z.ZodString;
11
+ //# sourceMappingURL=primitives.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../src/primitives.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB;;;;GAIG;AAEH,eAAO,MAAM,iBAAiB,aAEiD,CAAA;AAE/E,eAAO,MAAM,iBAAiB,aAE8E,CAAA;AAE5G,gGAAgG;AAChG,eAAO,MAAM,sBAAsB,aAI0C,CAAA"}
@@ -0,0 +1,20 @@
1
+ import { z } from 'zod';
2
+ import { ISO_DURATION_PATTERN, SYMBOLIC_REF_PATTERN } from './constants.js';
3
+ /**
4
+ * Grammar primitives shared across the envelope, bodies, and operations —
5
+ * kept dependency-free (constants only) so any schema module can import them
6
+ * without cycles.
7
+ */
8
+ export const isoDurationSchema = z
9
+ .string()
10
+ .regex(ISO_DURATION_PATTERN, 'must be an ISO-8601 duration (e.g. PT4H, P1D)');
11
+ export const symbolicRefSchema = z
12
+ .string()
13
+ .regex(SYMBOLIC_REF_PATTERN, 'must be a symbolic reference slug (a-z, 0-9, -, _) — never a literal value');
14
+ /** Repo-relative code path (entrypoints, decoders). Never absolute, never escaping the repo. */
15
+ export const repoRelativePathSchema = z
16
+ .string()
17
+ .min(1)
18
+ .refine((value) => !value.startsWith('/') && !value.startsWith('.'), 'must be a repo-relative path')
19
+ .refine((value) => !value.split('/').includes('..'), 'must not contain ..');
20
+ //# sourceMappingURL=primitives.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"primitives.js","sourceRoot":"","sources":["../src/primitives.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAE3E;;;;GAIG;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC;KAC/B,MAAM,EAAE;KACR,KAAK,CAAC,oBAAoB,EAAE,+CAA+C,CAAC,CAAA;AAE/E,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC;KAC/B,MAAM,EAAE;KACR,KAAK,CAAC,oBAAoB,EAAE,4EAA4E,CAAC,CAAA;AAE5G,gGAAgG;AAChG,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC;KACpC,MAAM,EAAE;KACR,GAAG,CAAC,CAAC,CAAC;KACN,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,8BAA8B,CAAC;KACnG,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,qBAAqB,CAAC,CAAA"}
@@ -0,0 +1,124 @@
1
+ import { z } from 'zod';
2
+ import { type PostgresSnapshotBinding, type SnapshotTransport } from './snapshot-transport.js';
3
+ import { type StageSpec } from './envelope.js';
4
+ /**
5
+ * The facts a deploy target contributes to resolution. Supplied by the
6
+ * caller, never discovered by the SDK.
7
+ *
8
+ * **One-workspace-per-deployment invariant:** each deploy target binds
9
+ * exactly one `workspace_id`. The field is schema-optional ONLY so that
10
+ * resolution can fail with a structured, enumerable error
11
+ * (`missing_workspace_binding`) instead of a generic parse error — there is
12
+ * no global-host fallback. (Today's shared first-party workspace is a
13
+ * transitional N:1 fact; the model assumes the target 1:1 coupling.)
14
+ */
15
+ export declare const targetFactsSchema: z.ZodObject<{
16
+ deploy_target: z.ZodString;
17
+ tenant_id: z.ZodOptional<z.ZodString>;
18
+ workspace_id: z.ZodOptional<z.ZodString>;
19
+ catalog: z.ZodString;
20
+ lakebase_branch: z.ZodOptional<z.ZodString>;
21
+ postgres_snapshot_bindings: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
22
+ bindingId: z.ZodString;
23
+ database: z.ZodString;
24
+ bindingHash: z.ZodString;
25
+ installationId: z.ZodString;
26
+ }, z.core.$strict>>>;
27
+ alert_channel_bindings: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
28
+ credential_bindings: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
29
+ }, z.core.$strict>;
30
+ export type TargetFacts = z.infer<typeof targetFactsSchema>;
31
+ export type TargetFactsInput = z.input<typeof targetFactsSchema>;
32
+ /** Where the resolved snapshot came from — stamped by the caller (deploy adapter / CI). */
33
+ export interface SpecProvenanceInput {
34
+ readonly source_repo: string;
35
+ readonly source_commit: string;
36
+ }
37
+ export interface ResolvedProvenance extends SpecProvenanceInput {
38
+ readonly spec_hash: string;
39
+ readonly contract_hash: string;
40
+ }
41
+ /** Identity facts stamped onto every resolved snapshot. */
42
+ export interface ResolvedIdentity {
43
+ readonly deploy_target: string;
44
+ readonly tenant_id?: string;
45
+ readonly workspace_id: string;
46
+ readonly catalog: string;
47
+ readonly lakebase_branch?: string;
48
+ }
49
+ /** Concrete bindings for the spec's symbolic references. */
50
+ export interface ResolvedBindings {
51
+ readonly credentials: Readonly<Record<string, string>>;
52
+ readonly alert_channels: Readonly<Record<string, string>>;
53
+ }
54
+ export interface ResolvedFeedNames {
55
+ /**
56
+ * Volume batch-directory prefix: `/Volumes/src_<source>/bronze/<feed>`
57
+ * (batches land under `batch_id=<ts>/`). Rooted in the per-source catalog,
58
+ * NOT the deployment catalog.
59
+ */
60
+ readonly volume_path: string;
61
+ /** Platform-derived append-only bronze table FQN: `src_<source>.bronze.<feed>`. */
62
+ readonly bronze_table: string;
63
+ }
64
+ export interface ResolvedIngestionNames {
65
+ readonly kind: 'ingestion';
66
+ readonly feeds: Readonly<Record<string, ResolvedFeedNames>>;
67
+ }
68
+ export interface ResolvedOutputNames {
69
+ /**
70
+ * Physical FQN of the output relation. Defaults to the deploy catalog;
71
+ * `config.catalog` pins a parallel UC namespace (e.g. `src_banksouth_fis`).
72
+ */
73
+ readonly table: string;
74
+ /** Physical FQN of the quarantine sibling — present iff any column quarantines. */
75
+ readonly quarantine_table?: string;
76
+ }
77
+ /**
78
+ * UC catalog a transformation writes. `config.catalog` pins a parallel
79
+ * source catalog; `identity.catalog` stays the deploy target.
80
+ */
81
+ export declare function transformationOutputCatalog(spec: Extract<StageSpec, {
82
+ type: 'transformation';
83
+ }>, deployCatalog: string, deployTarget?: string): string;
84
+ export interface ResolvedTransformationNames {
85
+ readonly kind: 'transformation';
86
+ readonly outputs: Readonly<Record<string, ResolvedOutputNames>>;
87
+ }
88
+ export interface ResolvedServingNames {
89
+ readonly transport?: {
90
+ readonly kind: 'native_lakebase_sync_v1';
91
+ } | (PostgresSnapshotBinding & Omit<SnapshotTransport, 'binding'>);
92
+ readonly kind: 'serving';
93
+ /** FQN of the UC source relation the sync reads. */
94
+ readonly source_table: string;
95
+ /**
96
+ * The declared public view. The Postgres physical relation is deliberately
97
+ * ABSENT: physical names are captured at provision time and stored in the
98
+ * registry, never re-derived (the estate has documented derivation drift).
99
+ */
100
+ readonly view: string;
101
+ /** Optional Lakebase reporting-schema compatibility relation. */
102
+ readonly reporting_table?: string;
103
+ }
104
+ export type ResolvedNames = ResolvedIngestionNames | ResolvedTransformationNames | ResolvedServingNames;
105
+ /**
106
+ * The immutable resolved snapshot: the portable spec, the identity it was
107
+ * resolved against, concrete bindings, derived physical names, and hashed
108
+ * provenance. Serialize with `canonicalJson` for storage — byte-stable.
109
+ */
110
+ export interface ResolvedSpec {
111
+ readonly spec: StageSpec;
112
+ readonly identity: ResolvedIdentity;
113
+ readonly bindings: ResolvedBindings;
114
+ readonly derived: ResolvedNames;
115
+ readonly provenance: ResolvedProvenance;
116
+ }
117
+ /**
118
+ * Resolve a portable spec against a deploy target's facts. Pure — binds
119
+ * symbolic references, derives physical names per the body derivation rules,
120
+ * stamps identity + hashed provenance. Throws `SpecResolutionError` with an
121
+ * enumerable code on any unresolvable fact.
122
+ */
123
+ export declare function resolveSpec(spec: StageSpec, facts: TargetFactsInput, provenance: SpecProvenanceInput): ResolvedSpec;
124
+ //# sourceMappingURL=resolve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAkC,KAAK,uBAAuB,EAAE,KAAK,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAK9H,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,eAAe,CAAA;AA0BlE;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;kBAiB5B,CAAA;AAEF,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAA;AAC3D,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAA;AAEhE,2FAA2F;AAC3F,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;CAC/B;AAED,MAAM,WAAW,kBAAmB,SAAQ,mBAAmB;IAC7D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;CAC/B;AAED,2DAA2D;AAC3D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAClC;AAED,4DAA4D;AAC5D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACtD,QAAQ,CAAC,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CAC1D;AAED,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,mFAAmF;IACnF,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;CAC9B;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;IAC1B,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAA;CAC5D;AAED,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,mFAAmF;IACnF,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CACnC;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,OAAO,CAAC,SAAS,EAAE;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAAC,EACpD,aAAa,EAAE,MAAM,EACrB,YAAY,CAAC,EAAE,MAAM,GACpB,MAAM,CAKR;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAA;IAC/B,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC,CAAA;CAChE;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,SAAS,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,yBAAyB,CAAA;KAAE,GAAG,CAAC,uBAAuB,GAAG,IAAI,CAAC,iBAAiB,EAAE,SAAS,CAAC,CAAC,CAAA;IAClI,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;IACxB,oDAAoD;IACpD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,iEAAiE;IACjE,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAClC;AAED,MAAM,MAAM,aAAa,GAAG,sBAAsB,GAAG,2BAA2B,GAAG,oBAAoB,CAAA;AAEvG;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;IACxB,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAA;IACnC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAA;IACnC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAA;IAC/B,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAA;CACxC;AAuHD;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,SAAS,EACf,KAAK,EAAE,gBAAgB,EACvB,UAAU,EAAE,mBAAmB,GAC9B,YAAY,CAqCd"}
@@ -0,0 +1,194 @@
1
+ import { z } from 'zod';
2
+ import { postgresSnapshotBindingsSchema } from './snapshot-transport.js';
3
+ import { resolveCatalogBinding } from './catalog-binding.js';
4
+ import { quarantineAssetName } from './constants.js';
5
+ import { requireResolvedColumns } from './columns.js';
6
+ import { SpecResolutionError } from './errors.js';
7
+ import { deployTargetSchema } from './envelope.js';
8
+ import { feedBronzeTable, feedVolumePath, ingestionSourceIdentity, symbolicRefSchema, } from './bodies/ingestion.js';
9
+ import { computeContractHash, computeSpecHash } from './hash.js';
10
+ import { collectBindingGaps } from './binding-gaps.js';
11
+ import { assertFeedDocumentationResolved } from './documentation.js';
12
+ /**
13
+ * A portable spec resolved against a deploy target's facts produces the
14
+ * immutable **resolved snapshot** that deployments record and telemetry
15
+ * references. `resolveSpec` is pure — no I/O, no discovery: the caller
16
+ * (deploy adapter / CLI) supplies the facts.
17
+ */
18
+ const nonEmpty = z.string().min(1);
19
+ /** Numeric Databricks workspace id (`DATABRICKS_ORG_ID`), not the `dbc-…` host prefix. */
20
+ const workspaceIdSchema = nonEmpty.regex(/^\d+$/, 'workspace_id must be the numeric Databricks workspace id (DATABRICKS_ORG_ID)');
21
+ /**
22
+ * The facts a deploy target contributes to resolution. Supplied by the
23
+ * caller, never discovered by the SDK.
24
+ *
25
+ * **One-workspace-per-deployment invariant:** each deploy target binds
26
+ * exactly one `workspace_id`. The field is schema-optional ONLY so that
27
+ * resolution can fail with a structured, enumerable error
28
+ * (`missing_workspace_binding`) instead of a generic parse error — there is
29
+ * no global-host fallback. (Today's shared first-party workspace is a
30
+ * transitional N:1 fact; the model assumes the target 1:1 coupling.)
31
+ */
32
+ export const targetFactsSchema = z.strictObject({
33
+ deploy_target: deployTargetSchema,
34
+ tenant_id: nonEmpty.optional(),
35
+ workspace_id: workspaceIdSchema.optional(),
36
+ /** UC catalog physical names are derived into (e.g. `banksouth`, `staging`). */
37
+ catalog: nonEmpty,
38
+ lakebase_branch: nonEmpty.optional(),
39
+ postgres_snapshot_bindings: postgresSnapshotBindingsSchema.optional(),
40
+ /** Symbolic alert channel → concrete route (Slack channel id, pager key). */
41
+ alert_channel_bindings: z.record(symbolicRefSchema, nonEmpty).default({}),
42
+ /**
43
+ * Databricks source credential family → binding id (secret-manager
44
+ * reference, never a secret value). Edge-worker Data Sync credential
45
+ * families stay on the worker binding and are validated by the Data Sync
46
+ * operation that runs on the registered machine.
47
+ */
48
+ credential_bindings: z.record(symbolicRefSchema, nonEmpty).default({}),
49
+ });
50
+ /**
51
+ * UC catalog a transformation writes. `config.catalog` pins a parallel
52
+ * source catalog; `identity.catalog` stays the deploy target.
53
+ */
54
+ export function transformationOutputCatalog(spec, deployCatalog, deployTarget) {
55
+ return resolveCatalogBinding({
56
+ binding: spec.config?.catalog,
57
+ deployTarget,
58
+ }) ?? deployCatalog;
59
+ }
60
+ function requireCredential(facts, symbolic) {
61
+ const binding = facts.credential_bindings[symbolic];
62
+ if (!binding) {
63
+ throw new SpecResolutionError('missing_credential_binding', `target '${facts.deploy_target}' has no credential binding for symbolic name '${symbolic}'`, symbolic);
64
+ }
65
+ return binding;
66
+ }
67
+ function resolveBindings(spec, facts) {
68
+ const credentials = {};
69
+ if (spec.type === 'ingestion') {
70
+ // Edge-worker credentials name the Data Sync environment family used by
71
+ // the registered machine (for example, fis_ibm -> FIS_IBM). The VM owns
72
+ // those credentials, so they must not be resolved through the Databricks
73
+ // managed-secret binding map.
74
+ //
75
+ // Keyless/public databricks sources omit `source.credential` — only
76
+ // resolve when a symbolic family is declared (never invent a sentinel
77
+ // binding).
78
+ if (spec.source?.credential) {
79
+ credentials[spec.source.credential] = requireCredential(facts, spec.source.credential);
80
+ }
81
+ }
82
+ const alertChannels = {};
83
+ for (const channel of spec.alerts?.channels ?? []) {
84
+ const route = facts.alert_channel_bindings[channel];
85
+ if (!route) {
86
+ throw new SpecResolutionError('missing_alert_channel_binding', `target '${facts.deploy_target}' has no alert channel binding for symbolic name '${channel}'`, channel);
87
+ }
88
+ alertChannels[channel] = route;
89
+ }
90
+ return { credentials, alert_channels: alertChannels };
91
+ }
92
+ function resolveServingTransport({ transport, facts }) {
93
+ if (transport.kind === 'native_lakebase_sync_v1')
94
+ return transport;
95
+ const binding = facts.postgres_snapshot_bindings?.[transport.binding];
96
+ if (!binding || binding.database !== transport.database)
97
+ throw new SpecResolutionError('invalid_target_facts', 'snapshot transport binding missing or mismatched');
98
+ const { binding: _alias, ...target } = transport;
99
+ return { ...target, ...binding };
100
+ }
101
+ function deriveNames(spec, facts) {
102
+ const catalog = facts.catalog;
103
+ switch (spec.type) {
104
+ case 'ingestion': {
105
+ // Ingestion names derive from the spec's OWN source identity into the
106
+ // per-source catalog (`src_<source>`) — never from the deployment
107
+ // catalog, which owns silver/gold/report/serving only. Canonical derivations
108
+ // live beside the body schema so docs, resolver, and tests can't drift.
109
+ const source = ingestionSourceIdentity(spec);
110
+ const feeds = Object.fromEntries(Object.keys(spec.feeds).map((feed) => [
111
+ feed,
112
+ {
113
+ volume_path: feedVolumePath({ source, feed }),
114
+ bronze_table: feedBronzeTable({ source, feed }),
115
+ },
116
+ ]));
117
+ return { kind: 'ingestion', feeds };
118
+ }
119
+ case 'transformation': {
120
+ const outputCatalog = transformationOutputCatalog(spec, catalog, facts.deploy_target);
121
+ const outputs = Object.fromEntries(Object.entries(spec.outputs).map(([asset, output]) => {
122
+ const table = `${outputCatalog}.${asset}`;
123
+ // Quarantine rows come from EITHER level (SEQ-2437/SEQ-2439): the
124
+ // output-level type-violation posture, or any single column's
125
+ // on_violation — both land in the same platform-derived sibling.
126
+ const columns = requireResolvedColumns(output.columns, `${spec.stage}: outputs.${asset}.columns`);
127
+ const quarantines = output.on_type_violation === 'quarantine' ||
128
+ Object.values(columns).some((column) => column.on_violation === 'quarantine');
129
+ return [
130
+ asset,
131
+ quarantines
132
+ ? { table, quarantine_table: `${outputCatalog}.${quarantineAssetName(asset)}` }
133
+ : { table },
134
+ ];
135
+ }));
136
+ return { kind: 'transformation', outputs };
137
+ }
138
+ case 'serving':
139
+ return {
140
+ kind: 'serving',
141
+ ...(spec.transport ? { transport: resolveServingTransport({ transport: spec.transport, facts }) } : {}),
142
+ // Optional `source.catalog` binds a parallel producer namespace
143
+ // (e.g. `src_banksouth_fis`); the synced-table destination still uses
144
+ // `facts.catalog`.
145
+ source_table: `${resolveCatalogBinding({
146
+ binding: spec.source.catalog,
147
+ deployTarget: facts.deploy_target,
148
+ }) ?? catalog}.${spec.source.output}`,
149
+ view: spec.expose.view,
150
+ ...(spec.expose.reporting_table
151
+ ? { reporting_table: spec.expose.reporting_table }
152
+ : {}),
153
+ };
154
+ }
155
+ }
156
+ /**
157
+ * Resolve a portable spec against a deploy target's facts. Pure — binds
158
+ * symbolic references, derives physical names per the body derivation rules,
159
+ * stamps identity + hashed provenance. Throws `SpecResolutionError` with an
160
+ * enumerable code on any unresolvable fact.
161
+ */
162
+ export function resolveSpec(spec, facts, provenance) {
163
+ assertFeedDocumentationResolved(spec);
164
+ const gaps = collectBindingGaps(spec, facts);
165
+ const gap = gaps[0];
166
+ if (gap) {
167
+ throw new SpecResolutionError(gap.code, gap.message, gap.symbolic);
168
+ }
169
+ const target = targetFactsSchema.parse(facts);
170
+ const workspaceId = target.workspace_id;
171
+ if (workspaceId === undefined) {
172
+ throw new SpecResolutionError('missing_workspace_binding', `target '${target.deploy_target}' has no workspace binding — every deploy target must bind exactly one workspace_id (no fallback)`, target.deploy_target);
173
+ }
174
+ const identity = {
175
+ deploy_target: target.deploy_target,
176
+ workspace_id: workspaceId,
177
+ catalog: target.catalog,
178
+ ...(target.tenant_id !== undefined ? { tenant_id: target.tenant_id } : {}),
179
+ ...(target.lakebase_branch !== undefined ? { lakebase_branch: target.lakebase_branch } : {}),
180
+ };
181
+ return {
182
+ spec,
183
+ identity,
184
+ bindings: resolveBindings(spec, target),
185
+ derived: deriveNames(spec, target),
186
+ provenance: {
187
+ source_repo: provenance.source_repo,
188
+ source_commit: provenance.source_commit,
189
+ spec_hash: computeSpecHash(spec),
190
+ contract_hash: computeContractHash(spec),
191
+ },
192
+ };
193
+ }
194
+ //# sourceMappingURL=resolve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.js","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Specs carry symbolic references only — credential families, alert channels,
3
+ * integrations. This scan walks every string leaf of a parsed spec and rejects
4
+ * anything that looks like a literal secret, credential, connection string, or
5
+ * webhook URL, so a copy-pasted token can never ride into the registry.
6
+ *
7
+ * It is a tripwire, not a scanner-of-record: the tight identifier grammars on
8
+ * symbolic fields do most of the work; this catches the free-text fields
9
+ * (descriptions, extraction params, runbook) where a literal could hide.
10
+ */
11
+ export interface CredentialFinding {
12
+ /** Dotted path to the offending string leaf (e.g. `feeds.games.extraction.conn`) — display only. */
13
+ readonly path: string;
14
+ /**
15
+ * Exact path segments to the leaf. Use THESE for Zod issue paths — keys may
16
+ * themselves contain dots (`outputs['gold.players']`), so splitting the
17
+ * dotted string would point at the wrong location.
18
+ */
19
+ readonly segments: readonly string[];
20
+ readonly reason: string;
21
+ }
22
+ /**
23
+ * Reason the string looks like a credential/webhook literal, or null when it
24
+ * is clean. `urlAllowed` permits a plain https URL (for `runbook`) while still
25
+ * rejecting webhook hosts and embedded credentials.
26
+ */
27
+ export declare function credentialLikeReason(value: string, urlAllowed?: boolean): string | null;
28
+ /**
29
+ * Walk every string leaf of a parsed spec (post-YAML object tree) and collect
30
+ * credential-looking values. Object keys are grammar-constrained by the
31
+ * schemas, so only values are scanned.
32
+ */
33
+ export declare function scanForCredentialLikeStrings(root: unknown): CredentialFinding[];
34
+ //# sourceMappingURL=secret-scan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-scan.d.ts","sourceRoot":"","sources":["../src/secret-scan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,WAAW,iBAAiB;IAChC,oGAAoG;IACpG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB;AA6BD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,UAAQ,GAAG,MAAM,GAAG,IAAI,CAyBrF;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,OAAO,GAAG,iBAAiB,EAAE,CAI/E"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Specs carry symbolic references only — credential families, alert channels,
3
+ * integrations. This scan walks every string leaf of a parsed spec and rejects
4
+ * anything that looks like a literal secret, credential, connection string, or
5
+ * webhook URL, so a copy-pasted token can never ride into the registry.
6
+ *
7
+ * It is a tripwire, not a scanner-of-record: the tight identifier grammars on
8
+ * symbolic fields do most of the work; this catches the free-text fields
9
+ * (descriptions, extraction params, runbook) where a literal could hide.
10
+ */
11
+ /** Fields that legitimately hold an https URL (still scanned for webhook/credential shapes). */
12
+ const URL_ALLOWED_PATHS = new Set(['runbook']);
13
+ const WEBHOOK_HOST_PATTERN = /hooks\.slack\.com|webhook\.site|discord(?:app)?\.com\/api\/webhooks|outlook\.office\.com\/webhook/i;
14
+ /** Scan backward from delimiters so long descriptions cannot cause regex backtracking. */
15
+ function containsUrlScheme(value) {
16
+ for (let delimiter = value.indexOf('://'); delimiter !== -1; delimiter = value.indexOf('://', delimiter + 3)) {
17
+ for (let cursor = delimiter - 1; cursor >= 0; cursor--) {
18
+ const character = value.charAt(cursor);
19
+ if (/[a-z]/i.test(character))
20
+ return true;
21
+ if (!/[0-9+.-]/.test(character))
22
+ break;
23
+ }
24
+ }
25
+ return false;
26
+ }
27
+ const CONNECTION_STRING_PATTERN = /^(?:jdbc|odbc):|(?:^|;)\s*(?:PWD|UID|DSN|DRIVER)\s*=/i;
28
+ const KEY_VALUE_SECRET_PATTERN = /(?:password|passwd|pwd|secret|api[_-]?key|access[_-]?key|private[_-]?key|client[_-]?secret|auth[_-]?token)\s*[=:]\s*\S+/i;
29
+ /** Well-known token prefixes (Slack, GitHub, OpenAI/Anthropic-style, AWS) and PEM blocks. */
30
+ const TOKEN_PREFIX_PATTERN = /\b(?:xox[a-z]-[A-Za-z0-9-]+|ghp_[A-Za-z0-9]{20,}|github_pat_[A-Za-z0-9_]{20,}|sk-[A-Za-z0-9_-]{16,}|AKIA[0-9A-Z]{16})\b|-----BEGIN [A-Z ]*PRIVATE KEY-----/;
31
+ /** Three dot-separated base64url segments of meaningful length — a JWT. */
32
+ const JWT_PATTERN = /\bey[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{5,}\b/;
33
+ /**
34
+ * Reason the string looks like a credential/webhook literal, or null when it
35
+ * is clean. `urlAllowed` permits a plain https URL (for `runbook`) while still
36
+ * rejecting webhook hosts and embedded credentials.
37
+ */
38
+ export function credentialLikeReason(value, urlAllowed = false) {
39
+ if (WEBHOOK_HOST_PATTERN.test(value))
40
+ return 'looks like a webhook URL — use a symbolic alert channel reference';
41
+ if (CONNECTION_STRING_PATTERN.test(value))
42
+ return 'looks like a connection string — use a symbolic credential reference';
43
+ if (KEY_VALUE_SECRET_PATTERN.test(value))
44
+ return 'looks like an embedded credential — use a symbolic credential reference';
45
+ if (TOKEN_PREFIX_PATTERN.test(value))
46
+ return 'looks like a literal secret token — use a symbolic credential reference';
47
+ if (JWT_PATTERN.test(value))
48
+ return 'looks like a literal JWT — use a symbolic credential reference';
49
+ if (containsUrlScheme(value)) {
50
+ if (urlAllowed && value.startsWith('https://')) {
51
+ // An allowed URL must not smuggle credentials in its userinfo
52
+ // (https://user:password@host/…) — parse and reject, don't trust shape.
53
+ try {
54
+ const url = new URL(value);
55
+ if (url.username !== '' || url.password !== '') {
56
+ return 'URL carries userinfo credentials — use a symbolic credential reference';
57
+ }
58
+ return null;
59
+ }
60
+ catch {
61
+ return 'must be a valid https:// URL';
62
+ }
63
+ }
64
+ return urlAllowed
65
+ ? 'must be an https:// URL'
66
+ : 'URLs and connection strings are not allowed here — use a symbolic reference';
67
+ }
68
+ return null;
69
+ }
70
+ /**
71
+ * Walk every string leaf of a parsed spec (post-YAML object tree) and collect
72
+ * credential-looking values. Object keys are grammar-constrained by the
73
+ * schemas, so only values are scanned.
74
+ */
75
+ export function scanForCredentialLikeStrings(root) {
76
+ const findings = [];
77
+ walk(root, [], findings);
78
+ return findings;
79
+ }
80
+ function walk(value, path, findings) {
81
+ if (typeof value === 'string') {
82
+ const urlAllowed = URL_ALLOWED_PATHS.has(path.join('.'));
83
+ const reason = credentialLikeReason(value, urlAllowed);
84
+ if (reason)
85
+ findings.push({ path: path.join('.'), segments: path, reason });
86
+ return;
87
+ }
88
+ if (Array.isArray(value)) {
89
+ value.forEach((entry, index) => walk(entry, [...path, String(index)], findings));
90
+ return;
91
+ }
92
+ if (value !== null && typeof value === 'object') {
93
+ for (const [key, entry] of Object.entries(value)) {
94
+ walk(entry, [...path, key], findings);
95
+ }
96
+ }
97
+ }
98
+ //# sourceMappingURL=secret-scan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-scan.js","sourceRoot":"","sources":["../src/secret-scan.ts"],"names":[],"mappings":"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"}