@runa-ai/runa-cli 0.10.2 → 0.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-LCJNIHZY.js → chunk-S7VGVFYF.js} +4933 -4288
- package/dist/{chunk-IR7SA2ME.js → chunk-SS7RIWW3.js} +1 -1
- package/dist/{ci-6XYG7XNX.js → ci-6P7VK6WB.js} +2 -2
- package/dist/{cli-2XL3VESS.js → cli-Q665YRVT.js} +4 -4
- 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-BQOVOQXU.js} +178 -137
- package/dist/index.js +3 -3
- package/dist/{vuln-check-LMDYYJUE.js → vuln-check-WW43E7PS.js} +1 -1
- package/dist/{vuln-checker-NHXLNZRM.js → vuln-checker-BC3ZAXJ3.js} +1 -1
- package/package.json +3 -3
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { createRequire } from 'module';
|
|
3
3
|
import { detectDatabaseStack, getStackPaths } from './chunk-MILCC3B6.js';
|
|
4
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-
|
|
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, FUNCTION_ACL_RECONCILIATION_RELATIVE_PATH, functionAclManifestHasEntries, validateFunctionAclMigration, isManagedFunctionAclFileContentStale, renderFunctionAclFile, assessPlanSize, formatPlanSizeSummary, 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-S7VGVFYF.js';
|
|
6
6
|
import { createError } from './chunk-NIS77243.js';
|
|
7
7
|
import { resolveDatabaseUrl, resolveDatabaseTarget, tryResolveDatabaseUrl } from './chunk-WGRVAGSR.js';
|
|
8
8
|
export { resolveDatabaseUrl, tryResolveDatabaseUrl } from './chunk-WGRVAGSR.js';
|
|
@@ -10,7 +10,7 @@ import { analyzeDeclarativeDependencyContract, formatDeclarativeDependencyViolat
|
|
|
10
10
|
import './chunk-UHDAYPHH.js';
|
|
11
11
|
import './chunk-EZ46JIEO.js';
|
|
12
12
|
import { loadEnvFiles } from './chunk-IWVXI5O4.js';
|
|
13
|
-
import './chunk-
|
|
13
|
+
import './chunk-SS7RIWW3.js';
|
|
14
14
|
import { diagnoseSupabaseStart } from './chunk-AAIE4F2U.js';
|
|
15
15
|
import { validateUserFilePath, filterSafePaths, resolveSafePath } from './chunk-B7C7CLW2.js';
|
|
16
16
|
import { runMachine } from './chunk-QDF7QXBL.js';
|
|
@@ -1145,7 +1145,8 @@ z.object({
|
|
|
1145
1145
|
});
|
|
1146
1146
|
var SchemaManagedBlockKindSchema = z.enum([
|
|
1147
1147
|
"file-header",
|
|
1148
|
-
"table-header"
|
|
1148
|
+
"table-header",
|
|
1149
|
+
"generated-file"
|
|
1149
1150
|
]);
|
|
1150
1151
|
var SchemaGuardrailPhaseIdSchema = z.enum([
|
|
1151
1152
|
"load_sources",
|
|
@@ -1166,6 +1167,7 @@ var SchemaGuardrailFailureCodeSchema = z.enum([
|
|
|
1166
1167
|
"dynamic_sql_blocked",
|
|
1167
1168
|
"extension_placement_blocked",
|
|
1168
1169
|
"stale_generated_header",
|
|
1170
|
+
"function_acl_migration_required",
|
|
1169
1171
|
"generated_header_validation_failed",
|
|
1170
1172
|
"generated_header_rewrite_failed",
|
|
1171
1173
|
"static_graph_build_failed",
|
|
@@ -1509,39 +1511,46 @@ function buildGuardrailConflictEntries(report, entries) {
|
|
|
1509
1511
|
pushSemanticEvidenceEntries(entries, report);
|
|
1510
1512
|
pushBoundaryGuidanceEntries(entries, report);
|
|
1511
1513
|
}
|
|
1512
|
-
function
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1514
|
+
function describeStaleBlock(block) {
|
|
1515
|
+
return block.kind === "file-header" ? "file metadata" : block.kind === "generated-file" ? "managed file body" : `table: ${block.target}`;
|
|
1516
|
+
}
|
|
1517
|
+
function pushStaleArtifactEntries(report, entries) {
|
|
1518
|
+
if (report.staleBlocks.length === 0) {
|
|
1519
|
+
return;
|
|
1520
|
+
}
|
|
1521
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
1522
|
+
for (const block of report.staleBlocks) {
|
|
1523
|
+
const kinds = byFile.get(block.file) ?? [];
|
|
1524
|
+
kinds.push(describeStaleBlock(block));
|
|
1525
|
+
byFile.set(block.file, kinds);
|
|
1526
|
+
}
|
|
1527
|
+
entries.push({
|
|
1528
|
+
level: "warn",
|
|
1529
|
+
message: `Generated SQL artifacts are stale (${report.staleBlocks.length} block(s) in ${byFile.size} file(s)):`
|
|
1530
|
+
});
|
|
1531
|
+
for (const [file, kinds] of byFile) {
|
|
1520
1532
|
entries.push({
|
|
1521
|
-
level: "
|
|
1522
|
-
message: `
|
|
1533
|
+
level: "info",
|
|
1534
|
+
message: ` ${file}: ${kinds.join(", ")}`
|
|
1535
|
+
});
|
|
1536
|
+
}
|
|
1537
|
+
if (!report.failure) {
|
|
1538
|
+
entries.push({
|
|
1539
|
+
level: "info",
|
|
1540
|
+
message: "Auto-fix: Run `runa db sync` to regenerate managed SQL artifacts automatically."
|
|
1541
|
+
});
|
|
1542
|
+
entries.push({
|
|
1543
|
+
level: "info",
|
|
1544
|
+
message: "Managed SQL artifacts track: FK references, RLS policies, triggers, function ownership, schema dependencies, and function ACL reconciliation."
|
|
1523
1545
|
});
|
|
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
1546
|
}
|
|
1547
|
+
}
|
|
1548
|
+
function buildGuardrailHeaderEntries(report, entries) {
|
|
1549
|
+
pushStaleArtifactEntries(report, entries);
|
|
1541
1550
|
if (report.headersRewritten.length > 0) {
|
|
1542
1551
|
entries.push({
|
|
1543
1552
|
level: "info",
|
|
1544
|
-
message: `Generated
|
|
1553
|
+
message: `Generated SQL artifacts refreshed in ${report.headersRewritten.length} file(s).`
|
|
1545
1554
|
});
|
|
1546
1555
|
}
|
|
1547
1556
|
}
|
|
@@ -2797,7 +2806,7 @@ function normalizeAllowlistSignature(value) {
|
|
|
2797
2806
|
function normalizeSuppressionPair(value) {
|
|
2798
2807
|
return value.split("::").map((part) => part.trim().toLowerCase()).filter((part) => part.length > 0).sort((left, right) => left.localeCompare(right)).join("::");
|
|
2799
2808
|
}
|
|
2800
|
-
function
|
|
2809
|
+
function normalizeFileList2(files) {
|
|
2801
2810
|
return [...new Set(files)].sort((a, b) => a.localeCompare(b));
|
|
2802
2811
|
}
|
|
2803
2812
|
function isSchemaGuardrailTextFallbackAllowed() {
|
|
@@ -2859,7 +2868,7 @@ function loadSchemaGuardrailConfig(targetDir) {
|
|
|
2859
2868
|
// Fallback: merge schema-ownership.json allowed_duplicates if present
|
|
2860
2869
|
...loadAllowedDuplicatesFromSchemaOwnership(targetDir)
|
|
2861
2870
|
],
|
|
2862
|
-
generatedHeaderRewriteTargets:
|
|
2871
|
+
generatedHeaderRewriteTargets: normalizeFileList2(
|
|
2863
2872
|
(databaseConfig.schemaGuardrails?.generatedHeaderRewriteTargets ?? []).map(
|
|
2864
2873
|
(value) => normalizePathForMatch(value)
|
|
2865
2874
|
)
|
|
@@ -2884,7 +2893,7 @@ function loadSchemaGuardrailConfig(targetDir) {
|
|
|
2884
2893
|
defaults,
|
|
2885
2894
|
normalizers: {
|
|
2886
2895
|
normalizeAllowlistSignature,
|
|
2887
|
-
normalizeFileList,
|
|
2896
|
+
normalizeFileList: normalizeFileList2,
|
|
2888
2897
|
normalizeFunctionQualifiedName,
|
|
2889
2898
|
normalizePathForMatch,
|
|
2890
2899
|
normalizeSuppressionPair
|
|
@@ -5441,7 +5450,7 @@ init_esm_shims();
|
|
|
5441
5450
|
|
|
5442
5451
|
// src/commands/db/sync/schema-guardrail-runtime.ts
|
|
5443
5452
|
init_esm_shims();
|
|
5444
|
-
function
|
|
5453
|
+
function stableSorted2(values, map) {
|
|
5445
5454
|
return [...values].sort((a, b) => map(a).localeCompare(map(b)));
|
|
5446
5455
|
}
|
|
5447
5456
|
function normalizeFkSet(foreignKeys) {
|
|
@@ -5563,8 +5572,8 @@ function reconcileRuntimeGraph(params) {
|
|
|
5563
5572
|
});
|
|
5564
5573
|
}
|
|
5565
5574
|
return {
|
|
5566
|
-
warnings:
|
|
5567
|
-
contradictions:
|
|
5575
|
+
warnings: stableSorted2(warnings, (value) => value.target),
|
|
5576
|
+
contradictions: stableSorted2(contradictions, (value) => `${value.code}.${value.target}`)
|
|
5568
5577
|
};
|
|
5569
5578
|
}
|
|
5570
5579
|
function runSchemaGuardrailRuntime(input) {
|
|
@@ -5594,7 +5603,7 @@ function runSchemaGuardrailRuntime(input) {
|
|
|
5594
5603
|
|
|
5595
5604
|
// src/commands/db/sync/schema-guardrail-local-blockers.ts
|
|
5596
5605
|
init_esm_shims();
|
|
5597
|
-
function
|
|
5606
|
+
function stableSorted3(values, keyOf) {
|
|
5598
5607
|
return [...values].sort((left, right) => keyOf(left).localeCompare(keyOf(right)));
|
|
5599
5608
|
}
|
|
5600
5609
|
function createCrossSchemaHelperSuggestion(_filePath) {
|
|
@@ -5623,7 +5632,7 @@ function buildRawCrossSchemaRlsBlockers(params) {
|
|
|
5623
5632
|
});
|
|
5624
5633
|
}
|
|
5625
5634
|
}
|
|
5626
|
-
return
|
|
5635
|
+
return stableSorted3(
|
|
5627
5636
|
blockers,
|
|
5628
5637
|
(value) => `${value.sourceFile}:${value.line ?? 0}:${value.target}`
|
|
5629
5638
|
);
|
|
@@ -5650,7 +5659,7 @@ function buildExtensionPlacementBlockers(params) {
|
|
|
5650
5659
|
});
|
|
5651
5660
|
}
|
|
5652
5661
|
}
|
|
5653
|
-
return
|
|
5662
|
+
return stableSorted3(
|
|
5654
5663
|
blockers,
|
|
5655
5664
|
(value) => `${value.sourceFile}:${value.line ?? 0}:${value.target}`
|
|
5656
5665
|
);
|
|
@@ -5741,7 +5750,7 @@ function buildDynamicSqlBlockers(params) {
|
|
|
5741
5750
|
blockers.push(...stmtBlockers);
|
|
5742
5751
|
}
|
|
5743
5752
|
}
|
|
5744
|
-
return
|
|
5753
|
+
return stableSorted3(blockers, (value) => `${value.sourceFile}:${value.line ?? 0}:${value.kind}`);
|
|
5745
5754
|
}
|
|
5746
5755
|
function buildLocalBlindSpotBlockers(params) {
|
|
5747
5756
|
const blockers = [
|
|
@@ -5758,7 +5767,7 @@ function buildLocalBlindSpotBlockers(params) {
|
|
|
5758
5767
|
requiredFile: detectExtensionFilePath()
|
|
5759
5768
|
})
|
|
5760
5769
|
];
|
|
5761
|
-
return
|
|
5770
|
+
return stableSorted3(
|
|
5762
5771
|
blockers,
|
|
5763
5772
|
(value) => `${value.kind}:${value.sourceFile}:${value.line ?? 0}:${value.target}`
|
|
5764
5773
|
);
|
|
@@ -5766,7 +5775,7 @@ function buildLocalBlindSpotBlockers(params) {
|
|
|
5766
5775
|
|
|
5767
5776
|
// src/commands/db/sync/schema-guardrail-semantic-warnings.ts
|
|
5768
5777
|
init_esm_shims();
|
|
5769
|
-
function
|
|
5778
|
+
function stableSorted4(values, map) {
|
|
5770
5779
|
return [...values].sort((a, b) => map(a).localeCompare(map(b)));
|
|
5771
5780
|
}
|
|
5772
5781
|
function normalizeFkSet2(foreignKeys) {
|
|
@@ -5971,50 +5980,7 @@ function buildSemanticDuplicateWarnings(params) {
|
|
|
5971
5980
|
suppressionKey: createSuppressionPair(proposed.qualifiedName, primary.qualifiedName)
|
|
5972
5981
|
});
|
|
5973
5982
|
}
|
|
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
|
-
}
|
|
5983
|
+
return stableSorted4(warnings, (value) => `${value.proposedTable}.${value.suppressionKey}`);
|
|
6018
5984
|
}
|
|
6019
5985
|
|
|
6020
5986
|
// src/commands/db/sync/schema-guardrail-graph-nodes.ts
|
|
@@ -6060,8 +6026,8 @@ function collectQualifiedObjectRefs(params) {
|
|
|
6060
6026
|
schemas.add(schema);
|
|
6061
6027
|
}
|
|
6062
6028
|
return {
|
|
6063
|
-
refs:
|
|
6064
|
-
schemas:
|
|
6029
|
+
refs: stableSorted(refs, (value) => value),
|
|
6030
|
+
schemas: stableSorted(schemas, (value) => value)
|
|
6065
6031
|
};
|
|
6066
6032
|
}
|
|
6067
6033
|
function isSearchPathLocked(statement) {
|
|
@@ -6099,7 +6065,7 @@ function buildDefinedFunctionMetadataByFile(params) {
|
|
|
6099
6065
|
}
|
|
6100
6066
|
metadataByFile.set(
|
|
6101
6067
|
file.relativePath,
|
|
6102
|
-
|
|
6068
|
+
stableSorted(fileMetadata, (value) => value.qualifiedSignature)
|
|
6103
6069
|
);
|
|
6104
6070
|
}
|
|
6105
6071
|
return metadataByFile;
|
|
@@ -6193,13 +6159,13 @@ async function buildDeclarativeFileRecord(file) {
|
|
|
6193
6159
|
file,
|
|
6194
6160
|
declaredSchemas: [...declaredSchemas].sort((a, b) => a.localeCompare(b)),
|
|
6195
6161
|
createSchemaClaims: [...createSchemaClaims].sort((a, b) => a.localeCompare(b)),
|
|
6196
|
-
tables:
|
|
6162
|
+
tables: stableSorted(
|
|
6197
6163
|
document.tables.map((table) => ({
|
|
6198
6164
|
schema: table.schema,
|
|
6199
6165
|
name: table.name,
|
|
6200
6166
|
qualifiedName: table.qualifiedName,
|
|
6201
6167
|
lineNumber: table.lineNumber,
|
|
6202
|
-
columns:
|
|
6168
|
+
columns: stableSorted(table.columns, (value) => value.name).map((value) => value.name),
|
|
6203
6169
|
outboundForeignKeys: table.foreignKeys.map((fk) => ({
|
|
6204
6170
|
column: fk.column,
|
|
6205
6171
|
referencesTable: fk.referencesTable,
|
|
@@ -6210,7 +6176,7 @@ async function buildDeclarativeFileRecord(file) {
|
|
|
6210
6176
|
})),
|
|
6211
6177
|
(value) => value.qualifiedName
|
|
6212
6178
|
),
|
|
6213
|
-
policies:
|
|
6179
|
+
policies: stableSorted(
|
|
6214
6180
|
document.policies.map((policy) => ({
|
|
6215
6181
|
name: policy.name,
|
|
6216
6182
|
targetTable: `${policy.schema}.${policy.table}`,
|
|
@@ -6264,10 +6230,10 @@ function collectDeclarativeClaims(records) {
|
|
|
6264
6230
|
};
|
|
6265
6231
|
}
|
|
6266
6232
|
function createDuplicateTableOwners(tableOwnerClaims) {
|
|
6267
|
-
return
|
|
6233
|
+
return stableSorted(
|
|
6268
6234
|
[...tableOwnerClaims.entries()].filter(([, files]) => files.size > 1).map(([qualifiedName, files]) => ({
|
|
6269
6235
|
qualifiedName,
|
|
6270
|
-
files:
|
|
6236
|
+
files: normalizeFileList(files)
|
|
6271
6237
|
})),
|
|
6272
6238
|
(value) => value.qualifiedName
|
|
6273
6239
|
);
|
|
@@ -6281,7 +6247,7 @@ function buildFunctionValidationArtifacts(params) {
|
|
|
6281
6247
|
...buildFunctionBodyHashMap(params.declarativeFiles, "declarative"),
|
|
6282
6248
|
...buildFunctionBodyHashMap(params.idempotentFiles, "idempotent")
|
|
6283
6249
|
]);
|
|
6284
|
-
const duplicateFunctionOwners =
|
|
6250
|
+
const duplicateFunctionOwners = stableSorted(
|
|
6285
6251
|
functionAnalysis.findings.filter(
|
|
6286
6252
|
(finding) => !isAllowlistedDuplicateFunction({
|
|
6287
6253
|
finding,
|
|
@@ -6291,16 +6257,16 @@ function buildFunctionValidationArtifacts(params) {
|
|
|
6291
6257
|
).map((finding) => ({
|
|
6292
6258
|
qualifiedName: finding.qualifiedName,
|
|
6293
6259
|
signature: finding.signature,
|
|
6294
|
-
declarativeFiles:
|
|
6260
|
+
declarativeFiles: normalizeFileList(
|
|
6295
6261
|
finding.declarativeDefinitions.map((value) => value.file)
|
|
6296
6262
|
),
|
|
6297
|
-
idempotentFiles:
|
|
6263
|
+
idempotentFiles: normalizeFileList(
|
|
6298
6264
|
finding.idempotentDefinitions.map((value) => value.file)
|
|
6299
6265
|
)
|
|
6300
6266
|
})),
|
|
6301
6267
|
(value) => `${value.qualifiedName}.${value.signature ?? ""}`
|
|
6302
6268
|
);
|
|
6303
|
-
const functionClaims =
|
|
6269
|
+
const functionClaims = stableSorted(
|
|
6304
6270
|
[
|
|
6305
6271
|
...functionAnalysis.definitions.declarative.map((definition) => ({
|
|
6306
6272
|
qualifiedName: definition.qualifiedName,
|
|
@@ -6329,7 +6295,7 @@ function buildFunctionValidationArtifacts(params) {
|
|
|
6329
6295
|
function buildOwnerFileByTable(tableOwnerClaims) {
|
|
6330
6296
|
const ownerFileByTable = /* @__PURE__ */ new Map();
|
|
6331
6297
|
for (const [qualifiedName, files] of tableOwnerClaims.entries()) {
|
|
6332
|
-
const normalizedFiles =
|
|
6298
|
+
const normalizedFiles = normalizeFileList(files);
|
|
6333
6299
|
if (normalizedFiles[0]) {
|
|
6334
6300
|
ownerFileByTable.set(qualifiedName, normalizedFiles[0]);
|
|
6335
6301
|
}
|
|
@@ -6349,7 +6315,7 @@ function buildPolicyOwnershipConflicts(params) {
|
|
|
6349
6315
|
conflicts.push({
|
|
6350
6316
|
policyName: policyClaim.name,
|
|
6351
6317
|
targetTable: policyClaim.targetTable,
|
|
6352
|
-
files:
|
|
6318
|
+
files: normalizeFileList([policyClaim.sourceFile]),
|
|
6353
6319
|
tableOwnerFile: ownerFile
|
|
6354
6320
|
});
|
|
6355
6321
|
}
|
|
@@ -6360,11 +6326,11 @@ function buildPolicyOwnershipConflicts(params) {
|
|
|
6360
6326
|
conflicts.push({
|
|
6361
6327
|
policyName,
|
|
6362
6328
|
targetTable,
|
|
6363
|
-
files:
|
|
6329
|
+
files: normalizeFileList(files),
|
|
6364
6330
|
tableOwnerFile: params.ownerFileByTable.get(targetTable) ?? ""
|
|
6365
6331
|
});
|
|
6366
6332
|
}
|
|
6367
|
-
return
|
|
6333
|
+
return stableSorted(
|
|
6368
6334
|
conflicts,
|
|
6369
6335
|
(value) => `${value.targetTable}.${value.policyName}.${value.files.join(",")}`
|
|
6370
6336
|
);
|
|
@@ -6380,16 +6346,16 @@ function buildTableNodesByName(params) {
|
|
|
6380
6346
|
ownerFile: record.file.relativePath,
|
|
6381
6347
|
lineNumber: table.lineNumber,
|
|
6382
6348
|
columns: table.columns,
|
|
6383
|
-
outboundForeignKeys:
|
|
6349
|
+
outboundForeignKeys: stableSorted(
|
|
6384
6350
|
table.outboundForeignKeys,
|
|
6385
6351
|
(value) => `${value.referencesTable}.${value.column}`
|
|
6386
6352
|
),
|
|
6387
6353
|
inboundForeignKeys: [],
|
|
6388
|
-
policies:
|
|
6354
|
+
policies: stableSorted(
|
|
6389
6355
|
params.tablePolicies.get(table.qualifiedName) ?? [],
|
|
6390
6356
|
(value) => value.name
|
|
6391
6357
|
),
|
|
6392
|
-
triggers:
|
|
6358
|
+
triggers: stableSorted(
|
|
6393
6359
|
record.triggersByTable.get(table.qualifiedName) ?? [],
|
|
6394
6360
|
(value) => value.name
|
|
6395
6361
|
)
|
|
@@ -6413,7 +6379,7 @@ function attachInboundForeignKeys(tableNodesByName) {
|
|
|
6413
6379
|
}
|
|
6414
6380
|
}
|
|
6415
6381
|
for (const tableNode of tableNodesByName.values()) {
|
|
6416
|
-
tableNode.inboundForeignKeys =
|
|
6382
|
+
tableNode.inboundForeignKeys = stableSorted(
|
|
6417
6383
|
tableNode.inboundForeignKeys,
|
|
6418
6384
|
(value) => `${value.fromTable}.${value.fromColumn}`
|
|
6419
6385
|
);
|
|
@@ -6432,12 +6398,12 @@ function buildFileDependencies(params) {
|
|
|
6432
6398
|
fileDependencyMap.set(tableNode.ownerFile, edges);
|
|
6433
6399
|
}
|
|
6434
6400
|
}
|
|
6435
|
-
return
|
|
6401
|
+
return stableSorted(
|
|
6436
6402
|
[...fileDependencyMap.entries()].flatMap(
|
|
6437
6403
|
([fromFile, toMap]) => [...toMap.entries()].map(([toFile, viaTables]) => ({
|
|
6438
6404
|
fromFile,
|
|
6439
6405
|
toFile,
|
|
6440
|
-
viaTables:
|
|
6406
|
+
viaTables: normalizeFileList(viaTables)
|
|
6441
6407
|
}))
|
|
6442
6408
|
),
|
|
6443
6409
|
(value) => `${value.fromFile}->${value.toFile}`
|
|
@@ -6459,7 +6425,7 @@ function buildFileNodes(params) {
|
|
|
6459
6425
|
["22_observability_cron.sql", "cron-registration"],
|
|
6460
6426
|
["25_storage_seed_bucket.sql", "storage-bootstrap"]
|
|
6461
6427
|
]);
|
|
6462
|
-
return
|
|
6428
|
+
return stableSorted(
|
|
6463
6429
|
[
|
|
6464
6430
|
...params.records.map((record) => {
|
|
6465
6431
|
const definedFunctions = params.definedFunctionMetadataByFile.get(record.file.relativePath) ?? [];
|
|
@@ -6469,7 +6435,7 @@ function buildFileNodes(params) {
|
|
|
6469
6435
|
schemas: [],
|
|
6470
6436
|
refs: []
|
|
6471
6437
|
};
|
|
6472
|
-
const triggerFunctions =
|
|
6438
|
+
const triggerFunctions = stableSorted(
|
|
6473
6439
|
new Set(
|
|
6474
6440
|
[...record.triggersByTable.values()].flat().map((trigger) => normalizeTriggerFunctionToken(trigger.functionName)).filter((value) => value !== null)
|
|
6475
6441
|
),
|
|
@@ -6482,7 +6448,7 @@ function buildFileNodes(params) {
|
|
|
6482
6448
|
domainName: path12.basename(record.file.relativePath, ".sql"),
|
|
6483
6449
|
declaredSchemas: record.declaredSchemas,
|
|
6484
6450
|
ownedTables: record.tables.map((table) => table.qualifiedName),
|
|
6485
|
-
forwardDependsOnFiles:
|
|
6451
|
+
forwardDependsOnFiles: stableSorted(
|
|
6486
6452
|
params.fileDependencies.filter((edge) => edge.fromFile === record.file.relativePath).map((edge) => edge.toFile),
|
|
6487
6453
|
(value) => value
|
|
6488
6454
|
),
|
|
@@ -6490,7 +6456,7 @@ function buildFileNodes(params) {
|
|
|
6490
6456
|
securityDefinerFunctions: definedFunctions.filter((value) => value.securityDefiner).map((value) => value.qualifiedSignature),
|
|
6491
6457
|
securityDefinerContracts: definedFunctions.filter((value) => value.securityDefiner && value.searchPathLocked).map((value) => value.qualifiedSignature),
|
|
6492
6458
|
triggerFunctions,
|
|
6493
|
-
functionCrossSchemaRefs:
|
|
6459
|
+
functionCrossSchemaRefs: stableSorted(
|
|
6494
6460
|
new Set(definedFunctions.flatMap((value) => value.crossSchemaRefs)),
|
|
6495
6461
|
(value) => value
|
|
6496
6462
|
),
|
|
@@ -6500,7 +6466,7 @@ function buildFileNodes(params) {
|
|
|
6500
6466
|
touchedExtensions: [],
|
|
6501
6467
|
touchedFunctions: [],
|
|
6502
6468
|
touchedPolicies: [],
|
|
6503
|
-
policyCrossSchemaRefs:
|
|
6469
|
+
policyCrossSchemaRefs: stableSorted(
|
|
6504
6470
|
new Set(
|
|
6505
6471
|
collectPolicyCrossSchemaReferences({
|
|
6506
6472
|
content: record.file.content,
|
|
@@ -6537,7 +6503,7 @@ function buildFileNodes(params) {
|
|
|
6537
6503
|
securityDefinerFunctions: definedFunctions.filter((value) => value.securityDefiner).map((value) => value.qualifiedSignature),
|
|
6538
6504
|
securityDefinerContracts: definedFunctions.filter((value) => value.securityDefiner && value.searchPathLocked).map((value) => value.qualifiedSignature),
|
|
6539
6505
|
triggerFunctions: [],
|
|
6540
|
-
functionCrossSchemaRefs:
|
|
6506
|
+
functionCrossSchemaRefs: stableSorted(
|
|
6541
6507
|
new Set(definedFunctions.flatMap((value) => value.crossSchemaRefs)),
|
|
6542
6508
|
(value) => value
|
|
6543
6509
|
),
|
|
@@ -6700,7 +6666,7 @@ function extractTouchedSchemas(content) {
|
|
|
6700
6666
|
}
|
|
6701
6667
|
}
|
|
6702
6668
|
}
|
|
6703
|
-
return
|
|
6669
|
+
return stableSorted(touched, (value) => value);
|
|
6704
6670
|
}
|
|
6705
6671
|
function extractTouchedFunctions(content) {
|
|
6706
6672
|
const touched = /* @__PURE__ */ new Set();
|
|
@@ -6717,7 +6683,7 @@ function extractTouchedFunctions(content) {
|
|
|
6717
6683
|
}
|
|
6718
6684
|
}
|
|
6719
6685
|
}
|
|
6720
|
-
return
|
|
6686
|
+
return stableSorted(touched, (value) => value);
|
|
6721
6687
|
}
|
|
6722
6688
|
function normalizeExtensionIdentifier(identifier) {
|
|
6723
6689
|
const trimmed = identifier.trim();
|
|
@@ -6740,7 +6706,7 @@ function extractTouchedExtensions(content) {
|
|
|
6740
6706
|
}
|
|
6741
6707
|
touched.add(normalizeExtensionIdentifier(identifier));
|
|
6742
6708
|
}
|
|
6743
|
-
return
|
|
6709
|
+
return stableSorted(touched, (value) => value);
|
|
6744
6710
|
}
|
|
6745
6711
|
function extractTouchedPolicies(content) {
|
|
6746
6712
|
const touched = /* @__PURE__ */ new Set();
|
|
@@ -6754,7 +6720,7 @@ function extractTouchedPolicies(content) {
|
|
|
6754
6720
|
}
|
|
6755
6721
|
touched.add(`${schemaName}.${tableName}.${policyName}`);
|
|
6756
6722
|
}
|
|
6757
|
-
return
|
|
6723
|
+
return stableSorted(touched, (value) => value);
|
|
6758
6724
|
}
|
|
6759
6725
|
function extractIdempotentTouchMetadata(file) {
|
|
6760
6726
|
const sanitizedContent = sanitizeIdempotentTouchScanContent(file.content);
|
|
@@ -6772,7 +6738,7 @@ function buildIdempotentTouchMetadata(files) {
|
|
|
6772
6738
|
// src/commands/db/sync/schema-guardrail-graph-guidance.ts
|
|
6773
6739
|
init_esm_shims();
|
|
6774
6740
|
function summarizeBoundaryTargets(targets) {
|
|
6775
|
-
const sortedTargets =
|
|
6741
|
+
const sortedTargets = stableSorted(new Set(targets), (value) => value);
|
|
6776
6742
|
if (sortedTargets.length <= 2) {
|
|
6777
6743
|
return sortedTargets.join(", ");
|
|
6778
6744
|
}
|
|
@@ -6925,7 +6891,7 @@ function buildUnlockedSecurityDefinerGuidanceWarnings(params) {
|
|
|
6925
6891
|
return [];
|
|
6926
6892
|
}
|
|
6927
6893
|
const lockedContracts = new Set(params.fileNode.securityDefinerContracts);
|
|
6928
|
-
const unlockedFunctions =
|
|
6894
|
+
const unlockedFunctions = stableSorted(
|
|
6929
6895
|
params.fileNode.securityDefinerFunctions.filter(
|
|
6930
6896
|
(qualifiedName) => !lockedContracts.has(qualifiedName)
|
|
6931
6897
|
),
|
|
@@ -6989,7 +6955,7 @@ function buildSecurityDefinerGuidanceWarnings(params) {
|
|
|
6989
6955
|
if (!suggestedIdempotentFile || !targets) {
|
|
6990
6956
|
return [];
|
|
6991
6957
|
}
|
|
6992
|
-
const touchedSecurityDefiners =
|
|
6958
|
+
const touchedSecurityDefiners = stableSorted(
|
|
6993
6959
|
new Set(targets.filter((target) => securityDefinerSet.has(target))),
|
|
6994
6960
|
(value) => value
|
|
6995
6961
|
);
|
|
@@ -7077,7 +7043,7 @@ function buildBoundaryGuidanceWarnings(params) {
|
|
|
7077
7043
|
);
|
|
7078
7044
|
continue;
|
|
7079
7045
|
}
|
|
7080
|
-
const touchedSchemas =
|
|
7046
|
+
const touchedSchemas = stableSorted(new Set(fileNode.touchedSchemas), (value) => value);
|
|
7081
7047
|
if (touchedSchemas.length <= MAX_SCHEMA_GUIDANCE_TARGETS_PER_FILE) {
|
|
7082
7048
|
for (const schema of touchedSchemas) {
|
|
7083
7049
|
const ownerFile = schemaOwnerByName.get(schema);
|
|
@@ -7114,7 +7080,7 @@ function buildBoundaryGuidanceWarnings(params) {
|
|
|
7114
7080
|
reason: "This idempotent file applies policy DDL against a table that is structurally owned in declarative SQL."
|
|
7115
7081
|
});
|
|
7116
7082
|
}
|
|
7117
|
-
return
|
|
7083
|
+
return stableSorted(
|
|
7118
7084
|
warnings,
|
|
7119
7085
|
(value) => `${value.sourceFile}.${value.kind}.${value.suggestedDeclarativeFile ?? ""}.${value.suggestedIdempotentFile ?? ""}.${value.target}`
|
|
7120
7086
|
);
|
|
@@ -7190,7 +7156,7 @@ function validateDispatchCoverage(argsByFunction, sources) {
|
|
|
7190
7156
|
}
|
|
7191
7157
|
}
|
|
7192
7158
|
}
|
|
7193
|
-
return
|
|
7159
|
+
return stableSorted(warnings, (w) => `${w.sourceFile}:${w.target}`);
|
|
7194
7160
|
}
|
|
7195
7161
|
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
7162
|
function extractIndexNames(content) {
|
|
@@ -7225,7 +7191,7 @@ function buildCrossLayerDuplicateIndexWarnings(sources) {
|
|
|
7225
7191
|
}
|
|
7226
7192
|
}
|
|
7227
7193
|
}
|
|
7228
|
-
return
|
|
7194
|
+
return stableSorted(warnings, (w) => `${w.sourceFile}:${w.target}`);
|
|
7229
7195
|
}
|
|
7230
7196
|
|
|
7231
7197
|
// src/commands/db/sync/schema-guardrail-graph.ts
|
|
@@ -7236,11 +7202,11 @@ function loadSqlSources(targetDir, config) {
|
|
|
7236
7202
|
};
|
|
7237
7203
|
}
|
|
7238
7204
|
function buildSchemaNodes(params) {
|
|
7239
|
-
return
|
|
7205
|
+
return stableSorted(
|
|
7240
7206
|
[...params.schemaClaims.entries()].map(([name, files]) => ({
|
|
7241
7207
|
name,
|
|
7242
|
-
claimFiles:
|
|
7243
|
-
createSchemaFiles:
|
|
7208
|
+
claimFiles: normalizeFileList(files),
|
|
7209
|
+
createSchemaFiles: normalizeFileList(params.createSchemaClaims.get(name) ?? [])
|
|
7244
7210
|
})),
|
|
7245
7211
|
(value) => value.name
|
|
7246
7212
|
);
|
|
@@ -7253,9 +7219,9 @@ function createSchemaGraphManifest(params) {
|
|
|
7253
7219
|
generatorVersion: GENERATOR_VERSION,
|
|
7254
7220
|
files: params.fileNodes,
|
|
7255
7221
|
schemas: params.schemaNodes,
|
|
7256
|
-
tables:
|
|
7222
|
+
tables: stableSorted(params.tableNodesByName.values(), (value) => value.qualifiedName),
|
|
7257
7223
|
functionClaims: params.functionClaims,
|
|
7258
|
-
policyClaims:
|
|
7224
|
+
policyClaims: stableSorted(
|
|
7259
7225
|
params.policyClaims,
|
|
7260
7226
|
(value) => `${value.targetTable}.${value.name}.${value.sourceFile}`
|
|
7261
7227
|
),
|
|
@@ -7282,7 +7248,12 @@ async function buildStaticGraph(targetDir, config, sources) {
|
|
|
7282
7248
|
const records = await Promise.all(
|
|
7283
7249
|
declarativeFiles.map((file) => buildDeclarativeFileRecord(file))
|
|
7284
7250
|
);
|
|
7251
|
+
const functionAclManifest = buildFunctionAclManifestFromSqlFiles(declarativeFiles);
|
|
7285
7252
|
const idempotentTouchMetadata = buildIdempotentTouchMetadata(idempotentFiles);
|
|
7253
|
+
idempotentTouchMetadata.set(
|
|
7254
|
+
FUNCTION_ACL_RECONCILIATION_RELATIVE_PATH,
|
|
7255
|
+
buildFunctionAclIdempotentTouchMetadata(functionAclManifest)
|
|
7256
|
+
);
|
|
7286
7257
|
const { tableOwnerClaims, schemaClaims, createSchemaClaims, tablePolicies, policyClaims } = collectDeclarativeClaims(records);
|
|
7287
7258
|
const duplicateTableOwners = createDuplicateTableOwners(tableOwnerClaims);
|
|
7288
7259
|
const { duplicateFunctionOwners, functionClaims } = buildFunctionValidationArtifacts({
|
|
@@ -7344,7 +7315,7 @@ async function buildStaticGraph(targetDir, config, sources) {
|
|
|
7344
7315
|
policyClaims,
|
|
7345
7316
|
fileDependencies
|
|
7346
7317
|
});
|
|
7347
|
-
const multiFileSchemas =
|
|
7318
|
+
const multiFileSchemas = stableSorted(
|
|
7348
7319
|
graph.schemas.filter((schemaNode) => schemaNode.claimFiles.length > 1).map((schemaNode) => ({
|
|
7349
7320
|
schema: schemaNode.name,
|
|
7350
7321
|
files: schemaNode.claimFiles
|
|
@@ -7376,6 +7347,7 @@ async function buildStaticGraph(targetDir, config, sources) {
|
|
|
7376
7347
|
});
|
|
7377
7348
|
return {
|
|
7378
7349
|
graph,
|
|
7350
|
+
functionAclManifest,
|
|
7379
7351
|
duplicateTableOwners,
|
|
7380
7352
|
duplicateFunctionOwners,
|
|
7381
7353
|
policyOwnershipConflicts,
|
|
@@ -7392,8 +7364,8 @@ var GUARDRAIL_PHASE_LABELS = {
|
|
|
7392
7364
|
load_sources: "Load declarative SQL sources",
|
|
7393
7365
|
build_static_graph: "Build static SQL graph",
|
|
7394
7366
|
validate_ownership: "Validate ownership",
|
|
7395
|
-
compare_generated_headers: "Compare generated
|
|
7396
|
-
refresh_generated_headers: "Refresh generated
|
|
7367
|
+
compare_generated_headers: "Compare generated SQL artifacts",
|
|
7368
|
+
refresh_generated_headers: "Refresh generated SQL artifacts",
|
|
7397
7369
|
handoff_db_sync: "Hand off to db sync",
|
|
7398
7370
|
runtime_reconcile: "Runtime reconcile",
|
|
7399
7371
|
publish_report: "Publish report"
|
|
@@ -7482,7 +7454,7 @@ function createCheckModePhases(report) {
|
|
|
7482
7454
|
details: {
|
|
7483
7455
|
file: block.file,
|
|
7484
7456
|
target: block.target,
|
|
7485
|
-
repair: "Run `runa db sync` to auto-regenerate
|
|
7457
|
+
repair: "Run `runa db sync` to auto-regenerate managed SQL artifacts"
|
|
7486
7458
|
}
|
|
7487
7459
|
}))
|
|
7488
7460
|
})
|
|
@@ -7984,12 +7956,35 @@ function buildHeaderRewritePlans(params) {
|
|
|
7984
7956
|
}
|
|
7985
7957
|
function loadHeaderRewritePlans(params) {
|
|
7986
7958
|
try {
|
|
7987
|
-
|
|
7959
|
+
const headerPlans = buildHeaderRewritePlans({
|
|
7988
7960
|
targetDir: params.targetDir,
|
|
7989
7961
|
graph: params.graph,
|
|
7990
7962
|
tableHeaderMaxWidth: params.config.tableHeaderMaxWidth,
|
|
7991
7963
|
generatedHeaderRewriteTargets: params.config.generatedHeaderRewriteTargets
|
|
7992
7964
|
});
|
|
7965
|
+
const generatedFileResult = buildGeneratedFileRewritePlans({
|
|
7966
|
+
targetDir: params.targetDir,
|
|
7967
|
+
manifest: params.functionAclManifest
|
|
7968
|
+
});
|
|
7969
|
+
if ("failure" in generatedFileResult) {
|
|
7970
|
+
const failureMessage = generatedFileResult.failure ?? "Unknown function ACL migration failure";
|
|
7971
|
+
return {
|
|
7972
|
+
failure: {
|
|
7973
|
+
graph: params.graph,
|
|
7974
|
+
report: setFailure2(
|
|
7975
|
+
params.report,
|
|
7976
|
+
"compare_generated_headers",
|
|
7977
|
+
"function_acl_migration_required",
|
|
7978
|
+
failureMessage
|
|
7979
|
+
)
|
|
7980
|
+
}
|
|
7981
|
+
};
|
|
7982
|
+
}
|
|
7983
|
+
return {
|
|
7984
|
+
staleBlocks: [...headerPlans.staleBlocks, ...generatedFileResult.staleBlocks],
|
|
7985
|
+
rewritePlans: headerPlans.rewritePlans,
|
|
7986
|
+
generatedFileRewritePlans: generatedFileResult.rewritePlans
|
|
7987
|
+
};
|
|
7993
7988
|
} catch (error) {
|
|
7994
7989
|
const message = error instanceof Error ? error.message : String(error);
|
|
7995
7990
|
return {
|
|
@@ -8018,7 +8013,7 @@ function finalizeCheckModeReport(params) {
|
|
|
8018
8013
|
params.report,
|
|
8019
8014
|
"compare_generated_headers",
|
|
8020
8015
|
"stale_generated_header",
|
|
8021
|
-
`Generated
|
|
8016
|
+
`Generated SQL artifacts are stale in ${params.report.staleBlocks.map((value) => `${value.file}:${value.kind}`).join(", ")}`
|
|
8022
8017
|
)
|
|
8023
8018
|
};
|
|
8024
8019
|
}
|
|
@@ -8037,6 +8032,15 @@ function rewriteManagedHeaders(params) {
|
|
|
8037
8032
|
writeFileSync(path12.join(params.targetDir, plan.filePath), rewrittenSql, "utf-8");
|
|
8038
8033
|
params.report.headersRewritten.push(plan.filePath);
|
|
8039
8034
|
}
|
|
8035
|
+
for (const plan of params.generatedFileRewritePlans) {
|
|
8036
|
+
const absolutePath = path12.join(params.targetDir, plan.filePath);
|
|
8037
|
+
const currentSql = existsSync(absolutePath) ? readFileSync(absolutePath, "utf-8") : "";
|
|
8038
|
+
if (normalizeMultilineText(currentSql) === normalizeMultilineText(plan.expectedSql)) {
|
|
8039
|
+
continue;
|
|
8040
|
+
}
|
|
8041
|
+
writeFileSync(absolutePath, plan.expectedSql, "utf-8");
|
|
8042
|
+
params.report.headersRewritten.push(plan.filePath);
|
|
8043
|
+
}
|
|
8040
8044
|
} catch (error) {
|
|
8041
8045
|
const message = error instanceof Error ? error.message : String(error);
|
|
8042
8046
|
return {
|
|
@@ -8054,6 +8058,41 @@ function rewriteManagedHeaders(params) {
|
|
|
8054
8058
|
params.report.staleBlocks = [];
|
|
8055
8059
|
return null;
|
|
8056
8060
|
}
|
|
8061
|
+
function buildGeneratedFileRewritePlans(params) {
|
|
8062
|
+
const absolutePath = path12.join(params.targetDir, FUNCTION_ACL_RECONCILIATION_RELATIVE_PATH);
|
|
8063
|
+
const fileExists = existsSync(absolutePath);
|
|
8064
|
+
const existingSql = fileExists ? readFileSync(absolutePath, "utf-8") : "";
|
|
8065
|
+
if (!fileExists && !functionAclManifestHasEntries(params.manifest)) {
|
|
8066
|
+
return {
|
|
8067
|
+
staleBlocks: [],
|
|
8068
|
+
rewritePlans: []
|
|
8069
|
+
};
|
|
8070
|
+
}
|
|
8071
|
+
if (fileExists) {
|
|
8072
|
+
const migrationGaps = validateFunctionAclMigration(params.manifest, existingSql);
|
|
8073
|
+
if (migrationGaps.length > 0) {
|
|
8074
|
+
return {
|
|
8075
|
+
failure: `Function ACL migration is required before auto-generation can proceed. Add declarative annotations for: ${migrationGaps.join(", ")}`
|
|
8076
|
+
};
|
|
8077
|
+
}
|
|
8078
|
+
}
|
|
8079
|
+
const staleBlocks = !fileExists || isManagedFunctionAclFileContentStale(params.manifest, existingSql) ? [
|
|
8080
|
+
{
|
|
8081
|
+
file: FUNCTION_ACL_RECONCILIATION_RELATIVE_PATH,
|
|
8082
|
+
kind: "generated-file",
|
|
8083
|
+
target: `file:${FUNCTION_ACL_RECONCILIATION_RELATIVE_PATH}`
|
|
8084
|
+
}
|
|
8085
|
+
] : [];
|
|
8086
|
+
return {
|
|
8087
|
+
staleBlocks,
|
|
8088
|
+
rewritePlans: [
|
|
8089
|
+
{
|
|
8090
|
+
filePath: FUNCTION_ACL_RECONCILIATION_RELATIVE_PATH,
|
|
8091
|
+
expectedSql: renderFunctionAclFile(params.manifest)
|
|
8092
|
+
}
|
|
8093
|
+
]
|
|
8094
|
+
};
|
|
8095
|
+
}
|
|
8057
8096
|
|
|
8058
8097
|
// src/commands/db/sync/schema-guardrail.ts
|
|
8059
8098
|
function createEmptyReport(mode) {
|
|
@@ -8125,7 +8164,7 @@ function validateLocalBlindSpotBlockers(report, graph) {
|
|
|
8125
8164
|
if (!primary) {
|
|
8126
8165
|
return null;
|
|
8127
8166
|
}
|
|
8128
|
-
const failureCode = primary.kind === "cross-schema-rls" ? "raw_cross_schema_rls_blocked" : primary.kind === "dynamic-sql" ? "dynamic_sql_blocked" : "extension_placement_blocked";
|
|
8167
|
+
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
8168
|
return {
|
|
8130
8169
|
graph,
|
|
8131
8170
|
report: setFailure3(report, "validate_ownership", failureCode, primary.details)
|
|
@@ -8216,6 +8255,7 @@ async function runSchemaGuardrailStatic(input) {
|
|
|
8216
8255
|
const headerPlanResult = loadHeaderRewritePlans({
|
|
8217
8256
|
targetDir: input.targetDir,
|
|
8218
8257
|
graph: staticGraphResult.graph,
|
|
8258
|
+
functionAclManifest: staticGraphResult.functionAclManifest,
|
|
8219
8259
|
config,
|
|
8220
8260
|
report
|
|
8221
8261
|
});
|
|
@@ -8237,6 +8277,7 @@ async function runSchemaGuardrailStatic(input) {
|
|
|
8237
8277
|
const rewriteFailure = rewriteManagedHeaders({
|
|
8238
8278
|
targetDir: input.targetDir,
|
|
8239
8279
|
rewritePlans: headerPlanResult.rewritePlans,
|
|
8280
|
+
generatedFileRewritePlans: headerPlanResult.generatedFileRewritePlans,
|
|
8240
8281
|
report
|
|
8241
8282
|
});
|
|
8242
8283
|
if (rewriteFailure) {
|