opencode-varlock 0.0.8 → 0.0.10

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 CHANGED
@@ -1,364 +1,106 @@
1
1
  # opencode-varlock
2
2
 
3
- OpenCode plugin that gives agents access to environment variables **without revealing secret values**.
3
+ [![npm version](https://img.shields.io/npm/v/opencode-varlock)](https://www.npmjs.com/package/opencode-varlock)
4
+ [![CI](https://github.com/itlackey/opencode-varlock/actions/workflows/test.yml/badge.svg)](https://github.com/itlackey/opencode-varlock/actions/workflows/test.yml)
4
5
 
5
- ## The Problem
6
+ OpenCode plugin that gives agents access to secrets without revealing the values. The plugin leverages [varlock](https://varlock.dev) and [opencode](https://opencode.ai) features to provide a multi-layered defense against intentional and accidental secret leakage by OpenCode agents.
6
7
 
7
- When an AI agent needs secrets (database URLs, API keys, tokens) to run your code, the obvious approach — letting it read `.env` — puts every secret directly into its context window. It can then echo them, log them, or hallucinate them into committed code.
8
+ > [!Important]
9
+ > This plugin is still early in development, and there is active work underway to improve its security model and edge-case protections. PRs, issue reports, and security feedback are very welcome.
8
10
 
9
- ## How It Works
11
+ ## What it does
10
12
 
11
- Three layers enforce the boundary:
12
-
13
- ```
14
- ┌──────────────────────────────────────────────────┐
15
- Agent context window │
16
- │ │
17
- "Loaded 3 vars: DB_URL, API_KEY, REDIS_HOST" │
18
- │ ↑ names only, never values │
19
- │ │
20
- ├──────────────────────────────────────────────────┤
21
- │ Layer 1 Custom tools (load_env / load_secrets)│
22
- │ Reads files or calls Varlock CLI, injects into │
23
- │ process.env, returns only key names. │
24
- ├──────────────────────────────────────────────────┤
25
- │ Layer 2 — Permission rules │
26
- │ Glob-based deny rules block `cat .env`, │
27
- │ `printenv`, `echo $SECRET`, etc. │
28
- ├──────────────────────────────────────────────────┤
29
- │ Layer 3 — EnvGuard hook │
30
- │ tool.execute.before intercept catches anything │
31
- │ the glob rules miss (python -c, scripting │
32
- │ escapes, indirect reads). │
33
- └──────────────────────────────────────────────────┘
34
- ```
13
+ - provides `load_env` so agents can use `.env` values without seeing them directly
14
+ - provides `load_secrets` and `secret_status` when the [Varlock CLI](https://varlock.dev) is available
15
+ - uses `varlock load --format json` and `varlock printenv` to integrate with the varlock.dev CLI
16
+ - blocks direct secret reads with a `tool.execute.before` guard covering:
17
+ - 50+ bash deny patterns and 9 interpreter-based env read detectors
18
+ - 30+ file processor commands (`sed`, `awk`, `dd`, `tee`, `xxd`, etc.)
19
+ - shell redirects, encoding/eval bypasses, and variable listing commands
20
+ - varlock CLI self-exfiltration (`varlock printenv`, `varlock load --format env`)
21
+ - scrubs loaded secret values from tool output via a `tool.execute.after` hook
22
+ - whitelists `.env.schema` and `.env.example` (safe for AI consumption per varlock.dev design)
23
+ - validates config files and prevents agents from tampering with plugin configuration
24
+ - prevents symlink traversal and command injection in tool arguments
35
25
 
36
26
  ## Install
37
27
 
38
- ### As an npm plugin
39
-
40
- ```bash
41
- npm install opencode-varlock
42
- ```
43
-
44
- ```json
45
- // opencode.json
46
- {
47
- "plugin": ["opencode-varlock"]
48
- }
49
- ```
50
-
51
- The published package ships compiled ESM in `dist/`, and the root entry exports only the plugin itself so OpenCode can load it cleanly through the normal npm plugin resolution flow.
52
-
53
- ### As a local plugin
54
-
55
- Reference the package directory locally after building it:
28
+ Add the package to your `opencode.json` file:
56
29
 
57
30
  ```json
58
31
  {
59
- "plugin": ["./path/to/opencode-varlock"]
32
+ "$schema": "https://opencode.ai/config.json",
33
+ "plugin": ["opencode-varlock@latest"]
60
34
  }
61
35
  ```
62
36
 
63
37
  ## Configuration
64
38
 
65
- All configuration lives in a single `varlock.config.json` file. The plugin searches for it in two locations (merged in order):
66
-
67
- 1. `./varlock.config.json` (project root)
68
- 2. `.opencode/varlock.config.json`
39
+ ### Permissions
69
40
 
70
- Programmatic overrides passed to `createVarlockPlugin()` take highest priority.
71
-
72
- ### Quick start
73
-
74
- Copy the default config into your project:
75
-
76
- ```bash
77
- cp node_modules/opencode-varlock/assets/varlock.config.json ./varlock.config.json
78
- ```
79
-
80
- Or create a minimal one — only the fields you want to change:
41
+ In addition to adding the plugin to the array, we recommend adding some additional permission settings to your config. There are a few recommended "presets" in the [assets/permissions.json](assets/permissions.json) file, but here is a basic example:
81
42
 
82
43
  ```json
83
44
  {
84
- "varlock": {
85
- "enabled": true,
86
- "namespace": "myapp"
45
+ "permission": {
46
+ "bash": {
47
+ "cat *.env*": "deny",
48
+ "less *.env*": "deny",
49
+ "more *.env*": "deny",
50
+ "head *.env*": "deny",
51
+ "tail *.env*": "deny",
52
+ "grep * .env*": "deny",
53
+ "echo $*": "deny",
54
+ "python*getenv*": "deny",
55
+ "python*os.environ*": "deny",
56
+ "python*open*env*": "deny",
57
+ "node*process.env*": "deny",
58
+ "printenv*": "deny",
59
+ "env": "deny",
60
+ "export -p": "deny",
61
+ "source .env*": "deny",
62
+ "varlock printenv*": "deny",
63
+ "varlock load --show*": "deny",
64
+ "varlock load --format*": "deny",
65
+ "varlock load -f*": "deny",
66
+ "sed * .env*": "deny",
67
+ "awk * .env*": "deny"
68
+ }
87
69
  }
88
70
  }
89
71
  ```
90
72
 
91
- Everything else inherits from the built-in defaults.
92
-
93
- The bundled template and permission presets now live in `assets/`:
94
-
95
- ```text
96
- assets/varlock.config.json
97
- assets/varlock.schema.json
98
- assets/permissions.json
99
- ```
100
-
101
- The copied config template points its `$schema` at `./node_modules/opencode-varlock/assets/varlock.schema.json`, so editors can validate and autocomplete it after install.
102
-
103
- ## Repo layout
104
-
105
- ```text
106
- src/ TypeScript source for the plugin entry, config, guard, and tools
107
- assets/ JSON assets shipped with the npm package
108
- docs/ Setup and integration guides
109
- ```
110
-
111
- ## Testing
73
+ ### Plugin Config
112
74
 
113
- ```bash
114
- npm run test:unit
115
- npm run test:integration
116
- npm run test:coverage
117
- ```
75
+ `varlock.config.json` is optional.
118
76
 
119
- - `test:unit` covers config, guard, tools, and plugin registration
120
- - `test:integration` starts a real OpenCode server through `@opencode-ai/sdk` and verifies the plugin inside real sessions
121
- - `test:coverage` emits text, HTML, and LCOV coverage reports under `coverage/`
77
+ If you do not provide one, the plugin uses its built-in defaults from [assets/varlock.config.json](assets/varlock.config.json). Create a local config and place it in your `.opencode` or `~/.config/opencode` directory when you want to override those defaults.
122
78
 
123
- ### Full config reference
79
+ Quick example:
124
80
 
125
81
  ```json
126
82
  {
127
- "guard": {
128
- "enabled": true,
129
-
130
- "sensitivePatterns": [
131
- ".env", ".secret", ".pem", ".key", "credentials", ".pgpass"
132
- ],
133
-
134
- "sensitiveGlobs": [
135
- "**/.env",
136
- "**/.env.*",
137
- "**/.env.local",
138
- "**/.env.production",
139
- "**/*.pem",
140
- "**/*.key",
141
- "**/credentials",
142
- "**/credentials.*",
143
- "**/.pgpass",
144
- "secrets/**"
145
- ],
146
-
147
- "bashDenyPatterns": [],
148
-
149
- "blockedReadTools": ["read", "grep", "glob", "view"],
150
- "blockedWriteTools": ["write", "edit"]
151
- },
152
-
153
- "env": {
154
- "enabled": true,
155
- "allowedRoot": "."
156
- },
157
-
83
+ "$schema": "https://raw.githubusercontent.com/itlackey/opencode-varlock/main/assets/varlock.schema.json",
158
84
  "varlock": {
159
- "enabled": false,
160
- "autoDetect": true,
161
- "command": "varlock",
162
- "namespace": "app"
163
- }
164
- }
165
- ```
166
-
167
- ### Config sections
168
-
169
- #### `guard` — EnvGuard hook
170
-
171
- | Field | Type | Default | Description |
172
- |---|---|---|---|
173
- | `enabled` | `boolean` | `true` | Master switch for the `tool.execute.before` hook |
174
- | `sensitivePatterns` | `string[]` | see above | Substring patterns — a path containing any of these is blocked |
175
- | `sensitiveGlobs` | `string[]` | see above | Glob patterns — matched against full paths using `*`, `**`, `?` |
176
- | `bashDenyPatterns` | `string[]` | `[]` | Extra bash substrings to deny (merged with ~30 built-ins) |
177
- | `blockedReadTools` | `string[]` | `["read","grep","glob","view"]` | Tool names that trigger the file-read check |
178
- | `blockedWriteTools` | `string[]` | `["write","edit"]` | Tool names that trigger the file-write check |
179
-
180
- #### `env` — .env file loader
181
-
182
- | Field | Type | Default | Description |
183
- |---|---|---|---|
184
- | `enabled` | `boolean` | `true` | Register the `load_env` tool |
185
- | `allowedRoot` | `string` | `"."` | Path containment boundary (resolved relative to cwd) |
186
-
187
- #### `varlock` — Varlock integration
188
-
189
- | Field | Type | Default | Description |
190
- |---|---|---|---|
191
- | `enabled` | `boolean` | `false` | Explicitly enable Varlock tools |
192
- | `autoDetect` | `boolean` | `true` | Probe for the CLI at startup and enable if found |
193
- | `command` | `string` | `"varlock"` | Path or name of the Varlock binary |
194
- | `namespace` | `string` | `"app"` | Default namespace for `load_secrets` / `secret_status` |
195
-
196
- **Varlock resolution logic:**
197
-
198
- - `enabled: true` → tools are registered (fails at runtime if CLI is missing)
199
- - `enabled: false, autoDetect: true` → probes `which <command>`, enables if found
200
- - `enabled: false, autoDetect: false` → Varlock is fully disabled
201
-
202
- ### Config merge behavior
203
-
204
- Arrays are **replaced**, not concatenated. This means you can fully override the default glob list in your config file without inheriting the defaults:
205
-
206
- ```json
207
- {
208
- "guard": {
209
- "sensitiveGlobs": ["secrets/**", "config/.env.*"]
85
+ "enabled": true,
86
+ "namespace": "myapp"
210
87
  }
211
88
  }
212
89
  ```
213
90
 
214
- Object sections are deep-merged. Scalar values overwrite.
215
-
216
- ### Programmatic overrides
217
-
218
- For project-specific customization beyond what JSON can express:
219
-
220
- ```typescript
221
- // .opencode/plugin/secrets.ts
222
- import { createVarlockPlugin } from "opencode-varlock/plugin"
223
-
224
- export default createVarlockPlugin({
225
- guard: {
226
- sensitiveGlobs: [
227
- "**/.env",
228
- "**/.env.*",
229
- "infra/secrets/**",
230
- "deploy/*.key",
231
- ],
232
- bashDenyPatterns: ["vault read", "aws secretsmanager"],
233
- },
234
- varlock: {
235
- enabled: true,
236
- command: "/usr/local/bin/varlock",
237
- namespace: "prod",
238
- },
239
- })
240
- ```
241
-
242
- ## Glob patterns
243
-
244
- The guard supports glob patterns alongside the existing substring patterns. Both are checked — a match on either blocks the access.
245
-
246
- ### Supported syntax
247
-
248
- | Pattern | Matches | Example |
249
- |---|---|---|
250
- | `*` | Any characters except `/` | `*.pem` matches `server.pem` |
251
- | `**` | Any characters including `/` | `secrets/**` matches `secrets/prod/db.key` |
252
- | `**/` | Zero or more directory levels | `**/.env` matches `.env` and `config/.env` |
253
- | `?` | Single character except `/` | `?.key` matches `a.key` |
254
-
255
- ### When to use which
256
-
257
- **Substring patterns** are fast and filename-oriented. Use them for extensions and file names that should be blocked everywhere regardless of path:
258
-
259
- ```json
260
- "sensitivePatterns": [".env", ".pem", "credentials"]
261
- ```
262
-
263
- **Glob patterns** are structural and path-aware. Use them for directory-scoped rules and more precise matching:
264
-
265
- ```json
266
- "sensitiveGlobs": [
267
- "secrets/**",
268
- "config/.env.*",
269
- "deploy/**/*.key",
270
- "**/node_modules/**/.env"
271
- ]
272
- ```
273
-
274
- ### How globs are checked
275
-
276
- For file tool calls (`read`, `write`, `edit`, etc.), the glob is matched against the path argument directly.
277
-
278
- For bash commands, the guard extracts file-path-like tokens from the command string and checks each one against the compiled globs. This catches things like `jq . secrets/config.json` even when the substring patterns wouldn't flag it.
279
-
280
- ## Tools
281
-
282
- ### `load_env`
283
-
284
- Parses a `.env` file and sets `process.env`. Returns only variable **names**.
285
-
286
- ```
287
- Agent → load_env(path: ".env")
288
- ← { loaded: ["DATABASE_URL", "REDIS_HOST"], skipped: ["NODE_ENV"] }
289
- ```
290
-
291
- ### `load_secrets` (Varlock)
292
-
293
- Pulls secrets from Varlock and injects into `process.env`.
294
-
295
- ```
296
- Agent → load_secrets(namespace: "prod", keys: ["db_url", "api_key"])
297
- ← { loaded: ["DB_URL", "API_KEY"], source: "varlock/prod" }
298
- ```
299
-
300
- ### `secret_status` (Varlock)
301
-
302
- Read-only check of which secrets exist and which are loaded.
303
-
304
- ```
305
- Agent → secret_status(namespace: "app")
306
- ← { total: 5, loaded: 3, unloaded: 2, keys: [...] }
307
- ```
308
-
309
- ## Permission sets
310
-
311
- The `assets/permissions.json` file contains three tiers (standard, strict, lockdown) plus an example agent definition. Copy the tier that fits your threat model into `opencode.json`.
312
-
313
- These permission rules complement the EnvGuard hook — the rules handle fast-path blocking while the hook catches edge cases the glob-based rules miss.
314
-
315
- ## Architecture
316
-
317
- ### Why three layers?
318
-
319
- **Permissions alone aren't enough.** An agent can try `python3 -c "print(open('.env').read())"` or `python -c "import os; print(os.getenv('API_KEY'))"` - the obvious glob rules won't catch every runtime exfiltration path.
320
-
321
- **Prompt instructions alone aren't enough.** Telling an agent "never read .env" is a soft boundary the model can reason past.
322
-
323
- **The plugin hook is the hard boundary.** `tool.execute.before` runs before every built-in tool call, inspects actual arguments, and throws an error the agent cannot suppress. The error message redirects it to the approved tools.
324
-
325
- ### What the agent sees
326
-
327
- ```
328
- ✓ "Loaded 5 variables: DATABASE_URL, API_KEY, REDIS_HOST, JWT_SECRET, SMTP_PASS"
329
- ✓ Writes code: const db = new Client(process.env.DATABASE_URL)
330
- ✗ cat .env → Blocked: deny pattern
331
- ✗ echo $API_KEY → Blocked: deny pattern
332
- ✗ python -c "os.getenv" → Blocked: runtime env read
333
- ✗ python -c "open..." → Blocked: sensitive file
334
- ✗ jq . secrets/app.json → Blocked: matches glob "secrets/**"
335
- ```
336
-
337
- ## Advanced: composing individual pieces
338
-
339
- Every component is exported for use in custom plugins:
91
+ ## Docs
340
92
 
341
- ```typescript
342
- import { loadConfig, DEFAULT_CONFIG } from "opencode-varlock/config"
343
- import { createVarlockPlugin } from "opencode-varlock/plugin"
344
- import { createEnvGuard, globToRegex } from "opencode-varlock/guard"
345
- import { createLoadEnvTool } from "opencode-varlock/tools"
93
+ - setup and overrides: `docs/configuration.md`
94
+ - security model and limitations: `docs/security.md`
95
+ - tests and validation: `docs/testing.md`
96
+ - exported APIs and tools: `docs/api.md`
97
+ - Docker + pass guide: `docs/docker-pass-guide.md`
346
98
 
347
- // Load config with custom overrides
348
- const config = loadConfig(process.cwd(), {
349
- guard: { sensitiveGlobs: ["my-secrets/**"] },
350
- })
99
+ ## Useful files
351
100
 
352
- // Use just the guard
353
- const guard = createEnvGuard(config.guard)
354
-
355
- // Use just the tool
356
- const loadEnv = createLoadEnvTool(config.env)
357
-
358
- // Test a glob pattern
359
- const regex = globToRegex("**/.env.*")
360
- regex.test("config/.env.production") // true
361
- ```
101
+ - default config: `assets/varlock.config.json`
102
+ - JSON schema: `assets/varlock.schema.json`
103
+ - recommended permission configurations: `assets/permissions.json`
362
104
 
363
105
  ## License
364
106
 
@@ -18,14 +18,22 @@
18
18
  "head *.env*": "deny",
19
19
  "tail *.env*": "deny",
20
20
  "grep * .env*": "deny",
21
+ "sed * .env*": "deny",
22
+ "awk * .env*": "deny",
21
23
  "echo $*": "deny",
22
24
  "python*getenv*": "deny",
23
25
  "python*os.environ*": "deny",
26
+ "python*open*env*": "deny",
24
27
  "node*process.env*": "deny",
28
+ "node*readFileSync*env*": "deny",
25
29
  "printenv*": "deny",
26
30
  "env": "deny",
27
31
  "export -p": "deny",
28
32
  "source .env*": "deny",
33
+ "varlock printenv*": "deny",
34
+ "varlock load --show*": "deny",
35
+ "varlock load --format*": "deny",
36
+ "varlock load -f*": "deny",
29
37
  "npm test": "allow",
30
38
  "npm run *": "allow",
31
39
  "bun test": "allow",
@@ -42,22 +50,27 @@
42
50
  "permission": {
43
51
  "read": {
44
52
  "*.env*": "deny",
53
+ "*.env.schema": "allow",
54
+ "*.env.example": "allow",
45
55
  "*.pem": "deny",
46
56
  "*.key": "deny",
47
57
  "*credentials*": "deny",
48
58
  "*.pgpass": "deny",
59
+ "*varlock.config*": "deny",
49
60
  "*": "ask"
50
61
  },
51
62
  "write": {
52
63
  "*.env*": "deny",
53
64
  "*.pem": "deny",
54
65
  "*.key": "deny",
66
+ "*varlock.config*": "deny",
55
67
  "*": "ask"
56
68
  },
57
69
  "edit": {
58
70
  "*.env*": "deny",
59
71
  "*.pem": "deny",
60
72
  "*.key": "deny",
73
+ "*varlock.config*": "deny",
61
74
  "*": "ask"
62
75
  },
63
76
  "bash": {
@@ -67,20 +80,39 @@
67
80
  "head *.env*": "deny",
68
81
  "tail *.env*": "deny",
69
82
  "grep * .env*": "deny",
83
+ "sed * .env*": "deny",
84
+ "awk * .env*": "deny",
85
+ "cut * .env*": "deny",
86
+ "sort .env*": "deny",
87
+ "dd if=.env*": "deny",
88
+ "tee * .env*": "deny",
89
+ "xxd .env*": "deny",
70
90
  "echo $*": "deny",
71
91
  "python*getenv*": "deny",
72
92
  "python*os.environ*": "deny",
93
+ "python*open*env*": "deny",
73
94
  "node*process.env*": "deny",
95
+ "node*readFileSync*env*": "deny",
96
+ "ruby*File.read*env*": "deny",
74
97
  "printenv*": "deny",
75
98
  "env": "deny",
76
99
  "env *": "deny",
77
100
  "export -p": "deny",
78
101
  "declare -x": "deny",
102
+ "compgen -v": "deny",
103
+ "compgen -A variable": "deny",
104
+ "typeset -x": "deny",
79
105
  "source .env*": "deny",
80
106
  ". .env*": "deny",
81
107
  "set -a*": "deny",
82
108
  "curl *env*": "deny",
83
109
  "wget *env*": "deny",
110
+ "varlock printenv*": "deny",
111
+ "varlock load --show*": "deny",
112
+ "varlock load --format*": "deny",
113
+ "varlock load -f*": "deny",
114
+ "*base64*|*bash*": "deny",
115
+ "*base64*|*sh*": "deny",
84
116
  "npm test": "allow",
85
117
  "npm run *": "allow",
86
118
  "bun test": "allow",
@@ -97,20 +129,25 @@
97
129
  "permission": {
98
130
  "read": {
99
131
  "*.env*": "deny",
132
+ "*.env.schema": "allow",
133
+ "*.env.example": "allow",
100
134
  "*.pem": "deny",
101
135
  "*.key": "deny",
102
136
  "*credentials*": "deny",
103
137
  "*secret*": "deny",
138
+ "*varlock.config*": "deny",
104
139
  "*": "allow"
105
140
  },
106
141
  "write": {
107
142
  "*.env*": "deny",
143
+ "*varlock.config*": "deny",
108
144
  "*.ts": "ask",
109
145
  "*.js": "ask",
110
146
  "*": "deny"
111
147
  },
112
148
  "edit": {
113
149
  "*.env*": "deny",
150
+ "*varlock.config*": "deny",
114
151
  "*.ts": "ask",
115
152
  "*.js": "ask",
116
153
  "*": "deny"
@@ -141,17 +178,27 @@
141
178
  "permission": {
142
179
  "read": {
143
180
  "*.env*": "deny",
181
+ "*.env.schema": "allow",
182
+ "*.env.example": "allow",
144
183
  "*.pem": "deny",
184
+ "*varlock.config*": "deny",
145
185
  "*": "allow"
146
186
  },
147
187
  "bash": {
148
188
  "cat *.env*": "deny",
189
+ "sed * .env*": "deny",
190
+ "awk * .env*": "deny",
149
191
  "printenv*": "deny",
150
192
  "echo $*": "deny",
151
193
  "python*getenv*": "deny",
152
194
  "python*os.environ*": "deny",
195
+ "python*open*env*": "deny",
153
196
  "node*process.env*": "deny",
154
197
  "env": "deny",
198
+ "compgen -v": "deny",
199
+ "varlock printenv*": "deny",
200
+ "varlock load --format*": "deny",
201
+ "varlock load --show*": "deny",
155
202
  "docker *": "allow",
156
203
  "npm *": "allow",
157
204
  "bun *": "allow",
@@ -1,5 +1,5 @@
1
1
  {
2
- "$schema": "./node_modules/opencode-varlock/assets/varlock.schema.json",
2
+ "$schema": "https://raw.githubusercontent.com/itlackey/opencode-varlock/main/assets/varlock.schema.json",
3
3
  "$comment": "opencode-varlock configuration. Place in project root or .opencode/",
4
4
 
5
5
  "guard": {
@@ -13,7 +13,8 @@
13
13
  ".pem",
14
14
  ".key",
15
15
  "credentials",
16
- ".pgpass"
16
+ ".pgpass",
17
+ "varlock.config"
17
18
  ],
18
19
 
19
20
  "sensitiveGlobs": [
@@ -26,7 +27,9 @@
26
27
  "**/credentials",
27
28
  "**/credentials.*",
28
29
  "**/.pgpass",
29
- "secrets/**"
30
+ "secrets/**",
31
+ "**/varlock.config.json",
32
+ "**/.opencode/varlock.config.json"
30
33
  ],
31
34
 
32
35
  "bashDenyPatterns": [],
@@ -43,7 +46,7 @@
43
46
  },
44
47
 
45
48
  "varlock": {
46
- "$comment": "Varlock integration - pull secrets from pass, Azure KV, AWS, 1Password, etc.",
49
+ "$comment": "Varlock integration - uses varlock load/printenv to pull secrets from configured backends",
47
50
 
48
51
  "enabled": false,
49
52
  "autoDetect": true,
package/dist/config.d.ts CHANGED
@@ -36,6 +36,11 @@ export type PluginConfig = {
36
36
  varlock: VarlockConfig;
37
37
  };
38
38
  export declare const DEFAULT_CONFIG: PluginConfig;
39
+ /**
40
+ * Validates a parsed config object against the expected schema.
41
+ * Returns an array of human-readable error strings (empty = valid).
42
+ */
43
+ export declare function validateConfig(config: unknown, logger?: ConfigLogger): string[];
39
44
  export declare function loadConfig(cwd: string, overrides?: DeepPartial<PluginConfig>, logger?: ConfigLogger): PluginConfig;
40
45
  type DeepPartial<T> = {
41
46
  [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,MAAM,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE;IACjC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;IAC1C,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAChC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AAE1B,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,OAAO,CAAA;IAChB,iBAAiB,EAAE,MAAM,EAAE,CAAA;IAC3B,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,iBAAiB,EAAE,MAAM,EAAE,CAAA;CAC5B,CAAA;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,OAAO,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,WAAW,CAAA;IAClB,GAAG,EAAE,SAAS,CAAA;IACd,OAAO,EAAE,aAAa,CAAA;CACvB,CAAA;AAED,eAAO,MAAM,cAAc,EAAE,YAqC5B,CAAA;AAOD,wBAAgB,UAAU,CACxB,GAAG,EAAE,MAAM,EACX,SAAS,GAAE,WAAW,CAAC,YAAY,CAAM,EACzC,MAAM,CAAC,EAAE,YAAY,GACpB,YAAY,CAyCd;AAED,KAAK,WAAW,CAAC,CAAC,IAAI;KACnB,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAChE,CAAA;AAED,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACrD,MAAM,EAAE,CAAC,EACT,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,GACrB,CAAC,CAyBH;AAED,YAAY,EAAE,WAAW,EAAE,CAAA"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,MAAM,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE;IACjC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;IAC1C,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAChC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AAE1B,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,OAAO,CAAA;IAChB,iBAAiB,EAAE,MAAM,EAAE,CAAA;IAC3B,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,iBAAiB,EAAE,MAAM,EAAE,CAAA;CAC5B,CAAA;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,OAAO,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,WAAW,CAAA;IAClB,GAAG,EAAE,SAAS,CAAA;IACd,OAAO,EAAE,aAAa,CAAA;CACvB,CAAA;AAED,eAAO,MAAM,cAAc,EAAE,YAwC5B,CAAA;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,OAAO,EACf,MAAM,CAAC,EAAE,YAAY,GACpB,MAAM,EAAE,CA8HV;AAwFD,wBAAgB,UAAU,CACxB,GAAG,EAAE,MAAM,EACX,SAAS,GAAE,WAAW,CAAC,YAAY,CAAM,EACzC,MAAM,CAAC,EAAE,YAAY,GACpB,YAAY,CAkFd;AAED,KAAK,WAAW,CAAC,CAAC,IAAI;KACnB,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAChE,CAAA;AAED,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACrD,MAAM,EAAE,CAAC,EACT,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,GACrB,CAAC,CAyBH;AAED,YAAY,EAAE,WAAW,EAAE,CAAA"}