permdock 0.9.0 → 0.11.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/dist/active-tenant-DVee32-T.js +39 -0
- package/dist/{adoption-scan-Ch07MdxN.js → adoption-scan-DKCOsfcF.js} +1 -1
- package/dist/{arazzo-BpS7LnV0.js → arazzo-BXaEhGHM.js} +1 -1
- package/dist/{arazzo-CmQaGPkM.js → arazzo-CTH5iN--.js} +1 -1
- package/dist/better-supabase/index.d.ts +188 -23
- package/dist/better-supabase/index.js +246 -62
- package/dist/{casbin-B7_yS-oo.js → casbin-BuTZnSPv.js} +1 -1
- package/dist/{casbin-bHyIxTNQ.js → casbin-DTi6HSsl.js} +1 -1
- package/dist/cli/bin.js +1 -1
- package/dist/cli/index.d.ts +6 -1
- package/dist/cli/index.js +10 -2
- package/dist/{cloud-3kWfjnYy.js → cloud-DiAiYFRo.js} +2 -2
- package/dist/{codemod-Bv5i-Mzo.js → codemod-C1U8_Zu3.js} +1 -1
- package/dist/{codemod-D9Aiii1r.js → codemod-_q_ZI01S.js} +2 -2
- package/dist/{collect-B80GYEot.js → collect-D9Tt0Bcx.js} +1 -1
- package/dist/{completion-_bc0OUQ-.js → completion-DLTuCf53.js} +1 -1
- package/dist/{config-BwPBfN0t.js → config-BR23fL8m.js} +2 -2
- package/dist/{config-D5XrLWpk.js → config-CmydKZr2.js} +1 -1
- package/dist/{config-report-BmWIskD7.js → config-report-5AwptLr2.js} +2 -2
- package/dist/{config-shape-ykV0Vm2n.js → config-shape-tsxHx71E.js} +2 -1
- package/dist/{create-BamXmeob.d.ts → create-CDd9c22W.d.ts} +10 -1
- package/dist/{doctor-LPMYjSqO.js → doctor-DxyVeUEE.js} +2 -2
- package/dist/{doctor-ClRVAtXQ.js → doctor-ktitU5Dl.js} +142 -14
- package/dist/{fields-D0vUI6dq.js → fields-DI8s3cPl.js} +1 -1
- package/dist/{gen-BtfFWGbz.js → gen-DuAhghDw.js} +1 -1
- package/dist/{gen-BFfzZSLH.js → gen-DwgCSC6V.js} +1 -1
- package/dist/{import-CST57XLp.js → import-CNBF96hB.js} +2 -2
- package/dist/{import-ACkOrv6g.js → import-t1yqnCyG.js} +1 -1
- package/dist/{index-vYjMrXyK.d.ts → index-Cay5-Kvx.d.ts} +3 -51
- package/dist/index.d.ts +2 -1
- package/dist/{init-txYTuW9u.js → init-CY7THM2v.js} +3 -3
- package/dist/{init-BjuFDYT1.js → init-DFwylmiN.js} +1 -1
- package/dist/{login-CgfCTO3F.js → login-B92-dZMK.js} +1 -1
- package/dist/{login-CfImTJGb.js → login-C5XLYZSF.js} +3 -3
- package/dist/{manifest-CzzWtnAb.d.ts → manifest-B5yF3CIq.d.ts} +19 -0
- package/dist/{manifest-wg8WkkpD.js → manifest-BXTbHNIV.js} +1 -1
- package/dist/{manifest-B2QPh19C.js → manifest-Cav1rjNQ.js} +33 -33
- package/dist/{manifest-schema-2r37XRhD.js → manifest-schema-DQkBK2Mr.js} +28 -1
- package/dist/{migrate-B7oP_sQU.js → migrate-BJHxQqT5.js} +2 -2
- package/dist/{module-values-BJTBdo6y.js → module-values-B1EVTkHP.js} +1 -1
- package/dist/next/index.d.ts +16 -3
- package/dist/next/index.js +1 -1
- package/dist/next/plugin.d.ts +1 -1
- package/dist/next/plugin.js +1 -1
- package/dist/{openapi-BGeuunWC.js → openapi-CuePQL4z.js} +1 -1
- package/dist/{openapi-BIpw3Mb7.js → openapi-gMQQSzNn.js} +2 -2
- package/dist/{output-DV5dwOTs.js → output-CtyBwTNB.js} +1 -1
- package/dist/{ownership-DA5YdYTm.js → ownership-qqBuGJXr.js} +3 -3
- package/dist/{postgrest-5Dr3W64L.js → postgrest-DAxFltvO.js} +1 -1
- package/dist/powersync-6vgKevSi.js +1 -0
- package/dist/{powersync-Bg8u-JcR.js → powersync-CBcsEvdr.js} +2 -2
- package/dist/{powersync-CJrT1DSc.js → powersync-CD8-Ypao.js} +188 -36
- package/dist/{pull-2nJr0qg_.js → pull-CAeaAioC.js} +2 -2
- package/dist/pull-DfJALUbS.js +1 -0
- package/dist/{push-Bn-lMEmI.js → push-Dq_ca4-j.js} +1 -1
- package/dist/{resolve-names-ConCSj1y.js → resolve-names-Y1Cb22cp.js} +4 -4
- package/dist/{rls-Ba9wN0SP.js → rls-BYHN5bcJ.js} +1 -1
- package/dist/{rls-Cx0dtsB7.js → rls-CtRaRrn3.js} +22 -15
- package/dist/run-0vOholnN.js +1 -0
- package/dist/{run-PbRlXTfh.js → run-B5nyNKe8.js} +3 -3
- package/dist/{run-ticket-Dv7aF7Dk.js → run-ticket-DfnZCh-u.js} +19 -6
- package/dist/{run-ticket-B2o2Kxz8.d.ts → run-ticket-ylovhyFQ.d.ts} +16 -1
- package/dist/{scan-CRTj6fke.js → scan-CvFWW_fU.js} +1 -1
- package/dist/{schema-BTsE1WRT.js → schema-CQzIJdEd.js} +1 -1
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.js +1 -1
- package/dist/{shared-Afctg7B0.js → shared-DrGLwM3s.js} +1 -1
- package/dist/{skills-C9uKfSF5.js → skills-BZc81VLt.js} +1 -1
- package/dist/{skills-CQQcuGBi.js → skills-Bar7ZqwM.js} +1 -1
- package/dist/{sources-CMAM-2A3.js → sources-C4vkzZJV.js} +12 -7
- package/dist/{types-BMVDHvI0.d.ts → sources-oB1Hg1Fm.d.ts} +316 -2
- package/dist/supabase/index.d.ts +10 -3
- package/dist/supabase/index.js +4 -4
- package/dist/{supabase-SBs3MYUE.js → supabase-CBEK6KEo.js} +2 -2
- package/dist/{supabase-DnMMg5Fn.js → supabase-CC6rIri4.js} +3 -2
- package/dist/supabase-hook-CWvEpdCh.js +1 -0
- package/dist/{supabase-hook-CrgU06WH.js → supabase-hook-CyuD9Wau.js} +110 -47
- package/dist/{supautils-ByezN3b8.js → supautils-C-_jqylY.js} +8 -8
- package/dist/{tables-BqrxBCir.js → tables-DimBcVWY.js} +2 -2
- package/dist/testing/fixtures/index.d.ts +1 -1
- package/dist/testing/fixtures/index.js +26 -28
- package/dist/testing/index.d.ts +4 -3
- package/dist/testing/index.js +3 -2
- package/dist/{types-CzOeVvcC.d.ts → types-Cklw5hJo.d.ts} +23 -2
- package/dist/unplugin/index.d.ts +1 -1
- package/dist/unplugin/index.js +1 -1
- package/dist/usage-CNca1i1W.js +1 -0
- package/dist/{usage-B9EtHWLa.js → usage-Y6xZUfE-.js} +2 -2
- package/dist/{usage-CBzgwfIs.js → usage-heV5KOiU.js} +1 -1
- package/dist/{verify-DlUcTDBz.js → verify-6EauWrkP.js} +6 -6
- package/dist/version-cache-Df11C2Qp.d.ts +51 -0
- package/dist/{watch-BFDKqmUa.js → watch-Bpci3hBY.js} +1 -1
- package/dist/watch-COuvly20.js +1 -0
- package/dist/workflow/index.d.ts +1 -1
- package/dist/workflow/index.js +22 -6
- package/dist/workflow-sdk/index.d.ts +1 -1
- package/package.json +2 -2
- package/schemas/run-v1.json +16 -0
- package/schemas/supabase-manifest-v1.json +28 -0
- package/skills/permdock-agents/references/operations-automations-chat.md +1 -0
- package/skills/permdock-approvals/references/stores-and-resume.md +1 -1
- package/skills/permdock-wire/references/adapters.md +2 -2
- package/dist/powersync-B701tvhE.js +0 -1
- package/dist/pull-C3EEGzSw.js +0 -1
- package/dist/run-Ck22anC2.js +0 -1
- package/dist/sources-CWG32C0G.d.ts +0 -312
- package/dist/supabase-hook-C0FyEACZ.js +0 -1
- package/dist/usage-0hjZPIRX.js +0 -1
- package/dist/watch-ClLuO2TL.js +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as compact } from "./compact-CAf557ZB.js";
|
|
2
|
-
import { c as isConditionDate, l as isConditionRef } from "./refs-C8BKxc_e.js";
|
|
2
|
+
import { c as isConditionDate, l as isConditionRef, o as hasConditionOp } from "./refs-C8BKxc_e.js";
|
|
3
3
|
import { g as localSnapshotManifest, j as memoryCustomRoleSource } from "./src-C_pi2Rnh.js";
|
|
4
4
|
import { n as findPermission } from "./permission-registry-B8tYxPIt.js";
|
|
5
5
|
import { f as scopeList, s as resolveScope } from "./scopes-0Up_UA2t.js";
|
|
@@ -10,16 +10,16 @@ import { u as usageResult } from "./errors-Vpu6rKHl.js";
|
|
|
10
10
|
import { c as requirePolicy } from "./load-DjSU5KXO.js";
|
|
11
11
|
import { s as quoteSqlLiteral, t as SQL_IDENT } from "./sql-0WjxIp9g.js";
|
|
12
12
|
import { a as scopeMembershipTable, i as scopeColumn } from "./compile-EzEMB-7v.js";
|
|
13
|
-
import "./sources-
|
|
13
|
+
import "./sources-C4vkzZJV.js";
|
|
14
14
|
import { t as applyFiles } from "./files-B3AA05f1.js";
|
|
15
15
|
import { i as fileDrift } from "./output-files-BIQ_9pIs.js";
|
|
16
16
|
import { n as fixtureSubject, r as loadFixtures, t as fixtureRow } from "./fixtures-A1_sp_tR.js";
|
|
17
|
-
import { O as quoteIdent, a as customRolesOn, t as CUSTOM_ROLES } from "./shared-
|
|
18
|
-
import { r as tableNames } from "./tables-
|
|
19
|
-
import { d as andConditions, l as collectGrants, o as assignableRoles, p as contextRefs, t as ownershipRules, u as roleNames } from "./ownership-
|
|
17
|
+
import { O as quoteIdent, a as customRolesOn, t as CUSTOM_ROLES } from "./shared-DrGLwM3s.js";
|
|
18
|
+
import { r as tableNames } from "./tables-DimBcVWY.js";
|
|
19
|
+
import { d as andConditions, l as collectGrants, o as assignableRoles, p as contextRefs, t as ownershipRules, u as roleNames } from "./ownership-qqBuGJXr.js";
|
|
20
20
|
import { t as membershipSourcesOf } from "./sources-qoIJQrJv.js";
|
|
21
21
|
import { n as pgConnector } from "./pg-DQTqRrou.js";
|
|
22
|
-
import { m as tableFor, t as canFixture } from "./verify-
|
|
22
|
+
import { m as tableFor, t as canFixture } from "./verify-6EauWrkP.js";
|
|
23
23
|
import { resolve } from "node:path";
|
|
24
24
|
//#region src/cli/powersync/names.ts
|
|
25
25
|
function ident(name) {
|
|
@@ -87,7 +87,7 @@ function scopeSourcesOf(sources, name) {
|
|
|
87
87
|
/** The source's stream form, or why its rows cannot filter a stream. */
|
|
88
88
|
function streamOf(source) {
|
|
89
89
|
const { stream } = source.sql;
|
|
90
|
-
if (stream === void 0) return `the ${source.sql.table} membership source has no stream form: build it with tableMembershipSource or
|
|
90
|
+
if (stream === void 0) return `the ${source.sql.table} membership source has no stream form: build it with tableMembershipSource, junctionMembershipSource or blockMembershipSource`;
|
|
91
91
|
if (stream.expiresAt !== void 0) return `the ${stream.table} membership source has no stream: it has an expiry`;
|
|
92
92
|
if (stream.disabledAt !== void 0) return `the ${stream.table} membership source has no stream: it has disabledAt`;
|
|
93
93
|
return stream;
|
|
@@ -399,6 +399,65 @@ function customRoleItems(ctx, grants, resource, key, table) {
|
|
|
399
399
|
}) };
|
|
400
400
|
}
|
|
401
401
|
//#endregion
|
|
402
|
+
//#region src/cli/powersync/tables.ts
|
|
403
|
+
/**
|
|
404
|
+
* One stream per `powersync.tables` entry: the user's own rows, and the rows
|
|
405
|
+
* that point at a resource row the user reads. A stream of the user's own rows
|
|
406
|
+
* alone carries `user`, so `verify` checks it holds no other user's row.
|
|
407
|
+
*/
|
|
408
|
+
function tableStreams(tables, dialect, taken, permitted) {
|
|
409
|
+
const streams = [];
|
|
410
|
+
const warnings = [];
|
|
411
|
+
const omitted = [];
|
|
412
|
+
for (const [source, spec] of Object.entries(tables)) {
|
|
413
|
+
const table = bare(source, dialect);
|
|
414
|
+
const from = fromTable(source, dialect);
|
|
415
|
+
const queries = [];
|
|
416
|
+
const follows = spec.follow ?? [];
|
|
417
|
+
const invalid = [...spec.user === void 0 ? [] : [spec.user], ...follows.flatMap((follow) => [follow.field, ...Object.keys(follow.match ?? {})])].find((column) => !SQL_IDENT.test(column));
|
|
418
|
+
if (taken.has(table) || invalid !== void 0) {
|
|
419
|
+
omitted.push({
|
|
420
|
+
resource: source,
|
|
421
|
+
reason: invalid === void 0 ? `a resource stream is named ${table}` : `${invalid} is not a column name`
|
|
422
|
+
});
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
if (spec.user !== void 0) queries.push(`SELECT * FROM ${from} WHERE ${dialect.column(table, spec.user)} = ${dialect.user}`);
|
|
426
|
+
for (const follow of follows) {
|
|
427
|
+
const { ids, gaps } = permitted(follow.resource);
|
|
428
|
+
for (const gap of gaps) warnings.push(`${source} under-syncs: ${gap}`);
|
|
429
|
+
if (ids === void 0) {
|
|
430
|
+
warnings.push(`${source} does not sync the rows of ${follow.resource}: no grant of its read permission compiles, or it has a deny grant`);
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
const match = Object.entries(follow.match ?? {}).map(([column, value]) => `${dialect.column(table, column)} = ${dialect.literal(value)}`);
|
|
434
|
+
for (const query of ids) queries.push(`SELECT * FROM ${from} WHERE ${[`${dialect.column(table, follow.field)} IN (${query})`, ...match].join(" AND ")}`);
|
|
435
|
+
}
|
|
436
|
+
if (queries.length === 0) {
|
|
437
|
+
omitted.push({
|
|
438
|
+
resource: source,
|
|
439
|
+
reason: "no query compiles"
|
|
440
|
+
});
|
|
441
|
+
continue;
|
|
442
|
+
}
|
|
443
|
+
streams.push(spec.user !== void 0 && follows.length === 0 ? {
|
|
444
|
+
name: table,
|
|
445
|
+
table,
|
|
446
|
+
user: spec.user,
|
|
447
|
+
queries
|
|
448
|
+
} : {
|
|
449
|
+
name: table,
|
|
450
|
+
table,
|
|
451
|
+
queries
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
return {
|
|
455
|
+
streams,
|
|
456
|
+
warnings,
|
|
457
|
+
omitted
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
//#endregion
|
|
402
461
|
//#region src/cli/powersync/streams.ts
|
|
403
462
|
const POWERSYNC = {
|
|
404
463
|
user: "auth.user_id()",
|
|
@@ -419,6 +478,8 @@ const POSTGRES = {
|
|
|
419
478
|
* than truncated.
|
|
420
479
|
*/
|
|
421
480
|
const MAX_QUERIES = 32;
|
|
481
|
+
/** Nested `inherit()` grants a stream follows; a longer chain syncs nothing. */
|
|
482
|
+
const MAX_INHERIT_DEPTH = 4;
|
|
422
483
|
/** Every combination of one clause list from each input, ANDed. */
|
|
423
484
|
function product(lists) {
|
|
424
485
|
let out = [[]];
|
|
@@ -502,15 +563,85 @@ function conditionSql(condition, table, ctx) {
|
|
|
502
563
|
return membershipSql(scope, left, condition.roles, ctx);
|
|
503
564
|
}
|
|
504
565
|
case "sqlFunction": return conditionSql(condition.twin, table, ctx);
|
|
566
|
+
case "related": return relatedSql(condition, table, ctx);
|
|
505
567
|
case "not":
|
|
506
568
|
case "contains":
|
|
507
|
-
case "related":
|
|
508
569
|
case "opaque":
|
|
509
570
|
case "liveSession": return;
|
|
510
571
|
default: return condition;
|
|
511
572
|
}
|
|
512
573
|
}
|
|
513
574
|
/**
|
|
575
|
+
* An `inherit()` condition: the row's `field` among the ids of the `resource`
|
|
576
|
+
* rows the user reaches with `permission`, one nested `IN (SELECT …)` per link
|
|
577
|
+
* hop. A relation reads the closure table, which Sync Streams cannot.
|
|
578
|
+
*/
|
|
579
|
+
function relatedSql(condition, table, ctx) {
|
|
580
|
+
const { permission } = condition;
|
|
581
|
+
if (permission === void 0 || condition.relation !== "" || condition.ids !== void 0 || condition.depth > 0 || condition.restrictedAncestors !== void 0 || ctx.depth >= MAX_INHERIT_DEPTH || !SQL_IDENT.test(condition.field)) return;
|
|
582
|
+
let ids = permittedSql(condition.resource, permission, {
|
|
583
|
+
...ctx,
|
|
584
|
+
depth: ctx.depth + 1
|
|
585
|
+
});
|
|
586
|
+
const hops = condition.hops ?? [];
|
|
587
|
+
for (let index = hops.length - 1; index > 0 && ids !== void 0; index -= 1) {
|
|
588
|
+
const hop = hops[index];
|
|
589
|
+
const node = ctx.policy.resources.get(hops[index - 1]?.resource ?? "");
|
|
590
|
+
const link = hop !== void 0 && node !== void 0 && Object.hasOwn(node.links, hop.link) ? node.links[hop.link] : void 0;
|
|
591
|
+
if (node === void 0 || link === void 0 || !SQL_IDENT.test(node.id) || !SQL_IDENT.test(link.field)) return;
|
|
592
|
+
const source = tableFor(node.name, tableNames(ctx.config.rls?.tables));
|
|
593
|
+
const name = bare(source, ctx.dialect);
|
|
594
|
+
ids = ids.map((query) => `SELECT ${ctx.dialect.column(name, node.id)} FROM ${fromTable(source, ctx.dialect)} WHERE ${ctx.dialect.column(name, link.field)} IN (${query})`);
|
|
595
|
+
}
|
|
596
|
+
const open = condition.restricted === void 0 ? [[]] : conditionSql({
|
|
597
|
+
op: "or",
|
|
598
|
+
conditions: [{
|
|
599
|
+
op: "isNull",
|
|
600
|
+
field: condition.restricted,
|
|
601
|
+
value: true
|
|
602
|
+
}, {
|
|
603
|
+
op: "eq",
|
|
604
|
+
field: condition.restricted,
|
|
605
|
+
value: false
|
|
606
|
+
}]
|
|
607
|
+
}, table, ctx);
|
|
608
|
+
if (ids === void 0 || open === void 0) return;
|
|
609
|
+
const left = ctx.dialect.column(table, condition.field);
|
|
610
|
+
return product([ids.map((query) => [`${left} IN (${query})`]), open]);
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* The `SELECT`s of the ids of the `resource` rows the user reaches with `key`:
|
|
614
|
+
* `[]` when no grant gives it, `undefined` when a deny grant could subtract
|
|
615
|
+
* rows or no grant compiles. A grant that does not compile leaves its rows out,
|
|
616
|
+
* which the caller reports as an under-sync.
|
|
617
|
+
*/
|
|
618
|
+
function permittedSql(resource, key, ctx) {
|
|
619
|
+
const node = ctx.policy.resources.get(resource);
|
|
620
|
+
const items = ctx.grants.filter((item) => item.grant.permission.key === key);
|
|
621
|
+
if (node === void 0 || !SQL_IDENT.test(node.id) || items.some((item) => item.grant.effect === "deny")) return;
|
|
622
|
+
const source = tableFor(resource, tableNames(ctx.config.rls?.tables));
|
|
623
|
+
const table = bare(source, ctx.dialect);
|
|
624
|
+
const custom = customRoleItems(ctx, ctx.grants, resource, key, table);
|
|
625
|
+
if (custom.skipped !== void 0) ctx.gaps.push(custom.skipped);
|
|
626
|
+
const reaches = [...items.map((item) => ({
|
|
627
|
+
item,
|
|
628
|
+
access: unsupported(item) ?? accessSql(item, table, ctx)
|
|
629
|
+
})), ...custom.items.map((entry) => ({
|
|
630
|
+
item: entry.item,
|
|
631
|
+
access: entry.access
|
|
632
|
+
}))];
|
|
633
|
+
const queries = /* @__PURE__ */ new Set();
|
|
634
|
+
for (const { item, access } of reaches) {
|
|
635
|
+
const where = typeof access === "string" || item.where === void 0 ? [[]] : conditionSql(item.where, table, ctx);
|
|
636
|
+
if (typeof access === "string" || where === void 0) {
|
|
637
|
+
ctx.gaps.push(`inherit() of ${key} leaves out ${item.label}: ${typeof access === "string" ? access : "its condition has no Sync Streams form"}`);
|
|
638
|
+
continue;
|
|
639
|
+
}
|
|
640
|
+
for (const clauses of product([access, where])) queries.add(`SELECT ${ctx.dialect.column(table, node.id)} FROM ${fromTable(source, ctx.dialect)}${clauses.length === 0 ? "" : ` WHERE ${clauses.join(" AND ")}`}`);
|
|
641
|
+
}
|
|
642
|
+
return queries.size === 0 && reaches.length > 0 ? void 0 : [...queries];
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
514
645
|
* One `IN (SELECT …)` per role source of the membership table: the row's `left`
|
|
515
646
|
* is an instance the user holds `roles` in.
|
|
516
647
|
*/
|
|
@@ -758,6 +889,7 @@ function powersyncPlan(policy, config, dialect = POWERSYNC) {
|
|
|
758
889
|
}
|
|
759
890
|
function planWith(policy, config, dialect) {
|
|
760
891
|
const scopes = scopeList(policy.scopes);
|
|
892
|
+
const grants = collectGrants(policy);
|
|
761
893
|
const ctx = {
|
|
762
894
|
policy,
|
|
763
895
|
config,
|
|
@@ -765,10 +897,11 @@ function planWith(policy, config, dialect) {
|
|
|
765
897
|
kinds: ownershipRules(policy, scopes)?.kinds ?? {},
|
|
766
898
|
dialect,
|
|
767
899
|
sources: guardedSources(policy, config),
|
|
900
|
+
grants,
|
|
901
|
+
depth: 0,
|
|
768
902
|
gaps: []
|
|
769
903
|
};
|
|
770
904
|
const action = config.powersync?.action ?? "read";
|
|
771
|
-
const grants = collectGrants(policy);
|
|
772
905
|
const resources = config.powersync?.resources ?? [...policy.resources.keys()].filter((name) => grants.some((item) => item.grant.permission.resource === name && item.grant.permission.action === action));
|
|
773
906
|
const streams = [];
|
|
774
907
|
const omitted = [];
|
|
@@ -849,11 +982,22 @@ function planWith(policy, config, dialect) {
|
|
|
849
982
|
queries: [...queries]
|
|
850
983
|
});
|
|
851
984
|
}
|
|
985
|
+
const tables = tableStreams(config.powersync?.tables ?? {}, dialect, new Set(streams.map((stream) => stream.name)), (resource) => ({
|
|
986
|
+
ids: permittedSql(resource, `${resource}.${action}`, ctx),
|
|
987
|
+
gaps: [...new Set(ctx.gaps.splice(0))]
|
|
988
|
+
}));
|
|
989
|
+
warnings.push(...tables.warnings);
|
|
990
|
+
omitted.push(...tables.omitted);
|
|
852
991
|
const subject = subjectStreams(ctx);
|
|
853
|
-
const outside = [...new Set([
|
|
992
|
+
const outside = [...new Set([
|
|
993
|
+
...streams,
|
|
994
|
+
...subject,
|
|
995
|
+
...tables.streams
|
|
996
|
+
].flatMap((stream) => stream.queries.flatMap((query) => [...query.matchAll(QUOTED_TABLE)].map(([, schema, name]) => `${schema ?? ""}.${name ?? ""}`))))].toSorted();
|
|
854
997
|
return {
|
|
855
998
|
streams,
|
|
856
999
|
subject,
|
|
1000
|
+
tables: tables.streams,
|
|
857
1001
|
omitted,
|
|
858
1002
|
warnings,
|
|
859
1003
|
unsynced,
|
|
@@ -862,31 +1006,6 @@ function planWith(policy, config, dialect) {
|
|
|
862
1006
|
...outside.length === 0 ? {} : { publication: `alter publication powersync add table ${outside.join(", ")};` }
|
|
863
1007
|
};
|
|
864
1008
|
}
|
|
865
|
-
/**
|
|
866
|
-
* A YAML scalar quoted as oxfmt and Prettier write it: single quotes around a
|
|
867
|
-
* `"`, unless a backslash needs a double-quoted escape.
|
|
868
|
-
*/
|
|
869
|
-
function yamlString(text) {
|
|
870
|
-
return text.includes("\"") && !text.includes("\\") ? `'${text.replaceAll("'", "''")}'` : JSON.stringify(text);
|
|
871
|
-
}
|
|
872
|
-
/**
|
|
873
|
-
* `sync-config.yaml`: edition 3 Sync Streams, one auto-subscribed stream per
|
|
874
|
-
* synced resource.
|
|
875
|
-
*/
|
|
876
|
-
function powersyncYaml(plan) {
|
|
877
|
-
const lines = [
|
|
878
|
-
"# Generated by permdock powersync generate from the policy. Do not edit.",
|
|
879
|
-
...plan.publication === void 0 ? [] : ["# Tables outside public must be in the powersync publication:", `# ${plan.publication}`],
|
|
880
|
-
"config:",
|
|
881
|
-
" edition: 3",
|
|
882
|
-
"",
|
|
883
|
-
"streams:"
|
|
884
|
-
];
|
|
885
|
-
if (plan.streams.length === 0 && plan.subject.length === 0) lines[lines.length - 1] = "streams: {}";
|
|
886
|
-
for (const stream of [...plan.streams, ...plan.subject]) lines.push(` ${stream.name}:`, " auto_subscribe: true", " queries:", ...stream.queries.map((query) => ` - ${yamlString(query)}`));
|
|
887
|
-
for (const item of plan.omitted) lines.push(`# ${item.resource}: not synced, ${item.reason}`);
|
|
888
|
-
return `${lines.join("\n")}\n`;
|
|
889
|
-
}
|
|
890
1009
|
//#endregion
|
|
891
1010
|
//#region src/cli/powersync/verify-gaps.ts
|
|
892
1011
|
function heldRoles(subject) {
|
|
@@ -911,6 +1030,37 @@ function warnedFor(unsynced, permission, subject, customRoles) {
|
|
|
911
1030
|
});
|
|
912
1031
|
}
|
|
913
1032
|
//#endregion
|
|
1033
|
+
//#region src/cli/powersync/yaml.ts
|
|
1034
|
+
/**
|
|
1035
|
+
* A YAML scalar quoted as oxfmt and Prettier write it: single quotes around a
|
|
1036
|
+
* `"`, unless a backslash needs a double-quoted escape.
|
|
1037
|
+
*/
|
|
1038
|
+
function yamlString(text) {
|
|
1039
|
+
return text.includes("\"") && !text.includes("\\") ? `'${text.replaceAll("'", "''")}'` : JSON.stringify(text);
|
|
1040
|
+
}
|
|
1041
|
+
/**
|
|
1042
|
+
* `sync-config.yaml`: edition 3 Sync Streams, one auto-subscribed stream per
|
|
1043
|
+
* synced resource.
|
|
1044
|
+
*/
|
|
1045
|
+
function powersyncYaml(plan) {
|
|
1046
|
+
const lines = [
|
|
1047
|
+
"# Generated by permdock powersync generate from the policy. Do not edit.",
|
|
1048
|
+
...plan.publication === void 0 ? [] : ["# Tables outside public must be in the powersync publication:", `# ${plan.publication}`],
|
|
1049
|
+
"config:",
|
|
1050
|
+
" edition: 3",
|
|
1051
|
+
"",
|
|
1052
|
+
"streams:"
|
|
1053
|
+
];
|
|
1054
|
+
if (plan.streams.length === 0 && plan.subject.length === 0 && plan.tables.length === 0) lines[lines.length - 1] = "streams: {}";
|
|
1055
|
+
for (const stream of [
|
|
1056
|
+
...plan.streams,
|
|
1057
|
+
...plan.subject,
|
|
1058
|
+
...plan.tables
|
|
1059
|
+
]) lines.push(` ${stream.name}:`, " auto_subscribe: true", " queries:", ...stream.queries.map((query) => ` - ${yamlString(query)}`));
|
|
1060
|
+
for (const item of plan.omitted) lines.push(`# ${item.resource}: not synced, ${item.reason}`);
|
|
1061
|
+
return `${lines.join("\n")}\n`;
|
|
1062
|
+
}
|
|
1063
|
+
//#endregion
|
|
914
1064
|
//#region src/cli/powersync/powersync.ts
|
|
915
1065
|
const POWERSYNC_HELP = `permdock powersync generate [--out sync-config.yaml] [--check]
|
|
916
1066
|
permdock powersync verify [--db-url-stdin] [--fixtures rls.fixtures.json]`;
|
|
@@ -997,6 +1147,7 @@ async function synced(query, stream, fixture) {
|
|
|
997
1147
|
}
|
|
998
1148
|
async function verifyStreams(input) {
|
|
999
1149
|
const plan = powersyncPlan(input.policy, input.config, POSTGRES);
|
|
1150
|
+
const inherited = new Set(collectGrants(input.policy).filter((item) => hasConditionOp(item.where, "related")).map((item) => item.grant.permission.key));
|
|
1000
1151
|
const mismatches = [];
|
|
1001
1152
|
const notes = [];
|
|
1002
1153
|
const client = await input.connect(input.db);
|
|
@@ -1007,7 +1158,7 @@ async function verifyStreams(input) {
|
|
|
1007
1158
|
for (const fixture of input.fixtures) {
|
|
1008
1159
|
if (checked.has(fixture.subject.id)) continue;
|
|
1009
1160
|
checked.add(fixture.subject.id);
|
|
1010
|
-
for (const stream of plan.subject) if (stream.user !== void 0 && await leaks(query, stream, stream.user, fixture)) mismatches.push(`stream ${stream.name} syncs another user's ${stream.table} rows to ${fixture.subject.id}`);
|
|
1161
|
+
for (const stream of [...plan.subject, ...plan.tables]) if (stream.user !== void 0 && await leaks(query, stream, stream.user, fixture)) mismatches.push(`stream ${stream.name} syncs another user's ${stream.table} rows to ${fixture.subject.id}`);
|
|
1011
1162
|
}
|
|
1012
1163
|
for (const fixture of input.fixtures) {
|
|
1013
1164
|
const permission = findPermission(input.policy.permissions, fixture.action);
|
|
@@ -1021,6 +1172,7 @@ async function verifyStreams(input) {
|
|
|
1021
1172
|
const granted = canFixture(permdock, permission, fixtureRow(fixture, permission.kind));
|
|
1022
1173
|
const holds = await synced(query, stream, fixture);
|
|
1023
1174
|
if (holds === void 0) notes.push(`${fixture.action} for ${fixture.subject.id}: not checked against stream ${stream.name}: the fixture row has no ${stream.id}`);
|
|
1175
|
+
else if (holds && !granted && inherited.has(permission.key)) notes.push(`${fixture.action} for ${fixture.subject.id}: stream ${stream.name} syncs the row through inherit(), which verify does not check: can() here has no relation source`);
|
|
1024
1176
|
else if (holds && !granted) mismatches.push(`${fixture.action} for ${fixture.subject.id}: stream ${stream.name} syncs a row the policy denies`);
|
|
1025
1177
|
else if (granted && !holds && warnedFor(plan.unsynced, permission.key, fixture.subject, input.customRoles)) notes.push(`${fixture.action} for ${fixture.subject.id}: granted, not synced (the app reads it from the server)`);
|
|
1026
1178
|
else if (granted && !holds) mismatches.push(`${fixture.action} for ${fixture.subject.id}: granted, but stream ${stream.name} does not sync the row and generate gave no warning for it`);
|
|
@@ -5,9 +5,9 @@ import { s as writeFileEnsuringDir } from "./files-BSjrtIHw.js";
|
|
|
5
5
|
import { s as cliVersion } from "./version-DMQ0dnN5.js";
|
|
6
6
|
import { o as formatCatalogJson } from "./catalog-doc-DjMKzJp9.js";
|
|
7
7
|
import { t as catalogPath } from "./catalog-path-CnI0XTFK.js";
|
|
8
|
-
import { n as parseSupabaseManifest } from "./manifest-
|
|
8
|
+
import { n as parseSupabaseManifest } from "./manifest-BXTbHNIV.js";
|
|
9
9
|
import { t as parseCatalog } from "./parse-1_ZheTW5.js";
|
|
10
|
-
import { a as nonEmptyOr } from "./output-
|
|
10
|
+
import { a as nonEmptyOr } from "./output-CtyBwTNB.js";
|
|
11
11
|
import { t as POLICY_NOT_PUBLISHED } from "./problem-types-DSsRfONQ.js";
|
|
12
12
|
import { n as httpRequest, t as authFailure } from "./http-DOL33cO0.js";
|
|
13
13
|
import { l as cloudUrl, n as cliRuntime, o as readAuth } from "./auth--yPyZNgr.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { n as runCloudPull } from "./pull-CAeaAioC.js";
|
|
@@ -4,7 +4,7 @@ import { t as catalogFingerprint } from "./catalog-fingerprint-e6aCWosn.js";
|
|
|
4
4
|
import { a as describeError, n as CliError } from "./errors-Vpu6rKHl.js";
|
|
5
5
|
import { s as cliVersion } from "./version-DMQ0dnN5.js";
|
|
6
6
|
import { i as loadConfiguredPolicy } from "./load-DjSU5KXO.js";
|
|
7
|
-
import { n as parseSupabaseManifest } from "./manifest-
|
|
7
|
+
import { n as parseSupabaseManifest } from "./manifest-BXTbHNIV.js";
|
|
8
8
|
import { t as parseCatalog } from "./parse-1_ZheTW5.js";
|
|
9
9
|
import { r as pushedPolicy } from "./pushed-policy-CDuOL2de.js";
|
|
10
10
|
import { n as runCatalog } from "./catalog-CGlSwU6j.js";
|
|
@@ -3,10 +3,10 @@ import { c as listPermissions } from "./permission-registry-B8tYxPIt.js";
|
|
|
3
3
|
import { f as scopeList } from "./scopes-0Up_UA2t.js";
|
|
4
4
|
import { i as configError } from "./errors-Vpu6rKHl.js";
|
|
5
5
|
import "./budget-BELja5A9.js";
|
|
6
|
-
import "./sources-
|
|
7
|
-
import { A as quoteQualified, D as qualified, I as scopeTypeOf, O as quoteIdent } from "./shared-
|
|
8
|
-
import { F as globalRoleRows, Q as graphSqlName, Z as graphHelper, _ as PERMISSION_HELPERS, at as memberForHelper, c as holderSources, ct as memberIdsHelper, dt as permittedForHelper, ft as permittedIdsHelper, ht as scopeTable, lt as memberOfHelper, nt as inheritedRowsHelper, o as graphPlan, pt as restrictedHelper, r as tableNames, rt as isTeamScope, tt as hasPermittedUsers, v as checkName, x as permittedByPermissionHelper } from "./tables-
|
|
9
|
-
import { t as FIELD_VIEWS } from "./fields-
|
|
6
|
+
import "./sources-C4vkzZJV.js";
|
|
7
|
+
import { A as quoteQualified, D as qualified, I as scopeTypeOf, O as quoteIdent } from "./shared-DrGLwM3s.js";
|
|
8
|
+
import { F as globalRoleRows, Q as graphSqlName, Z as graphHelper, _ as PERMISSION_HELPERS, at as memberForHelper, c as holderSources, ct as memberIdsHelper, dt as permittedForHelper, ft as permittedIdsHelper, ht as scopeTable, lt as memberOfHelper, nt as inheritedRowsHelper, o as graphPlan, pt as restrictedHelper, r as tableNames, rt as isTeamScope, tt as hasPermittedUsers, v as checkName, x as permittedByPermissionHelper } from "./tables-DimBcVWY.js";
|
|
9
|
+
import { t as FIELD_VIEWS } from "./fields-DI8s3cPl.js";
|
|
10
10
|
//#region src/cli/rls/permission-holders.ts
|
|
11
11
|
/**
|
|
12
12
|
* `permitted_<scope>_users(p_permission, p_id)`. Names are part of the SQL
|
|
@@ -192,7 +192,7 @@ async function rlsInput(ctx, verb, shape, options) {
|
|
|
192
192
|
};
|
|
193
193
|
}
|
|
194
194
|
async function runRls(input) {
|
|
195
|
-
return (await import("./rls-
|
|
195
|
+
return (await import("./rls-CtRaRrn3.js")).runRls(input);
|
|
196
196
|
}
|
|
197
197
|
const generate = defineLeaf({
|
|
198
198
|
flags: {
|
|
@@ -7,26 +7,26 @@ import { t as policyRowConditionKeys } from "./row-conditions-BAGHOmVq.js";
|
|
|
7
7
|
import { o as sqlFiles } from "./files-BSjrtIHw.js";
|
|
8
8
|
import { c as requirePolicy } from "./load-DjSU5KXO.js";
|
|
9
9
|
import { i as qualifySqlTable, r as escapeSqlIdent } from "./sql-0WjxIp9g.js";
|
|
10
|
-
import "./sources-
|
|
10
|
+
import "./sources-C4vkzZJV.js";
|
|
11
11
|
import { t as policyFromCatalog } from "./policy-from-catalog-CU3An8uP.js";
|
|
12
12
|
import { t as beforeFirst } from "./text-BMFRfBqc.js";
|
|
13
13
|
import { i as INDEXES_MARKER, n as GRANTS_MARKER, o as SEEDS_MARKER, t as BACKFILL_MARKER } from "./markers-BeHZ4x9Q.js";
|
|
14
|
-
import { a as nonEmptyOr } from "./output-
|
|
14
|
+
import { a as nonEmptyOr } from "./output-CtyBwTNB.js";
|
|
15
15
|
import { i as requirePeer, n as packageManagerOf, t as addLine } from "./peer-Q0fuZ6hx.js";
|
|
16
16
|
import { t as POLICY_NOT_PUBLISHED } from "./problem-types-DSsRfONQ.js";
|
|
17
|
-
import { t as fetchProjectPolicy } from "./pull-
|
|
17
|
+
import { t as fetchProjectPolicy } from "./pull-CAeaAioC.js";
|
|
18
18
|
import { n as MIGRATION_DIRS } from "./constants-DcJABbLW.js";
|
|
19
19
|
import { a as isSeedsDirectory, c as parseSplit, d as seedsMigration, f as writeOutputFiles, l as partPath, n as dataMigrationFile, r as driftOf, u as pgDeltaPath } from "./output-files-BIQ_9pIs.js";
|
|
20
|
-
import {
|
|
21
|
-
import { A as quoteQualified, D as qualified$1, I as scopeTypeOf, O as quoteIdent$1, _ as subjectClaimJsonSql, c as SESSION_LIVE_HELPER, g as sessionLiveHelperSql, j as quoteTable, k as quoteLiteral, r as HELPERS, t as CUSTOM_ROLES, y as subjectIdSql } from "./shared-
|
|
22
|
-
import { C as accessSql, G as byKey, T as seedSql, Z as graphHelper, ct as memberIdsHelper, ft as permittedIdsHelper, ht as scopeTable, mt as scopeSources, r as tableNames, s as graphSql, w as helpersSql, x as permittedByPermissionHelper, y as permissionHelpersSql } from "./tables-
|
|
23
|
-
import { c as breakGlassKey, i as assignmentSql, l as collectGrants, n as ownershipSql, s as breakGlassHolder } from "./ownership-
|
|
20
|
+
import { b as rbacScaffold, d as resolveSchemas, f as schemasRefusal, o as supabaseHookSql, p as declarativeSql, s as approvalsSql, t as grantsLabel, u as isSupabaseSchemas, y as parseRbacAuthorize } from "./supabase-hook-CyuD9Wau.js";
|
|
21
|
+
import { A as quoteQualified, D as qualified$1, I as scopeTypeOf, O as quoteIdent$1, _ as subjectClaimJsonSql, c as SESSION_LIVE_HELPER, g as sessionLiveHelperSql, j as quoteTable, k as quoteLiteral, r as HELPERS, t as CUSTOM_ROLES, y as subjectIdSql } from "./shared-DrGLwM3s.js";
|
|
22
|
+
import { C as accessSql, G as byKey, T as seedSql, Z as graphHelper, ct as memberIdsHelper, ft as permittedIdsHelper, ht as scopeTable, mt as scopeSources, r as tableNames, s as graphSql, w as helpersSql, x as permittedByPermissionHelper, y as permissionHelpersSql } from "./tables-DimBcVWY.js";
|
|
23
|
+
import { c as breakGlassKey, i as assignmentSql, l as collectGrants, n as ownershipSql, s as breakGlassHolder } from "./ownership-qqBuGJXr.js";
|
|
24
24
|
import { a as splitUndiffed } from "./deciding-columns-NB4wcyBf.js";
|
|
25
25
|
import { t as connectPgPool } from "./pg-DQTqRrou.js";
|
|
26
|
-
import { n as
|
|
27
|
-
import {
|
|
28
|
-
import { _ as indexTargets, a as verifyResult, b as readTableIndexFacts, c as callsHelper, g as INDEX_COLUMNS_SQL, h as COLUMNS_SQL, i as verifyIgnores, l as helperCallKeys, m as tableFor, n as runRlsVerify, o as HELPER_TABLES, p as compileGrants, r as rlsFinding, v as indexesSql, y as pruneIndexTargets } from "./verify-
|
|
29
|
-
import { a as buildContext, c as levelKeys, d as rebuildPlan, i as splitsPart, l as rowHelpersSql, n as generateOptions, o as CANDIDATES, r as isRefusal, s as inheritTargets, t as supautilsRejections, u as DROPPED_LIST } from "./supautils-
|
|
26
|
+
import { a as fieldViewsSql, c as ACTOR_MAY_WRITE, f as readOnlyActorKinds, i as fieldViews, l as actorMayWriteSql, n as columnGrantSql, o as rowBranches, p as readOnlyActorPolicies, r as columnRevokeSql, u as assemblePolicies } from "./fields-DI8s3cPl.js";
|
|
27
|
+
import { n as permissionHoldersSql } from "./resolve-names-Y1Cb22cp.js";
|
|
28
|
+
import { _ as indexTargets, a as verifyResult, b as readTableIndexFacts, c as callsHelper, g as INDEX_COLUMNS_SQL, h as COLUMNS_SQL, i as verifyIgnores, l as helperCallKeys, m as tableFor, n as runRlsVerify, o as HELPER_TABLES, p as compileGrants, r as rlsFinding, v as indexesSql, y as pruneIndexTargets } from "./verify-6EauWrkP.js";
|
|
29
|
+
import { a as buildContext, c as levelKeys, d as rebuildPlan, i as splitsPart, l as rowHelpersSql, n as generateOptions, o as CANDIDATES, r as isRefusal, s as inheritTargets, t as supautilsRejections, u as DROPPED_LIST } from "./supautils-C-_jqylY.js";
|
|
30
30
|
import { readFileSync } from "node:fs";
|
|
31
31
|
import { basename, delimiter, join } from "node:path";
|
|
32
32
|
import { spawn } from "node:child_process";
|
|
@@ -1409,7 +1409,7 @@ function sectionsSql(input, policy, options, built, generated, jsonSchema, warni
|
|
|
1409
1409
|
if (ctx.assignments !== void 0 && (ownership === void 0 || ownership.assigns.length === 0)) warnings.push("rls.assignments needs a role that declares assigns: no assignment trigger is written");
|
|
1410
1410
|
let approvals;
|
|
1411
1411
|
try {
|
|
1412
|
-
approvals = approvalsSql(ctx, rls?.approvals, jsonSchema ?? false);
|
|
1412
|
+
approvals = approvalsSql(ctx, rls?.approvals, jsonSchema ?? false, readOnlyActorKinds(rls?.readOnlyActors) !== void 0);
|
|
1413
1413
|
} catch (cause) {
|
|
1414
1414
|
return { refusal: describeError(cause) };
|
|
1415
1415
|
}
|
|
@@ -2232,6 +2232,13 @@ const WRITES = [
|
|
|
2232
2232
|
"delete"
|
|
2233
2233
|
];
|
|
2234
2234
|
/**
|
|
2235
|
+
* `rls generate` inlines the check in its `<table>_<command>_read_only_actors`
|
|
2236
|
+
* policies.
|
|
2237
|
+
*/
|
|
2238
|
+
function inlinesActorCheck(expression) {
|
|
2239
|
+
return expression.includes("'act'") && expression.includes("'read_only'");
|
|
2240
|
+
}
|
|
2241
|
+
/**
|
|
2235
2242
|
* Each table and write command whose permissive policies reach `authenticated`
|
|
2236
2243
|
* (or `public`) without the read-only actor check: no restrictive policy for
|
|
2237
2244
|
* the command calls `permdock_actor_may_write()`, and some permissive one does
|
|
@@ -2245,7 +2252,7 @@ function unguardedWrites(policies, fn) {
|
|
|
2245
2252
|
const permissive = applying.filter((policy) => policy.restrictive !== true && (policy.roles ?? []).some((role) => role === "authenticated" || role === "public"));
|
|
2246
2253
|
if (permissive.length === 0) continue;
|
|
2247
2254
|
const calls = (expression) => expression.includes(fn);
|
|
2248
|
-
if (!(applying.some((policy) => policy.restrictive === true && calls(policy.expression)) || permissive.every((policy) => calls(policy.expression)))) out.push(rlsFinding("write-unguarded", table, command, `${table}: ${command} policies for authenticated do not call ${fn}(), so a read-only support or impersonation session can write (rls.readOnlyActors)`));
|
|
2255
|
+
if (!(applying.some((policy) => policy.restrictive === true && (calls(policy.expression) || inlinesActorCheck(policy.expression))) || permissive.every((policy) => calls(policy.expression)))) out.push(rlsFinding("write-unguarded", table, command, `${table}: ${command} policies for authenticated do not call ${fn}(), so a read-only support or impersonation session can write (rls.readOnlyActors)`));
|
|
2249
2256
|
}
|
|
2250
2257
|
return out;
|
|
2251
2258
|
}
|
|
@@ -2474,7 +2481,7 @@ async function migrate(input) {
|
|
|
2474
2481
|
output: generated.output
|
|
2475
2482
|
};
|
|
2476
2483
|
await requirePeer(() => import("pgsql-parser"), "pgsql-parser", "permdock rls migrate", input.cwd, PGSQL_PARSER_MAJOR);
|
|
2477
|
-
const { migrateTarget, runRlsMigrate } = await import("./migrate-
|
|
2484
|
+
const { migrateTarget, runRlsMigrate } = await import("./migrate-BJHxQqT5.js");
|
|
2478
2485
|
return runRlsMigrate({
|
|
2479
2486
|
cwd: input.cwd,
|
|
2480
2487
|
sql: input.sql,
|
|
@@ -2590,7 +2597,7 @@ async function runRls(input) {
|
|
|
2590
2597
|
}
|
|
2591
2598
|
case "import": {
|
|
2592
2599
|
await requirePeer(() => import("pgsql-parser"), "pgsql-parser", "permdock rls import", input.cwd, PGSQL_PARSER_MAJOR);
|
|
2593
|
-
const { runRlsImport } = await import("./import-
|
|
2600
|
+
const { runRlsImport } = await import("./import-CNBF96hB.js");
|
|
2594
2601
|
return runRlsImport({
|
|
2595
2602
|
cwd: input.cwd,
|
|
2596
2603
|
config: input.config,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { t as run } from "./run-B5nyNKe8.js";
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { i as dateAt } from "./time-nR1JesoH.js";
|
|
2
2
|
import { a as describeError, l as problemOf, n as CliError, r as cliProblem, s as kindOfCode } from "./errors-Vpu6rKHl.js";
|
|
3
3
|
import { s as cliVersion } from "./version-DMQ0dnN5.js";
|
|
4
|
-
import { a as resolveCwd, i as readConfig } from "./config-
|
|
4
|
+
import { a as resolveCwd, i as readConfig } from "./config-BR23fL8m.js";
|
|
5
5
|
import { t as beforeFirst } from "./text-BMFRfBqc.js";
|
|
6
6
|
import { a as suggestion, i as parseLeaf, n as flagSpellings, o as GLOBAL_FLAGS, r as parseFlags } from "./args-0FrVs5EH.js";
|
|
7
7
|
import { r as progressReporter, t as redact } from "./credentials-CdDxp7jN.js";
|
|
8
|
-
import { a as resolve, i as leaves, n as ROOT, r as SECTIONS, t as DOCS_BASE } from "./manifest-
|
|
8
|
+
import { a as resolve, i as leaves, n as ROOT, r as SECTIONS, t as DOCS_BASE } from "./manifest-Cav1rjNQ.js";
|
|
9
9
|
import { t as createStyle } from "./style-Ds11Hmk4.js";
|
|
10
|
-
import { i as githubAnnotations, n as envelope, o as sarifLog, t as dataOf } from "./output-
|
|
10
|
+
import { i as githubAnnotations, n as envelope, o as sarifLog, t as dataOf } from "./output-CtyBwTNB.js";
|
|
11
11
|
import { i as renameMessage, r as flagRename, t as COMMAND_MOVES } from "./renames-CGj7YwcQ.js";
|
|
12
12
|
import { stripVTControlCharacters } from "node:util";
|
|
13
13
|
import { existsSync, statSync } from "node:fs";
|
|
@@ -26,7 +26,8 @@ const RUN_TICKET_CLAIMS = Object.freeze([
|
|
|
26
26
|
"automation",
|
|
27
27
|
"tenant",
|
|
28
28
|
"trigger",
|
|
29
|
-
"binding"
|
|
29
|
+
"binding",
|
|
30
|
+
"resource"
|
|
30
31
|
]);
|
|
31
32
|
const RUN_KINDS = [
|
|
32
33
|
"automation",
|
|
@@ -97,6 +98,14 @@ function parseAutomation(value) {
|
|
|
97
98
|
version: record["version"]
|
|
98
99
|
};
|
|
99
100
|
}
|
|
101
|
+
function parseResource(value) {
|
|
102
|
+
const record = ownRecord(value);
|
|
103
|
+
if (record === void 0 || !isId(record["type"]) || !isId(record["id"])) return;
|
|
104
|
+
return {
|
|
105
|
+
type: record["type"],
|
|
106
|
+
id: record["id"]
|
|
107
|
+
};
|
|
108
|
+
}
|
|
100
109
|
function parseBinding(value) {
|
|
101
110
|
const record = ownRecord(value);
|
|
102
111
|
if (record === void 0) return;
|
|
@@ -140,7 +149,8 @@ function parseBody(record) {
|
|
|
140
149
|
const automation = optional(record, "automation", parseAutomation);
|
|
141
150
|
const trigger = optional(record, "trigger", parseTrigger);
|
|
142
151
|
const binding = optional(record, "binding", parseBinding);
|
|
143
|
-
|
|
152
|
+
const resource = optional(record, "resource", parseResource);
|
|
153
|
+
if (!act.ok || !details.ok || !automation.ok || !trigger.ok || !binding.ok || !resource.ok || scope === void 0 && details.value === void 0 || kind === "automation" !== (automation.value !== void 0)) return;
|
|
144
154
|
return compact({
|
|
145
155
|
v: 1,
|
|
146
156
|
sub,
|
|
@@ -151,7 +161,8 @@ function parseBody(record) {
|
|
|
151
161
|
automation: automation.value,
|
|
152
162
|
tenant,
|
|
153
163
|
trigger: trigger.value,
|
|
154
|
-
binding: binding.value
|
|
164
|
+
binding: binding.value,
|
|
165
|
+
resource: resource.value
|
|
155
166
|
});
|
|
156
167
|
}
|
|
157
168
|
/**
|
|
@@ -218,9 +229,10 @@ function signRunTicket(input, signer, options = {}) {
|
|
|
218
229
|
automation: input.automation,
|
|
219
230
|
tenant: input.tenant,
|
|
220
231
|
trigger: input.trigger,
|
|
221
|
-
binding: input.binding
|
|
232
|
+
binding: input.binding,
|
|
233
|
+
resource: input.resource
|
|
222
234
|
}));
|
|
223
|
-
if (body === void 0) invalid("is invalid: check principal, kind, automation, delegation, trigger and
|
|
235
|
+
if (body === void 0) invalid("is invalid: check principal, kind, automation, delegation, trigger, binding and resource");
|
|
224
236
|
if (input.id !== void 0 && !isId(input.id)) invalid("id must be a non-empty string");
|
|
225
237
|
return signer.sign(body, compact({
|
|
226
238
|
typ: RUN_TICKET_TYP,
|
|
@@ -338,7 +350,8 @@ async function subjectFromRunTicket(token, options) {
|
|
|
338
350
|
id: ticket.jti,
|
|
339
351
|
kind: ticket.kind,
|
|
340
352
|
automation: ticket.automation,
|
|
341
|
-
binding: ticket.binding
|
|
353
|
+
binding: ticket.binding,
|
|
354
|
+
resource: ticket.resource
|
|
342
355
|
});
|
|
343
356
|
return Object.freeze(compact({
|
|
344
357
|
principal: Object.freeze({
|
|
@@ -24,6 +24,14 @@ type RunAutomation = {
|
|
|
24
24
|
readonly id: string;
|
|
25
25
|
readonly version: number | string;
|
|
26
26
|
};
|
|
27
|
+
/**
|
|
28
|
+
* The record a run is bound to. `authorization_details` carries the binding as
|
|
29
|
+
* `identifier`; this claim names it for the adapter and the audit trail.
|
|
30
|
+
*/
|
|
31
|
+
type RunResource = {
|
|
32
|
+
readonly type: string;
|
|
33
|
+
readonly id: string;
|
|
34
|
+
};
|
|
27
35
|
/**
|
|
28
36
|
* The v1 claims of a `vnd.permdock.run+jwt`. At least one of `scope` and
|
|
29
37
|
* `authorization_details` is present.
|
|
@@ -49,6 +57,7 @@ type RunTicket = {
|
|
|
49
57
|
*/
|
|
50
58
|
readonly trigger?: Readonly<Record<string, unknown>>;
|
|
51
59
|
readonly binding?: RunBinding;
|
|
60
|
+
readonly resource?: RunResource;
|
|
52
61
|
};
|
|
53
62
|
/**
|
|
54
63
|
* Every v1 claim of a `vnd.permdock.run+jwt`, the set `parseRunTicket` keeps. A
|
|
@@ -70,6 +79,11 @@ type RunTicketInput = {
|
|
|
70
79
|
readonly tenant?: string;
|
|
71
80
|
readonly trigger?: Readonly<Record<string, unknown>>;
|
|
72
81
|
readonly binding?: RunBinding;
|
|
82
|
+
/**
|
|
83
|
+
* The record the run is bound to. Narrow `delegation` to it with an
|
|
84
|
+
* `authorization_details` `identifier`; this claim grants nothing.
|
|
85
|
+
*/
|
|
86
|
+
readonly resource?: RunResource;
|
|
73
87
|
/** `jti`; a fresh UUID when absent. */
|
|
74
88
|
readonly id?: string;
|
|
75
89
|
/** Lifetime in whole seconds. Exactly one of `expiresIn` and `expiresAt`. */
|
|
@@ -113,6 +127,7 @@ type RunContext = {
|
|
|
113
127
|
readonly kind: RunKind;
|
|
114
128
|
readonly automation?: RunAutomation;
|
|
115
129
|
readonly binding?: RunBinding;
|
|
130
|
+
readonly resource?: RunResource;
|
|
116
131
|
};
|
|
117
132
|
/** The principal of a run subject, with the verified ticket attached. */
|
|
118
133
|
type RunPrincipal = Principal & {
|
|
@@ -141,4 +156,4 @@ declare function signRunTicket(input: RunTicketInput, signer: TokenSigner, optio
|
|
|
141
156
|
*/
|
|
142
157
|
declare function subjectFromRunTicket(token: string | undefined | null, options: RunTicketSubjectOptions): Promise<Subject<RunPrincipal>>;
|
|
143
158
|
//#endregion
|
|
144
|
-
export { RunContext as a,
|
|
159
|
+
export { subjectFromRunTicket as _, RunContext as a, RunResource as c, RunTicketFailureCause as d, RunTicketInput as f, signRunTicket as g, parseRunTicket as h, RunBinding as i, RunTicket as l, RunTicketSubjectOptions as m, RunActClaim as n, RunKind as o, RunTicketOptions as p, RunAutomation as r, RunPrincipal as s, RUN_TICKET_CLAIMS as t, RunTicketAutomations as u };
|
|
@@ -16,7 +16,7 @@ const scan = defineLeaf({
|
|
|
16
16
|
}
|
|
17
17
|
},
|
|
18
18
|
async run(ctx, { flags }) {
|
|
19
|
-
const { runAdoptionScan } = await import("./adoption-scan-
|
|
19
|
+
const { runAdoptionScan } = await import("./adoption-scan-DKCOsfcF.js");
|
|
20
20
|
return runAdoptionScan({
|
|
21
21
|
cwd: ctx.cwd,
|
|
22
22
|
srcPath: flags.src.length > 0 ? flags.src : ctx.config.collect?.srcPath ?? ["src"],
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { r as isRecord } from "./compact-CAf557ZB.js";
|
|
2
2
|
import { l as packageRoot } from "./version-DMQ0dnN5.js";
|
|
3
3
|
import { t as DRAFT_PINS } from "./pins-nqarl3oE.js";
|
|
4
|
-
import { a as nonEmptyOr } from "./output-
|
|
4
|
+
import { a as nonEmptyOr } from "./output-CtyBwTNB.js";
|
|
5
5
|
import { t as require__2020 } from "./2020-CJbO8Bvz.js";
|
|
6
6
|
import { readFileSync } from "node:fs";
|
|
7
7
|
import { join } from "node:path";
|