|
1 | 1 | # Configuration design: env vars, the socket-cli config file, and what we deliberately don't read |
2 | 2 |
|
3 | | -Status: **implemented** (v3.5). This document records the settled design so |
4 | | -future configuration surface grows inside it instead of inventing new |
5 | | -mechanisms. |
| 3 | +Status: **implemented** (v3.5); section 4 (`socket.yml` patch policy) is |
| 4 | +**planned** for v5.0 (see `staged-rollout.md`). This document records the |
| 5 | +settled design so future configuration surface grows inside it instead of |
| 6 | +inventing new mechanisms. |
6 | 7 |
|
7 | 8 | ## Problem |
8 | 9 |
|
@@ -69,35 +70,71 @@ UX policy and are ignored. |
69 | 70 | - The python `socketsecurity` CLI already accepts `SOCKET_API_TOKEN`, so |
70 | 71 | the canonical names are the cross-tool bridge; no `SOCKET_SECURITY_*` |
71 | 72 | aliases were added. |
72 | | -- `socket.yml` stays a scanning-product surface (projectIgnorePaths / |
73 | | - issueRules / githubApp); socket-patch does not read it. |
| 73 | +- `socket.yml` is shared with the scanning product (projectIgnorePaths / |
| 74 | + triggerPaths / issueRules / githubApp). As of v5.0 socket-patch reads |
| 75 | + exactly two of its keys, `projectIgnorePaths` and a new `patches` block, |
| 76 | + and nothing else (section 4). |
74 | 77 | - `SOCKET_PROXY_URL` (the public patch **endpoint**) must never be |
75 | 78 | conflated with socket-cli's `apiProxy` (an HTTP **forward proxy**). |
76 | 79 | Forward-proxy behavior comes from the standard |
77 | 80 | `HTTP_PROXY`/`HTTPS_PROXY`/`NO_PROXY` vars, which reqwest honors. |
78 | 81 |
|
| 82 | +### 4. `socket.yml` carries patch selection policy, never settings (v5.0) |
| 83 | + |
| 84 | +Revisits the v3.5 position that socket-patch does not read `socket.yml`. |
| 85 | +Staged rollout needs a repo-owned, reviewable place to say which projects, |
| 86 | +ecosystems and packages may be patched, a severity floor and a per-run cap |
| 87 | +on new patches (`staged-rollout.md`). `socket.yml` is where Socket users |
| 88 | +already express repo policy, it lives at the repo root, and a new |
| 89 | +top-level `patches:` key is stripped or ignored by every existing parser. |
| 90 | + |
| 91 | +The trust boundary is unchanged and gains its positive half: |
| 92 | + |
| 93 | +- A repository file may **narrow or pace** what `scan` patches. It may |
| 94 | + never widen it, name an endpoint or credential, choose a mode or download |
| 95 | + format, or disable a safety interlock. The parser has no fields for any |
| 96 | + of those; such keys are unknown keys and fail validation. |
| 97 | +- Because the file only narrows, an unreadable file or an invalid |
| 98 | + `patches` block fails closed (exit 1, `socket_yml_invalid`, nothing |
| 99 | + written) instead of being treated as absent. (A repo with no `patches` |
| 100 | + block and a malformed `projectIgnorePaths` gets a warning, so repos that |
| 101 | + never opted in do not start failing.) This is the opposite of the socket-cli `config.json` rule above |
| 102 | + (corrupt → warn and ignore), and deliberately so: ignoring a broken |
| 103 | + user-level login file loses a convenience; ignoring a broken repo policy |
| 104 | + widens the rollout. |
| 105 | +- Lookup is bounded to the repository (nearest `.git` ancestor of |
| 106 | + `--cwd` owned by the user, honoring `GIT_CEILING_DIRECTORIES`, else |
| 107 | + `--cwd`), root files only, regular files only. |
| 108 | +- Flags and env vars still win over the file for scalars (CLI > env > |
| 109 | + file > default) and intersect with it for list filters; |
| 110 | + `--no-socket-yml` / `SOCKET_NO_SOCKET_YML` ignores the file. |
| 111 | +- Only `scan` (every mode) and the in-memory engine honor it. Commands |
| 112 | + that report, attest or undo existing state (`list`, `vex`, `rollback`, |
| 113 | + `remove`, `repair`, `apply`, `vendor`) ignore it; `get` bypasses it with |
| 114 | + a warning. |
| 115 | + |
79 | 116 | ## Explicitly rejected |
80 | 117 |
|
81 | 118 | | Idea | Why not | |
82 | 119 | |---|---| |
83 | 120 | | Auto-loading `.env` / `.env.local` | Trust boundary: the tool mutates installed packages while holding an API token; a file in a *cloned repo* must never redirect endpoints, disable interlocks, or spend the token. Also the wrong convention class — npm/cargo/pip/git read no `.env`; dotenv is an app-runtime convention. Users who want it have direnv/mise/dotenvx. | |
84 | 121 | | A new socket-patch config file (`.socket/config.toml`, …) | Duplicates socket-cli's persisted config; one more file format to trust, document, and migrate. | |
85 | 122 | | Writing to socket-cli's `config.json` | No login flow here; shared mutable state and format drift for zero benefit. | |
86 | | -| Honoring endpoints/credentials from repo-level files (manifest, socket.yml) | Same trust boundary as `.env`. Stated as a contract property in `CLI_CONTRACT.md`. | |
| 123 | +| Honoring endpoints/credentials/interlock switches from repo-level files (manifest, socket.yml) | Same trust boundary as `.env`. Stated as a contract property in `CLI_CONTRACT.md`. Selection policy that only narrows is the one exception (section 4). | |
| 124 | +| A `version: 3` socket.yml for the `patches` block | socket-cli rejects any version but 2; older ajv parsers would treat 3 as 2 anyway. The block is additive under `version: 2`. | |
| 125 | +| Per-directory `socket.yml` files | No existing consumer supports them; one root file with `includePaths` covers monorepos. | |
87 | 126 | | `SOCKET_CLI_CONFIG` (ephemeral full-JSON config override) | Imports socket-cli's whole config vocabulary as a permanent compat contract. | |
88 | 127 | | Mapping `apiProxy` → anything | Forward-proxy vs patch-endpoint semantic trap; `HTTP_PROXY` et al. already work. | |
89 | 128 | | `enforcedOrgs` / `skipAskToPersistDefaultOrg` | Interactive socket-cli UX policy with no socket-patch analog. | |
90 | 129 |
|
91 | 130 | ## Deferred (designated homes, no implementation yet) |
92 | 131 |
|
93 | | -- **Project-level behavioral defaults** (`ecosystems`, `downloadMode`, |
94 | | - `vendorSource`): if demand materializes, they go in the manifest `setup` |
95 | | - block (`setup.defaults`, camelCase) — the manifest already controls what |
96 | | - gets patched, so behavioral defaults there grant no new capability, and |
97 | | - the serde struct simply has no fields for URLs/credentials/interlocks. |
98 | | - Requires teaching the TS zod twin |
99 | | - (`npm/socket-patch/src/schema/manifest-schema.ts`) to model `setup`. |
100 | | - Precedence would be flag > env > `setup.defaults` > default. |
| 132 | +- **Project-level behavioral defaults** (`downloadMode`, `vendorSource`, |
| 133 | + mode): not planned. The v3.5 idea of a manifest `setup.defaults` block is |
| 134 | + obsolete in v5 (hosted and vendored projects have no manifest and `setup` |
| 135 | + is removed). Selection policy (ecosystems, packages, paths, severity, |
| 136 | + per-run cap) went to `socket.yml` `patches` instead (section 4). Anything |
| 137 | + that is not pure narrowing stays out of repo files. |
101 | 138 | - **Env cleanup sweep**: core's direct env readers (`SOCKET_OFFLINE` in |
102 | 139 | `utils/env_compat.rs`, `SOCKET_TELEMETRY_DISABLED` in `telemetry.rs`) |
103 | 140 | still match only `1|true`, unlike `parse_bool_flag`'s vocabulary (the CLI |
|
0 commit comments