rowstile 0.1.0-alpha.3 → 0.1.0-alpha.5
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/README.md +3 -2
- package/bin/rowstile.js +29 -1
- package/command/authzlib/__init__.py +4 -1
- package/command/authzlib/base.py +46 -7
- package/command/authzlib/compiler.py +577 -259
- package/command/authzlib/conditions.py +17 -8
- package/command/authzlib/connection.py +1 -0
- package/command/authzlib/coverage.py +12 -5
- package/command/authzlib/database.py +333 -124
- package/command/authzlib/devtools.py +15 -8
- package/command/authzlib/draft.py +235 -62
- package/command/authzlib/errors.py +201 -101
- package/command/authzlib/evaluate.py +92 -44
- package/command/authzlib/fmt.py +33 -16
- package/command/authzlib/governance.py +105 -50
- package/command/authzlib/grant.py +100 -52
- package/command/authzlib/hardening.py +122 -54
- package/command/authzlib/identity.py +22 -15
- package/command/authzlib/insight.py +161 -86
- package/command/authzlib/migrate.py +193 -102
- package/command/authzlib/output.py +376 -196
- package/command/authzlib/parse.py +249 -98
- package/command/authzlib/perf.py +78 -32
- package/command/authzlib/prove.py +23 -11
- package/command/authzlib/refusals.py +107 -48
- package/command/authzlib/review.py +361 -139
- package/command/authzlib/sqlutil.py +196 -33
- package/command/authzlib/statements.py +26 -19
- package/command/authzlib/testing.py +98 -45
- package/command/authzlib/trees.py +427 -275
- package/command/cli/init.py +27 -8
- package/command/cli/lsp.py +140 -51
- package/command/cli/mcp.py +107 -45
- package/command/cli/migrations.py +74 -21
- package/command/cli/pgwire.py +161 -67
- package/command/cli/rowstile_cli.py +351 -105
- package/command/cli/stack.py +67 -30
- package/command/cli/studio.py +258 -84
- package/package.json +30 -9
package/README.md
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# rowstile
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
ships as migrations for your app's tool (Prisma, Drizzle Kit, Alembic, SQL files).
|
|
3
|
+
Authorization for Postgres apps: access rules in a policy language that the `rowstile` command compiles into
|
|
4
|
+
row-level security, and ships as migrations for your app's tool (Prisma, Drizzle Kit, Alembic, SQL files).
|
|
5
|
+
Sharing, groups, nested folders and tenants, with no service to run beside the database.
|
|
5
6
|
|
|
6
7
|
npx rowstile init # a first policy from your tables, rowstile.toml, the SDK for your stack
|
|
7
8
|
npx rowstile dev # on each save: check, apply to the development database, test, write the types
|
package/bin/rowstile.js
CHANGED
|
@@ -64,7 +64,35 @@ function onPath() {
|
|
|
64
64
|
return null;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
/** On Windows, a file of the bundled Python whose path is longer than Windows loads (259 characters, unless long
|
|
68
|
+
* paths are turned on): Python then stops with "DLL load failed ... The filename or extension is too long",
|
|
69
|
+
* from inside node_modules. Null when every file is within the limit.
|
|
70
|
+
* @param {string} exe @returns {string | null} */
|
|
71
|
+
function tooLong(exe) {
|
|
72
|
+
if (process.platform !== "win32") return null;
|
|
73
|
+
try {
|
|
74
|
+
const dlls = path.join(path.dirname(fs.realpathSync.native(exe)), "DLLs");
|
|
75
|
+
const longest = fs.readdirSync(dlls).map((f) => path.join(dlls, f)).sort((a, b) => b.length - a.length)[0];
|
|
76
|
+
if (!longest || longest.length <= 259) return null;
|
|
77
|
+
// with long paths turned on, or when only files the command never loads are past the limit, it runs all
|
|
78
|
+
// the same: ask it for the compiled modules the command uses
|
|
79
|
+
const probe = "import unicodedata, ssl, hashlib, socket, select, zlib, decimal";
|
|
80
|
+
return spawnSync(exe, ["-E", "-s", "-c", probe]).status === 0 ? null : longest;
|
|
81
|
+
} catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const own = process.env.ROWSTILE_PYTHON || process.env.ROWFENCE_PYTHON ? null : bundled(); // ROWFENCE_PYTHON: the name before the rename
|
|
87
|
+
const long = own && tooLong(own);
|
|
88
|
+
if (long && !onPath()) {
|
|
89
|
+
console.error(`rowstile: this project's path is too long for Windows to load the Python that came with the package ` +
|
|
90
|
+
`(${long.length} characters to ${path.basename(long)}; Windows loads up to 259). Move the project to a shorter path, ` +
|
|
91
|
+
"or turn long paths on in Windows (LongPathsEnabled), or install Python 3.11 or later: rowstile then runs on that one");
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
// a Python on PATH, when the bundled one can't be loaded from here
|
|
95
|
+
const python = process.env.ROWSTILE_PYTHON || process.env.ROWFENCE_PYTHON || (long ? null : own) || onPath();
|
|
68
96
|
if (!python) {
|
|
69
97
|
console.error(`rowstile: no Python to run on. The package for this platform (@rowstile/cli-${key}) isn't installed` +
|
|
70
98
|
(PLATFORMS.includes(key) ? " (optional dependencies turned off?)" : `, and there is none for ${key}`) +
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""authzlib: compile a .authz policy file into PostgreSQL (views, closure tables,
|
|
2
2
|
triggers, row-level security policies and an API for app code)."""
|
|
3
|
+
|
|
3
4
|
from .devtools import DevMixin
|
|
4
5
|
from .output import OutputMixin
|
|
5
6
|
from .parse import Loc, PolicyError, parse_policy
|
|
@@ -10,7 +11,8 @@ class Compiler(TestMixin, DevMixin, OutputMixin):
|
|
|
10
11
|
"""A policy compiled: each part of the output is one of its bases (OutputMixin assembles them)."""
|
|
11
12
|
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
# set with packaging/version.py (the packages copy it); authz.policy_versions records it on each apply
|
|
15
|
+
__version__ = "0.1.0-alpha.5"
|
|
14
16
|
|
|
15
17
|
|
|
16
18
|
def _build() -> str:
|
|
@@ -20,6 +22,7 @@ def _build() -> str:
|
|
|
20
22
|
return __version__
|
|
21
23
|
import hashlib
|
|
22
24
|
import os
|
|
25
|
+
|
|
23
26
|
here, h = os.path.dirname(os.path.abspath(__file__)), hashlib.sha256()
|
|
24
27
|
for name in sorted(os.listdir(here)):
|
|
25
28
|
if name.endswith(".py"):
|
package/command/authzlib/base.py
CHANGED
|
@@ -177,10 +177,49 @@ CREATE OR REPLACE FUNCTION authz.link_hashes() RETURNS text[] LANGUAGE sql STABL
|
|
|
177
177
|
WHERE btrim(x) <> '' $$;"""
|
|
178
178
|
|
|
179
179
|
# Functions each apply recreates (dropped first, whatever their old signature).
|
|
180
|
-
GENERATED_FUNCTIONS = (
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
180
|
+
GENERATED_FUNCTIONS = (
|
|
181
|
+
"act_as",
|
|
182
|
+
"can",
|
|
183
|
+
"list",
|
|
184
|
+
"perms",
|
|
185
|
+
"perms_of",
|
|
186
|
+
"share",
|
|
187
|
+
"unshare",
|
|
188
|
+
"verify",
|
|
189
|
+
"create_link",
|
|
190
|
+
"principal",
|
|
191
|
+
"create_role",
|
|
192
|
+
"set_role_permissions",
|
|
193
|
+
"delete_role",
|
|
194
|
+
"roles_of",
|
|
195
|
+
"who",
|
|
196
|
+
"explain",
|
|
197
|
+
"list_shares",
|
|
198
|
+
"shares",
|
|
199
|
+
"create_api_key",
|
|
200
|
+
"list_api_keys",
|
|
201
|
+
"revoke_api_key",
|
|
202
|
+
"login_key",
|
|
203
|
+
"login_jwt",
|
|
204
|
+
"view_as",
|
|
205
|
+
"sync_members",
|
|
206
|
+
"changes_since",
|
|
207
|
+
"trim_changes",
|
|
208
|
+
"trim_audit",
|
|
209
|
+
"request_access",
|
|
210
|
+
"pending_requests",
|
|
211
|
+
"decide_request",
|
|
212
|
+
"cancel_request",
|
|
213
|
+
"break_glass",
|
|
214
|
+
"start_review",
|
|
215
|
+
"review_items",
|
|
216
|
+
"review_decide",
|
|
217
|
+
"close_review",
|
|
218
|
+
"check_invariants",
|
|
219
|
+
"lint",
|
|
220
|
+
"connection_check",
|
|
221
|
+
"explain_rule",
|
|
222
|
+
"who_among",
|
|
223
|
+
"list_links",
|
|
224
|
+
"revoke_link",
|
|
225
|
+
)
|