Skip to content

Commit 5e81d02

Browse files
authored
feat(codegen): Allow plugins to access environment variables (#2669)
Allow plugins, both process-based and WASM-based, to read environment variables from the host, configured via a per-variable allowlist. Plugins can not declare the environment variables they have access to outside of the sqlc.yaml configuration file. ```yaml version: '2' plugins: - name: py env: - PATH wasm: url: https://github.com/sqlc-dev/sqlc-gen-python/releases/download/v0.16.0-alpha/sqlc-gen-python.wasm sha256: 428476c7408fd4c032da4ec74e8a7344f4fa75e0f98a5a3302f238283b9b95f2 ``` * Add SQLC_VERSION to docs
1 parent 579da69 commit 5e81d02

File tree

18 files changed

+203
-57
lines changed

18 files changed

+203
-57
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,12 @@ jobs:
5555
with:
5656
go-version: '1.21.0'
5757

58-
- name: gotestsum
58+
- name: install gotestsum
5959
run: go install gotest.tools/gotestsum@latest
6060

61+
- name: install sqlc-gen-test
62+
run: go install github.com/sqlc-dev/sqlc-gen-test@v0.1.0
63+
6164
- name: install ./...
6265
run: go install ./...
6366

docs/guides/plugins.md

Lines changed: 58 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -15,32 +15,20 @@ top-level `plugins` map. The `options` are serialized to a string and passed on
1515
to the plugin itself.
1616

1717

18-
```json
19-
{
20-
"version": "2",
21-
"plugins": [
22-
{
23-
"name": "greeter",
24-
"wasm": {
25-
"url": "https://github.com/sqlc-dev/sqlc-gen-greeter/releases/download/v0.1.0/sqlc-gen-greeter.wasm",
26-
"sha256": "afc486dac2068d741d7a4110146559d12a013fd0286f42a2fc7dcd802424ad07"
27-
}
28-
}
29-
],
30-
"sql": [
31-
{
32-
"schema": "schema.sql",
33-
"queries": "query.sql",
34-
"engine": "postgresql",
35-
"codegen": [
36-
{
37-
"out": "gen",
38-
"plugin": "greeter"
39-
}
40-
]
41-
}
42-
]
43-
}
18+
```yaml
19+
version: '2'
20+
plugins:
21+
- name: greeter
22+
wasm:
23+
url: https://github.com/sqlc-dev/sqlc-gen-greeter/releases/download/v0.1.0/sqlc-gen-greeter.wasm
24+
sha256: afc486dac2068d741d7a4110146559d12a013fd0286f42a2fc7dcd802424ad07
25+
sql:
26+
- schema: schema.sql
27+
queries: query.sql
28+
engine: postgresql
29+
codegen:
30+
- out: gen
31+
plugin: greeter
4432
```
4533
4634
For a complete working example see the following files:
@@ -59,39 +47,54 @@ the new files. The `plugin` key must reference a plugin defined in the
5947
top-level `plugins` map. The `options` are serialized to a string and passed on
6048
to the plugin itself.
6149

62-
```json
63-
{
64-
"version": "2",
65-
"plugins": [
66-
{
67-
"name": "jsonb",
68-
"process": {
69-
"cmd": "sqlc-gen-json"
70-
}
71-
}
72-
],
73-
"sql": [
74-
{
75-
"schema": "schema.sql",
76-
"queries": "query.sql",
77-
"engine": "postgresql",
78-
"codegen": [
79-
{
80-
"out": "gen",
81-
"plugin": "jsonb",
82-
"options": {
83-
"indent": " ",
84-
"filename": "codegen.json"
85-
}
86-
}
87-
]
88-
}
89-
]
90-
}
50+
```yaml
51+
version: '2'
52+
plugins:
53+
- name: jsonb
54+
process:
55+
cmd: sqlc-gen-json
56+
sql:
57+
- schema: schema.sql
58+
queries: query.sql
59+
engine: postgresql
60+
codegen:
61+
- out: gen
62+
plugin: jsonb
63+
options:
64+
indent: " "
65+
filename: codegen.json
9166
```
9267

9368
For a complete working example see the following files:
9469
- [sqlc-gen-json](https://github.com/sqlc-dev/sqlc/tree/main/cmd/sqlc-gen-json)
9570
- A process-based plugin that serializes the CodeGenRequest to JSON
9671
- [process_plugin_sqlc_gen_json](https://github.com/sqlc-dev/sqlc/tree/main/internal/endtoend/testdata/process_plugin_sqlc_gen_json)
9772
- An example project showing how to use a process-based plugin
73+
74+
## Environment variables
75+
76+
By default, plugins do not inherit access to environment variables. Instead,
77+
access can be configured on a per-variable basis. For example, if your plugin
78+
needs the `PATH` environment variable, add the `PATH` to the `env` option in the
79+
`plugins` collection.
80+
81+
```yaml
82+
version: '2'
83+
sql:
84+
- schema: schema.sql
85+
queries: query.sql
86+
engine: postgresql
87+
codegen:
88+
- out: gen
89+
plugin: test
90+
plugins:
91+
- name: test
92+
env:
93+
- PATH
94+
wasm:
95+
url: https://github.com/sqlc-dev/sqlc-gen-test/releases/download/v0.1.0/sqlc-gen-test.wasm
96+
sha256: 138220eae508d4b65a5a8cea555edd155eb2290daf576b7a8b96949acfeb3790
97+
```
98+
99+
The `SQLC_VERSION` environment variable will always be included in the
100+
environment, set to the version of the `sqlc` executable.

docs/reference/config.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,8 @@ Each mapping in the `plugins` collection has the following keys:
316316

317317
- `name`:
318318
- The name of this plugin. Required
319+
- `env`
320+
- A list of environment variables to pass to the plugin. By default, no environment variables are passed.
319321
- `process`: A mapping with a single `cmd` key
320322
- `cmd`:
321323
- The executable to call when using this plugin
@@ -333,6 +335,8 @@ plugins:
333335
url: "https://github.com/sqlc-dev/sqlc-gen-python/releases/download/v0.16.0-alpha/sqlc-gen-python.wasm"
334336
sha256: "428476c7408fd4c032da4ec74e8a7344f4fa75e0f98a5a3302f238283b9b95f2"
335337
- name: "js"
338+
env:
339+
- PATH
336340
process:
337341
cmd: "sqlc-gen-json"
338342
```

internal/cmd/generate.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,11 +386,13 @@ func codegen(ctx context.Context, combo config.CombinedSettings, sql outPair, re
386386
case plug.Process != nil:
387387
handler = &process.Runner{
388388
Cmd: plug.Process.Cmd,
389+
Env: plug.Env,
389390
}
390391
case plug.WASM != nil:
391392
handler = &wasm.Runner{
392393
URL: plug.WASM.URL,
393394
SHA256: plug.WASM.SHA256,
395+
Env: plug.Env,
394396
}
395397
default:
396398
return "", nil, fmt.Errorf("unsupported plugin type")

internal/config/config.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ type Cloud struct {
7979
}
8080

8181
type Plugin struct {
82-
Name string `json:"name" yaml:"name"`
82+
Name string `json:"name" yaml:"name"`
83+
Env []string `json:"env" yaml:"env"`
8384
Process *struct {
8485
Cmd string `json:"cmd" yaml:"cmd"`
8586
} `json:"process" yaml:"process"`

internal/endtoend/endtoend_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ func BenchmarkExamples(b *testing.B) {
7575
}
7676

7777
func TestReplay(t *testing.T) {
78+
// Ensure that this environment variable is always set to true when running
79+
// end-to-end tests
80+
os.Setenv("SQLC_DUMMY_VALUE", "true")
81+
7882
t.Parallel()
7983
ctx := context.Background()
8084
var dirs []string
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"process": "sqlc-gen-test"
3+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"env": [
3+
"SQLC_VERSION=v1.20.0",
4+
"SQLC_DUMMY_VALUE=true"
5+
]
6+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
-- name: GetAuthor :one
2+
SELECT * FROM authors
3+
WHERE id = $1 LIMIT 1;
4+
5+
-- name: ListAuthors :many
6+
SELECT * FROM authors
7+
ORDER BY name;
8+
9+
-- name: CreateAuthor :one
10+
INSERT INTO authors (
11+
name, bio
12+
) VALUES (
13+
$1, $2
14+
)
15+
RETURNING *;
16+
17+
-- name: DeleteAuthor :exec
18+
DELETE FROM authors
19+
WHERE id = $1;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
CREATE TABLE authors (
2+
id BIGSERIAL PRIMARY KEY,
3+
name text NOT NULL,
4+
bio text
5+
);
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"version": "2",
3+
"sql": [
4+
{
5+
"schema": "schema.sql",
6+
"queries": "query.sql",
7+
"engine": "postgresql",
8+
"codegen": [
9+
{
10+
"out": "gen",
11+
"plugin": "test"
12+
}
13+
]
14+
}
15+
],
16+
"plugins": [
17+
{
18+
"name": "test",
19+
"env": ["SQLC_DUMMY_VALUE"],
20+
"process": {
21+
"cmd": "sqlc-gen-test"
22+
}
23+
}
24+
]
25+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"env": [
3+
"SQLC_VERSION=v1.20.0",
4+
"SQLC_DUMMY_VALUE=true"
5+
]
6+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
-- name: GetAuthor :one
2+
SELECT * FROM authors
3+
WHERE id = $1 LIMIT 1;
4+
5+
-- name: ListAuthors :many
6+
SELECT * FROM authors
7+
ORDER BY name;
8+
9+
-- name: CreateAuthor :one
10+
INSERT INTO authors (
11+
name, bio
12+
) VALUES (
13+
$1, $2
14+
)
15+
RETURNING *;
16+
17+
-- name: DeleteAuthor :exec
18+
DELETE FROM authors
19+
WHERE id = $1;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
CREATE TABLE authors (
2+
id BIGSERIAL PRIMARY KEY,
3+
name text NOT NULL,
4+
bio text
5+
);
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"version": "2",
3+
"sql": [
4+
{
5+
"schema": "schema.sql",
6+
"queries": "query.sql",
7+
"engine": "postgresql",
8+
"codegen": [
9+
{
10+
"out": "gen",
11+
"plugin": "test"
12+
}
13+
]
14+
}
15+
],
16+
"plugins": [
17+
{
18+
"name": "test",
19+
"env": ["SQLC_DUMMY_VALUE"],
20+
"wasm": {
21+
"url": "https://github.com/sqlc-dev/sqlc-gen-test/releases/download/v0.1.0/sqlc-gen-test.wasm",
22+
"sha256": "138220eae508d4b65a5a8cea555edd155eb2290daf576b7a8b96949acfeb3790"
23+
}
24+
}
25+
]
26+
}

internal/ext/process/gen.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"context"
66
"errors"
77
"fmt"
8+
"os"
89
"os/exec"
910

1011
"google.golang.org/protobuf/proto"
@@ -14,6 +15,7 @@ import (
1415

1516
type Runner struct {
1617
Cmd string
18+
Env []string
1719
}
1820

1921
// TODO: Update the gen func signature to take a ctx
@@ -34,6 +36,9 @@ func (r Runner) Generate(ctx context.Context, req *plugin.CodeGenRequest) (*plug
3436
cmd.Env = []string{
3537
fmt.Sprintf("SQLC_VERSION=%s", req.SqlcVersion),
3638
}
39+
for _, key := range r.Env {
40+
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", key, os.Getenv(key)))
41+
}
3742

3843
out, err := cmd.Output()
3944
if err != nil {

internal/ext/wasm/wasm.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ func cacheDir() (string, error) {
4747
type Runner struct {
4848
URL string
4949
SHA256 string
50+
Env []string
5051
}
5152

5253
var flight singleflight.Group
@@ -255,6 +256,14 @@ func (r *Runner) Generate(ctx context.Context, req *plugin.CodeGenRequest) (*plu
255256
wasiConfig.SetStdoutFile(stdoutPath)
256257
wasiConfig.SetStderrFile(stderrPath)
257258

259+
keys := []string{"SQLC_VERSION"}
260+
vals := []string{req.SqlcVersion}
261+
for _, key := range r.Env {
262+
keys = append(keys, key)
263+
vals = append(vals, os.Getenv(key))
264+
}
265+
wasiConfig.SetEnv(keys, vals)
266+
258267
store := wasmtime.NewStore(engine)
259268
store.SetWasi(wasiConfig)
260269

scripts/regenerate/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ func regenerate(dir string) error {
5656
}
5757

5858
cmd := exec.Command("sqlc-dev", "generate")
59+
cmd.Env = append(cmd.Env, "SQLC_DUMMY_VALUE=true")
5960
cmd.Dir = cwd
6061
out, failed := cmd.CombinedOutput()
6162
if failed != nil && !expectFailure {

0 commit comments

Comments
 (0)