@runa-ai/runa-cli 0.10.2 → 0.10.4
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/dist/{build-P2A6345N.js → build-C65G2QQE.js} +3 -2
- package/dist/{chunk-UHDAYPHH.js → chunk-47BG6DRP.js} +1 -1
- package/dist/chunk-AYYHYZU7.js +3636 -0
- package/dist/{chunk-MAFJAA2P.js → chunk-C3SRIUWX.js} +1 -1
- package/dist/{chunk-QSEF4T3Y.js → chunk-F2AQ3EYJ.js} +10 -199
- package/dist/chunk-NOXYPVMZ.js +204 -0
- package/dist/{chunk-LCJNIHZY.js → chunk-OUMW5LKJ.js} +4745 -7689
- package/dist/{chunk-IR7SA2ME.js → chunk-WIT46HVC.js} +1 -1
- package/dist/{chunk-XFXGFUAM.js → chunk-XVGMGFKF.js} +1 -1
- package/dist/{chunk-WGRVAGSR.js → chunk-ZDETCPCE.js} +2 -2
- package/dist/{ci-6XYG7XNX.js → ci-Q4PLRFPB.js} +11 -9
- package/dist/{cli-2XL3VESS.js → cli-LS2THG3F.js} +12 -12
- package/dist/commands/db/apply/helpers/plan-check-filter.d.ts +1 -1
- package/dist/commands/db/sync/schema-guardrail-graph.d.ts +2 -0
- package/dist/commands/db/sync/schema-guardrail-rewrite.d.ts +8 -0
- package/dist/commands/db/sync/schema-guardrail-types.d.ts +2 -2
- package/dist/commands/db/utils/function-acl-manifest.d.ts +39 -0
- package/dist/{db-4AGPISOW.js → db-MB3LQIGI.js} +226 -166
- package/dist/{dev-QR55VDNZ.js → dev-N3BFJZ7F.js} +3 -2
- package/dist/{env-KYR6Q7WO.js → env-2XM45E7O.js} +4 -3
- package/dist/{env-XPPACZM4.js → env-KIMSQSPS.js} +3 -2
- package/dist/helpers-PDT3WQNF.js +15 -0
- package/dist/{hotfix-JYHDY2M6.js → hotfix-QP5J6FCD.js} +4 -3
- package/dist/index.js +3 -3
- package/dist/local-supabase-KTTC3O2L.js +8 -0
- package/dist/{risk-detector-GDDLISVE.js → risk-detector-4D5HRUMY.js} +1 -1
- package/dist/{risk-detector-core-YI3M6INI.js → risk-detector-core-CHUY6M5N.js} +1 -1
- package/dist/{vuln-check-LMDYYJUE.js → vuln-check-JSPRI5ZY.js} +1 -1
- package/dist/{vuln-checker-NHXLNZRM.js → vuln-checker-H3VJY5WX.js} +1 -1
- package/dist/{watch-4RHXVCQ3.js → watch-VQQHKDNQ.js} +1 -1
- package/package.json +1 -1
- package/dist/{risk-detector-plpgsql-4GWEQXUG.js → risk-detector-plpgsql-NNUZU3OQ.js} +1 -1
|
@@ -1,30 +1,32 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'module';
|
|
3
|
-
import { detectDatabaseStack, getStackPaths } from './chunk-MILCC3B6.js';
|
|
4
|
-
import { categorizeRisks, detectSchemaRisks } from './chunk-XFXGFUAM.js';
|
|
5
|
-
import { isExecaError, resolveDbPreviewEnvironment, buildDbPlanCommandLabel, runDbApply, buildDbApplyCliError, DbPlanOutputSchema, parseDbPreviewProfile, DEFAULT_DB_PREVIEW_PROFILE, getDbPreviewModeLabel, buildDbPreviewCommandLabel, isCompareOnlyPreviewProfile, DbApplyOutputSchema, applyCommand, getDbPreviewIdempotentSchemaCount, classifyDbSyncCommandFailure, getDbSyncFallbackSuggestions, detectAppSchemas, normalizeDatabaseUrlForDdl, analyzeDuplicateFunctionOwnership, formatDuplicateFunctionOwnershipFinding, reviewDeclarativeDependencyWarnings, logDeclarativeDependencyWarnings, buildDeclarativeDependencyWarningFailureLines, parsePlanOutput, validateDependencyOrder, getBoundaryPolicy, resolveProductionApplyStrictMode, findDeclarativeRiskAllowlistMatch, assertBoundaryPolicyUsable, assertBoundaryPolicyQualityGate, formatSchemasForSql, findDirectoryPlacementAllowlistMatch, formatAllowlistMetadata, assessPlanSize, formatPlanSizeSummary, extractFunctionOwnershipDefinition } from './chunk-LCJNIHZY.js';
|
|
6
3
|
import { createError } from './chunk-NIS77243.js';
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
import './chunk-
|
|
4
|
+
import { detectDatabaseStack, getStackPaths } from './chunk-MILCC3B6.js';
|
|
5
|
+
import { categorizeRisks, detectSchemaRisks } from './chunk-XVGMGFKF.js';
|
|
6
|
+
import { isExecaError, resolveDbPreviewEnvironment, buildDbPlanCommandLabel, runDbApply, buildDbApplyCliError, parseDbPreviewProfile, DEFAULT_DB_PREVIEW_PROFILE, getDbPreviewModeLabel, buildDbPreviewCommandLabel, isCompareOnlyPreviewProfile, applyCommand, getDbPreviewIdempotentSchemaCount, classifyDbSyncCommandFailure, getDbSyncFallbackSuggestions, reviewDeclarativeDependencyWarnings, logDeclarativeDependencyWarnings, buildDeclarativeDependencyWarningFailureLines, getBoundaryPolicy, resolveProductionApplyStrictMode, findDeclarativeRiskAllowlistMatch, assertBoundaryPolicyUsable, assertBoundaryPolicyQualityGate, findDirectoryPlacementAllowlistMatch, formatAllowlistMetadata, assessPlanSize, formatPlanSizeSummary } from './chunk-AYYHYZU7.js';
|
|
7
|
+
import { DbPlanOutputSchema, DbApplyOutputSchema, detectAppSchemas, normalizeDatabaseUrlForDdl, analyzeDuplicateFunctionOwnership, formatDuplicateFunctionOwnershipFinding, parsePlanOutput, validateDependencyOrder, formatSchemasForSql, FUNCTION_ACL_RECONCILIATION_RELATIVE_PATH, functionAclManifestHasEntries, validateFunctionAclMigration, isManagedFunctionAclFileContentStale, renderFunctionAclFile, buildFunctionAclManifestFromSqlFiles, buildFunctionAclIdempotentTouchMetadata, stableSorted, normalizePolicyCommand, normalizeFileList, extractFunctionOwnershipDefinition, SECURITY_DEFINER_RE, MANAGED_BOUNDARY_SCHEMAS, currentIsoTimestamp, makeGraphVersion, GENERATOR_VERSION, MAX_SCHEMA_GUIDANCE_TARGETS_PER_FILE, QUALIFIED_SQL_OBJECT_RE, SEARCH_PATH_LOCK_RE, TRIGGER_GUIDANCE_SUPPRESSED_FUNCTIONS, SQL_EXTENSION_IDENTIFIER_PATTERN, SQL_IDENTIFIER_PATTERN } from './chunk-OUMW5LKJ.js';
|
|
11
8
|
import './chunk-EZ46JIEO.js';
|
|
9
|
+
import { resolveDatabaseUrl, resolveDatabaseTarget, tryResolveDatabaseUrl } from './chunk-ZDETCPCE.js';
|
|
10
|
+
export { resolveDatabaseUrl, tryResolveDatabaseUrl } from './chunk-ZDETCPCE.js';
|
|
11
|
+
import { analyzeDeclarativeDependencyContract, formatDeclarativeDependencyViolation, parseSqlFilename, collectSqlFiles, splitSqlStatements, ALLOW_DYNAMIC_SQL_ANNOTATION, extractFirstDollarBody, sanitizeExecutableCode, detectExtensionFilePath, FUNCTION_DEFINITION_RE, blankQuotedStrings, sanitizeExecutableCodePreserveStrings, countNewlines, shouldReviewUnknownDeclarativeDdl, extractDdlObject, isNonSchemaOperation, isNonDdlMaintenanceStatement, shouldReviewUnknownIdempotentDdl } from './chunk-HWR5NUUZ.js';
|
|
12
|
+
import './chunk-47BG6DRP.js';
|
|
13
|
+
import { writeEnvLocalBridge, removeEnvLocalBridge } from './chunk-KUH3G522.js';
|
|
14
|
+
import { extractSchemaTablesAndEnums, fetchDbTablesAndEnums, extractTablesFromIdempotentSql, extractDynamicTablePatternsFromIdempotentSql, diffSchema, getSqlParserUtils, buildTablePatternMatcher } from './chunk-O3M7A73M.js';
|
|
15
|
+
import { psqlExec, psqlQuery, blankDollarQuotedBodies, stripSqlComments, parsePostgresUrl, buildPsqlArgs, buildPsqlEnv } from './chunk-A6A7JIRD.js';
|
|
12
16
|
import { loadEnvFiles } from './chunk-IWVXI5O4.js';
|
|
13
|
-
import './chunk-
|
|
17
|
+
import './chunk-WIT46HVC.js';
|
|
14
18
|
import { diagnoseSupabaseStart } from './chunk-AAIE4F2U.js';
|
|
15
19
|
import { validateUserFilePath, filterSafePaths, resolveSafePath } from './chunk-B7C7CLW2.js';
|
|
16
20
|
import { runMachine } from './chunk-QDF7QXBL.js';
|
|
17
21
|
import './chunk-XVNDDHAF.js';
|
|
18
|
-
import { writeEnvLocalBridge, removeEnvLocalBridge } from './chunk-KUH3G522.js';
|
|
19
|
-
import { extractSchemaTablesAndEnums, fetchDbTablesAndEnums, extractTablesFromIdempotentSql, extractDynamicTablePatternsFromIdempotentSql, diffSchema, getSqlParserUtils, buildTablePatternMatcher } from './chunk-O3M7A73M.js';
|
|
20
|
-
import { psqlExec, psqlQuery, blankDollarQuotedBodies, stripSqlComments, parsePostgresUrl, buildPsqlArgs, buildPsqlEnv } from './chunk-A6A7JIRD.js';
|
|
21
22
|
import { redactSecrets } from './chunk-II7VYQEM.js';
|
|
22
|
-
import {
|
|
23
|
-
export { DATABASE_DEFAULTS, SCRIPT_LOCATIONS, SEED_DEFAULTS } from './chunk-
|
|
23
|
+
import { init_constants, DATABASE_DEFAULTS, SEED_DEFAULTS, SCRIPT_LOCATIONS } from './chunk-NOXYPVMZ.js';
|
|
24
|
+
export { DATABASE_DEFAULTS, SCRIPT_LOCATIONS, SEED_DEFAULTS } from './chunk-NOXYPVMZ.js';
|
|
24
25
|
import { secureSupabase, secureDocker } from './chunk-RZLYEO4U.js';
|
|
25
26
|
import { emitJsonSuccess } from './chunk-KE6QJBZG.js';
|
|
26
27
|
import './chunk-WJXC4MVY.js';
|
|
27
28
|
import { getOutputFormatFromEnv } from './chunk-HKUWEGUX.js';
|
|
29
|
+
import { init_local_supabase, detectLocalSupabasePorts, buildLocalDatabaseUrl } from './chunk-F2AQ3EYJ.js';
|
|
28
30
|
import { getDatabasePackagePath, loadRunaConfig, getSDKScriptsPath } from './chunk-OERS32LW.js';
|
|
29
31
|
import { findRunaConfig, findWorkspaceRoot } from './chunk-GT5DMS5R.js';
|
|
30
32
|
import { init_esm_shims } from './chunk-VRXHCR5K.js';
|
|
@@ -1145,7 +1147,8 @@ z.object({
|
|
|
1145
1147
|
});
|
|
1146
1148
|
var SchemaManagedBlockKindSchema = z.enum([
|
|
1147
1149
|
"file-header",
|
|
1148
|
-
"table-header"
|
|
1150
|
+
"table-header",
|
|
1151
|
+
"generated-file"
|
|
1149
1152
|
]);
|
|
1150
1153
|
var SchemaGuardrailPhaseIdSchema = z.enum([
|
|
1151
1154
|
"load_sources",
|
|
@@ -1166,6 +1169,7 @@ var SchemaGuardrailFailureCodeSchema = z.enum([
|
|
|
1166
1169
|
"dynamic_sql_blocked",
|
|
1167
1170
|
"extension_placement_blocked",
|
|
1168
1171
|
"stale_generated_header",
|
|
1172
|
+
"function_acl_migration_required",
|
|
1169
1173
|
"generated_header_validation_failed",
|
|
1170
1174
|
"generated_header_rewrite_failed",
|
|
1171
1175
|
"static_graph_build_failed",
|
|
@@ -1509,39 +1513,46 @@ function buildGuardrailConflictEntries(report, entries) {
|
|
|
1509
1513
|
pushSemanticEvidenceEntries(entries, report);
|
|
1510
1514
|
pushBoundaryGuidanceEntries(entries, report);
|
|
1511
1515
|
}
|
|
1512
|
-
function
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1516
|
+
function describeStaleBlock(block) {
|
|
1517
|
+
return block.kind === "file-header" ? "file metadata" : block.kind === "generated-file" ? "managed file body" : `table: ${block.target}`;
|
|
1518
|
+
}
|
|
1519
|
+
function pushStaleArtifactEntries(report, entries) {
|
|
1520
|
+
if (report.staleBlocks.length === 0) {
|
|
1521
|
+
return;
|
|
1522
|
+
}
|
|
1523
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
1524
|
+
for (const block of report.staleBlocks) {
|
|
1525
|
+
const kinds = byFile.get(block.file) ?? [];
|
|
1526
|
+
kinds.push(describeStaleBlock(block));
|
|
1527
|
+
byFile.set(block.file, kinds);
|
|
1528
|
+
}
|
|
1529
|
+
entries.push({
|
|
1530
|
+
level: "warn",
|
|
1531
|
+
message: `Generated SQL artifacts are stale (${report.staleBlocks.length} block(s) in ${byFile.size} file(s)):`
|
|
1532
|
+
});
|
|
1533
|
+
for (const [file, kinds] of byFile) {
|
|
1520
1534
|
entries.push({
|
|
1521
|
-
level: "
|
|
1522
|
-
message: `
|
|
1535
|
+
level: "info",
|
|
1536
|
+
message: ` ${file}: ${kinds.join(", ")}`
|
|
1537
|
+
});
|
|
1538
|
+
}
|
|
1539
|
+
if (!report.failure) {
|
|
1540
|
+
entries.push({
|
|
1541
|
+
level: "info",
|
|
1542
|
+
message: "Auto-fix: Run `runa db sync` to regenerate managed SQL artifacts automatically."
|
|
1543
|
+
});
|
|
1544
|
+
entries.push({
|
|
1545
|
+
level: "info",
|
|
1546
|
+
message: "Managed SQL artifacts track: FK references, RLS policies, triggers, function ownership, schema dependencies, and function ACL reconciliation."
|
|
1523
1547
|
});
|
|
1524
|
-
for (const [file, kinds] of byFile) {
|
|
1525
|
-
entries.push({
|
|
1526
|
-
level: "info",
|
|
1527
|
-
message: ` ${file}: ${kinds.join(", ")}`
|
|
1528
|
-
});
|
|
1529
|
-
}
|
|
1530
|
-
if (!report.failure) {
|
|
1531
|
-
entries.push({
|
|
1532
|
-
level: "info",
|
|
1533
|
-
message: "Auto-fix: Run `runa db sync` to regenerate all headers automatically."
|
|
1534
|
-
});
|
|
1535
|
-
entries.push({
|
|
1536
|
-
level: "info",
|
|
1537
|
-
message: "Headers track: FK references, RLS policies, triggers, function ownership, and schema dependencies."
|
|
1538
|
-
});
|
|
1539
|
-
}
|
|
1540
1548
|
}
|
|
1549
|
+
}
|
|
1550
|
+
function buildGuardrailHeaderEntries(report, entries) {
|
|
1551
|
+
pushStaleArtifactEntries(report, entries);
|
|
1541
1552
|
if (report.headersRewritten.length > 0) {
|
|
1542
1553
|
entries.push({
|
|
1543
1554
|
level: "info",
|
|
1544
|
-
message: `Generated
|
|
1555
|
+
message: `Generated SQL artifacts refreshed in ${report.headersRewritten.length} file(s).`
|
|
1545
1556
|
});
|
|
1546
1557
|
}
|
|
1547
1558
|
}
|
|
@@ -2797,7 +2808,7 @@ function normalizeAllowlistSignature(value) {
|
|
|
2797
2808
|
function normalizeSuppressionPair(value) {
|
|
2798
2809
|
return value.split("::").map((part) => part.trim().toLowerCase()).filter((part) => part.length > 0).sort((left, right) => left.localeCompare(right)).join("::");
|
|
2799
2810
|
}
|
|
2800
|
-
function
|
|
2811
|
+
function normalizeFileList2(files) {
|
|
2801
2812
|
return [...new Set(files)].sort((a, b) => a.localeCompare(b));
|
|
2802
2813
|
}
|
|
2803
2814
|
function isSchemaGuardrailTextFallbackAllowed() {
|
|
@@ -2859,7 +2870,7 @@ function loadSchemaGuardrailConfig(targetDir) {
|
|
|
2859
2870
|
// Fallback: merge schema-ownership.json allowed_duplicates if present
|
|
2860
2871
|
...loadAllowedDuplicatesFromSchemaOwnership(targetDir)
|
|
2861
2872
|
],
|
|
2862
|
-
generatedHeaderRewriteTargets:
|
|
2873
|
+
generatedHeaderRewriteTargets: normalizeFileList2(
|
|
2863
2874
|
(databaseConfig.schemaGuardrails?.generatedHeaderRewriteTargets ?? []).map(
|
|
2864
2875
|
(value) => normalizePathForMatch(value)
|
|
2865
2876
|
)
|
|
@@ -2884,7 +2895,7 @@ function loadSchemaGuardrailConfig(targetDir) {
|
|
|
2884
2895
|
defaults,
|
|
2885
2896
|
normalizers: {
|
|
2886
2897
|
normalizeAllowlistSignature,
|
|
2887
|
-
normalizeFileList,
|
|
2898
|
+
normalizeFileList: normalizeFileList2,
|
|
2888
2899
|
normalizeFunctionQualifiedName,
|
|
2889
2900
|
normalizePathForMatch,
|
|
2890
2901
|
normalizeSuppressionPair
|
|
@@ -4196,7 +4207,7 @@ init_esm_shims();
|
|
|
4196
4207
|
var riskDetectorLoader = null;
|
|
4197
4208
|
function loadRiskDetectorModule() {
|
|
4198
4209
|
if (!riskDetectorLoader) {
|
|
4199
|
-
riskDetectorLoader = import('./risk-detector-
|
|
4210
|
+
riskDetectorLoader = import('./risk-detector-4D5HRUMY.js').then((module) => ({
|
|
4200
4211
|
detectSchemaRisks: module.detectSchemaRisks
|
|
4201
4212
|
})).catch((error) => {
|
|
4202
4213
|
riskDetectorLoader = null;
|
|
@@ -5441,7 +5452,7 @@ init_esm_shims();
|
|
|
5441
5452
|
|
|
5442
5453
|
// src/commands/db/sync/schema-guardrail-runtime.ts
|
|
5443
5454
|
init_esm_shims();
|
|
5444
|
-
function
|
|
5455
|
+
function stableSorted2(values, map) {
|
|
5445
5456
|
return [...values].sort((a, b) => map(a).localeCompare(map(b)));
|
|
5446
5457
|
}
|
|
5447
5458
|
function normalizeFkSet(foreignKeys) {
|
|
@@ -5563,8 +5574,8 @@ function reconcileRuntimeGraph(params) {
|
|
|
5563
5574
|
});
|
|
5564
5575
|
}
|
|
5565
5576
|
return {
|
|
5566
|
-
warnings:
|
|
5567
|
-
contradictions:
|
|
5577
|
+
warnings: stableSorted2(warnings, (value) => value.target),
|
|
5578
|
+
contradictions: stableSorted2(contradictions, (value) => `${value.code}.${value.target}`)
|
|
5568
5579
|
};
|
|
5569
5580
|
}
|
|
5570
5581
|
function runSchemaGuardrailRuntime(input) {
|
|
@@ -5594,7 +5605,7 @@ function runSchemaGuardrailRuntime(input) {
|
|
|
5594
5605
|
|
|
5595
5606
|
// src/commands/db/sync/schema-guardrail-local-blockers.ts
|
|
5596
5607
|
init_esm_shims();
|
|
5597
|
-
function
|
|
5608
|
+
function stableSorted3(values, keyOf) {
|
|
5598
5609
|
return [...values].sort((left, right) => keyOf(left).localeCompare(keyOf(right)));
|
|
5599
5610
|
}
|
|
5600
5611
|
function createCrossSchemaHelperSuggestion(_filePath) {
|
|
@@ -5623,7 +5634,7 @@ function buildRawCrossSchemaRlsBlockers(params) {
|
|
|
5623
5634
|
});
|
|
5624
5635
|
}
|
|
5625
5636
|
}
|
|
5626
|
-
return
|
|
5637
|
+
return stableSorted3(
|
|
5627
5638
|
blockers,
|
|
5628
5639
|
(value) => `${value.sourceFile}:${value.line ?? 0}:${value.target}`
|
|
5629
5640
|
);
|
|
@@ -5650,7 +5661,7 @@ function buildExtensionPlacementBlockers(params) {
|
|
|
5650
5661
|
});
|
|
5651
5662
|
}
|
|
5652
5663
|
}
|
|
5653
|
-
return
|
|
5664
|
+
return stableSorted3(
|
|
5654
5665
|
blockers,
|
|
5655
5666
|
(value) => `${value.sourceFile}:${value.line ?? 0}:${value.target}`
|
|
5656
5667
|
);
|
|
@@ -5741,7 +5752,7 @@ function buildDynamicSqlBlockers(params) {
|
|
|
5741
5752
|
blockers.push(...stmtBlockers);
|
|
5742
5753
|
}
|
|
5743
5754
|
}
|
|
5744
|
-
return
|
|
5755
|
+
return stableSorted3(blockers, (value) => `${value.sourceFile}:${value.line ?? 0}:${value.kind}`);
|
|
5745
5756
|
}
|
|
5746
5757
|
function buildLocalBlindSpotBlockers(params) {
|
|
5747
5758
|
const blockers = [
|
|
@@ -5758,7 +5769,7 @@ function buildLocalBlindSpotBlockers(params) {
|
|
|
5758
5769
|
requiredFile: detectExtensionFilePath()
|
|
5759
5770
|
})
|
|
5760
5771
|
];
|
|
5761
|
-
return
|
|
5772
|
+
return stableSorted3(
|
|
5762
5773
|
blockers,
|
|
5763
5774
|
(value) => `${value.kind}:${value.sourceFile}:${value.line ?? 0}:${value.target}`
|
|
5764
5775
|
);
|
|
@@ -5766,7 +5777,7 @@ function buildLocalBlindSpotBlockers(params) {
|
|
|
5766
5777
|
|
|
5767
5778
|
// src/commands/db/sync/schema-guardrail-semantic-warnings.ts
|
|
5768
5779
|
init_esm_shims();
|
|
5769
|
-
function
|
|
5780
|
+
function stableSorted4(values, map) {
|
|
5770
5781
|
return [...values].sort((a, b) => map(a).localeCompare(map(b)));
|
|
5771
5782
|
}
|
|
5772
5783
|
function normalizeFkSet2(foreignKeys) {
|
|
@@ -5971,50 +5982,7 @@ function buildSemanticDuplicateWarnings(params) {
|
|
|
5971
5982
|
suppressionKey: createSuppressionPair(proposed.qualifiedName, primary.qualifiedName)
|
|
5972
5983
|
});
|
|
5973
5984
|
}
|
|
5974
|
-
return
|
|
5975
|
-
}
|
|
5976
|
-
|
|
5977
|
-
// src/commands/db/sync/schema-guardrail-graph-types.ts
|
|
5978
|
-
init_esm_shims();
|
|
5979
|
-
var GENERATOR_VERSION = "1.0.0";
|
|
5980
|
-
var SQL_IDENTIFIER_PATTERN = /"(?:[^"]|"")+"|[A-Za-z_][A-Za-z0-9_$]*/g;
|
|
5981
|
-
var SQL_EXTENSION_IDENTIFIER_PATTERN = /"(?:[^"]|"")+"|[A-Za-z0-9_-]+/g;
|
|
5982
|
-
var QUALIFIED_SQL_OBJECT_RE = /\b([A-Za-z_][A-Za-z0-9_$]*)\s*\.\s*([A-Za-z_][A-Za-z0-9_$]*)\b/g;
|
|
5983
|
-
var SECURITY_DEFINER_RE = /\bSECURITY\s+DEFINER\b/i;
|
|
5984
|
-
var SEARCH_PATH_LOCK_RE = /\bSET\s+search_path\s*(?:=|TO)\s*''/i;
|
|
5985
|
-
var MANAGED_BOUNDARY_SCHEMAS = [
|
|
5986
|
-
"auth",
|
|
5987
|
-
"storage",
|
|
5988
|
-
"extensions",
|
|
5989
|
-
"net",
|
|
5990
|
-
"supabase_functions"
|
|
5991
|
-
];
|
|
5992
|
-
var TRIGGER_GUIDANCE_SUPPRESSED_FUNCTIONS = /* @__PURE__ */ new Set(["public.handle_updated_at()"]);
|
|
5993
|
-
var MAX_SCHEMA_GUIDANCE_TARGETS_PER_FILE = 3;
|
|
5994
|
-
function makeGraphVersion(graph) {
|
|
5995
|
-
const canonical = JSON.stringify(graph);
|
|
5996
|
-
const hash = createHash("sha256").update(canonical).digest("hex");
|
|
5997
|
-
return `sha256:${hash}`;
|
|
5998
|
-
}
|
|
5999
|
-
function currentIsoTimestamp() {
|
|
6000
|
-
return (/* @__PURE__ */ new Date()).toISOString();
|
|
6001
|
-
}
|
|
6002
|
-
function stableSorted4(values, map) {
|
|
6003
|
-
return [...values].sort((a, b) => map(a).localeCompare(map(b)));
|
|
6004
|
-
}
|
|
6005
|
-
function normalizeFileList2(files) {
|
|
6006
|
-
return [...new Set(files)].sort((a, b) => a.localeCompare(b));
|
|
6007
|
-
}
|
|
6008
|
-
function normalizePolicyCommand(input) {
|
|
6009
|
-
switch (input.toLowerCase()) {
|
|
6010
|
-
case "select":
|
|
6011
|
-
case "insert":
|
|
6012
|
-
case "update":
|
|
6013
|
-
case "delete":
|
|
6014
|
-
return input.toLowerCase();
|
|
6015
|
-
default:
|
|
6016
|
-
return "all";
|
|
6017
|
-
}
|
|
5985
|
+
return stableSorted4(warnings, (value) => `${value.proposedTable}.${value.suppressionKey}`);
|
|
6018
5986
|
}
|
|
6019
5987
|
|
|
6020
5988
|
// src/commands/db/sync/schema-guardrail-graph-nodes.ts
|
|
@@ -6060,8 +6028,8 @@ function collectQualifiedObjectRefs(params) {
|
|
|
6060
6028
|
schemas.add(schema);
|
|
6061
6029
|
}
|
|
6062
6030
|
return {
|
|
6063
|
-
refs:
|
|
6064
|
-
schemas:
|
|
6031
|
+
refs: stableSorted(refs, (value) => value),
|
|
6032
|
+
schemas: stableSorted(schemas, (value) => value)
|
|
6065
6033
|
};
|
|
6066
6034
|
}
|
|
6067
6035
|
function isSearchPathLocked(statement) {
|
|
@@ -6099,7 +6067,7 @@ function buildDefinedFunctionMetadataByFile(params) {
|
|
|
6099
6067
|
}
|
|
6100
6068
|
metadataByFile.set(
|
|
6101
6069
|
file.relativePath,
|
|
6102
|
-
|
|
6070
|
+
stableSorted(fileMetadata, (value) => value.qualifiedSignature)
|
|
6103
6071
|
);
|
|
6104
6072
|
}
|
|
6105
6073
|
return metadataByFile;
|
|
@@ -6193,13 +6161,13 @@ async function buildDeclarativeFileRecord(file) {
|
|
|
6193
6161
|
file,
|
|
6194
6162
|
declaredSchemas: [...declaredSchemas].sort((a, b) => a.localeCompare(b)),
|
|
6195
6163
|
createSchemaClaims: [...createSchemaClaims].sort((a, b) => a.localeCompare(b)),
|
|
6196
|
-
tables:
|
|
6164
|
+
tables: stableSorted(
|
|
6197
6165
|
document.tables.map((table) => ({
|
|
6198
6166
|
schema: table.schema,
|
|
6199
6167
|
name: table.name,
|
|
6200
6168
|
qualifiedName: table.qualifiedName,
|
|
6201
6169
|
lineNumber: table.lineNumber,
|
|
6202
|
-
columns:
|
|
6170
|
+
columns: stableSorted(table.columns, (value) => value.name).map((value) => value.name),
|
|
6203
6171
|
outboundForeignKeys: table.foreignKeys.map((fk) => ({
|
|
6204
6172
|
column: fk.column,
|
|
6205
6173
|
referencesTable: fk.referencesTable,
|
|
@@ -6210,7 +6178,7 @@ async function buildDeclarativeFileRecord(file) {
|
|
|
6210
6178
|
})),
|
|
6211
6179
|
(value) => value.qualifiedName
|
|
6212
6180
|
),
|
|
6213
|
-
policies:
|
|
6181
|
+
policies: stableSorted(
|
|
6214
6182
|
document.policies.map((policy) => ({
|
|
6215
6183
|
name: policy.name,
|
|
6216
6184
|
targetTable: `${policy.schema}.${policy.table}`,
|
|
@@ -6264,10 +6232,10 @@ function collectDeclarativeClaims(records) {
|
|
|
6264
6232
|
};
|
|
6265
6233
|
}
|
|
6266
6234
|
function createDuplicateTableOwners(tableOwnerClaims) {
|
|
6267
|
-
return
|
|
6235
|
+
return stableSorted(
|
|
6268
6236
|
[...tableOwnerClaims.entries()].filter(([, files]) => files.size > 1).map(([qualifiedName, files]) => ({
|
|
6269
6237
|
qualifiedName,
|
|
6270
|
-
files:
|
|
6238
|
+
files: normalizeFileList(files)
|
|
6271
6239
|
})),
|
|
6272
6240
|
(value) => value.qualifiedName
|
|
6273
6241
|
);
|
|
@@ -6281,7 +6249,7 @@ function buildFunctionValidationArtifacts(params) {
|
|
|
6281
6249
|
...buildFunctionBodyHashMap(params.declarativeFiles, "declarative"),
|
|
6282
6250
|
...buildFunctionBodyHashMap(params.idempotentFiles, "idempotent")
|
|
6283
6251
|
]);
|
|
6284
|
-
const duplicateFunctionOwners =
|
|
6252
|
+
const duplicateFunctionOwners = stableSorted(
|
|
6285
6253
|
functionAnalysis.findings.filter(
|
|
6286
6254
|
(finding) => !isAllowlistedDuplicateFunction({
|
|
6287
6255
|
finding,
|
|
@@ -6291,16 +6259,16 @@ function buildFunctionValidationArtifacts(params) {
|
|
|
6291
6259
|
).map((finding) => ({
|
|
6292
6260
|
qualifiedName: finding.qualifiedName,
|
|
6293
6261
|
signature: finding.signature,
|
|
6294
|
-
declarativeFiles:
|
|
6262
|
+
declarativeFiles: normalizeFileList(
|
|
6295
6263
|
finding.declarativeDefinitions.map((value) => value.file)
|
|
6296
6264
|
),
|
|
6297
|
-
idempotentFiles:
|
|
6265
|
+
idempotentFiles: normalizeFileList(
|
|
6298
6266
|
finding.idempotentDefinitions.map((value) => value.file)
|
|
6299
6267
|
)
|
|
6300
6268
|
})),
|
|
6301
6269
|
(value) => `${value.qualifiedName}.${value.signature ?? ""}`
|
|
6302
6270
|
);
|
|
6303
|
-
const functionClaims =
|
|
6271
|
+
const functionClaims = stableSorted(
|
|
6304
6272
|
[
|
|
6305
6273
|
...functionAnalysis.definitions.declarative.map((definition) => ({
|
|
6306
6274
|
qualifiedName: definition.qualifiedName,
|
|
@@ -6329,7 +6297,7 @@ function buildFunctionValidationArtifacts(params) {
|
|
|
6329
6297
|
function buildOwnerFileByTable(tableOwnerClaims) {
|
|
6330
6298
|
const ownerFileByTable = /* @__PURE__ */ new Map();
|
|
6331
6299
|
for (const [qualifiedName, files] of tableOwnerClaims.entries()) {
|
|
6332
|
-
const normalizedFiles =
|
|
6300
|
+
const normalizedFiles = normalizeFileList(files);
|
|
6333
6301
|
if (normalizedFiles[0]) {
|
|
6334
6302
|
ownerFileByTable.set(qualifiedName, normalizedFiles[0]);
|
|
6335
6303
|
}
|
|
@@ -6349,7 +6317,7 @@ function buildPolicyOwnershipConflicts(params) {
|
|
|
6349
6317
|
conflicts.push({
|
|
6350
6318
|
policyName: policyClaim.name,
|
|
6351
6319
|
targetTable: policyClaim.targetTable,
|
|
6352
|
-
files:
|
|
6320
|
+
files: normalizeFileList([policyClaim.sourceFile]),
|
|
6353
6321
|
tableOwnerFile: ownerFile
|
|
6354
6322
|
});
|
|
6355
6323
|
}
|
|
@@ -6360,11 +6328,11 @@ function buildPolicyOwnershipConflicts(params) {
|
|
|
6360
6328
|
conflicts.push({
|
|
6361
6329
|
policyName,
|
|
6362
6330
|
targetTable,
|
|
6363
|
-
files:
|
|
6331
|
+
files: normalizeFileList(files),
|
|
6364
6332
|
tableOwnerFile: params.ownerFileByTable.get(targetTable) ?? ""
|
|
6365
6333
|
});
|
|
6366
6334
|
}
|
|
6367
|
-
return
|
|
6335
|
+
return stableSorted(
|
|
6368
6336
|
conflicts,
|
|
6369
6337
|
(value) => `${value.targetTable}.${value.policyName}.${value.files.join(",")}`
|
|
6370
6338
|
);
|
|
@@ -6380,16 +6348,16 @@ function buildTableNodesByName(params) {
|
|
|
6380
6348
|
ownerFile: record.file.relativePath,
|
|
6381
6349
|
lineNumber: table.lineNumber,
|
|
6382
6350
|
columns: table.columns,
|
|
6383
|
-
outboundForeignKeys:
|
|
6351
|
+
outboundForeignKeys: stableSorted(
|
|
6384
6352
|
table.outboundForeignKeys,
|
|
6385
6353
|
(value) => `${value.referencesTable}.${value.column}`
|
|
6386
6354
|
),
|
|
6387
6355
|
inboundForeignKeys: [],
|
|
6388
|
-
policies:
|
|
6356
|
+
policies: stableSorted(
|
|
6389
6357
|
params.tablePolicies.get(table.qualifiedName) ?? [],
|
|
6390
6358
|
(value) => value.name
|
|
6391
6359
|
),
|
|
6392
|
-
triggers:
|
|
6360
|
+
triggers: stableSorted(
|
|
6393
6361
|
record.triggersByTable.get(table.qualifiedName) ?? [],
|
|
6394
6362
|
(value) => value.name
|
|
6395
6363
|
)
|
|
@@ -6413,7 +6381,7 @@ function attachInboundForeignKeys(tableNodesByName) {
|
|
|
6413
6381
|
}
|
|
6414
6382
|
}
|
|
6415
6383
|
for (const tableNode of tableNodesByName.values()) {
|
|
6416
|
-
tableNode.inboundForeignKeys =
|
|
6384
|
+
tableNode.inboundForeignKeys = stableSorted(
|
|
6417
6385
|
tableNode.inboundForeignKeys,
|
|
6418
6386
|
(value) => `${value.fromTable}.${value.fromColumn}`
|
|
6419
6387
|
);
|
|
@@ -6432,12 +6400,12 @@ function buildFileDependencies(params) {
|
|
|
6432
6400
|
fileDependencyMap.set(tableNode.ownerFile, edges);
|
|
6433
6401
|
}
|
|
6434
6402
|
}
|
|
6435
|
-
return
|
|
6403
|
+
return stableSorted(
|
|
6436
6404
|
[...fileDependencyMap.entries()].flatMap(
|
|
6437
6405
|
([fromFile, toMap]) => [...toMap.entries()].map(([toFile, viaTables]) => ({
|
|
6438
6406
|
fromFile,
|
|
6439
6407
|
toFile,
|
|
6440
|
-
viaTables:
|
|
6408
|
+
viaTables: normalizeFileList(viaTables)
|
|
6441
6409
|
}))
|
|
6442
6410
|
),
|
|
6443
6411
|
(value) => `${value.fromFile}->${value.toFile}`
|
|
@@ -6459,7 +6427,7 @@ function buildFileNodes(params) {
|
|
|
6459
6427
|
["22_observability_cron.sql", "cron-registration"],
|
|
6460
6428
|
["25_storage_seed_bucket.sql", "storage-bootstrap"]
|
|
6461
6429
|
]);
|
|
6462
|
-
return
|
|
6430
|
+
return stableSorted(
|
|
6463
6431
|
[
|
|
6464
6432
|
...params.records.map((record) => {
|
|
6465
6433
|
const definedFunctions = params.definedFunctionMetadataByFile.get(record.file.relativePath) ?? [];
|
|
@@ -6469,7 +6437,7 @@ function buildFileNodes(params) {
|
|
|
6469
6437
|
schemas: [],
|
|
6470
6438
|
refs: []
|
|
6471
6439
|
};
|
|
6472
|
-
const triggerFunctions =
|
|
6440
|
+
const triggerFunctions = stableSorted(
|
|
6473
6441
|
new Set(
|
|
6474
6442
|
[...record.triggersByTable.values()].flat().map((trigger) => normalizeTriggerFunctionToken(trigger.functionName)).filter((value) => value !== null)
|
|
6475
6443
|
),
|
|
@@ -6482,7 +6450,7 @@ function buildFileNodes(params) {
|
|
|
6482
6450
|
domainName: path12.basename(record.file.relativePath, ".sql"),
|
|
6483
6451
|
declaredSchemas: record.declaredSchemas,
|
|
6484
6452
|
ownedTables: record.tables.map((table) => table.qualifiedName),
|
|
6485
|
-
forwardDependsOnFiles:
|
|
6453
|
+
forwardDependsOnFiles: stableSorted(
|
|
6486
6454
|
params.fileDependencies.filter((edge) => edge.fromFile === record.file.relativePath).map((edge) => edge.toFile),
|
|
6487
6455
|
(value) => value
|
|
6488
6456
|
),
|
|
@@ -6490,7 +6458,7 @@ function buildFileNodes(params) {
|
|
|
6490
6458
|
securityDefinerFunctions: definedFunctions.filter((value) => value.securityDefiner).map((value) => value.qualifiedSignature),
|
|
6491
6459
|
securityDefinerContracts: definedFunctions.filter((value) => value.securityDefiner && value.searchPathLocked).map((value) => value.qualifiedSignature),
|
|
6492
6460
|
triggerFunctions,
|
|
6493
|
-
functionCrossSchemaRefs:
|
|
6461
|
+
functionCrossSchemaRefs: stableSorted(
|
|
6494
6462
|
new Set(definedFunctions.flatMap((value) => value.crossSchemaRefs)),
|
|
6495
6463
|
(value) => value
|
|
6496
6464
|
),
|
|
@@ -6500,7 +6468,7 @@ function buildFileNodes(params) {
|
|
|
6500
6468
|
touchedExtensions: [],
|
|
6501
6469
|
touchedFunctions: [],
|
|
6502
6470
|
touchedPolicies: [],
|
|
6503
|
-
policyCrossSchemaRefs:
|
|
6471
|
+
policyCrossSchemaRefs: stableSorted(
|
|
6504
6472
|
new Set(
|
|
6505
6473
|
collectPolicyCrossSchemaReferences({
|
|
6506
6474
|
content: record.file.content,
|
|
@@ -6537,7 +6505,7 @@ function buildFileNodes(params) {
|
|
|
6537
6505
|
securityDefinerFunctions: definedFunctions.filter((value) => value.securityDefiner).map((value) => value.qualifiedSignature),
|
|
6538
6506
|
securityDefinerContracts: definedFunctions.filter((value) => value.securityDefiner && value.searchPathLocked).map((value) => value.qualifiedSignature),
|
|
6539
6507
|
triggerFunctions: [],
|
|
6540
|
-
functionCrossSchemaRefs:
|
|
6508
|
+
functionCrossSchemaRefs: stableSorted(
|
|
6541
6509
|
new Set(definedFunctions.flatMap((value) => value.crossSchemaRefs)),
|
|
6542
6510
|
(value) => value
|
|
6543
6511
|
),
|
|
@@ -6700,7 +6668,7 @@ function extractTouchedSchemas(content) {
|
|
|
6700
6668
|
}
|
|
6701
6669
|
}
|
|
6702
6670
|
}
|
|
6703
|
-
return
|
|
6671
|
+
return stableSorted(touched, (value) => value);
|
|
6704
6672
|
}
|
|
6705
6673
|
function extractTouchedFunctions(content) {
|
|
6706
6674
|
const touched = /* @__PURE__ */ new Set();
|
|
@@ -6717,7 +6685,7 @@ function extractTouchedFunctions(content) {
|
|
|
6717
6685
|
}
|
|
6718
6686
|
}
|
|
6719
6687
|
}
|
|
6720
|
-
return
|
|
6688
|
+
return stableSorted(touched, (value) => value);
|
|
6721
6689
|
}
|
|
6722
6690
|
function normalizeExtensionIdentifier(identifier) {
|
|
6723
6691
|
const trimmed = identifier.trim();
|
|
@@ -6740,7 +6708,7 @@ function extractTouchedExtensions(content) {
|
|
|
6740
6708
|
}
|
|
6741
6709
|
touched.add(normalizeExtensionIdentifier(identifier));
|
|
6742
6710
|
}
|
|
6743
|
-
return
|
|
6711
|
+
return stableSorted(touched, (value) => value);
|
|
6744
6712
|
}
|
|
6745
6713
|
function extractTouchedPolicies(content) {
|
|
6746
6714
|
const touched = /* @__PURE__ */ new Set();
|
|
@@ -6754,7 +6722,7 @@ function extractTouchedPolicies(content) {
|
|
|
6754
6722
|
}
|
|
6755
6723
|
touched.add(`${schemaName}.${tableName}.${policyName}`);
|
|
6756
6724
|
}
|
|
6757
|
-
return
|
|
6725
|
+
return stableSorted(touched, (value) => value);
|
|
6758
6726
|
}
|
|
6759
6727
|
function extractIdempotentTouchMetadata(file) {
|
|
6760
6728
|
const sanitizedContent = sanitizeIdempotentTouchScanContent(file.content);
|
|
@@ -6772,7 +6740,7 @@ function buildIdempotentTouchMetadata(files) {
|
|
|
6772
6740
|
// src/commands/db/sync/schema-guardrail-graph-guidance.ts
|
|
6773
6741
|
init_esm_shims();
|
|
6774
6742
|
function summarizeBoundaryTargets(targets) {
|
|
6775
|
-
const sortedTargets =
|
|
6743
|
+
const sortedTargets = stableSorted(new Set(targets), (value) => value);
|
|
6776
6744
|
if (sortedTargets.length <= 2) {
|
|
6777
6745
|
return sortedTargets.join(", ");
|
|
6778
6746
|
}
|
|
@@ -6925,7 +6893,7 @@ function buildUnlockedSecurityDefinerGuidanceWarnings(params) {
|
|
|
6925
6893
|
return [];
|
|
6926
6894
|
}
|
|
6927
6895
|
const lockedContracts = new Set(params.fileNode.securityDefinerContracts);
|
|
6928
|
-
const unlockedFunctions =
|
|
6896
|
+
const unlockedFunctions = stableSorted(
|
|
6929
6897
|
params.fileNode.securityDefinerFunctions.filter(
|
|
6930
6898
|
(qualifiedName) => !lockedContracts.has(qualifiedName)
|
|
6931
6899
|
),
|
|
@@ -6989,7 +6957,7 @@ function buildSecurityDefinerGuidanceWarnings(params) {
|
|
|
6989
6957
|
if (!suggestedIdempotentFile || !targets) {
|
|
6990
6958
|
return [];
|
|
6991
6959
|
}
|
|
6992
|
-
const touchedSecurityDefiners =
|
|
6960
|
+
const touchedSecurityDefiners = stableSorted(
|
|
6993
6961
|
new Set(targets.filter((target) => securityDefinerSet.has(target))),
|
|
6994
6962
|
(value) => value
|
|
6995
6963
|
);
|
|
@@ -7077,7 +7045,7 @@ function buildBoundaryGuidanceWarnings(params) {
|
|
|
7077
7045
|
);
|
|
7078
7046
|
continue;
|
|
7079
7047
|
}
|
|
7080
|
-
const touchedSchemas =
|
|
7048
|
+
const touchedSchemas = stableSorted(new Set(fileNode.touchedSchemas), (value) => value);
|
|
7081
7049
|
if (touchedSchemas.length <= MAX_SCHEMA_GUIDANCE_TARGETS_PER_FILE) {
|
|
7082
7050
|
for (const schema of touchedSchemas) {
|
|
7083
7051
|
const ownerFile = schemaOwnerByName.get(schema);
|
|
@@ -7114,7 +7082,7 @@ function buildBoundaryGuidanceWarnings(params) {
|
|
|
7114
7082
|
reason: "This idempotent file applies policy DDL against a table that is structurally owned in declarative SQL."
|
|
7115
7083
|
});
|
|
7116
7084
|
}
|
|
7117
|
-
return
|
|
7085
|
+
return stableSorted(
|
|
7118
7086
|
warnings,
|
|
7119
7087
|
(value) => `${value.sourceFile}.${value.kind}.${value.suggestedDeclarativeFile ?? ""}.${value.suggestedIdempotentFile ?? ""}.${value.target}`
|
|
7120
7088
|
);
|
|
@@ -7190,7 +7158,7 @@ function validateDispatchCoverage(argsByFunction, sources) {
|
|
|
7190
7158
|
}
|
|
7191
7159
|
}
|
|
7192
7160
|
}
|
|
7193
|
-
return
|
|
7161
|
+
return stableSorted(warnings, (w) => `${w.sourceFile}:${w.target}`);
|
|
7194
7162
|
}
|
|
7195
7163
|
var CREATE_INDEX_PATTERN = /^\s*CREATE\s+(?:UNIQUE\s+)?(?:INDEX\s+)?(?:CONCURRENTLY\s+)?(?:IF\s+NOT\s+EXISTS\s+)?(?:"([^"]+)"|([A-Za-z_]\w*))\s+ON\b/gim;
|
|
7196
7164
|
function extractIndexNames(content) {
|
|
@@ -7225,7 +7193,7 @@ function buildCrossLayerDuplicateIndexWarnings(sources) {
|
|
|
7225
7193
|
}
|
|
7226
7194
|
}
|
|
7227
7195
|
}
|
|
7228
|
-
return
|
|
7196
|
+
return stableSorted(warnings, (w) => `${w.sourceFile}:${w.target}`);
|
|
7229
7197
|
}
|
|
7230
7198
|
|
|
7231
7199
|
// src/commands/db/sync/schema-guardrail-graph.ts
|
|
@@ -7236,11 +7204,11 @@ function loadSqlSources(targetDir, config) {
|
|
|
7236
7204
|
};
|
|
7237
7205
|
}
|
|
7238
7206
|
function buildSchemaNodes(params) {
|
|
7239
|
-
return
|
|
7207
|
+
return stableSorted(
|
|
7240
7208
|
[...params.schemaClaims.entries()].map(([name, files]) => ({
|
|
7241
7209
|
name,
|
|
7242
|
-
claimFiles:
|
|
7243
|
-
createSchemaFiles:
|
|
7210
|
+
claimFiles: normalizeFileList(files),
|
|
7211
|
+
createSchemaFiles: normalizeFileList(params.createSchemaClaims.get(name) ?? [])
|
|
7244
7212
|
})),
|
|
7245
7213
|
(value) => value.name
|
|
7246
7214
|
);
|
|
@@ -7253,9 +7221,9 @@ function createSchemaGraphManifest(params) {
|
|
|
7253
7221
|
generatorVersion: GENERATOR_VERSION,
|
|
7254
7222
|
files: params.fileNodes,
|
|
7255
7223
|
schemas: params.schemaNodes,
|
|
7256
|
-
tables:
|
|
7224
|
+
tables: stableSorted(params.tableNodesByName.values(), (value) => value.qualifiedName),
|
|
7257
7225
|
functionClaims: params.functionClaims,
|
|
7258
|
-
policyClaims:
|
|
7226
|
+
policyClaims: stableSorted(
|
|
7259
7227
|
params.policyClaims,
|
|
7260
7228
|
(value) => `${value.targetTable}.${value.name}.${value.sourceFile}`
|
|
7261
7229
|
),
|
|
@@ -7282,7 +7250,12 @@ async function buildStaticGraph(targetDir, config, sources) {
|
|
|
7282
7250
|
const records = await Promise.all(
|
|
7283
7251
|
declarativeFiles.map((file) => buildDeclarativeFileRecord(file))
|
|
7284
7252
|
);
|
|
7253
|
+
const functionAclManifest = buildFunctionAclManifestFromSqlFiles(declarativeFiles);
|
|
7285
7254
|
const idempotentTouchMetadata = buildIdempotentTouchMetadata(idempotentFiles);
|
|
7255
|
+
idempotentTouchMetadata.set(
|
|
7256
|
+
FUNCTION_ACL_RECONCILIATION_RELATIVE_PATH,
|
|
7257
|
+
buildFunctionAclIdempotentTouchMetadata(functionAclManifest)
|
|
7258
|
+
);
|
|
7286
7259
|
const { tableOwnerClaims, schemaClaims, createSchemaClaims, tablePolicies, policyClaims } = collectDeclarativeClaims(records);
|
|
7287
7260
|
const duplicateTableOwners = createDuplicateTableOwners(tableOwnerClaims);
|
|
7288
7261
|
const { duplicateFunctionOwners, functionClaims } = buildFunctionValidationArtifacts({
|
|
@@ -7344,7 +7317,7 @@ async function buildStaticGraph(targetDir, config, sources) {
|
|
|
7344
7317
|
policyClaims,
|
|
7345
7318
|
fileDependencies
|
|
7346
7319
|
});
|
|
7347
|
-
const multiFileSchemas =
|
|
7320
|
+
const multiFileSchemas = stableSorted(
|
|
7348
7321
|
graph.schemas.filter((schemaNode) => schemaNode.claimFiles.length > 1).map((schemaNode) => ({
|
|
7349
7322
|
schema: schemaNode.name,
|
|
7350
7323
|
files: schemaNode.claimFiles
|
|
@@ -7376,6 +7349,7 @@ async function buildStaticGraph(targetDir, config, sources) {
|
|
|
7376
7349
|
});
|
|
7377
7350
|
return {
|
|
7378
7351
|
graph,
|
|
7352
|
+
functionAclManifest,
|
|
7379
7353
|
duplicateTableOwners,
|
|
7380
7354
|
duplicateFunctionOwners,
|
|
7381
7355
|
policyOwnershipConflicts,
|
|
@@ -7392,8 +7366,8 @@ var GUARDRAIL_PHASE_LABELS = {
|
|
|
7392
7366
|
load_sources: "Load declarative SQL sources",
|
|
7393
7367
|
build_static_graph: "Build static SQL graph",
|
|
7394
7368
|
validate_ownership: "Validate ownership",
|
|
7395
|
-
compare_generated_headers: "Compare generated
|
|
7396
|
-
refresh_generated_headers: "Refresh generated
|
|
7369
|
+
compare_generated_headers: "Compare generated SQL artifacts",
|
|
7370
|
+
refresh_generated_headers: "Refresh generated SQL artifacts",
|
|
7397
7371
|
handoff_db_sync: "Hand off to db sync",
|
|
7398
7372
|
runtime_reconcile: "Runtime reconcile",
|
|
7399
7373
|
publish_report: "Publish report"
|
|
@@ -7482,7 +7456,7 @@ function createCheckModePhases(report) {
|
|
|
7482
7456
|
details: {
|
|
7483
7457
|
file: block.file,
|
|
7484
7458
|
target: block.target,
|
|
7485
|
-
repair: "Run `runa db sync` to auto-regenerate
|
|
7459
|
+
repair: "Run `runa db sync` to auto-regenerate managed SQL artifacts"
|
|
7486
7460
|
}
|
|
7487
7461
|
}))
|
|
7488
7462
|
})
|
|
@@ -7984,12 +7958,35 @@ function buildHeaderRewritePlans(params) {
|
|
|
7984
7958
|
}
|
|
7985
7959
|
function loadHeaderRewritePlans(params) {
|
|
7986
7960
|
try {
|
|
7987
|
-
|
|
7961
|
+
const headerPlans = buildHeaderRewritePlans({
|
|
7988
7962
|
targetDir: params.targetDir,
|
|
7989
7963
|
graph: params.graph,
|
|
7990
7964
|
tableHeaderMaxWidth: params.config.tableHeaderMaxWidth,
|
|
7991
7965
|
generatedHeaderRewriteTargets: params.config.generatedHeaderRewriteTargets
|
|
7992
7966
|
});
|
|
7967
|
+
const generatedFileResult = buildGeneratedFileRewritePlans({
|
|
7968
|
+
targetDir: params.targetDir,
|
|
7969
|
+
manifest: params.functionAclManifest
|
|
7970
|
+
});
|
|
7971
|
+
if ("failure" in generatedFileResult) {
|
|
7972
|
+
const failureMessage = generatedFileResult.failure ?? "Unknown function ACL migration failure";
|
|
7973
|
+
return {
|
|
7974
|
+
failure: {
|
|
7975
|
+
graph: params.graph,
|
|
7976
|
+
report: setFailure2(
|
|
7977
|
+
params.report,
|
|
7978
|
+
"compare_generated_headers",
|
|
7979
|
+
"function_acl_migration_required",
|
|
7980
|
+
failureMessage
|
|
7981
|
+
)
|
|
7982
|
+
}
|
|
7983
|
+
};
|
|
7984
|
+
}
|
|
7985
|
+
return {
|
|
7986
|
+
staleBlocks: [...headerPlans.staleBlocks, ...generatedFileResult.staleBlocks],
|
|
7987
|
+
rewritePlans: headerPlans.rewritePlans,
|
|
7988
|
+
generatedFileRewritePlans: generatedFileResult.rewritePlans
|
|
7989
|
+
};
|
|
7993
7990
|
} catch (error) {
|
|
7994
7991
|
const message = error instanceof Error ? error.message : String(error);
|
|
7995
7992
|
return {
|
|
@@ -8018,7 +8015,7 @@ function finalizeCheckModeReport(params) {
|
|
|
8018
8015
|
params.report,
|
|
8019
8016
|
"compare_generated_headers",
|
|
8020
8017
|
"stale_generated_header",
|
|
8021
|
-
`Generated
|
|
8018
|
+
`Generated SQL artifacts are stale in ${params.report.staleBlocks.map((value) => `${value.file}:${value.kind}`).join(", ")}`
|
|
8022
8019
|
)
|
|
8023
8020
|
};
|
|
8024
8021
|
}
|
|
@@ -8037,6 +8034,15 @@ function rewriteManagedHeaders(params) {
|
|
|
8037
8034
|
writeFileSync(path12.join(params.targetDir, plan.filePath), rewrittenSql, "utf-8");
|
|
8038
8035
|
params.report.headersRewritten.push(plan.filePath);
|
|
8039
8036
|
}
|
|
8037
|
+
for (const plan of params.generatedFileRewritePlans) {
|
|
8038
|
+
const absolutePath = path12.join(params.targetDir, plan.filePath);
|
|
8039
|
+
const currentSql = existsSync(absolutePath) ? readFileSync(absolutePath, "utf-8") : "";
|
|
8040
|
+
if (normalizeMultilineText(currentSql) === normalizeMultilineText(plan.expectedSql)) {
|
|
8041
|
+
continue;
|
|
8042
|
+
}
|
|
8043
|
+
writeFileSync(absolutePath, plan.expectedSql, "utf-8");
|
|
8044
|
+
params.report.headersRewritten.push(plan.filePath);
|
|
8045
|
+
}
|
|
8040
8046
|
} catch (error) {
|
|
8041
8047
|
const message = error instanceof Error ? error.message : String(error);
|
|
8042
8048
|
return {
|
|
@@ -8054,6 +8060,41 @@ function rewriteManagedHeaders(params) {
|
|
|
8054
8060
|
params.report.staleBlocks = [];
|
|
8055
8061
|
return null;
|
|
8056
8062
|
}
|
|
8063
|
+
function buildGeneratedFileRewritePlans(params) {
|
|
8064
|
+
const absolutePath = path12.join(params.targetDir, FUNCTION_ACL_RECONCILIATION_RELATIVE_PATH);
|
|
8065
|
+
const fileExists = existsSync(absolutePath);
|
|
8066
|
+
const existingSql = fileExists ? readFileSync(absolutePath, "utf-8") : "";
|
|
8067
|
+
if (!fileExists && !functionAclManifestHasEntries(params.manifest)) {
|
|
8068
|
+
return {
|
|
8069
|
+
staleBlocks: [],
|
|
8070
|
+
rewritePlans: []
|
|
8071
|
+
};
|
|
8072
|
+
}
|
|
8073
|
+
if (fileExists) {
|
|
8074
|
+
const migrationGaps = validateFunctionAclMigration(params.manifest, existingSql);
|
|
8075
|
+
if (migrationGaps.length > 0) {
|
|
8076
|
+
return {
|
|
8077
|
+
failure: `Function ACL migration is required before auto-generation can proceed. Add declarative annotations for: ${migrationGaps.join(", ")}`
|
|
8078
|
+
};
|
|
8079
|
+
}
|
|
8080
|
+
}
|
|
8081
|
+
const staleBlocks = !fileExists || isManagedFunctionAclFileContentStale(params.manifest, existingSql) ? [
|
|
8082
|
+
{
|
|
8083
|
+
file: FUNCTION_ACL_RECONCILIATION_RELATIVE_PATH,
|
|
8084
|
+
kind: "generated-file",
|
|
8085
|
+
target: `file:${FUNCTION_ACL_RECONCILIATION_RELATIVE_PATH}`
|
|
8086
|
+
}
|
|
8087
|
+
] : [];
|
|
8088
|
+
return {
|
|
8089
|
+
staleBlocks,
|
|
8090
|
+
rewritePlans: [
|
|
8091
|
+
{
|
|
8092
|
+
filePath: FUNCTION_ACL_RECONCILIATION_RELATIVE_PATH,
|
|
8093
|
+
expectedSql: renderFunctionAclFile(params.manifest)
|
|
8094
|
+
}
|
|
8095
|
+
]
|
|
8096
|
+
};
|
|
8097
|
+
}
|
|
8057
8098
|
|
|
8058
8099
|
// src/commands/db/sync/schema-guardrail.ts
|
|
8059
8100
|
function createEmptyReport(mode) {
|
|
@@ -8125,7 +8166,7 @@ function validateLocalBlindSpotBlockers(report, graph) {
|
|
|
8125
8166
|
if (!primary) {
|
|
8126
8167
|
return null;
|
|
8127
8168
|
}
|
|
8128
|
-
const failureCode = primary.kind === "cross-schema-rls" ? "raw_cross_schema_rls_blocked" : primary.kind === "dynamic-sql" ? "dynamic_sql_blocked" : "extension_placement_blocked";
|
|
8169
|
+
const failureCode = primary.kind === "cross-schema-rls" ? "raw_cross_schema_rls_blocked" : primary.kind === "dynamic-sql" || primary.kind === "dynamic-sql-infra" ? "dynamic_sql_blocked" : "extension_placement_blocked";
|
|
8129
8170
|
return {
|
|
8130
8171
|
graph,
|
|
8131
8172
|
report: setFailure3(report, "validate_ownership", failureCode, primary.details)
|
|
@@ -8216,6 +8257,7 @@ async function runSchemaGuardrailStatic(input) {
|
|
|
8216
8257
|
const headerPlanResult = loadHeaderRewritePlans({
|
|
8217
8258
|
targetDir: input.targetDir,
|
|
8218
8259
|
graph: staticGraphResult.graph,
|
|
8260
|
+
functionAclManifest: staticGraphResult.functionAclManifest,
|
|
8219
8261
|
config,
|
|
8220
8262
|
report
|
|
8221
8263
|
});
|
|
@@ -8237,6 +8279,7 @@ async function runSchemaGuardrailStatic(input) {
|
|
|
8237
8279
|
const rewriteFailure = rewriteManagedHeaders({
|
|
8238
8280
|
targetDir: input.targetDir,
|
|
8239
8281
|
rewritePlans: headerPlanResult.rewritePlans,
|
|
8282
|
+
generatedFileRewritePlans: headerPlanResult.generatedFileRewritePlans,
|
|
8240
8283
|
report
|
|
8241
8284
|
});
|
|
8242
8285
|
if (rewriteFailure) {
|
|
@@ -8388,6 +8431,37 @@ function tryGetProductionAdminUrl(targetDir) {
|
|
|
8388
8431
|
}
|
|
8389
8432
|
return void 0;
|
|
8390
8433
|
}
|
|
8434
|
+
function validateProductionPlan(planOutput, log) {
|
|
8435
|
+
if (!planOutput.trim() || planOutput.includes("No changes")) {
|
|
8436
|
+
log.info("\u2705 Production schema is up-to-date (no changes needed)");
|
|
8437
|
+
return;
|
|
8438
|
+
}
|
|
8439
|
+
const plan = parsePlanOutput(planOutput);
|
|
8440
|
+
const orderIssues = validateDependencyOrder(plan);
|
|
8441
|
+
if (orderIssues.length > 0) {
|
|
8442
|
+
for (const issue of orderIssues) {
|
|
8443
|
+
logger3.error(issue);
|
|
8444
|
+
}
|
|
8445
|
+
throw new Error(
|
|
8446
|
+
`\u274C Production DDL ordering issue detected (${orderIssues.length} problem(s)):
|
|
8447
|
+
` + orderIssues.map((i) => ` \u2022 ${i}`).join("\n") + "\n\nThis plan would fail during production deploy. The automatic reorder will attempt to fix this, but review the ordering."
|
|
8448
|
+
);
|
|
8449
|
+
}
|
|
8450
|
+
log.info("\u2705 Production DDL ordering verified");
|
|
8451
|
+
}
|
|
8452
|
+
async function resolveTempDbDsnForProductionCheck(targetDir) {
|
|
8453
|
+
const envDsn = process.env.PG_SCHEMA_DIFF_TEMP_DB_DSN?.trim();
|
|
8454
|
+
if (envDsn) return envDsn;
|
|
8455
|
+
try {
|
|
8456
|
+
const { buildLocalDatabaseUrl: buildLocalDatabaseUrl2 } = await import('./local-supabase-KTTC3O2L.js');
|
|
8457
|
+
const { verifyDatabaseConnection } = await import('./helpers-PDT3WQNF.js');
|
|
8458
|
+
const localDsn = buildLocalDatabaseUrl2(targetDir);
|
|
8459
|
+
await verifyDatabaseConnection(localDsn, { maxRetries: 0 });
|
|
8460
|
+
return localDsn;
|
|
8461
|
+
} catch {
|
|
8462
|
+
}
|
|
8463
|
+
return void 0;
|
|
8464
|
+
}
|
|
8391
8465
|
async function runProductionDdlOrderCheck(params) {
|
|
8392
8466
|
const productionUrl = tryGetProductionAdminUrl(params.targetDir);
|
|
8393
8467
|
if (productionUrl) {
|
|
@@ -8407,30 +8481,16 @@ async function runProductionDdlOrderCheck(params) {
|
|
|
8407
8481
|
params.logger.info("\u{1F50D} Checking production DDL ordering...");
|
|
8408
8482
|
try {
|
|
8409
8483
|
const { executePgSchemaDiffPlan } = await import('./pg-schema-diff-helpers-JZO4GAQG.js');
|
|
8484
|
+
const tempDbDsn = await resolveTempDbDsnForProductionCheck(params.targetDir);
|
|
8410
8485
|
const { planOutput } = executePgSchemaDiffPlan(
|
|
8411
8486
|
productionUrl,
|
|
8412
8487
|
schemasDir,
|
|
8413
8488
|
includeSchemas,
|
|
8414
8489
|
false,
|
|
8415
8490
|
// not verbose
|
|
8416
|
-
{ targetDir: params.targetDir }
|
|
8491
|
+
{ targetDir: params.targetDir, tempDbDsn }
|
|
8417
8492
|
);
|
|
8418
|
-
|
|
8419
|
-
params.logger.info("\u2705 Production schema is up-to-date (no changes needed)");
|
|
8420
|
-
return;
|
|
8421
|
-
}
|
|
8422
|
-
const plan = parsePlanOutput(planOutput);
|
|
8423
|
-
const orderIssues = validateDependencyOrder(plan);
|
|
8424
|
-
if (orderIssues.length > 0) {
|
|
8425
|
-
for (const issue of orderIssues) {
|
|
8426
|
-
logger3.error(issue);
|
|
8427
|
-
}
|
|
8428
|
-
throw new Error(
|
|
8429
|
-
`\u274C Production DDL ordering issue detected (${orderIssues.length} problem(s)):
|
|
8430
|
-
` + orderIssues.map((i) => ` \u2022 ${i}`).join("\n") + "\n\nThis plan would fail during production deploy. The automatic reorder will attempt to fix this, but review the ordering."
|
|
8431
|
-
);
|
|
8432
|
-
}
|
|
8433
|
-
params.logger.info("\u2705 Production DDL ordering verified");
|
|
8493
|
+
validateProductionPlan(planOutput, params.logger);
|
|
8434
8494
|
} catch (error) {
|
|
8435
8495
|
if (error instanceof Error && error.message.includes("DDL ordering issue")) {
|
|
8436
8496
|
throw error;
|