-
Notifications
You must be signed in to change notification settings - Fork 5.8k
feat(ext/node): support path-scoped FFI for SQLite extension loading #31428
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Walkthroughopen_db signature now accepts a Sequence DiagramsequenceDiagram
participant TestRunner as Test Runner
participant Subprocess as Deno Subprocess
participant SQLiteOps as SQLite Ops
participant Perms as PermissionsContainer
rect rgb(200,240,220)
Note over TestRunner,Subprocess: Allowed extension path flow
TestRunner->>Subprocess: spawn with --allow-read --allow-ffi=/allowed/ext.so --allow-run
Subprocess->>SQLiteOps: open_db(...) -> set_db_config(ENABLE_LOAD_EXTENSION = allow_extension)
SQLiteOps->>Perms: borrow_mut -> check_ffi_partial_with_path(/allowed/ext.so)
Perms-->>SQLiteOps: allowed
SQLiteOps-->>Subprocess: load extension -> run query -> return OK
end
rect rgb(240,200,200)
Note over TestRunner,Subprocess: Denied extension path flow
TestRunner->>Subprocess: spawn with --allow-ffi=/other/path --allow-run
Subprocess->>SQLiteOps: open_db(...) -> set_db_config(ENABLE_LOAD_EXTENSION = allow_extension)
Subprocess->>SQLiteOps: attempt load_extension(/denied/ext.so)
SQLiteOps->>Perms: borrow_mut -> check_ffi_partial_with_path(/denied/ext.so)
Perms-->>SQLiteOps: denied (NotCapable)
SQLiteOps-->>Subprocess: propagate permission error -> stderr contains NotCapable
end
Pre-merge checks and finishing touches✅ Passed checks (5 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (1)
🧰 Additional context used📓 Path-based instructions (2)**/*.{ts,tsx,js}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
**/*.rs📄 CodeRabbit inference engine (CLAUDE.md)
Files:
⚙️ CodeRabbit configuration file
Files:
🧬 Code graph analysis (2)tests/sqlite_extension_test/sqlite_extension_test.ts (5)
ext/node/ops/sqlite/database.rs (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
🔇 Additional comments (10)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
tests/sqlite_extension_test/sqlite_extension_test.ts (1)
97-102: Consider consolidating the extension existence check.Both new tests duplicate the same skip logic. A helper function or
beforeAll-style check could reduce duplication, but this is minor for test code.// Optional: Extract to a helper at the top of the file function skipIfExtensionNotFound(): boolean { try { Deno.statSync(extensionPath); return false; } catch { return true; } }Also applies to: 149-154
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
ext/node/ops/sqlite/database.rs(6 hunks)tests/sqlite_extension_test/sqlite_extension_test.ts(1 hunks)tests/sqlite_extension_test/tests/integration_tests.rs(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.rs: For debugging Rust code, set breakpoints in IDE debuggers (VS Code with rust-analyzer, IntelliJ IDEA) or uselldbdirectly
Useeprintln!()ordbg!()macros for debug prints in Rust code
Files:
ext/node/ops/sqlite/database.rstests/sqlite_extension_test/tests/integration_tests.rs
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,js}: For JavaScript runtime debugging, enable V8 inspector with--inspect-brkflag and connect Chrome DevTools tochrome://inspect
Useconsole.log()for debug prints in JavaScript runtime code
Files:
tests/sqlite_extension_test/sqlite_extension_test.ts
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: denoland/deno PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:19:37.808Z
Learning: Applies to runtime/permissions.rs : Permission system is implemented in `runtime/permissions.rs`
📚 Learning: 2025-11-24T16:19:37.808Z
Learnt from: CR
Repo: denoland/deno PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:19:37.808Z
Learning: Applies to runtime/permissions.rs : Permission system is implemented in `runtime/permissions.rs`
Applied to files:
ext/node/ops/sqlite/database.rstests/sqlite_extension_test/tests/integration_tests.rs
🧬 Code graph analysis (1)
tests/sqlite_extension_test/sqlite_extension_test.ts (2)
ext/node/ops/sqlite/mod.rs (1)
code(174-189)cli/js/40_test.js (1)
exitCode(98-98)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
- GitHub Check: lint debug windows-x86_64
- GitHub Check: lint debug macos-x86_64
- GitHub Check: lint debug linux-x86_64
- GitHub Check: test debug linux-x86_64
- GitHub Check: test debug linux-aarch64
- GitHub Check: test debug windows-x86_64
- GitHub Check: test release linux-x86_64
- GitHub Check: test release macos-aarch64
- GitHub Check: test debug macos-x86_64
- GitHub Check: test debug macos-aarch64
- GitHub Check: build libs
🔇 Additional comments (6)
ext/node/ops/sqlite/database.rs (3)
294-294: Permission scoping implemented correctly.The switch from
check_ffi_all()tocheck_ffi_partial_no_path()at database open time aligns with the PR objective: requiring partial FFI permission (any scope) rather than unrestricted FFI whenallowExtension: true. This defers the path-specific check to the actualloadExtension()call.Also applies to: 332-332, 347-347
719-742: Path-scoped FFI check inload_extensionlooks correct.The updated doc comment accurately describes the two-step requirement. The
check_ffi_partial_with_path(Cow::Borrowed(Path::new(path)))call enforces that FFI permission must cover the specific extension path being loaded, matching the--allow-ffi=/path/to/extension.sobehavior described in PR objectives.
277-277: I'll help you verify whetherborrow_mut()is required at line 277 in the SQLite database code. Let me search for the relevant permission check method signatures and how they're used.
<function_calls>
find ext/node/ops/sqlite -name "*.rs" | head -20
</function_calls>Let me search for the permission check methods to verify their signatures:
<function_calls>
rg -n "fn check_ffi_partial" --type rust
</function_calls>Let me also look at the specific file and context around line 277:
<function_calls>
sed -n '270,290p' ext/node/ops/sqlite/database.rs
</function_calls><function_calls>
wc -l ext/node/ops/sqlite/database.rs
</function_calls><function_calls>
rg -n "check_ffi_partial_no_path|check_ffi_partial_with_path" ext/node/ops/sqlite/database.rs
</function_calls><function_calls>
rg -n "check_ffi" --type rust -A 3
</function_calls>tests/sqlite_extension_test/tests/integration_tests.rs (1)
53-53: Necessary addition for subprocess-based tests.The
--allow-runflag is required to enable the new scoped FFI permission tests insqlite_extension_test.tsthat useDeno.Commandto spawn subprocesses with specific permission flags.tests/sqlite_extension_test/sqlite_extension_test.ts (2)
93-142: Well-structured test for scoped FFI success case.The test correctly validates that
--allow-ffi=${extensionPath}permits loading only that specific extension. The subprocess pattern is appropriate sinceDeno.testpermissions don't support scoped FFI.
144-203: Good negative test for path restriction enforcement.This test properly validates that FFI permission for a different path (
/some/other/path) does not grant access to load the actual extension. The explicit check forDeno.errors.NotCapableconfirms the expected permission error.One minor consideration: the subprocess doesn't check exit code, only stdout. Since the test catches the error and continues to
db.close(), exit code 0 is expected. This is fine.
|
@coderabbitai generate docstrings |
✅ Actions performedInitiated docstring generation; will generate only if new commits exist. |
|
Note Docstrings generation - SUCCESS |
Docstrings generation was requested by @charles-dyfis-net. * #31428 (comment) The following files were modified: * `ext/node/ops/sqlite/database.rs`
cb9591e to
d5e862c
Compare
|
I'm unclear on the docstring coverage limit being flagged -- is this perhaps applying to tests? (Do folks really want docstrings for tests?) |
d5e862c to
69cfa6b
Compare
|
In attempting to address automated review feedback about docstrings, I appear to have broken the build -- it looks like |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAIU this does not prevent loading extension from SQL like so:
SELECT load_extension("a.dll");and that was the reason sqlite required unscoped ffi perms.
Ah! Thank you for that clarification. As I read https://sqlite.org/c3ref/c_dbconfig_defensive.html#sqlitedbconfigenableloadextension, it should be possible to enable only the C call and not the SQL -- I'll go back and extend the tests to look for that specific state, and then see about determining how to get into it. |
6f0e03a to
3e9464f
Compare
|
On updating the tests to distinguish between a normal pass and a test that was short-circuited due to the extension not being compiled, it looks like the extension tests were always being skipped because they were attempting to load the extension from the wrong location, triggering the early I suspect we'll want a separate PR to fix the extension used for test coverage before this one can be considered -- I'll get a separate ticket and PR together. |
|
Filed ticket #31454 for the issues preventing this from being correctly tested. |
3e9464f to
1780863
Compare
|
About to push an updated version of this PR stacked on top of #31455. The expectation is that it will remain in draft until the latter (or something equivalent) is merged. |
1780863 to
b2eabbf
Compare
b2eabbf to
e758bf3
Compare
|
...with #31455 merged, rebasing onto main and removing from draft |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
ext/node/ops/sqlite/database.rs(5 hunks)tests/sqlite_extension_test/sqlite_extension_test.ts(3 hunks)tests/sqlite_extension_test/tests/integration_tests.rs(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- ext/node/ops/sqlite/database.rs
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.rs: For debugging Rust code, set breakpoints in IDE debuggers (VS Code with rust-analyzer, IntelliJ IDEA) or uselldbdirectly
Useeprintln!()ordbg!()macros for debug prints in Rust code
Files:
tests/sqlite_extension_test/tests/integration_tests.rs
⚙️ CodeRabbit configuration file
Don't worry about coverage of Rust docstrings. Don't be nitpicky about it. Leave it to the author's judgement if such a documentation is necessary.
Files:
tests/sqlite_extension_test/tests/integration_tests.rs
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,js}: For JavaScript runtime debugging, enable V8 inspector with--inspect-brkflag and connect Chrome DevTools tochrome://inspect
Useconsole.log()for debug prints in JavaScript runtime code
Files:
tests/sqlite_extension_test/sqlite_extension_test.ts
🧠 Learnings (1)
📚 Learning: 2025-11-24T16:19:37.808Z
Learnt from: CR
Repo: denoland/deno PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:19:37.808Z
Learning: Applies to runtime/permissions.rs : Permission system is implemented in `runtime/permissions.rs`
Applied to files:
tests/sqlite_extension_test/tests/integration_tests.rs
🧬 Code graph analysis (1)
tests/sqlite_extension_test/sqlite_extension_test.ts (2)
tests/unit/test_util.ts (1)
assertThrows(19-19)ext/node/ops/sqlite/mod.rs (1)
code(174-190)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
- GitHub Check: test debug linux-aarch64
- GitHub Check: test debug macos-aarch64
- GitHub Check: test release linux-aarch64
- GitHub Check: test debug linux-x86_64
- GitHub Check: bench release linux-x86_64
- GitHub Check: test release linux-x86_64
- GitHub Check: test debug windows-x86_64
- GitHub Check: test debug macos-x86_64
- GitHub Check: lint debug windows-x86_64
- GitHub Check: lint debug macos-x86_64
- GitHub Check: lint debug linux-x86_64
- GitHub Check: build libs
🔇 Additional comments (5)
tests/sqlite_extension_test/tests/integration_tests.rs (1)
66-76: Adding--allow-runis appropriate for subprocess-based testsThis aligns the CLI invocation with the new tests that use
Deno.Commandand requirerunpermission; scoped to tests, so security impact is acceptable.tests/sqlite_extension_test/sqlite_extension_test.ts (4)
60-60: Non-null assertion onstmt.get()is reasonable hereGiven the query always returns a row when the extension works, asserting non-null via
stmt.get()!is appropriate for the test.
71-84: Deferring the NotCapable error toloadExtension()matches the new permission modelCreating
DatabaseSyncwithallowExtension: trueunderffi: falseand expectingDeno.errors.NotCapableonly whenloadExtension()is called accurately encodes the intended deferred FFI check.
105-151: Positive-path scoped FFI subprocess test is well-scopedThe subprocess setup correctly:
- Grants
--allow-read/--allow-ffionly forextensionPath.- Uses
runpermission solely to startdenoviaDeno.Command.- Asserts both exit code and
"OK"output, which tightly verifies the success path.
153-207: Negative scoped FFI test correctly distinguishes permission failureGranting FFI for a different path and asserting that the child prints
"EXPECTED_PERMISSION_ERROR"whenNotCapableis thrown cleanly validates that path-scoped FFI is enforced, not just “any FFI”.
e758bf3 to
af5a4c9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
tests/sqlite_extension_test/sqlite_extension_test.ts (1)
153-206: Good negative test for path-scoped FFI boundaries.Verifies that
--allow-ffi=/some/other/pathdoesn't grant permission to load an extension from a different location. The subprocess error handling properly distinguishesNotCapablefrom other error types.Minor suggestion: Consider also asserting
exitCode === 0since the subprocess catches the error and exits cleanly.- const { stdout } = await child.output(); + const { code: exitCode, stdout } = await child.output(); const stdoutText = new TextDecoder().decode(stdout); + assertEquals(exitCode, 0, "Subprocess should exit cleanly after catching error"); assertEquals( stdoutText.trim(), "EXPECTED_PERMISSION_ERROR", `Expected NotCapable error but got: ${stdoutText}`, );
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
ext/node/ops/sqlite/database.rs(5 hunks)tests/sqlite_extension_test/sqlite_extension_test.ts(3 hunks)tests/sqlite_extension_test/tests/integration_tests.rs(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- tests/sqlite_extension_test/tests/integration_tests.rs
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.rs: For debugging Rust code, set breakpoints in IDE debuggers (VS Code with rust-analyzer, IntelliJ IDEA) or uselldbdirectly
Useeprintln!()ordbg!()macros for debug prints in Rust code
Files:
ext/node/ops/sqlite/database.rs
⚙️ CodeRabbit configuration file
Don't worry about coverage of Rust docstrings. Don't be nitpicky about it. Leave it to the author's judgement if such a documentation is necessary.
Files:
ext/node/ops/sqlite/database.rs
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,js}: For JavaScript runtime debugging, enable V8 inspector with--inspect-brkflag and connect Chrome DevTools tochrome://inspect
Useconsole.log()for debug prints in JavaScript runtime code
Files:
tests/sqlite_extension_test/sqlite_extension_test.ts
🧠 Learnings (1)
📚 Learning: 2025-11-24T16:19:37.808Z
Learnt from: CR
Repo: denoland/deno PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:19:37.808Z
Learning: Applies to runtime/permissions.rs : Permission system is implemented in `runtime/permissions.rs`
Applied to files:
ext/node/ops/sqlite/database.rs
🧬 Code graph analysis (1)
tests/sqlite_extension_test/sqlite_extension_test.ts (3)
ext/node/polyfills/sqlite.ts (1)
DatabaseSync(129-129)tests/unit/test_util.ts (1)
assertThrows(19-19)ext/node/ops/sqlite/mod.rs (1)
code(174-190)
🔇 Additional comments (8)
ext/node/ops/sqlite/database.rs (4)
443-452: LGTM on the documentation.Clear explanation of the deferred permission check design and the distinction between C API and SQL function for extension loading.
475-481: Consistent extension configuration across all database open paths.The
SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSIONis now uniformly set based onallow_extensionin all three branches (in-memory, read-only, and standard file). This ensures consistent behavior regardless of how the database is opened.Also applies to: 511-517, 524-530
1091-1116: Path-scoped FFI permission check implementation looks correct.The flow is sound:
- Verify
allowExtensionwas set at database creation- Check FFI permission for the specific extension path via
check_ffi_partial_with_path- Proceed with loading
This correctly implements the deferred, path-scoped permission model described in the PR objectives.
459-462: Verify that mutable borrow is necessary.The change from
borrow()toborrow_mut()forPermissionsContaineris notable. Ifcheck_has_all_permissionsandcheck_openonly require shared access, this could be reverted to avoid unnecessary mutable borrows.#!/bin/bash # Check if PermissionsContainer methods require &mut self ast-grep --pattern 'fn check_has_all_permissions(&mut self$$$)' ast-grep --pattern 'fn check_open(&mut self$$$)' rg -n "fn check_has_all_permissions|fn check_open" --type rust -A 2tests/sqlite_extension_test/sqlite_extension_test.ts (4)
60-60: Non-null assertion is appropriate here.The test explicitly expects
stmt.get()to return a result. If it doesn't, failing fast with a clear error is the right behavior.
67-85: Test correctly validates deferred permission behavior.The test now properly verifies that:
- Creating
DatabaseSyncwithallowExtension: truesucceeds without FFI permission- The
NotCapableerror is thrown only whenloadExtension()is calledGood cleanup with
db.close()at the end.
108-151: Well-structured subprocess test for scoped FFI.Using a subprocess is the right approach since
Deno.testpermissions don't support path-scoped FFI. The test properly:
- Scopes both
--allow-readand--allow-ffito the extension path- Validates both the exit code and stdout output
- Includes helpful error message in assertion
209-242: Important security test confirming SQL-level load_extension remains disabled.This validates a key security property: even with
allowExtension: true, only the C APIloadExtension()works—the SQLload_extension()function stays disabled. Using the parameterized statement addresses the prior review feedback about path interpolation.
|
(The checks marked as failing -- at least, the two so far -- appear to be related to the macos-13 runner being removed in favor of macos-15, and not related to the content of the PR at hand). |
|
Taking a closer look at CodeRabbit's review notes, only one of the two |
af5a4c9 to
5f37c31
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
tests/sqlite_extension_test/sqlite_extension_test.ts (1)
108-151: Consider adding null check for consistencyLine 119 in the subprocess code does
const { result } = stmt.get();without a null check. If the query returns no rows, this would throw a confusing destructuring error rather than a clear test failure.For consistency with line 60 (which uses
stmt.get()!), consider:const stmt = db.prepare("SELECT test_func('test') AS result"); - const { result } = stmt.get(); + const row = stmt.get(); + if (!row) throw new Error("Expected a result row"); + const { result } = row;This is minor since a test failure would still surface the issue.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
ext/node/ops/sqlite/database.rs(5 hunks)tests/sqlite_extension_test/sqlite_extension_test.ts(3 hunks)tests/sqlite_extension_test/tests/integration_tests.rs(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.rs: For debugging Rust code, set breakpoints in IDE debuggers (VS Code with rust-analyzer, IntelliJ IDEA) or uselldbdirectly
Useeprintln!()ordbg!()macros for debug prints in Rust code
Files:
tests/sqlite_extension_test/tests/integration_tests.rsext/node/ops/sqlite/database.rs
⚙️ CodeRabbit configuration file
Don't worry about coverage of Rust docstrings. Don't be nitpicky about it. Leave it to the author's judgement if such a documentation is necessary.
Files:
tests/sqlite_extension_test/tests/integration_tests.rsext/node/ops/sqlite/database.rs
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,js}: For JavaScript runtime debugging, enable V8 inspector with--inspect-brkflag and connect Chrome DevTools tochrome://inspect
Useconsole.log()for debug prints in JavaScript runtime code
Files:
tests/sqlite_extension_test/sqlite_extension_test.ts
🧠 Learnings (1)
📚 Learning: 2025-11-24T16:19:37.808Z
Learnt from: CR
Repo: denoland/deno PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:19:37.808Z
Learning: Applies to runtime/permissions.rs : Permission system is implemented in `runtime/permissions.rs`
Applied to files:
tests/sqlite_extension_test/tests/integration_tests.rsext/node/ops/sqlite/database.rs
🧬 Code graph analysis (2)
tests/sqlite_extension_test/sqlite_extension_test.ts (1)
ext/node/ops/sqlite/mod.rs (1)
code(174-190)
ext/node/ops/sqlite/database.rs (1)
ext/kv/sqlite.rs (1)
open(62-209)
🔇 Additional comments (9)
tests/sqlite_extension_test/tests/integration_tests.rs (1)
71-71: LGTM!The
--allow-runpermission is required for the new subprocess-based scoped FFI tests in the TypeScript test file.tests/sqlite_extension_test/sqlite_extension_test.ts (4)
60-60: LGTM!Non-null assertion is appropriate here since the test expects a valid row result from the query.
67-85: LGTM!Good refactor to validate the new deferred permission model - database creation with
allowExtension: truenow succeeds, and the permission check happens atloadExtension()time.
153-207: LGTM!Good negative test case validating that scoped FFI permission enforcement rejects paths outside the granted scope.
209-242: LGTM!Important security test verifying that SQL-level
load_extension()remains disabled (defensive mode) while the C APIloadExtension()works. This prevents SQL injection from bypassing extension controls.ext/node/ops/sqlite/database.rs (4)
443-452: LGTM! Clear documentation of the deferred permission model.The docstring accurately explains that FFI permission checks are deferred to
load_extensionwhere path-scoped validation can occur.
475-481: LGTM!Clean consolidation of extension loading configuration. Using
set_db_configwithSQLITE_DBCONFIG_ENABLE_LOAD_EXTENSIONcorrectly enables only the C API while keeping the SQLload_extension()function disabled.
511-530: LGTM!Consistent application of the extension loading configuration across read-only and read-write paths.
1091-1116: LGTM! Core security change implementing path-scoped FFI validation.The change from a global FFI check to
check_ffi_partial_with_pathwith the specific extension path correctly implements scoped permissions like--allow-ffi=/path/to/extension.so. The method exists inPermissionsContainerand returns the allowed path or aPermissionCheckError, enforcing the permission boundary as intended.
Previously, using `allowExtension: true` or calling `loadExtension()` required unrestricted `--allow-ffi` permission. This made it impossible to sandbox code that needs to load only specific, pre-approved SQLite extensions. This change allows scoped FFI permissions: - `allowExtension: true` no longer runs an up-front / connection-time check (the `partial` check function did not return true as expected in practice when only scoped FFI permissions exist) - `loadExtension(path)` requires FFI permission covering that specific path Example: `--allow-ffi=/path/to/extension.so` now permits loading only that extension, rather than granting unrestricted FFI access. Note that this now universally disables the SQL `load_extension()` function, whether or not FFI is globally enabled. Fixes: denoland#31426
5f37c31 to
6a96f7f
Compare
Previously, using
allowExtension: trueor callingloadExtension()required unrestricted--allow-ffipermission. This made it impossible to sandbox code that needs to load only specific, pre-approved SQLite extensions.This change allows scoped FFI permissions:
allowExtension: truenow requires partial FFI permission (any scope)loadExtension(path)requires FFI permission covering that specific pathExample:
--allow-ffi=/path/to/extension.sonow permits loading only that extension, rather than granting unrestricted FFI access.Fixes: #31426