@fabricorg/databricks-testkit 0.4.0 → 0.6.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.
- package/LICENSE +21 -0
- package/README.md +11 -2
- package/dist/index.cjs +903 -75
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +100 -1
- package/dist/index.d.ts +100 -1
- package/dist/index.js +881 -76
- package/dist/index.js.map +1 -1
- package/package.json +13 -11
package/dist/index.js
CHANGED
|
@@ -142,15 +142,15 @@ function defineLiveSuite(spec) {
|
|
|
142
142
|
async function runLiveSuite(spec, runtime = {}) {
|
|
143
143
|
const env = spec.env ?? process.env;
|
|
144
144
|
if (env.DBX_TEST_LIVE !== "1") return void 0;
|
|
145
|
-
const
|
|
145
|
+
const required3 = [...spec.required ?? []];
|
|
146
146
|
const known = new Set(spec.checks.map((check) => check.id));
|
|
147
|
-
for (const id of
|
|
147
|
+
for (const id of required3) {
|
|
148
148
|
if (!known.has(id)) throw new Error(`Required live check '${id}' is not defined`);
|
|
149
149
|
}
|
|
150
150
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
151
151
|
const ownedWarehouse = runtime.warehouse === void 0;
|
|
152
152
|
const client = runtime.client ?? createClientFromEnv(env);
|
|
153
|
-
const
|
|
153
|
+
const warehouse2 = runtime.warehouse ?? (hasWarehouseConfig(env) ? await createWorkspaceContext({ env, client }) : unavailableWarehouseContext());
|
|
154
154
|
const results = [];
|
|
155
155
|
try {
|
|
156
156
|
for (const check of spec.checks) {
|
|
@@ -165,7 +165,7 @@ async function runLiveSuite(spec, runtime = {}) {
|
|
|
165
165
|
}
|
|
166
166
|
const before = performance.now();
|
|
167
167
|
try {
|
|
168
|
-
const details = await check.run({ env, warehouse, client });
|
|
168
|
+
const details = await check.run({ env, warehouse: warehouse2, client });
|
|
169
169
|
results.push({
|
|
170
170
|
id: check.id,
|
|
171
171
|
description: check.description,
|
|
@@ -184,9 +184,9 @@ async function runLiveSuite(spec, runtime = {}) {
|
|
|
184
184
|
}
|
|
185
185
|
}
|
|
186
186
|
} finally {
|
|
187
|
-
if (ownedWarehouse) await
|
|
187
|
+
if (ownedWarehouse) await warehouse2.close();
|
|
188
188
|
}
|
|
189
|
-
const success =
|
|
189
|
+
const success = required3.every(
|
|
190
190
|
(id) => results.find((result) => result.id === id)?.status === "pass"
|
|
191
191
|
);
|
|
192
192
|
const evidence = {
|
|
@@ -195,7 +195,7 @@ async function runLiveSuite(spec, runtime = {}) {
|
|
|
195
195
|
startedAt,
|
|
196
196
|
finishedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
197
197
|
success,
|
|
198
|
-
required:
|
|
198
|
+
required: required3,
|
|
199
199
|
results,
|
|
200
200
|
...spec.targetPack ? { targetPack: spec.targetPack } : {}
|
|
201
201
|
};
|
|
@@ -298,8 +298,8 @@ function sqlRoundTripCheck() {
|
|
|
298
298
|
id: "sql",
|
|
299
299
|
description: "SQL Statement Execution round-trip",
|
|
300
300
|
configured: (env) => Boolean(env.DATABRICKS_WAREHOUSE_ID || env.DATABRICKS_HTTP_PATH),
|
|
301
|
-
async run({ warehouse }) {
|
|
302
|
-
const rows = await
|
|
301
|
+
async run({ warehouse: warehouse2 }) {
|
|
302
|
+
const rows = await warehouse2.query("SELECT 1 AS dbx_test_ok");
|
|
303
303
|
if (Number(rows[0]?.dbx_test_ok) !== 1)
|
|
304
304
|
throw new Error("SQL round-trip returned an unexpected value");
|
|
305
305
|
return { rows: rows.length };
|
|
@@ -343,9 +343,9 @@ function deltaContractCheck(tableEnv = "DBX_TEST_DELTA_TABLE", columns = []) {
|
|
|
343
343
|
id: "delta-contract",
|
|
344
344
|
description: "Delta table schema contract",
|
|
345
345
|
configured: (env) => Boolean(env[tableEnv]),
|
|
346
|
-
async run({ env, warehouse }) {
|
|
346
|
+
async run({ env, warehouse: warehouse2 }) {
|
|
347
347
|
const table = env[tableEnv];
|
|
348
|
-
const rows = await
|
|
348
|
+
const rows = await warehouse2.query(`DESCRIBE TABLE ${table}`);
|
|
349
349
|
assertDeltaContract(table, rows, columns);
|
|
350
350
|
return { table, columns: rows.length };
|
|
351
351
|
}
|
|
@@ -356,10 +356,10 @@ function unityCatalogAccessCheck() {
|
|
|
356
356
|
id: "uc-grants",
|
|
357
357
|
description: "Unity Catalog allow/deny access assertions",
|
|
358
358
|
configured: (env) => Boolean(env.DBX_TEST_UC_ALLOWED_TABLE && env.DBX_TEST_UC_DENIED_TABLE),
|
|
359
|
-
async run({ env, warehouse }) {
|
|
360
|
-
await
|
|
359
|
+
async run({ env, warehouse: warehouse2 }) {
|
|
360
|
+
await warehouse2.query(`SELECT * FROM ${env.DBX_TEST_UC_ALLOWED_TABLE} LIMIT 1`);
|
|
361
361
|
try {
|
|
362
|
-
await
|
|
362
|
+
await warehouse2.query(`SELECT * FROM ${env.DBX_TEST_UC_DENIED_TABLE} LIMIT 1`);
|
|
363
363
|
} catch (error) {
|
|
364
364
|
if (/permission.?denied|insufficient.?priv|403|unauthoriz/i.test(String(error))) {
|
|
365
365
|
return { allowed: env.DBX_TEST_UC_ALLOWED_TABLE, denied: env.DBX_TEST_UC_DENIED_TABLE };
|
|
@@ -819,7 +819,7 @@ function autoLoaderIngestionCheck(options = {}) {
|
|
|
819
819
|
configured: (env) => Boolean(
|
|
820
820
|
env.DBX_TEST_AUTOLOADER_PIPELINE_ID && env.DBX_TEST_AUTOLOADER_TABLE && env.DBX_TEST_AUTOLOADER_FIXTURE && env.DBX_TEST_VOLUME
|
|
821
821
|
),
|
|
822
|
-
async run({ env, client, warehouse }) {
|
|
822
|
+
async run({ env, client, warehouse: warehouse2 }) {
|
|
823
823
|
const pipelineId = env.DBX_TEST_AUTOLOADER_PIPELINE_ID;
|
|
824
824
|
if (pipelineId === env.DBX_TEST_PIPELINE_ID) {
|
|
825
825
|
throw new Error("DBX_TEST_AUTOLOADER_PIPELINE_ID must not be the production pipeline");
|
|
@@ -844,7 +844,7 @@ function autoLoaderIngestionCheck(options = {}) {
|
|
|
844
844
|
pollIntervalMs: Number(env.DBX_TEST_POLL_INTERVAL_MS ?? 1e4)
|
|
845
845
|
});
|
|
846
846
|
const table = env.DBX_TEST_AUTOLOADER_TABLE;
|
|
847
|
-
const rows = await
|
|
847
|
+
const rows = await warehouse2.query(
|
|
848
848
|
`SELECT COUNT(*) AS n, SUM(CASE WHEN _rescued_data IS NOT NULL THEN 1 ELSE 0 END) AS rescued FROM ${table}`
|
|
849
849
|
);
|
|
850
850
|
const count = Number(rows[0]?.n ?? 0);
|
|
@@ -867,7 +867,7 @@ function performanceBudgetCheck() {
|
|
|
867
867
|
id: "performance",
|
|
868
868
|
description: "SQL Statement Execution p95 stays within the configured latency budget",
|
|
869
869
|
configured: (env) => Boolean(env.DBX_TEST_PERFORMANCE_P95_MS),
|
|
870
|
-
async run({ env, warehouse }) {
|
|
870
|
+
async run({ env, warehouse: warehouse2 }) {
|
|
871
871
|
const budgetMs = Number(env.DBX_TEST_PERFORMANCE_P95_MS);
|
|
872
872
|
const runs = Number(env.DBX_TEST_PERFORMANCE_RUNS ?? 7);
|
|
873
873
|
if (!Number.isFinite(budgetMs) || budgetMs <= 0) {
|
|
@@ -876,11 +876,11 @@ function performanceBudgetCheck() {
|
|
|
876
876
|
if (!Number.isInteger(runs) || runs < 3 || runs > 100) {
|
|
877
877
|
throw new Error("DBX_TEST_PERFORMANCE_RUNS must be an integer from 3 to 100");
|
|
878
878
|
}
|
|
879
|
-
await
|
|
879
|
+
await warehouse2.query("SELECT 1 AS warmup");
|
|
880
880
|
const durations = [];
|
|
881
881
|
for (let index = 0; index < runs; index += 1) {
|
|
882
882
|
const started = performance.now();
|
|
883
|
-
await
|
|
883
|
+
await warehouse2.query("SELECT 1 AS performance_probe");
|
|
884
884
|
durations.push(performance.now() - started);
|
|
885
885
|
}
|
|
886
886
|
durations.sort((left, right) => left - right);
|
|
@@ -902,15 +902,15 @@ function failureRecoveryCheck() {
|
|
|
902
902
|
id: "failure-recovery",
|
|
903
903
|
description: "A failed statement is isolated and a subsequent statement recovers",
|
|
904
904
|
configured: (env) => Boolean(env.DATABRICKS_WAREHOUSE_ID || env.DATABRICKS_HTTP_PATH),
|
|
905
|
-
async run({ warehouse }) {
|
|
905
|
+
async run({ warehouse: warehouse2 }) {
|
|
906
906
|
let failedAsExpected = false;
|
|
907
907
|
try {
|
|
908
|
-
await
|
|
908
|
+
await warehouse2.query("SELECT * FROM __fabric_experiments_expected_missing_table__");
|
|
909
909
|
} catch {
|
|
910
910
|
failedAsExpected = true;
|
|
911
911
|
}
|
|
912
912
|
if (!failedAsExpected) throw new Error("Injected failure unexpectedly succeeded");
|
|
913
|
-
const rows = await
|
|
913
|
+
const rows = await warehouse2.query("SELECT 1 AS recovered");
|
|
914
914
|
if (Number(rows[0]?.recovered) !== 1) {
|
|
915
915
|
throw new Error("Statement execution did not recover after the injected failure");
|
|
916
916
|
}
|
|
@@ -948,20 +948,20 @@ function backupRestoreCheck() {
|
|
|
948
948
|
id: "backup-restore",
|
|
949
949
|
description: "Delta DEEP CLONE backup restores a dropped scratch table",
|
|
950
950
|
configured: (env) => Boolean(env.DATABRICKS_WAREHOUSE_ID || env.DATABRICKS_HTTP_PATH),
|
|
951
|
-
async run({ warehouse }) {
|
|
952
|
-
const source =
|
|
953
|
-
const backup =
|
|
951
|
+
async run({ warehouse: warehouse2 }) {
|
|
952
|
+
const source = warehouse2.qual(safeName("backup_source"));
|
|
953
|
+
const backup = warehouse2.qual(safeName("backup_clone"));
|
|
954
954
|
try {
|
|
955
|
-
await
|
|
956
|
-
await
|
|
957
|
-
await
|
|
958
|
-
await
|
|
959
|
-
const rows = await
|
|
955
|
+
await warehouse2.exec(`CREATE TABLE ${source} USING DELTA AS SELECT 7 AS value`);
|
|
956
|
+
await warehouse2.exec(`CREATE TABLE ${backup} DEEP CLONE ${source}`);
|
|
957
|
+
await warehouse2.exec(`DROP TABLE ${source}`);
|
|
958
|
+
await warehouse2.exec(`CREATE TABLE ${source} DEEP CLONE ${backup}`);
|
|
959
|
+
const rows = await warehouse2.query(`SELECT value FROM ${source}`);
|
|
960
960
|
if (Number(rows[0]?.value) !== 7) throw new Error("Restored Delta table lost its data");
|
|
961
961
|
return { restoredRows: rows.length, deepClone: true };
|
|
962
962
|
} finally {
|
|
963
|
-
await
|
|
964
|
-
await
|
|
963
|
+
await warehouse2.exec(`DROP TABLE IF EXISTS ${source}`).catch(() => void 0);
|
|
964
|
+
await warehouse2.exec(`DROP TABLE IF EXISTS ${backup}`).catch(() => void 0);
|
|
965
965
|
}
|
|
966
966
|
}
|
|
967
967
|
};
|
|
@@ -971,25 +971,25 @@ function rollbackCheck() {
|
|
|
971
971
|
id: "rollback",
|
|
972
972
|
description: "Delta time-travel rollback restores a known-good table version",
|
|
973
973
|
configured: (env) => Boolean(env.DATABRICKS_WAREHOUSE_ID || env.DATABRICKS_HTTP_PATH),
|
|
974
|
-
async run({ warehouse }) {
|
|
975
|
-
const table =
|
|
974
|
+
async run({ warehouse: warehouse2 }) {
|
|
975
|
+
const table = warehouse2.qual(safeName("rollback_probe"));
|
|
976
976
|
try {
|
|
977
|
-
await
|
|
978
|
-
await
|
|
979
|
-
const history = await
|
|
977
|
+
await warehouse2.exec(`CREATE TABLE ${table} (value INT) USING DELTA`);
|
|
978
|
+
await warehouse2.exec(`INSERT INTO ${table} VALUES (1)`);
|
|
979
|
+
const history = await warehouse2.query(`DESCRIBE HISTORY ${table} LIMIT 1`);
|
|
980
980
|
const knownGoodVersion = Number(history[0]?.version);
|
|
981
981
|
if (!Number.isInteger(knownGoodVersion)) {
|
|
982
982
|
throw new Error("Delta history did not return a known-good version");
|
|
983
983
|
}
|
|
984
|
-
await
|
|
985
|
-
await
|
|
986
|
-
const rows = await
|
|
984
|
+
await warehouse2.exec(`INSERT INTO ${table} VALUES (999)`);
|
|
985
|
+
await warehouse2.exec(`RESTORE TABLE ${table} TO VERSION AS OF ${knownGoodVersion}`);
|
|
986
|
+
const rows = await warehouse2.query(`SELECT value FROM ${table} ORDER BY value`);
|
|
987
987
|
if (rows.length !== 1 || Number(rows[0]?.value) !== 1) {
|
|
988
988
|
throw new Error("Delta rollback did not restore the known-good contents");
|
|
989
989
|
}
|
|
990
990
|
return { knownGoodVersion, restoredRows: rows.length };
|
|
991
991
|
} finally {
|
|
992
|
-
await
|
|
992
|
+
await warehouse2.exec(`DROP TABLE IF EXISTS ${table}`).catch(() => void 0);
|
|
993
993
|
}
|
|
994
994
|
}
|
|
995
995
|
};
|
|
@@ -999,13 +999,13 @@ function serverlessComputeCheck() {
|
|
|
999
999
|
id: "azure-serverless",
|
|
1000
1000
|
description: "Azure Databricks serverless SQL warehouse is enabled and executes SQL",
|
|
1001
1001
|
configured: (env) => Boolean(env.DATABRICKS_WAREHOUSE_ID),
|
|
1002
|
-
async run({ env, client, warehouse }) {
|
|
1002
|
+
async run({ env, client, warehouse: warehouse2 }) {
|
|
1003
1003
|
const id = env.DATABRICKS_WAREHOUSE_ID;
|
|
1004
1004
|
const details = await client.get(`/api/2.0/sql/warehouses/${encodeURIComponent(id)}`);
|
|
1005
1005
|
if (details.enable_serverless_compute !== true) {
|
|
1006
1006
|
throw new Error(`SQL warehouse ${id} is not configured for serverless compute`);
|
|
1007
1007
|
}
|
|
1008
|
-
const rows = await
|
|
1008
|
+
const rows = await warehouse2.query("SELECT current_catalog() AS catalog");
|
|
1009
1009
|
return { warehouseId: id, name: details.name, state: details.state, rows: rows.length };
|
|
1010
1010
|
}
|
|
1011
1011
|
};
|
|
@@ -1100,9 +1100,9 @@ function defineTargetPack(spec) {
|
|
|
1100
1100
|
}
|
|
1101
1101
|
ids.add(check.id);
|
|
1102
1102
|
}
|
|
1103
|
-
for (const
|
|
1104
|
-
if (!ids.has(
|
|
1105
|
-
throw new Error(`Target pack '${spec.id}' requires unknown check '${
|
|
1103
|
+
for (const required3 of spec.requiredChecks ?? []) {
|
|
1104
|
+
if (!ids.has(required3)) {
|
|
1105
|
+
throw new Error(`Target pack '${spec.id}' requires unknown check '${required3}'`);
|
|
1106
1106
|
}
|
|
1107
1107
|
}
|
|
1108
1108
|
return checks;
|
|
@@ -1126,25 +1126,25 @@ function createTargetPackRegistry(packs) {
|
|
|
1126
1126
|
return registry;
|
|
1127
1127
|
}
|
|
1128
1128
|
function doctorTargetPack(pack, env = process.env, requiredChecks = pack.requiredChecks ?? []) {
|
|
1129
|
-
const requirements = (pack.requirements ?? []).map((
|
|
1130
|
-
id:
|
|
1131
|
-
description:
|
|
1132
|
-
satisfied:
|
|
1133
|
-
required:
|
|
1134
|
-
variables: [...
|
|
1129
|
+
const requirements = (pack.requirements ?? []).map((requirement2) => ({
|
|
1130
|
+
id: requirement2.id,
|
|
1131
|
+
description: requirement2.description,
|
|
1132
|
+
satisfied: requirement2.anyOf.some((name) => Boolean(env[name]?.trim())),
|
|
1133
|
+
required: requirement2.required !== false,
|
|
1134
|
+
variables: [...requirement2.anyOf]
|
|
1135
1135
|
}));
|
|
1136
|
-
const
|
|
1136
|
+
const required3 = new Set(requiredChecks);
|
|
1137
1137
|
const checks = pack.checks().map((check) => ({
|
|
1138
1138
|
id: check.id,
|
|
1139
1139
|
description: check.description,
|
|
1140
1140
|
configured: check.configured ? check.configured(env) : true,
|
|
1141
|
-
required:
|
|
1141
|
+
required: required3.has(check.id)
|
|
1142
1142
|
}));
|
|
1143
1143
|
const known = new Set(checks.map((check) => check.id));
|
|
1144
|
-
const missingRequirements = requirements.filter((
|
|
1144
|
+
const missingRequirements = requirements.filter((requirement2) => requirement2.required && !requirement2.satisfied).map((requirement2) => requirement2.id);
|
|
1145
1145
|
const missingRequiredChecks = [
|
|
1146
1146
|
...checks.filter((check) => check.required && !check.configured).map((check) => check.id),
|
|
1147
|
-
...[...
|
|
1147
|
+
...[...required3].filter((id) => !known.has(id))
|
|
1148
1148
|
];
|
|
1149
1149
|
return {
|
|
1150
1150
|
pack: {
|
|
@@ -1495,20 +1495,20 @@ function jobsOrchestrationCheck() {
|
|
|
1495
1495
|
const configured = env.DBX_TEST_JOBS_ORCHESTRATION_JSON;
|
|
1496
1496
|
if (!configured) throw new Error("DBX_TEST_JOBS_ORCHESTRATION_JSON is required");
|
|
1497
1497
|
const spec = parseJobOrchestrationLiveSpec(configured);
|
|
1498
|
-
const
|
|
1499
|
-
const runId = await
|
|
1500
|
-
let run = await
|
|
1498
|
+
const adapter2 = new DatabricksJobsAdapter(client);
|
|
1499
|
+
const runId = await adapter2.submit(spec.request);
|
|
1500
|
+
let run = await adapter2.wait(runId, {
|
|
1501
1501
|
timeoutMs: Number(env.DBX_TEST_TIMEOUT_MS ?? 9e5),
|
|
1502
1502
|
pollIntervalMs: Number(env.DBX_TEST_POLL_INTERVAL_MS ?? 1e4)
|
|
1503
1503
|
});
|
|
1504
1504
|
let repairId;
|
|
1505
1505
|
if (spec.repairFailedTasks && run.resultState !== "SUCCESS") {
|
|
1506
1506
|
const failed = run.tasks.filter((task) => task.resultState === "FAILED").map((task) => task.taskKey);
|
|
1507
|
-
repairId = await
|
|
1507
|
+
repairId = await adapter2.repair(runId, {
|
|
1508
1508
|
rerunTasks: failed.length > 0 ? failed : void 0,
|
|
1509
1509
|
rerunDependentTasks: true
|
|
1510
1510
|
});
|
|
1511
|
-
run = await
|
|
1511
|
+
run = await adapter2.waitForRepair(runId, repairId, {
|
|
1512
1512
|
timeoutMs: Number(env.DBX_TEST_TIMEOUT_MS ?? 9e5),
|
|
1513
1513
|
pollIntervalMs: Number(env.DBX_TEST_POLL_INTERVAL_MS ?? 1e4)
|
|
1514
1514
|
});
|
|
@@ -1528,13 +1528,13 @@ function jobsOrchestrationCheck() {
|
|
|
1528
1528
|
}
|
|
1529
1529
|
let cancellation;
|
|
1530
1530
|
if (spec.cancellation) {
|
|
1531
|
-
const cancellationRunId = await
|
|
1532
|
-
await
|
|
1531
|
+
const cancellationRunId = await adapter2.submit(spec.cancellation.request);
|
|
1532
|
+
await adapter2.waitUntilActive(cancellationRunId, {
|
|
1533
1533
|
timeoutMs: Number(env.DBX_TEST_TIMEOUT_MS ?? 9e5),
|
|
1534
1534
|
pollIntervalMs: Number(env.DBX_TEST_POLL_INTERVAL_MS ?? 1e4)
|
|
1535
1535
|
});
|
|
1536
|
-
await
|
|
1537
|
-
const canceled = await
|
|
1536
|
+
await adapter2.cancel(cancellationRunId);
|
|
1537
|
+
const canceled = await adapter2.wait(cancellationRunId, {
|
|
1538
1538
|
timeoutMs: Number(env.DBX_TEST_TIMEOUT_MS ?? 9e5),
|
|
1539
1539
|
pollIntervalMs: Number(env.DBX_TEST_POLL_INTERVAL_MS ?? 1e4)
|
|
1540
1540
|
});
|
|
@@ -1689,9 +1689,9 @@ function jobsCertificationCheck() {
|
|
|
1689
1689
|
);
|
|
1690
1690
|
try {
|
|
1691
1691
|
await importNotebooks(client, paths);
|
|
1692
|
-
const
|
|
1693
|
-
const runId = await
|
|
1694
|
-
const initial = await
|
|
1692
|
+
const adapter2 = new DatabricksJobsAdapter(client);
|
|
1693
|
+
const runId = await adapter2.submit(certificationRequest(paths));
|
|
1694
|
+
const initial = await adapter2.wait(runId, waitOptions(env));
|
|
1695
1695
|
if (initial.resultState !== "FAILED") {
|
|
1696
1696
|
throw new Error(
|
|
1697
1697
|
`Certification run ${runId} expected FAILED before repair, got ${initial.resultState}`
|
|
@@ -1705,19 +1705,19 @@ function jobsCertificationCheck() {
|
|
|
1705
1705
|
assertTask(initial.tasks, "branch", "SUCCESS");
|
|
1706
1706
|
assertTask(initial.tasks, "foreach", "SUCCESS");
|
|
1707
1707
|
assertTask(initial.tasks, "repair", "FAILED");
|
|
1708
|
-
const repairId = await
|
|
1708
|
+
const repairId = await adapter2.repair(runId, {
|
|
1709
1709
|
rerunTasks: ["repair"],
|
|
1710
1710
|
rerunDependentTasks: true
|
|
1711
1711
|
});
|
|
1712
|
-
const repaired = await
|
|
1712
|
+
const repaired = await adapter2.waitForRepair(runId, repairId, waitOptions(env));
|
|
1713
1713
|
if (repaired.resultState !== "SUCCESS") {
|
|
1714
1714
|
throw new Error(`Certification repair ${repairId} ended in ${repaired.resultState}`);
|
|
1715
1715
|
}
|
|
1716
1716
|
assertTask(repaired.tasks, "repair", "SUCCESS");
|
|
1717
|
-
const cancellationRunId = await
|
|
1718
|
-
await
|
|
1719
|
-
await
|
|
1720
|
-
const canceled = await
|
|
1717
|
+
const cancellationRunId = await adapter2.submit(cancellationRequest(paths));
|
|
1718
|
+
await adapter2.waitUntilActive(cancellationRunId, waitOptions(env));
|
|
1719
|
+
await adapter2.cancel(cancellationRunId);
|
|
1720
|
+
const canceled = await adapter2.wait(cancellationRunId, waitOptions(env));
|
|
1721
1721
|
if (canceled.resultState !== "CANCELED") {
|
|
1722
1722
|
throw new Error(`Certification cancellation ended in ${canceled.resultState}`);
|
|
1723
1723
|
}
|
|
@@ -1885,12 +1885,817 @@ function createLakeflowJobsTargetPack() {
|
|
|
1885
1885
|
});
|
|
1886
1886
|
}
|
|
1887
1887
|
|
|
1888
|
+
// src/advanced-workload-checks.ts
|
|
1889
|
+
var DatabricksAdvancedWorkloadsAdapter = class {
|
|
1890
|
+
constructor(client) {
|
|
1891
|
+
this.client = client;
|
|
1892
|
+
}
|
|
1893
|
+
client;
|
|
1894
|
+
pipeline(id) {
|
|
1895
|
+
return this.client.get(`/api/2.0/pipelines/${segment(id)}`);
|
|
1896
|
+
}
|
|
1897
|
+
table(fullName) {
|
|
1898
|
+
return this.client.get(`/api/2.1/unity-catalog/tables/${segment(fullName)}`);
|
|
1899
|
+
}
|
|
1900
|
+
dashboard(id) {
|
|
1901
|
+
return this.client.get(`/api/2.0/lakeview/dashboards/${segment(id)}`);
|
|
1902
|
+
}
|
|
1903
|
+
genieSpace(id) {
|
|
1904
|
+
return this.client.get(`/api/2.0/genie/spaces/${segment(id)}`);
|
|
1905
|
+
}
|
|
1906
|
+
startGenieConversation(spaceId, question) {
|
|
1907
|
+
return this.client.post(`/api/2.0/genie/spaces/${segment(spaceId)}/start-conversation`, {
|
|
1908
|
+
content: question
|
|
1909
|
+
});
|
|
1910
|
+
}
|
|
1911
|
+
experiment(id) {
|
|
1912
|
+
return this.client.get("/api/2.0/mlflow/experiments/get", { experiment_id: id });
|
|
1913
|
+
}
|
|
1914
|
+
registeredModel(fullName) {
|
|
1915
|
+
return this.client.get(`/api/2.1/unity-catalog/models/${segment(fullName)}`);
|
|
1916
|
+
}
|
|
1917
|
+
modelVersion(fullName, version) {
|
|
1918
|
+
return this.client.get(
|
|
1919
|
+
`/api/2.1/unity-catalog/models/${segment(fullName)}/versions/${segment(version)}`
|
|
1920
|
+
);
|
|
1921
|
+
}
|
|
1922
|
+
onlineTable(fullName) {
|
|
1923
|
+
return this.client.get(`/api/2.0/online-tables/${segment(fullName)}`);
|
|
1924
|
+
}
|
|
1925
|
+
servingEndpoint(name) {
|
|
1926
|
+
return this.client.get(`/api/2.0/serving-endpoints/${segment(name)}`);
|
|
1927
|
+
}
|
|
1928
|
+
invokeServingEndpoint(name, request) {
|
|
1929
|
+
return this.client.post(`/serving-endpoints/${segment(name)}/invocations`, request);
|
|
1930
|
+
}
|
|
1931
|
+
vectorSearchEndpoint(name) {
|
|
1932
|
+
return this.client.get(`/api/2.0/vector-search/endpoints/${segment(name)}`);
|
|
1933
|
+
}
|
|
1934
|
+
vectorSearchIndex(name) {
|
|
1935
|
+
return this.client.get(`/api/2.0/vector-search/indexes/${segment(name)}`);
|
|
1936
|
+
}
|
|
1937
|
+
queryVectorSearchIndex(name, request) {
|
|
1938
|
+
return this.client.post(`/api/2.0/vector-search/indexes/${segment(name)}/query`, request);
|
|
1939
|
+
}
|
|
1940
|
+
connection(name) {
|
|
1941
|
+
return this.client.get(`/api/2.1/unity-catalog/connections/${segment(name)}`);
|
|
1942
|
+
}
|
|
1943
|
+
share(name) {
|
|
1944
|
+
return this.client.get(`/api/2.1/unity-catalog/shares/${segment(name)}`);
|
|
1945
|
+
}
|
|
1946
|
+
cleanRoom(name) {
|
|
1947
|
+
return this.client.get(`/api/2.0/clean-rooms/${segment(name)}`);
|
|
1948
|
+
}
|
|
1949
|
+
ipAccessList(id) {
|
|
1950
|
+
return this.client.get(`/api/2.0/ip-access-lists/${segment(id)}`);
|
|
1951
|
+
}
|
|
1952
|
+
clusterPolicy(id) {
|
|
1953
|
+
return this.client.get("/api/2.0/policies/clusters/get", { policy_id: id });
|
|
1954
|
+
}
|
|
1955
|
+
warehouse(id) {
|
|
1956
|
+
return this.client.get(`/api/2.0/sql/warehouses/${segment(id)}`);
|
|
1957
|
+
}
|
|
1958
|
+
};
|
|
1959
|
+
function segment(value) {
|
|
1960
|
+
return encodeURIComponent(value);
|
|
1961
|
+
}
|
|
1962
|
+
function adapter(client) {
|
|
1963
|
+
return new DatabricksAdvancedWorkloadsAdapter(client);
|
|
1964
|
+
}
|
|
1965
|
+
function required2(env, names) {
|
|
1966
|
+
return names.filter((name) => !env[name]?.trim());
|
|
1967
|
+
}
|
|
1968
|
+
function requireEnv(env, names) {
|
|
1969
|
+
const missing = required2(env, names);
|
|
1970
|
+
if (missing.length > 0) throw new Error(`Missing required configuration: ${missing.join(", ")}`);
|
|
1971
|
+
}
|
|
1972
|
+
function parseJson(value, name) {
|
|
1973
|
+
if (!value) return void 0;
|
|
1974
|
+
try {
|
|
1975
|
+
return JSON.parse(value);
|
|
1976
|
+
} catch {
|
|
1977
|
+
throw new Error(`${name} must contain valid JSON`);
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
function assertNotFailed(label, state) {
|
|
1981
|
+
if (typeof state === "string" && /FAIL|ERROR|DELET/i.test(state)) {
|
|
1982
|
+
throw new Error(`${label} is ${state}`);
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
function assertReady(label, state, accepted) {
|
|
1986
|
+
if (typeof state !== "string" || !accepted.includes(state.toUpperCase())) {
|
|
1987
|
+
throw new Error(`${label} is ${String(state ?? "UNKNOWN")}; expected ${accepted.join(" or ")}`);
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
async function booleanSql(label, sql, query) {
|
|
1991
|
+
if (!sql) return;
|
|
1992
|
+
const rows = await query(sql);
|
|
1993
|
+
const first = rows[0] ? Object.values(rows[0])[0] : void 0;
|
|
1994
|
+
if (!(first === true || first === 1 || first === "1" || first === "true")) {
|
|
1995
|
+
throw new Error(`${label} assertion did not return a truthy first column`);
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
function advancedStreamingCdcCheck() {
|
|
1999
|
+
const names = [
|
|
2000
|
+
"DBX_TEST_STREAMING_PIPELINE_ID",
|
|
2001
|
+
"DBX_TEST_STREAMING_TABLE",
|
|
2002
|
+
"DBX_TEST_CDC_ASSERTION_SQL",
|
|
2003
|
+
"DBX_TEST_STREAMING_ASSERTION_SQL"
|
|
2004
|
+
];
|
|
2005
|
+
return {
|
|
2006
|
+
id: "streaming-cdc",
|
|
2007
|
+
description: "Streaming pipeline, streaming table and CDC assertions are healthy",
|
|
2008
|
+
configured: (env) => required2(env, names).length === 0,
|
|
2009
|
+
async run({ env, client, warehouse: warehouse2 }) {
|
|
2010
|
+
requireEnv(env, names);
|
|
2011
|
+
const api = adapter(client);
|
|
2012
|
+
const pipeline = await api.pipeline(env.DBX_TEST_STREAMING_PIPELINE_ID);
|
|
2013
|
+
assertNotFailed("Streaming pipeline", pipeline.state);
|
|
2014
|
+
const table = await api.table(env.DBX_TEST_STREAMING_TABLE);
|
|
2015
|
+
const tableType = String(table.table_type ?? table.data_source_format ?? "").toUpperCase();
|
|
2016
|
+
if (!["STREAMING_TABLE", "MATERIALIZED_VIEW", "DELTA"].includes(tableType)) {
|
|
2017
|
+
throw new Error(`Streaming target has unsupported table type ${tableType || "UNKNOWN"}`);
|
|
2018
|
+
}
|
|
2019
|
+
await booleanSql("CDC", env.DBX_TEST_CDC_ASSERTION_SQL, warehouse2.query);
|
|
2020
|
+
await booleanSql(
|
|
2021
|
+
"Streaming freshness",
|
|
2022
|
+
env.DBX_TEST_STREAMING_ASSERTION_SQL,
|
|
2023
|
+
warehouse2.query
|
|
2024
|
+
);
|
|
2025
|
+
return { pipelineId: pipeline.pipeline_id, table: env.DBX_TEST_STREAMING_TABLE, tableType };
|
|
2026
|
+
}
|
|
2027
|
+
};
|
|
2028
|
+
}
|
|
2029
|
+
function lakeflowConnectCheck() {
|
|
2030
|
+
const names = ["DBX_TEST_CONNECT_PIPELINE_ID", "DBX_TEST_CONNECT_ASSERTION_SQL"];
|
|
2031
|
+
return {
|
|
2032
|
+
id: "lakeflow-connect",
|
|
2033
|
+
description: "Lakeflow Connect ingestion pipeline exists and is not failed",
|
|
2034
|
+
configured: (env) => required2(env, names).length === 0,
|
|
2035
|
+
async run({ env, client, warehouse: warehouse2 }) {
|
|
2036
|
+
requireEnv(env, names);
|
|
2037
|
+
const id = env.DBX_TEST_CONNECT_PIPELINE_ID;
|
|
2038
|
+
const pipeline = await adapter(client).pipeline(id);
|
|
2039
|
+
assertNotFailed("Lakeflow Connect pipeline", pipeline.state);
|
|
2040
|
+
const ingestion = pipeline.spec?.ingestion_definition;
|
|
2041
|
+
if (!ingestion || !Array.isArray(ingestion.objects) || ingestion.objects.length === 0) {
|
|
2042
|
+
throw new Error("Lakeflow Connect pipeline has no managed ingestion definition");
|
|
2043
|
+
}
|
|
2044
|
+
await booleanSql(
|
|
2045
|
+
"Lakeflow Connect replication",
|
|
2046
|
+
env.DBX_TEST_CONNECT_ASSERTION_SQL,
|
|
2047
|
+
warehouse2.query
|
|
2048
|
+
);
|
|
2049
|
+
return {
|
|
2050
|
+
pipelineId: pipeline.pipeline_id ?? id,
|
|
2051
|
+
state: pipeline.state ?? "IDLE",
|
|
2052
|
+
sourceType: ingestion.source_type ?? "MANAGED_INGESTION",
|
|
2053
|
+
objects: ingestion.objects.length
|
|
2054
|
+
};
|
|
2055
|
+
}
|
|
2056
|
+
};
|
|
2057
|
+
}
|
|
2058
|
+
function aiBiDashboardCheck() {
|
|
2059
|
+
return {
|
|
2060
|
+
id: "aibi-dashboard",
|
|
2061
|
+
description: "Published AI/BI dashboard is accessible",
|
|
2062
|
+
configured: (env) => Boolean(env.DBX_TEST_DASHBOARD_ID),
|
|
2063
|
+
async run({ env, client }) {
|
|
2064
|
+
const dashboard = await adapter(client).dashboard(env.DBX_TEST_DASHBOARD_ID);
|
|
2065
|
+
assertNotFailed("AI/BI dashboard", dashboard.lifecycle_state);
|
|
2066
|
+
return {
|
|
2067
|
+
dashboardId: dashboard.dashboard_id ?? env.DBX_TEST_DASHBOARD_ID,
|
|
2068
|
+
name: dashboard.display_name
|
|
2069
|
+
};
|
|
2070
|
+
}
|
|
2071
|
+
};
|
|
2072
|
+
}
|
|
2073
|
+
function genieCheck() {
|
|
2074
|
+
const names = ["DBX_TEST_GENIE_SPACE_ID", "DBX_TEST_GENIE_QUESTION"];
|
|
2075
|
+
return {
|
|
2076
|
+
id: "genie",
|
|
2077
|
+
description: "Genie space is accessible and can optionally start a grounded conversation",
|
|
2078
|
+
configured: (env) => required2(env, names).length === 0,
|
|
2079
|
+
async run({ env, client }) {
|
|
2080
|
+
requireEnv(env, names);
|
|
2081
|
+
const api = adapter(client);
|
|
2082
|
+
const id = env.DBX_TEST_GENIE_SPACE_ID;
|
|
2083
|
+
const space = await api.genieSpace(id);
|
|
2084
|
+
let conversation;
|
|
2085
|
+
if (env.DBX_TEST_GENIE_QUESTION) {
|
|
2086
|
+
conversation = await api.startGenieConversation(id, env.DBX_TEST_GENIE_QUESTION);
|
|
2087
|
+
if (!conversation.conversation_id && !conversation.message_id) {
|
|
2088
|
+
throw new Error("Genie did not return a conversation or message identifier");
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
return {
|
|
2092
|
+
spaceId: space.space_id ?? id,
|
|
2093
|
+
title: space.title,
|
|
2094
|
+
conversationStarted: Boolean(conversation)
|
|
2095
|
+
};
|
|
2096
|
+
}
|
|
2097
|
+
};
|
|
2098
|
+
}
|
|
2099
|
+
function mlflowLifecycleCheck() {
|
|
2100
|
+
const names = [
|
|
2101
|
+
"DBX_TEST_MLFLOW_EXPERIMENT_ID",
|
|
2102
|
+
"DBX_TEST_REGISTERED_MODEL",
|
|
2103
|
+
"DBX_TEST_MODEL_VERSION"
|
|
2104
|
+
];
|
|
2105
|
+
return {
|
|
2106
|
+
id: "mlflow-lifecycle",
|
|
2107
|
+
description: "MLflow experiment and Unity Catalog model version are accessible",
|
|
2108
|
+
configured: (env) => required2(env, names).length === 0,
|
|
2109
|
+
async run({ env, client }) {
|
|
2110
|
+
requireEnv(env, names);
|
|
2111
|
+
const api = adapter(client);
|
|
2112
|
+
const experiment = await api.experiment(env.DBX_TEST_MLFLOW_EXPERIMENT_ID);
|
|
2113
|
+
const model = await api.registeredModel(env.DBX_TEST_REGISTERED_MODEL);
|
|
2114
|
+
const version = await api.modelVersion(
|
|
2115
|
+
env.DBX_TEST_REGISTERED_MODEL,
|
|
2116
|
+
env.DBX_TEST_MODEL_VERSION
|
|
2117
|
+
);
|
|
2118
|
+
assertNotFailed("Model version", version.status);
|
|
2119
|
+
return {
|
|
2120
|
+
experimentId: experiment.experiment?.experiment_id ?? env.DBX_TEST_MLFLOW_EXPERIMENT_ID,
|
|
2121
|
+
model: model.full_name ?? model.name ?? env.DBX_TEST_REGISTERED_MODEL,
|
|
2122
|
+
version: version.version ?? env.DBX_TEST_MODEL_VERSION
|
|
2123
|
+
};
|
|
2124
|
+
}
|
|
2125
|
+
};
|
|
2126
|
+
}
|
|
2127
|
+
function featureEngineeringServingCheck() {
|
|
2128
|
+
return {
|
|
2129
|
+
id: "feature-engineering",
|
|
2130
|
+
description: "Feature table and online materialization are healthy",
|
|
2131
|
+
configured: (env) => Boolean(
|
|
2132
|
+
env.DBX_TEST_FEATURE_TABLE && env.DBX_TEST_FEATURE_ASSERTION_SQL && (env.DBX_TEST_ONLINE_TABLE || env.DBX_TEST_FEATURE_SERVING_PIPELINE_ID)
|
|
2133
|
+
),
|
|
2134
|
+
async run({ env, client, warehouse: warehouse2 }) {
|
|
2135
|
+
requireEnv(env, ["DBX_TEST_FEATURE_TABLE"]);
|
|
2136
|
+
if (!env.DBX_TEST_ONLINE_TABLE && !env.DBX_TEST_FEATURE_SERVING_PIPELINE_ID) {
|
|
2137
|
+
throw new Error(
|
|
2138
|
+
"Feature serving requires DBX_TEST_ONLINE_TABLE or DBX_TEST_FEATURE_SERVING_PIPELINE_ID"
|
|
2139
|
+
);
|
|
2140
|
+
}
|
|
2141
|
+
const api = adapter(client);
|
|
2142
|
+
const source = await api.table(env.DBX_TEST_FEATURE_TABLE);
|
|
2143
|
+
let state;
|
|
2144
|
+
let servingResource;
|
|
2145
|
+
if (env.DBX_TEST_ONLINE_TABLE) {
|
|
2146
|
+
const online = await api.onlineTable(env.DBX_TEST_ONLINE_TABLE);
|
|
2147
|
+
const status = online.status;
|
|
2148
|
+
state = status?.state ?? status?.detailed_state ?? online.state;
|
|
2149
|
+
assertReady("Online table", state, ["ONLINE", "ACTIVE", "READY", "PROVISIONED"]);
|
|
2150
|
+
servingResource = env.DBX_TEST_ONLINE_TABLE;
|
|
2151
|
+
} else {
|
|
2152
|
+
const pipelineId = env.DBX_TEST_FEATURE_SERVING_PIPELINE_ID;
|
|
2153
|
+
const pipeline = await api.pipeline(pipelineId);
|
|
2154
|
+
state = pipeline.state ?? "IDLE";
|
|
2155
|
+
assertNotFailed("Synced Table pipeline", state);
|
|
2156
|
+
servingResource = pipeline.pipeline_id ?? pipelineId;
|
|
2157
|
+
}
|
|
2158
|
+
await booleanSql("Feature freshness", env.DBX_TEST_FEATURE_ASSERTION_SQL, warehouse2.query);
|
|
2159
|
+
return {
|
|
2160
|
+
featureTable: source.full_name ?? env.DBX_TEST_FEATURE_TABLE,
|
|
2161
|
+
servingResource,
|
|
2162
|
+
state
|
|
2163
|
+
};
|
|
2164
|
+
}
|
|
2165
|
+
};
|
|
2166
|
+
}
|
|
2167
|
+
function modelServingCheck() {
|
|
2168
|
+
const names = [
|
|
2169
|
+
"DBX_TEST_SERVING_ENDPOINT",
|
|
2170
|
+
"DBX_TEST_SERVING_REQUEST_JSON",
|
|
2171
|
+
"DBX_TEST_AI_GATEWAY_REQUIRED"
|
|
2172
|
+
];
|
|
2173
|
+
return {
|
|
2174
|
+
id: "model-serving",
|
|
2175
|
+
description: "Model Serving endpoint is ready and can optionally serve an inference request",
|
|
2176
|
+
configured: (env) => required2(env, names).length === 0,
|
|
2177
|
+
async run({ env, client }) {
|
|
2178
|
+
requireEnv(env, names);
|
|
2179
|
+
if (env.DBX_TEST_AI_GATEWAY_REQUIRED !== "1") {
|
|
2180
|
+
throw new Error("DBX_TEST_AI_GATEWAY_REQUIRED must be 1 for the Model Serving target pack");
|
|
2181
|
+
}
|
|
2182
|
+
const api = adapter(client);
|
|
2183
|
+
const name = env.DBX_TEST_SERVING_ENDPOINT;
|
|
2184
|
+
const endpoint = await api.servingEndpoint(name);
|
|
2185
|
+
assertReady("Serving endpoint", endpoint.state?.ready, ["READY"]);
|
|
2186
|
+
if (env.DBX_TEST_AI_GATEWAY_REQUIRED === "1" && !endpoint.ai_gateway) {
|
|
2187
|
+
throw new Error(`Serving endpoint ${name} has no AI Gateway configuration`);
|
|
2188
|
+
}
|
|
2189
|
+
let response;
|
|
2190
|
+
if (env.DBX_TEST_SERVING_REQUEST_JSON) {
|
|
2191
|
+
response = await api.invokeServingEndpoint(
|
|
2192
|
+
name,
|
|
2193
|
+
parseJson(env.DBX_TEST_SERVING_REQUEST_JSON, "DBX_TEST_SERVING_REQUEST_JSON")
|
|
2194
|
+
);
|
|
2195
|
+
if (Object.keys(response).length === 0)
|
|
2196
|
+
throw new Error("Serving invocation returned an empty response");
|
|
2197
|
+
}
|
|
2198
|
+
return {
|
|
2199
|
+
endpoint: endpoint.name ?? name,
|
|
2200
|
+
ready: endpoint.state?.ready,
|
|
2201
|
+
aiGateway: Boolean(endpoint.ai_gateway),
|
|
2202
|
+
invoked: Boolean(response)
|
|
2203
|
+
};
|
|
2204
|
+
}
|
|
2205
|
+
};
|
|
2206
|
+
}
|
|
2207
|
+
function vectorSearchCheck() {
|
|
2208
|
+
const names = ["DBX_TEST_VECTOR_ENDPOINT", "DBX_TEST_VECTOR_INDEX"];
|
|
2209
|
+
return {
|
|
2210
|
+
id: "vector-search",
|
|
2211
|
+
description: "Vector Search endpoint and index are online",
|
|
2212
|
+
configured: (env) => required2(env, names).length === 0,
|
|
2213
|
+
async run({ env, client }) {
|
|
2214
|
+
requireEnv(env, names);
|
|
2215
|
+
const api = adapter(client);
|
|
2216
|
+
const endpoint = await api.vectorSearchEndpoint(env.DBX_TEST_VECTOR_ENDPOINT);
|
|
2217
|
+
assertReady("Vector Search endpoint", endpoint.endpoint_status?.state, ["ONLINE", "READY"]);
|
|
2218
|
+
const index = await api.vectorSearchIndex(env.DBX_TEST_VECTOR_INDEX);
|
|
2219
|
+
if (index.status?.ready !== true)
|
|
2220
|
+
throw new Error(`Vector Search index is not ready: ${index.status?.message ?? "UNKNOWN"}`);
|
|
2221
|
+
return {
|
|
2222
|
+
endpoint: endpoint.name ?? env.DBX_TEST_VECTOR_ENDPOINT,
|
|
2223
|
+
index: index.name ?? env.DBX_TEST_VECTOR_INDEX,
|
|
2224
|
+
indexedRows: index.status.indexed_row_count
|
|
2225
|
+
};
|
|
2226
|
+
}
|
|
2227
|
+
};
|
|
2228
|
+
}
|
|
2229
|
+
function ragAgentCheck() {
|
|
2230
|
+
const names = [
|
|
2231
|
+
"DBX_TEST_VECTOR_INDEX",
|
|
2232
|
+
"DBX_TEST_VECTOR_QUERY_JSON",
|
|
2233
|
+
"DBX_TEST_AGENT_ENDPOINT",
|
|
2234
|
+
"DBX_TEST_AGENT_REQUEST_JSON"
|
|
2235
|
+
];
|
|
2236
|
+
return {
|
|
2237
|
+
id: "rag-agent",
|
|
2238
|
+
description: "RAG retrieval and agent serving endpoint return non-empty responses",
|
|
2239
|
+
configured: (env) => required2(env, names).length === 0,
|
|
2240
|
+
async run({ env, client }) {
|
|
2241
|
+
requireEnv(env, names);
|
|
2242
|
+
const api = adapter(client);
|
|
2243
|
+
let retrieval;
|
|
2244
|
+
if (env.DBX_TEST_VECTOR_QUERY_JSON) {
|
|
2245
|
+
retrieval = await api.queryVectorSearchIndex(
|
|
2246
|
+
env.DBX_TEST_VECTOR_INDEX,
|
|
2247
|
+
parseJson(env.DBX_TEST_VECTOR_QUERY_JSON, "DBX_TEST_VECTOR_QUERY_JSON")
|
|
2248
|
+
);
|
|
2249
|
+
if (!retrieval.result && !retrieval.data_array && !retrieval.manifest) {
|
|
2250
|
+
throw new Error("Vector query returned no result payload");
|
|
2251
|
+
}
|
|
2252
|
+
}
|
|
2253
|
+
let agent;
|
|
2254
|
+
if (env.DBX_TEST_AGENT_ENDPOINT) {
|
|
2255
|
+
const endpoint = await api.servingEndpoint(env.DBX_TEST_AGENT_ENDPOINT);
|
|
2256
|
+
assertReady("Agent endpoint", endpoint.state?.ready, ["READY"]);
|
|
2257
|
+
if (env.DBX_TEST_AGENT_REQUEST_JSON) {
|
|
2258
|
+
agent = await api.invokeServingEndpoint(
|
|
2259
|
+
env.DBX_TEST_AGENT_ENDPOINT,
|
|
2260
|
+
parseJson(env.DBX_TEST_AGENT_REQUEST_JSON, "DBX_TEST_AGENT_REQUEST_JSON")
|
|
2261
|
+
);
|
|
2262
|
+
if (Object.keys(agent).length === 0)
|
|
2263
|
+
throw new Error("Agent invocation returned an empty response");
|
|
2264
|
+
}
|
|
2265
|
+
}
|
|
2266
|
+
return {
|
|
2267
|
+
retrieval: Boolean(retrieval),
|
|
2268
|
+
agentEndpoint: env.DBX_TEST_AGENT_ENDPOINT,
|
|
2269
|
+
agentInvoked: Boolean(agent)
|
|
2270
|
+
};
|
|
2271
|
+
}
|
|
2272
|
+
};
|
|
2273
|
+
}
|
|
2274
|
+
function federationSharingCleanRoomsCheck() {
|
|
2275
|
+
const names = [
|
|
2276
|
+
"DBX_TEST_CONNECTION",
|
|
2277
|
+
"DBX_TEST_SHARE",
|
|
2278
|
+
"DBX_TEST_CLEAN_ROOM",
|
|
2279
|
+
"DBX_TEST_FEDERATION_ASSERTION_SQL"
|
|
2280
|
+
];
|
|
2281
|
+
return {
|
|
2282
|
+
id: "federation-sharing-cleanrooms",
|
|
2283
|
+
description: "Lakehouse Federation connection, Delta Share and Clean Room are accessible",
|
|
2284
|
+
configured: (env) => required2(env, names).length === 0,
|
|
2285
|
+
async run({ env, client, warehouse: warehouse2 }) {
|
|
2286
|
+
requireEnv(env, names);
|
|
2287
|
+
const api = adapter(client);
|
|
2288
|
+
const connection = await api.connection(env.DBX_TEST_CONNECTION);
|
|
2289
|
+
const share = await api.share(env.DBX_TEST_SHARE);
|
|
2290
|
+
const room = await api.cleanRoom(env.DBX_TEST_CLEAN_ROOM);
|
|
2291
|
+
await booleanSql("Federated query", env.DBX_TEST_FEDERATION_ASSERTION_SQL, warehouse2.query);
|
|
2292
|
+
return {
|
|
2293
|
+
connection: connection.name ?? env.DBX_TEST_CONNECTION,
|
|
2294
|
+
share: share.name ?? env.DBX_TEST_SHARE,
|
|
2295
|
+
cleanRoom: room.name ?? env.DBX_TEST_CLEAN_ROOM
|
|
2296
|
+
};
|
|
2297
|
+
}
|
|
2298
|
+
};
|
|
2299
|
+
}
|
|
2300
|
+
function securityPostureCostCheck() {
|
|
2301
|
+
const names = [
|
|
2302
|
+
"DBX_TEST_IP_ACCESS_LIST_ID",
|
|
2303
|
+
"DBX_TEST_CLUSTER_POLICY_ID",
|
|
2304
|
+
"DBX_TEST_COST_ASSERTION_SQL"
|
|
2305
|
+
];
|
|
2306
|
+
return {
|
|
2307
|
+
id: "security-cost",
|
|
2308
|
+
description: "Network access controls, compute policy and cost guardrail are enforced",
|
|
2309
|
+
configured: (env) => required2(env, names).length === 0,
|
|
2310
|
+
async run({ env, client, warehouse: warehouse2 }) {
|
|
2311
|
+
requireEnv(env, names);
|
|
2312
|
+
const api = adapter(client);
|
|
2313
|
+
const access = await api.ipAccessList(env.DBX_TEST_IP_ACCESS_LIST_ID);
|
|
2314
|
+
if (access.enabled === false) throw new Error("Configured IP access list is disabled");
|
|
2315
|
+
const policy = await api.clusterPolicy(env.DBX_TEST_CLUSTER_POLICY_ID);
|
|
2316
|
+
if (!policy.policy_id && !policy.name)
|
|
2317
|
+
throw new Error("Cluster policy response has no identity");
|
|
2318
|
+
if (env.DBX_TEST_EXPECT_HOST_SUFFIX && !env.DATABRICKS_HOST?.endsWith(env.DBX_TEST_EXPECT_HOST_SUFFIX)) {
|
|
2319
|
+
throw new Error(`Workspace host does not end with ${env.DBX_TEST_EXPECT_HOST_SUFFIX}`);
|
|
2320
|
+
}
|
|
2321
|
+
await booleanSql("Cost guardrail", env.DBX_TEST_COST_ASSERTION_SQL, warehouse2.query);
|
|
2322
|
+
return {
|
|
2323
|
+
ipAccessList: access.list_id ?? env.DBX_TEST_IP_ACCESS_LIST_ID,
|
|
2324
|
+
policy: policy.policy_id ?? policy.name,
|
|
2325
|
+
costGuardrail: "pass"
|
|
2326
|
+
};
|
|
2327
|
+
}
|
|
2328
|
+
};
|
|
2329
|
+
}
|
|
2330
|
+
function regionalDrCheck(options = {}) {
|
|
2331
|
+
const names = [
|
|
2332
|
+
"DBX_TEST_DR_HOST",
|
|
2333
|
+
"DBX_TEST_DR_WAREHOUSE_ID",
|
|
2334
|
+
"DBX_TEST_DR_ASSERTION_SQL"
|
|
2335
|
+
];
|
|
2336
|
+
return {
|
|
2337
|
+
id: "regional-dr",
|
|
2338
|
+
description: "Secondary-region workspace authentication and SQL warehouse are reachable",
|
|
2339
|
+
configured: (env) => required2(env, names).length === 0,
|
|
2340
|
+
async run({ env }) {
|
|
2341
|
+
requireEnv(env, names);
|
|
2342
|
+
const drEnv = {
|
|
2343
|
+
...env,
|
|
2344
|
+
DATABRICKS_HOST: env.DBX_TEST_DR_HOST,
|
|
2345
|
+
DATABRICKS_WAREHOUSE_ID: env.DBX_TEST_DR_WAREHOUSE_ID,
|
|
2346
|
+
DATABRICKS_HTTP_PATH: void 0,
|
|
2347
|
+
DATABRICKS_BEARER: env.DBX_TEST_DR_BEARER,
|
|
2348
|
+
DATABRICKS_TOKEN: env.DBX_TEST_DR_TOKEN,
|
|
2349
|
+
DATABRICKS_CLIENT_ID: env.DBX_TEST_DR_CLIENT_ID ?? env.DATABRICKS_CLIENT_ID,
|
|
2350
|
+
DATABRICKS_CLIENT_SECRET: env.DBX_TEST_DR_CLIENT_SECRET ?? env.DATABRICKS_CLIENT_SECRET
|
|
2351
|
+
};
|
|
2352
|
+
const client = options.clientFactory?.(drEnv) ?? createClientFromEnv(drEnv);
|
|
2353
|
+
const secondary = await adapter(client).warehouse(env.DBX_TEST_DR_WAREHOUSE_ID);
|
|
2354
|
+
assertReady("DR SQL warehouse", secondary.state, ["RUNNING"]);
|
|
2355
|
+
const drWarehouse = await createWorkspaceContext({ env: drEnv, client });
|
|
2356
|
+
try {
|
|
2357
|
+
await booleanSql("Regional DR workload", env.DBX_TEST_DR_ASSERTION_SQL, drWarehouse.query);
|
|
2358
|
+
} finally {
|
|
2359
|
+
await drWarehouse.close();
|
|
2360
|
+
}
|
|
2361
|
+
return {
|
|
2362
|
+
secondaryWorkspace: "reachable",
|
|
2363
|
+
warehouseId: secondary.id ?? env.DBX_TEST_DR_WAREHOUSE_ID,
|
|
2364
|
+
state: secondary.state
|
|
2365
|
+
};
|
|
2366
|
+
}
|
|
2367
|
+
};
|
|
2368
|
+
}
|
|
2369
|
+
|
|
2370
|
+
// src/advanced-target-packs.ts
|
|
2371
|
+
var DOCS2 = "https://experiments.fabric.pro/docs/testing/target-packs/";
|
|
2372
|
+
var AZURE_USER_SCOPE = "Azure Databricks, West US, interactive user OAuth, public network path; existing certification fixtures";
|
|
2373
|
+
var workspace = {
|
|
2374
|
+
id: "workspace",
|
|
2375
|
+
description: "Databricks workspace host",
|
|
2376
|
+
anyOf: ["DATABRICKS_HOST"]
|
|
2377
|
+
};
|
|
2378
|
+
var auth = {
|
|
2379
|
+
id: "authentication",
|
|
2380
|
+
description: "Databricks OAuth, OIDC, bearer, or PAT authentication",
|
|
2381
|
+
anyOf: [
|
|
2382
|
+
"DATABRICKS_BEARER",
|
|
2383
|
+
"DATABRICKS_TOKEN",
|
|
2384
|
+
"DATABRICKS_CLIENT_ID",
|
|
2385
|
+
"DATABRICKS_OIDC_TOKEN",
|
|
2386
|
+
"DATABRICKS_OIDC_TOKEN_FILEPATH"
|
|
2387
|
+
],
|
|
2388
|
+
secret: true
|
|
2389
|
+
};
|
|
2390
|
+
var warehouse = {
|
|
2391
|
+
id: "warehouse",
|
|
2392
|
+
description: "SQL warehouse for data-plane assertions",
|
|
2393
|
+
anyOf: ["DATABRICKS_WAREHOUSE_ID", "DATABRICKS_HTTP_PATH"]
|
|
2394
|
+
};
|
|
2395
|
+
var requirement = (id, description, ...anyOf) => ({
|
|
2396
|
+
id,
|
|
2397
|
+
description,
|
|
2398
|
+
anyOf
|
|
2399
|
+
});
|
|
2400
|
+
function createAdvancedStreamingTargetPack() {
|
|
2401
|
+
return defineTargetPack({
|
|
2402
|
+
id: "streaming-cdc-connect",
|
|
2403
|
+
name: "Advanced streaming, CDC and Lakeflow Connect",
|
|
2404
|
+
description: "Streaming tables, pipeline health, CDC correctness, freshness and managed connector replication.",
|
|
2405
|
+
version: "1.0.0",
|
|
2406
|
+
maturity: "live-gated",
|
|
2407
|
+
capabilities: [
|
|
2408
|
+
"streaming.tables",
|
|
2409
|
+
"streaming.freshness",
|
|
2410
|
+
"cdc.correctness",
|
|
2411
|
+
"lakeflow-connect.replication"
|
|
2412
|
+
],
|
|
2413
|
+
checks: () => [restrictedPrincipalCheck(), advancedStreamingCdcCheck(), lakeflowConnectCheck()],
|
|
2414
|
+
requiredChecks: ["streaming-cdc", "lakeflow-connect"],
|
|
2415
|
+
requirements: [
|
|
2416
|
+
workspace,
|
|
2417
|
+
auth,
|
|
2418
|
+
warehouse,
|
|
2419
|
+
requirement("streaming-pipeline", "Streaming pipeline ID", "DBX_TEST_STREAMING_PIPELINE_ID"),
|
|
2420
|
+
requirement("streaming-table", "Streaming target table", "DBX_TEST_STREAMING_TABLE"),
|
|
2421
|
+
requirement(
|
|
2422
|
+
"connect-pipeline",
|
|
2423
|
+
"Lakeflow Connect ingestion pipeline",
|
|
2424
|
+
"DBX_TEST_CONNECT_PIPELINE_ID"
|
|
2425
|
+
),
|
|
2426
|
+
requirement(
|
|
2427
|
+
"streaming-assertion",
|
|
2428
|
+
"Streaming freshness SQL",
|
|
2429
|
+
"DBX_TEST_STREAMING_ASSERTION_SQL"
|
|
2430
|
+
),
|
|
2431
|
+
requirement("cdc-assertion", "CDC correctness SQL", "DBX_TEST_CDC_ASSERTION_SQL"),
|
|
2432
|
+
requirement(
|
|
2433
|
+
"connect-assertion",
|
|
2434
|
+
"Lakeflow Connect replication SQL",
|
|
2435
|
+
"DBX_TEST_CONNECT_ASSERTION_SQL"
|
|
2436
|
+
)
|
|
2437
|
+
],
|
|
2438
|
+
docsUrl: `${DOCS2}#advanced-streaming-cdc-and-lakeflow-connect`,
|
|
2439
|
+
certificationScopes: [
|
|
2440
|
+
`${AZURE_USER_SCOPE}; serverless Lakeflow pipeline AUTO CDC and query-based PostgreSQL foreign-catalog ingestion`
|
|
2441
|
+
]
|
|
2442
|
+
});
|
|
2443
|
+
}
|
|
2444
|
+
function createAiBiGenieTargetPack() {
|
|
2445
|
+
return defineTargetPack({
|
|
2446
|
+
id: "aibi-genie",
|
|
2447
|
+
name: "AI/BI dashboards and Genie",
|
|
2448
|
+
description: "Dashboard accessibility and authenticated Genie space/conversation behavior.",
|
|
2449
|
+
version: "0.1.0",
|
|
2450
|
+
maturity: "live-gated",
|
|
2451
|
+
capabilities: ["aibi.dashboard", "genie.space", "genie.conversation"],
|
|
2452
|
+
checks: () => [restrictedPrincipalCheck(), aiBiDashboardCheck(), genieCheck()],
|
|
2453
|
+
requiredChecks: ["aibi-dashboard", "genie"],
|
|
2454
|
+
requirements: [
|
|
2455
|
+
workspace,
|
|
2456
|
+
auth,
|
|
2457
|
+
requirement("dashboard", "AI/BI dashboard ID", "DBX_TEST_DASHBOARD_ID"),
|
|
2458
|
+
requirement("genie-space", "Genie space ID", "DBX_TEST_GENIE_SPACE_ID"),
|
|
2459
|
+
requirement(
|
|
2460
|
+
"genie-question",
|
|
2461
|
+
"Grounded Genie certification question",
|
|
2462
|
+
"DBX_TEST_GENIE_QUESTION"
|
|
2463
|
+
)
|
|
2464
|
+
],
|
|
2465
|
+
docsUrl: `${DOCS2}#aibi-dashboards-and-genie`,
|
|
2466
|
+
certificationScopes: [
|
|
2467
|
+
`${AZURE_USER_SCOPE}; AI/BI dashboard metadata and Genie conversation start`
|
|
2468
|
+
]
|
|
2469
|
+
});
|
|
2470
|
+
}
|
|
2471
|
+
function createMlflowLifecycleTargetPack() {
|
|
2472
|
+
return defineTargetPack({
|
|
2473
|
+
id: "mlflow-lifecycle",
|
|
2474
|
+
name: "MLflow and model lifecycle",
|
|
2475
|
+
description: "MLflow experiments plus Unity Catalog registered-model and model-version lifecycle evidence.",
|
|
2476
|
+
version: "0.1.0",
|
|
2477
|
+
maturity: "live-gated",
|
|
2478
|
+
capabilities: [
|
|
2479
|
+
"mlflow.experiments",
|
|
2480
|
+
"models.unity-catalog",
|
|
2481
|
+
"models.versions",
|
|
2482
|
+
"models.lifecycle"
|
|
2483
|
+
],
|
|
2484
|
+
checks: () => [restrictedPrincipalCheck(), mlflowLifecycleCheck()],
|
|
2485
|
+
requiredChecks: ["mlflow-lifecycle"],
|
|
2486
|
+
requirements: [
|
|
2487
|
+
workspace,
|
|
2488
|
+
auth,
|
|
2489
|
+
requirement("experiment", "MLflow experiment ID", "DBX_TEST_MLFLOW_EXPERIMENT_ID"),
|
|
2490
|
+
requirement(
|
|
2491
|
+
"registered-model",
|
|
2492
|
+
"Unity Catalog registered model",
|
|
2493
|
+
"DBX_TEST_REGISTERED_MODEL"
|
|
2494
|
+
),
|
|
2495
|
+
requirement("model-version", "Registered model version", "DBX_TEST_MODEL_VERSION")
|
|
2496
|
+
],
|
|
2497
|
+
docsUrl: `${DOCS2}#mlflow-and-model-lifecycle`,
|
|
2498
|
+
certificationScopes: [
|
|
2499
|
+
`${AZURE_USER_SCOPE}; MLflow experiment and Unity Catalog model version 20`
|
|
2500
|
+
]
|
|
2501
|
+
});
|
|
2502
|
+
}
|
|
2503
|
+
function createFeatureEngineeringTargetPack() {
|
|
2504
|
+
return defineTargetPack({
|
|
2505
|
+
id: "feature-engineering-serving",
|
|
2506
|
+
name: "Feature engineering and serving",
|
|
2507
|
+
description: "Unity Catalog feature tables, online materialization state and freshness assertions.",
|
|
2508
|
+
version: "0.1.0",
|
|
2509
|
+
maturity: "live-gated",
|
|
2510
|
+
capabilities: [
|
|
2511
|
+
"features.tables",
|
|
2512
|
+
"features.online-tables",
|
|
2513
|
+
"features.freshness",
|
|
2514
|
+
"features.serving"
|
|
2515
|
+
],
|
|
2516
|
+
checks: () => [restrictedPrincipalCheck(), featureEngineeringServingCheck()],
|
|
2517
|
+
requiredChecks: ["feature-engineering"],
|
|
2518
|
+
requirements: [
|
|
2519
|
+
workspace,
|
|
2520
|
+
auth,
|
|
2521
|
+
warehouse,
|
|
2522
|
+
requirement("feature-table", "Unity Catalog feature table", "DBX_TEST_FEATURE_TABLE"),
|
|
2523
|
+
requirement(
|
|
2524
|
+
"online-materialization",
|
|
2525
|
+
"Databricks Online Table or Synced Table pipeline",
|
|
2526
|
+
"DBX_TEST_ONLINE_TABLE",
|
|
2527
|
+
"DBX_TEST_FEATURE_SERVING_PIPELINE_ID"
|
|
2528
|
+
),
|
|
2529
|
+
requirement(
|
|
2530
|
+
"feature-assertion",
|
|
2531
|
+
"Feature freshness/correctness SQL",
|
|
2532
|
+
"DBX_TEST_FEATURE_ASSERTION_SQL"
|
|
2533
|
+
)
|
|
2534
|
+
],
|
|
2535
|
+
docsUrl: `${DOCS2}#feature-engineering-and-serving`,
|
|
2536
|
+
certificationScopes: [
|
|
2537
|
+
`${AZURE_USER_SCOPE}; Delta feature table, PostgreSQL-backed Synced Table, and SQL freshness`
|
|
2538
|
+
]
|
|
2539
|
+
});
|
|
2540
|
+
}
|
|
2541
|
+
function createModelServingTargetPack() {
|
|
2542
|
+
return defineTargetPack({
|
|
2543
|
+
id: "model-serving-gateway",
|
|
2544
|
+
name: "Model Serving and AI Gateway",
|
|
2545
|
+
description: "Serving readiness, inference behavior and optional AI Gateway policy presence.",
|
|
2546
|
+
version: "0.1.0",
|
|
2547
|
+
maturity: "live-gated",
|
|
2548
|
+
capabilities: [
|
|
2549
|
+
"model-serving.readiness",
|
|
2550
|
+
"model-serving.inference",
|
|
2551
|
+
"ai-gateway.configuration"
|
|
2552
|
+
],
|
|
2553
|
+
checks: () => [restrictedPrincipalCheck(), modelServingCheck()],
|
|
2554
|
+
requiredChecks: ["model-serving"],
|
|
2555
|
+
requirements: [
|
|
2556
|
+
workspace,
|
|
2557
|
+
auth,
|
|
2558
|
+
requirement("serving-endpoint", "Model Serving endpoint name", "DBX_TEST_SERVING_ENDPOINT"),
|
|
2559
|
+
requirement(
|
|
2560
|
+
"serving-request",
|
|
2561
|
+
"Safe inference request JSON",
|
|
2562
|
+
"DBX_TEST_SERVING_REQUEST_JSON"
|
|
2563
|
+
),
|
|
2564
|
+
requirement(
|
|
2565
|
+
"ai-gateway",
|
|
2566
|
+
"AI Gateway enforcement flag set to 1",
|
|
2567
|
+
"DBX_TEST_AI_GATEWAY_REQUIRED"
|
|
2568
|
+
)
|
|
2569
|
+
],
|
|
2570
|
+
docsUrl: `${DOCS2}#model-serving-and-ai-gateway`,
|
|
2571
|
+
certificationScopes: [
|
|
2572
|
+
`${AZURE_USER_SCOPE}; custom-model inference and AI Gateway inference-table configuration`
|
|
2573
|
+
]
|
|
2574
|
+
});
|
|
2575
|
+
}
|
|
2576
|
+
function createVectorRagAgentsTargetPack() {
|
|
2577
|
+
return defineTargetPack({
|
|
2578
|
+
id: "vector-rag-agents",
|
|
2579
|
+
name: "Vector Search, RAG and agents",
|
|
2580
|
+
description: "Vector endpoint/index readiness, retrieval behavior and agent endpoint inference.",
|
|
2581
|
+
version: "0.1.0",
|
|
2582
|
+
maturity: "live-gated",
|
|
2583
|
+
capabilities: [
|
|
2584
|
+
"vector-search.endpoint",
|
|
2585
|
+
"vector-search.index",
|
|
2586
|
+
"rag.retrieval",
|
|
2587
|
+
"agents.serving"
|
|
2588
|
+
],
|
|
2589
|
+
checks: () => [restrictedPrincipalCheck(), vectorSearchCheck(), ragAgentCheck()],
|
|
2590
|
+
requiredChecks: ["vector-search", "rag-agent"],
|
|
2591
|
+
requirements: [
|
|
2592
|
+
workspace,
|
|
2593
|
+
auth,
|
|
2594
|
+
requirement("vector-endpoint", "Vector Search endpoint", "DBX_TEST_VECTOR_ENDPOINT"),
|
|
2595
|
+
requirement("vector-index", "Vector Search index", "DBX_TEST_VECTOR_INDEX"),
|
|
2596
|
+
requirement("vector-query", "Vector retrieval request JSON", "DBX_TEST_VECTOR_QUERY_JSON"),
|
|
2597
|
+
requirement("agent-endpoint", "Agent serving endpoint", "DBX_TEST_AGENT_ENDPOINT"),
|
|
2598
|
+
requirement("agent-request", "Safe agent request JSON", "DBX_TEST_AGENT_REQUEST_JSON")
|
|
2599
|
+
],
|
|
2600
|
+
docsUrl: `${DOCS2}#vector-search-rag-and-agents`,
|
|
2601
|
+
certificationScopes: [
|
|
2602
|
+
`${AZURE_USER_SCOPE}; Delta Sync vector retrieval and custom PyFunc agent invocation`
|
|
2603
|
+
]
|
|
2604
|
+
});
|
|
2605
|
+
}
|
|
2606
|
+
function createFederationSharingTargetPack() {
|
|
2607
|
+
return defineTargetPack({
|
|
2608
|
+
id: "federation-sharing-cleanrooms",
|
|
2609
|
+
name: "Federation, Delta Sharing and Clean Rooms",
|
|
2610
|
+
description: "Federated connection, data-plane query, Delta Share and Clean Room governance access.",
|
|
2611
|
+
version: "1.0.0",
|
|
2612
|
+
maturity: "live-gated",
|
|
2613
|
+
capabilities: [
|
|
2614
|
+
"federation.connections",
|
|
2615
|
+
"federation.query",
|
|
2616
|
+
"delta-sharing.shares",
|
|
2617
|
+
"clean-rooms.access"
|
|
2618
|
+
],
|
|
2619
|
+
checks: () => [restrictedPrincipalCheck(), federationSharingCleanRoomsCheck()],
|
|
2620
|
+
requiredChecks: ["federation-sharing-cleanrooms"],
|
|
2621
|
+
requirements: [
|
|
2622
|
+
workspace,
|
|
2623
|
+
auth,
|
|
2624
|
+
warehouse,
|
|
2625
|
+
requirement("connection", "Lakehouse Federation connection", "DBX_TEST_CONNECTION"),
|
|
2626
|
+
requirement("share", "Delta Sharing share", "DBX_TEST_SHARE"),
|
|
2627
|
+
requirement("clean-room", "Clean Room name", "DBX_TEST_CLEAN_ROOM"),
|
|
2628
|
+
requirement(
|
|
2629
|
+
"federation-assertion",
|
|
2630
|
+
"Federated data-plane SQL",
|
|
2631
|
+
"DBX_TEST_FEDERATION_ASSERTION_SQL"
|
|
2632
|
+
)
|
|
2633
|
+
],
|
|
2634
|
+
docsUrl: `${DOCS2}#federation-delta-sharing-and-clean-rooms`,
|
|
2635
|
+
certificationScopes: [
|
|
2636
|
+
`${AZURE_USER_SCOPE}; managed PostgreSQL federation, Delta Sharing table, and two-metastore Clean Room`
|
|
2637
|
+
]
|
|
2638
|
+
});
|
|
2639
|
+
}
|
|
2640
|
+
function createSecurityCostDrTargetPack() {
|
|
2641
|
+
return defineTargetPack({
|
|
2642
|
+
id: "security-cost-dr",
|
|
2643
|
+
name: "Networking, security posture, cost and regional DR",
|
|
2644
|
+
description: "IP controls, compute policy, cost guardrail and authenticated secondary-region readiness.",
|
|
2645
|
+
version: "1.0.0",
|
|
2646
|
+
maturity: "live-gated",
|
|
2647
|
+
capabilities: [
|
|
2648
|
+
"network.ip-access",
|
|
2649
|
+
"security.compute-policy",
|
|
2650
|
+
"cost.system-tables",
|
|
2651
|
+
"dr.secondary-region"
|
|
2652
|
+
],
|
|
2653
|
+
checks: () => [restrictedPrincipalCheck(), securityPostureCostCheck(), regionalDrCheck()],
|
|
2654
|
+
requiredChecks: ["security-cost", "regional-dr"],
|
|
2655
|
+
requirements: [
|
|
2656
|
+
workspace,
|
|
2657
|
+
auth,
|
|
2658
|
+
warehouse,
|
|
2659
|
+
requirement(
|
|
2660
|
+
"ip-access-list",
|
|
2661
|
+
"Enabled workspace IP access list",
|
|
2662
|
+
"DBX_TEST_IP_ACCESS_LIST_ID"
|
|
2663
|
+
),
|
|
2664
|
+
requirement("cluster-policy", "Compute policy ID", "DBX_TEST_CLUSTER_POLICY_ID"),
|
|
2665
|
+
requirement("cost-assertion", "Boolean SQL cost guardrail", "DBX_TEST_COST_ASSERTION_SQL"),
|
|
2666
|
+
requirement("dr-workspace", "Secondary workspace host", "DBX_TEST_DR_HOST"),
|
|
2667
|
+
requirement("dr-warehouse", "Running secondary-region warehouse", "DBX_TEST_DR_WAREHOUSE_ID"),
|
|
2668
|
+
requirement("dr-assertion", "Secondary-region workload SQL", "DBX_TEST_DR_ASSERTION_SQL")
|
|
2669
|
+
],
|
|
2670
|
+
docsUrl: `${DOCS2}#networking-security-cost-and-regional-dr`,
|
|
2671
|
+
certificationScopes: [
|
|
2672
|
+
`${AZURE_USER_SCOPE}; TEST-NET block list, bounded compute policy, billing system-table guardrail, and West US 3 serverless DR warehouse`
|
|
2673
|
+
]
|
|
2674
|
+
});
|
|
2675
|
+
}
|
|
2676
|
+
function createAdvancedTargetPacks() {
|
|
2677
|
+
return [
|
|
2678
|
+
createAdvancedStreamingTargetPack(),
|
|
2679
|
+
createAiBiGenieTargetPack(),
|
|
2680
|
+
createMlflowLifecycleTargetPack(),
|
|
2681
|
+
createFeatureEngineeringTargetPack(),
|
|
2682
|
+
createModelServingTargetPack(),
|
|
2683
|
+
createVectorRagAgentsTargetPack(),
|
|
2684
|
+
createFederationSharingTargetPack(),
|
|
2685
|
+
createSecurityCostDrTargetPack()
|
|
2686
|
+
];
|
|
2687
|
+
}
|
|
2688
|
+
|
|
1888
2689
|
// src/builtin-packs.ts
|
|
1889
2690
|
function createBuiltinTargetPacks() {
|
|
1890
|
-
return [
|
|
2691
|
+
return [
|
|
2692
|
+
...createFoundationTargetPacks(),
|
|
2693
|
+
createLakeflowJobsTargetPack(),
|
|
2694
|
+
...createAdvancedTargetPacks()
|
|
2695
|
+
];
|
|
1891
2696
|
}
|
|
1892
2697
|
var builtinTargetPacks = createBuiltinTargetPacks();
|
|
1893
2698
|
|
|
1894
|
-
export { DatabricksJobsAdapter, appHealthCheck, assertDeltaContract, autoLoaderIngestionCheck, backupRestoreCheck, builtinTargetPacks, classicComputeCheck, createAppsOperationalFoundationPack, createBuiltinTargetPacks, createEphemeralLakebaseBranch, createExecutionContext, createFoundationTargetPacks, createJobsCodeFoundationPack, createLakebaseTestProvider, createLakeflowFoundationPack, createLakeflowJobsTargetPack, createMockDatabricksClient, createSqlDeltaFoundationPack, createTargetPackRegistry, createUnityStorageFoundationPack, customLiveCheck, dbtBuildCheck, defineLiveSuite, defineTargetPack, defineTargetPackRun, deleteEphemeralLakebaseBranch, deleteVolumeFile, deltaContractCheck, doctorTargetPack, ensureVolumeDirectory, expectQueryToMatchGolden, expectTable, failureRecoveryCheck, foundationTargetPacks, jobRunCheck, jobsCertificationCheck, jobsOrchestrationCheck, lakebaseCredentialCheck, lakebaseRoundTripCheck, normalizeJobRun, normalizeVolumeRoot, notebookSubmitCheck, parseJobOrchestrationLiveSpec, performanceBudgetCheck, pipelineRefreshCheck, renderJUnit, resolveLakebaseProject, resolveProfile, restrictedPrincipalCheck, rollbackCheck, runLiveSuite, runTargetPack, secretRotationCheck, secretScopeCheck, serverlessComputeCheck, sqlRoundTripCheck, toLakebaseBranchId, unityCatalogAccessCheck, uploadVolumeFile, validateJobGraph, volumeIOCheck, waitForPipelineUpdate };
|
|
2699
|
+
export { DatabricksAdvancedWorkloadsAdapter, DatabricksJobsAdapter, advancedStreamingCdcCheck, aiBiDashboardCheck, appHealthCheck, assertDeltaContract, autoLoaderIngestionCheck, backupRestoreCheck, builtinTargetPacks, classicComputeCheck, createAdvancedStreamingTargetPack, createAdvancedTargetPacks, createAiBiGenieTargetPack, createAppsOperationalFoundationPack, createBuiltinTargetPacks, createEphemeralLakebaseBranch, createExecutionContext, createFeatureEngineeringTargetPack, createFederationSharingTargetPack, createFoundationTargetPacks, createJobsCodeFoundationPack, createLakebaseTestProvider, createLakeflowFoundationPack, createLakeflowJobsTargetPack, createMlflowLifecycleTargetPack, createMockDatabricksClient, createModelServingTargetPack, createSecurityCostDrTargetPack, createSqlDeltaFoundationPack, createTargetPackRegistry, createUnityStorageFoundationPack, createVectorRagAgentsTargetPack, customLiveCheck, dbtBuildCheck, defineLiveSuite, defineTargetPack, defineTargetPackRun, deleteEphemeralLakebaseBranch, deleteVolumeFile, deltaContractCheck, doctorTargetPack, ensureVolumeDirectory, expectQueryToMatchGolden, expectTable, failureRecoveryCheck, featureEngineeringServingCheck, federationSharingCleanRoomsCheck, foundationTargetPacks, genieCheck, jobRunCheck, jobsCertificationCheck, jobsOrchestrationCheck, lakebaseCredentialCheck, lakebaseRoundTripCheck, lakeflowConnectCheck, mlflowLifecycleCheck, modelServingCheck, normalizeJobRun, normalizeVolumeRoot, notebookSubmitCheck, parseJobOrchestrationLiveSpec, performanceBudgetCheck, pipelineRefreshCheck, ragAgentCheck, regionalDrCheck, renderJUnit, resolveLakebaseProject, resolveProfile, restrictedPrincipalCheck, rollbackCheck, runLiveSuite, runTargetPack, secretRotationCheck, secretScopeCheck, securityPostureCostCheck, serverlessComputeCheck, sqlRoundTripCheck, toLakebaseBranchId, unityCatalogAccessCheck, uploadVolumeFile, validateJobGraph, vectorSearchCheck, volumeIOCheck, waitForPipelineUpdate };
|
|
1895
2700
|
//# sourceMappingURL=index.js.map
|
|
1896
2701
|
//# sourceMappingURL=index.js.map
|