Skip to content

Commit 3dbd00d

Browse files
authored
In response to issue #325, rework the dependency allow-list. (#332)
* In response to issue #325, rework the dependency allow-list. Generally, the changes here allow a single dependency in the allow-list to have one **or more** versions specified, either as exact (`=`) or bounded ranges (`>=,<=`) or wildcards (`*`). PL/Rust will pick the largest (newest, hopefully) entry from the allow-list that matches the version the user's requested version. Depending on how either is written, the allow-list version could be used or the user's requested version could be used. See the new documentation for more details.
1 parent 4f0fb3b commit 3dbd00d

File tree

10 files changed

+800
-143
lines changed

10 files changed

+800
-143
lines changed

doc/src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,6 @@
3333

3434
- [Architecture](./architecture.md)
3535
- [Designing for Trust](./designing-for-trust.md)
36+
- [External Dependencies](./dependencies.md)
3637
- [Lints](./config-lints.md)
3738
- [Environment variables](./config-env-var.md)

doc/src/config-pg.md

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,18 +51,7 @@ PL/Rust functions.
5151
When `plrust.allowed_dependencies` is not defined, all Rust crates are allowed
5252
when creating PL/Rust functions.
5353

54-
Consider a file `/path/to/plrust_allowed.toml` with the following contents.
55-
56-
```toml
57-
foo = "1.1.5"
58-
```
59-
60-
The configuration to restrict crates looks like the following example.
61-
62-
```bash
63-
plrust.allowed_dependencies = /path/to/plrust_allowed.toml
64-
```
65-
54+
For more discussion, see [dependencies.md](dependencies.md)
6655

6756
#### `plrust.path_override` (string)
6857

doc/src/dependencies.md

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
# External Dependencies
2+
3+
PL/Rust supports the use of external dependencies. By default, this is unrestricted even when PL/Rust is used as a
4+
Trusted Language Handler, allowing user functions to specify any desired dependency.
5+
6+
For instance:
7+
8+
```sql
9+
CREATE OR REPLACE FUNCTION randint() RETURNS bigint LANGUAGE plrust AS $$
10+
[dependencies]
11+
rand = "0.8"
12+
13+
[code]
14+
use rand::Rng;
15+
Ok(Some(rand::thread_rng().gen()))
16+
$$;
17+
```
18+
19+
It is recommended that administrators create a dependency allow-list file and specify its path in `postgresql.conf` using
20+
the `plrust.allowed_dependencies` setting.
21+
22+
To disable external dependencies completely, create a zero-byte file or point the configuration to `/dev/null`.
23+
24+
## The Allow-List File
25+
26+
The dependency allow-list is a TOML file. Its format mirrors that of the `[dependencies]` section in a standard
27+
`Cargo.toml`, albeit with certain requirements on the version strings.
28+
29+
### The Format
30+
31+
The file consists of `dependency_name = version_requirement` pairs, where `version_requirement` can adopt several forms.
32+
It can be a quoted string such as `"=1.2.3"`, a TOML table like `{ version = "=1.2.3", features = ["a", "b", "c"] }`, or
33+
an array of either, such as `[ "=1.2.3", { version = "=1.2.3" }, ">=4, <5"`.
34+
35+
Here is a valid allow-list file for reference:
36+
37+
```toml
38+
rand = ">=0.8, <0.9"
39+
bitvec = [">=1, <2", "=0.2", { version = "1.0.1", features = [ "alloc" ], default-features = false }]
40+
```
41+
42+
This added flexibility empowers administrators to specify the exact crate version and its associated features and properties.
43+
44+
When a `LANGUAGE plrust` function designates a dependency and version, the largest (presumably most recent) matching
45+
version from the allow-list is used.
46+
47+
### Version Requirement Format
48+
49+
PL/Rust employs Cargo's interpretation of semver to manage dependency versions, but it requires each version requirement
50+
to be an exact value like `=1.2.3`, a bounded range such as `>=1, <2`, or a bare wildcard (`*`).
51+
52+
For example, these are valid version requirement values:
53+
54+
```toml
55+
rand = "=0.8.5"
56+
serde = ">=1.0.151, <1.1"
57+
bitvec = "*"
58+
```
59+
60+
These, however, are not:
61+
62+
```toml
63+
rand = "0.8.5"
64+
serde = ">1.1"
65+
```
66+
67+
The `cargo` tool may select a slightly different version based on the specification. However, with exact and bounded
68+
values, `cargo`'s choices are limited to the versions that administrators allow.
69+
70+
The bare wildcard pattern (`*`) is acceptable and has a unique interpretation within a user `LANGUAGE plrust` function.
71+
72+
### Using a Dependency
73+
74+
As shown above, a `LANGUAGE plrust` function can include a `[dependencies]` section. Authors should specify exact versions
75+
for each dependency. PL/Rust will match this exact version with an entry in the allow-list.
76+
77+
If a function requests a version in the `1.2.3` format and it matches an entry on the allow-list, PL/Rust will revise
78+
it to an exact version, i.e., `=1.2.3`.
79+
80+
If the allow-list merely contains a wildcard version:
81+
82+
```toml
83+
rand = "*"
84+
```
85+
86+
... and the user function asks for a specific version, such as `0.8.5`, PL/Rust will utilize that exact version.
87+
88+
Conversely, if the allow-list specifies one or more particular version requirements...
89+
90+
```toml
91+
rand = [ "0.8.5", "0.6" ]
92+
```
93+
94+
... and the PL/Rust function requests a wildcard (i.e., `rand = "*"`), PL/Rust will select the largest version requirement
95+
from the allow-list. In this case, it would be `0.8.5`.
96+
97+
### Working with Crate Features
98+
99+
When a user function employs a crate from the allow-list, the allow-list controls the permitted set of dependency properties
100+
such as `features` and `default-features` for each version. Users cannot override these. They can specify them, but the
101+
specifications must match exactly with the allow-list.
102+
103+
This control enables administrators to dictate the usage of dependencies.
104+
105+
For instance, this would be acceptable for a user function:
106+
107+
```sql
108+
CREATE OR REPLACE FUNCTION randint(seed bigint) RETURNS bigint STRICT LANGUAGE plrust AS $$
109+
[dependencies]
110+
rand = { version = "*", features = [ "small_rng" ], default-features = false }
111+
112+
[code]
113+
use rand::rngs::SmallRng;
114+
use rand::SeedableRng;
115+
use rand::RngCore;
116+
117+
let mut rng = SmallRng::seed_from_u64(seed as _);
118+
Ok(Some(rng.next_u64() as _))
119+
$$;
120+
```
121+
122+
Provided that the allow-list includes the following:
123+
124+
```toml
125+
rand = { version = "=0.8.5", features = [ "small_rng" ], default-features = false }
126+
```
127+
128+
Note that the user function could omit the dependency features since the allow-list declares them:
129+
130+
```sql
131+
CREATE OR REPLACE FUNCTION randint(seed bigint) RETURNS bigint STRICT LANGUAGE plrust AS $$
132+
[dependencies]
133+
rand = "*"
134+
135+
[code]
136+
use rand::rngs::SmallRng;
137+
use rand::SeedableRng;
138+
use rand::RngCore;
139+
140+
let mut rng = SmallRng::seed_from_u64(seed as _);
141+
Ok(Some(rng.next_u64() as _))
142+
$$;
143+
```
144+
145+
### Operational Notes
146+
147+
- The dependency allow-list file path must be set in `plrust.allowed_dependencies` GUC value in `postgresql.conf`.
148+
- The file must be readable by the user that runs Postgres backend connections. Typically, this user is named `postgres`.
149+
- Every time a `CREATE FUNCTION ... LANGUAGE plrust` statement is executed, the file is read, parsed, and validated. This arrangement allows administrators to edit it without needing to restart the Postgres cluster.

plrust/build

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ cargo update -p pgrx
2929
cargo fetch
3030
if [ "$CI" != true ]; then
3131
cargo install cargo-pgrx \
32-
--version "0.9.4" \
32+
--version "0.9.5" \
3333
--locked # use the Cargo.lock in the pgrx repo
3434
fi
3535

0 commit comments

Comments
 (0)