@reegaviljoen/eldlock 0.1.0

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.
Files changed (91) hide show
  1. package/README.md +285 -0
  2. package/bin/eldlock +11 -0
  3. package/docs/architecture.md +164 -0
  4. package/docs/threat-model.md +47 -0
  5. package/eldlock-cli/README.md +56 -0
  6. package/eldlock-cli/bin/eldlock +3 -0
  7. package/eldlock-cli/package-lock.json +805 -0
  8. package/eldlock-cli/package.json +71 -0
  9. package/eldlock-cli/src/api.ts +250 -0
  10. package/eldlock-cli/src/cli.ts +490 -0
  11. package/eldlock-cli/src/main.ts +10 -0
  12. package/eldlock-cli/src/tui.ts +676 -0
  13. package/eldlock-cli/tsconfig.json +13 -0
  14. package/eldlock-cli/vendor/npm/ansi-regex-6.2.2.tgz +0 -0
  15. package/eldlock-cli/vendor/npm/bun-ffi-structs-0.2.2.tgz +0 -0
  16. package/eldlock-cli/vendor/npm/diff-9.0.0.tgz +0 -0
  17. package/eldlock-cli/vendor/npm/emoji-regex-10.6.0.tgz +0 -0
  18. package/eldlock-cli/vendor/npm/esbuild-0.28.0.tgz +0 -0
  19. package/eldlock-cli/vendor/npm/esbuild-darwin-arm64-0.28.0.tgz +0 -0
  20. package/eldlock-cli/vendor/npm/esbuild-darwin-x64-0.28.0.tgz +0 -0
  21. package/eldlock-cli/vendor/npm/esbuild-linux-arm64-0.28.0.tgz +0 -0
  22. package/eldlock-cli/vendor/npm/esbuild-linux-x64-0.28.0.tgz +0 -0
  23. package/eldlock-cli/vendor/npm/fsevents-2.3.3.tgz +0 -0
  24. package/eldlock-cli/vendor/npm/get-east-asian-width-1.6.0.tgz +0 -0
  25. package/eldlock-cli/vendor/npm/marked-17.0.1.tgz +0 -0
  26. package/eldlock-cli/vendor/npm/opentui-core-0.3.1.tgz +0 -0
  27. package/eldlock-cli/vendor/npm/opentui-core-darwin-arm64-0.3.1.tgz +0 -0
  28. package/eldlock-cli/vendor/npm/opentui-core-darwin-x64-0.3.1.tgz +0 -0
  29. package/eldlock-cli/vendor/npm/opentui-core-linux-arm64-0.3.1.tgz +0 -0
  30. package/eldlock-cli/vendor/npm/opentui-core-linux-x64-0.3.1.tgz +0 -0
  31. package/eldlock-cli/vendor/npm/string-width-7.2.0.tgz +0 -0
  32. package/eldlock-cli/vendor/npm/strip-ansi-7.1.2.tgz +0 -0
  33. package/eldlock-cli/vendor/npm/tsx-4.22.4.tgz +0 -0
  34. package/eldlock-cli/vendor/npm/types-node-22.19.19.tgz +0 -0
  35. package/eldlock-cli/vendor/npm/typescript-5.9.3.tgz +0 -0
  36. package/eldlock-cli/vendor/npm/undici-types-6.21.0.tgz +0 -0
  37. package/eldlock-cli/vendor/npm/web-tree-sitter-0.25.10.tgz +0 -0
  38. package/eldlock-cli/vendor/npm/yoga-layout-3.2.1.tgz +0 -0
  39. package/eldlock-server/cmd/eldlock-server/main.go +132 -0
  40. package/eldlock-server/go.mod +10 -0
  41. package/eldlock-server/go.sum +11 -0
  42. package/eldlock-server/internal/api/README.md +14 -0
  43. package/eldlock-server/internal/api/core.go +126 -0
  44. package/eldlock-server/internal/api/exec.go +97 -0
  45. package/eldlock-server/internal/api/secrets.go +358 -0
  46. package/eldlock-server/internal/api/server.go +72 -0
  47. package/eldlock-server/internal/api/service_test.go +416 -0
  48. package/eldlock-server/internal/api/types.go +48 -0
  49. package/eldlock-server/internal/api/vault.go +69 -0
  50. package/eldlock-server/internal/api/vendor.go +44 -0
  51. package/eldlock-server/internal/libfido2/LICENSE +21 -0
  52. package/eldlock-server/internal/libfido2/README.md +127 -0
  53. package/eldlock-server/internal/libfido2/examples_test.go +614 -0
  54. package/eldlock-server/internal/libfido2/fido2.go +1234 -0
  55. package/eldlock-server/internal/libfido2/fido2_darwin.go +7 -0
  56. package/eldlock-server/internal/libfido2/fido2_other.go +9 -0
  57. package/eldlock-server/internal/libfido2/fido2_test.go +101 -0
  58. package/eldlock-server/internal/libfido2/go.mod +10 -0
  59. package/eldlock-server/internal/libfido2/go.sum +16 -0
  60. package/eldlock-server/internal/libfido2/log.go +87 -0
  61. package/eldlock-server/internal/store/README.md +7 -0
  62. package/eldlock-server/internal/store/store.go +434 -0
  63. package/eldlock-server/internal/store/store_test.go +125 -0
  64. package/eldlock-server/internal/yubikey/README.md +25 -0
  65. package/eldlock-server/internal/yubikey/default_fido2.go +7 -0
  66. package/eldlock-server/internal/yubikey/default_stub.go +7 -0
  67. package/eldlock-server/internal/yubikey/fido2_disabled.go +9 -0
  68. package/eldlock-server/internal/yubikey/fido2_libfido2.go +225 -0
  69. package/eldlock-server/internal/yubikey/fido2_libfido2_test.go +66 -0
  70. package/eldlock-server/internal/yubikey/passkey.go +139 -0
  71. package/eldlock-server/internal/yubikey/passkey_test.go +36 -0
  72. package/eldlock-server/vendor/github.com/keys-pub/go-libfido2/LICENSE +21 -0
  73. package/eldlock-server/vendor/github.com/keys-pub/go-libfido2/README.md +127 -0
  74. package/eldlock-server/vendor/github.com/keys-pub/go-libfido2/fido2.go +1234 -0
  75. package/eldlock-server/vendor/github.com/keys-pub/go-libfido2/fido2_darwin.go +7 -0
  76. package/eldlock-server/vendor/github.com/keys-pub/go-libfido2/fido2_other.go +9 -0
  77. package/eldlock-server/vendor/github.com/keys-pub/go-libfido2/log.go +87 -0
  78. package/eldlock-server/vendor/github.com/pkg/errors/.travis.yml +10 -0
  79. package/eldlock-server/vendor/github.com/pkg/errors/LICENSE +23 -0
  80. package/eldlock-server/vendor/github.com/pkg/errors/Makefile +44 -0
  81. package/eldlock-server/vendor/github.com/pkg/errors/README.md +59 -0
  82. package/eldlock-server/vendor/github.com/pkg/errors/appveyor.yml +32 -0
  83. package/eldlock-server/vendor/github.com/pkg/errors/errors.go +288 -0
  84. package/eldlock-server/vendor/github.com/pkg/errors/go113.go +38 -0
  85. package/eldlock-server/vendor/github.com/pkg/errors/stack.go +177 -0
  86. package/eldlock-server/vendor/modules.txt +7 -0
  87. package/examples/eldlock.toml +17 -0
  88. package/install.sh +66 -0
  89. package/package.json +66 -0
  90. package/scripts/build-production.mjs +177 -0
  91. package/scripts/postinstall-production.mjs +23 -0
package/README.md ADDED
@@ -0,0 +1,285 @@
1
+ # Eldlock
2
+
3
+ Eldlock is a local-first secret broker for developer machines.
4
+
5
+ It keeps developer secrets out of long-lived plaintext files, shell profiles,
6
+ and extractable private-key paths while preserving the interfaces developers
7
+ already use: `SSH_AUTH_SOCK`, shells, env vars, `.env` workflows, process
8
+ launchers, and local credential helpers.
9
+
10
+ Eldlock is not a hosted secrets manager. The vault lives on your machine,
11
+ secrets are encrypted on your machine, and normal secret release does not need
12
+ the internet.
13
+
14
+ ```text
15
+ eldlock CLI / TUI
16
+ |
17
+ | local Unix socket
18
+ v
19
+ eldlock-server local daemon
20
+ |
21
+ v
22
+ local encrypted vault
23
+ ```
24
+
25
+ ## Install
26
+
27
+ Eldlock currently builds from source on the target machine. The installer uses
28
+ vendored Go and npm dependencies after it downloads the repository archive.
29
+
30
+ Install prerequisites first:
31
+
32
+ ```bash
33
+ # macOS
34
+ brew install go node pkg-config keys-pub/tap/libfido2
35
+ curl -fsSL https://bun.sh/install | bash
36
+
37
+ # Ubuntu / Debian
38
+ sudo apt update
39
+ sudo apt install golang nodejs npm pkg-config libfido2-dev
40
+ curl -fsSL https://bun.sh/install | bash
41
+
42
+ # Red Hat / Fedora
43
+ sudo dnf install golang nodejs npm pkgconf-pkg-config libfido2-devel
44
+ curl -fsSL https://bun.sh/install | bash
45
+
46
+ # Arch Linux
47
+ sudo pacman -Syu go nodejs npm pkgconf libfido2
48
+ curl -fsSL https://bun.sh/install | bash
49
+ ```
50
+
51
+ Then run the installer:
52
+
53
+ ```bash
54
+ curl -fsSL https://raw.githubusercontent.com/reeganviljoen/eldlock/main/install.sh | bash
55
+ ```
56
+
57
+ Or install from npm after the package is published:
58
+
59
+ ```bash
60
+ npm install -g @reegaviljoen/eldlock
61
+ ```
62
+
63
+ If the repository is private, pass a GitHub token that can read it:
64
+
65
+ ```bash
66
+ export GITHUB_TOKEN="github_pat_or_ghp_token_with_repo_read_access"
67
+ curl -fsSL -H "Authorization: Bearer $GITHUB_TOKEN" \
68
+ https://raw.githubusercontent.com/reeganviljoen/eldlock/main/install.sh | bash
69
+ ```
70
+
71
+ The default install writes:
72
+
73
+ - `~/.local/bin/eldlock`
74
+ - `~/.local/share/eldlock/bin/eldlock-server`
75
+ - `~/.local/share/eldlock/lib/eldlock-cli`
76
+
77
+ Add the command directory to your shell path if needed:
78
+
79
+ ```bash
80
+ export PATH="$HOME/.local/bin:$PATH"
81
+ ```
82
+
83
+ Initialize and check the daemon:
84
+
85
+ ```bash
86
+ eldlock start
87
+ eldlock init
88
+ eldlock status
89
+ ```
90
+
91
+ `eldlock` uses `~/.eldlock` as its default state directory. Override it with
92
+ `ELDLOCK_STATE_DIR` when you want isolated state for testing.
93
+
94
+ ## Use
95
+
96
+ Store and read a secret:
97
+
98
+ ```bash
99
+ eldlock secret add personal/openai/api_key=sk-test
100
+ eldlock secret list
101
+ eldlock secret read personal/openai/api_key
102
+ eldlock secret read personal/openai/api_key --plain
103
+ ```
104
+
105
+ Import env-style secrets and launch a process with injected env vars:
106
+
107
+ ```bash
108
+ eldlock import .env
109
+ eldlock exec -- rails s
110
+ eldlock exec -- 'echo "$NODE_AUTH_TOKEN"'
111
+ eldlock shell --vault eldlock_secrets
112
+ ```
113
+
114
+ The enclosed command runs through your current shell and receives normal env
115
+ vars. The difference is that the secret is released just in time by the daemon
116
+ instead of living indefinitely in a parent shell or plaintext project file.
117
+ Use `eldlock shell` when you want an interactive copy of your current shell
118
+ with the vault env already present. Eldlock unlocks the vault through the
119
+ daemon first, prints a success line, then starts a clean interactive instance
120
+ of your shell from the CLI process with an `(eldlock:<vault>)` prompt marker.
121
+ Type `exit` to leave it.
122
+
123
+ Manual local test builds can use a stub passkey provider:
124
+
125
+ ```bash
126
+ export ELDLOCK_STUB_PASSKEY="local-test-passkey-change-me"
127
+ npm run build:dev
128
+ source .eldlock/dev-env.sh
129
+ eldlock init
130
+ eldlock start
131
+ ```
132
+
133
+ For YubiKey Bio / FIDO2 testing, install `libfido2`, then build and run with:
134
+
135
+ ```bash
136
+ export GOFLAGS="-tags=fido2"
137
+ export ELDLOCK_FIDO2_UV=true
138
+ ```
139
+
140
+ If your key requires a PIN, the CLI prompts after the daemon reports that the
141
+ PIN is required.
142
+
143
+ ## Philosophy
144
+
145
+ Eldlock's hard product principle:
146
+
147
+ > If adoption requires rewriting the app, changing every deploy process, or
148
+ > teaching every tool about Eldlock, the design has failed.
149
+
150
+ The daemon is the trust boundary. The CLI and TUI are frontends only: they may
151
+ request actions, show state, and launch flows, but security-critical behavior
152
+ belongs in `eldlock-server`.
153
+
154
+ That means policy decisions, approval state, caller inspection, encryption,
155
+ decryption, SSH signing, env injection, and audit logging must be enforced
156
+ daemon-side. A raw local socket client should not be able to bypass the rules by
157
+ skipping the CLI.
158
+
159
+ For integrations, Eldlock proxies the smallest useful operation:
160
+
161
+ | Secret type | Eldlock integration point |
162
+ | --- | --- |
163
+ | SSH keys | OpenSSH-compatible agent socket via `SSH_AUTH_SOCK` |
164
+ | Env vars | `eldlock exec -- <command>` |
165
+ | `.env` compatibility | ephemeral materialization first; stronger virtual-file approaches later |
166
+ | API tokens used by CLIs | wrapper, credential helper, plugin, or env injection |
167
+
168
+ Env vars cannot be intercepted after a process has already started. Eldlock can
169
+ launch a process with the required env vars, but it cannot make arbitrary env
170
+ reads magically lazy.
171
+
172
+ ## Threat Model
173
+
174
+ Eldlock helps against passive or opportunistic secret theft:
175
+
176
+ - dependency install scripts scraping `.env`, `~/.ssh`, and common token files
177
+ - local token grabbers scanning developer directories
178
+ - accidental commits of `.env` files
179
+ - stolen laptops where the attacker only has disk access
180
+ - silent SSH private-key exfiltration
181
+ - tools that need standard env vars or normal OpenSSH agent behavior
182
+
183
+ Eldlock does not fully protect against:
184
+
185
+ - malware running as your user during an approved secret release
186
+ - malware replacing shell hooks or common binaries like `git`, `ssh`, or `npm`
187
+ - malware reading child process memory
188
+ - malware scraping injected env vars after `eldlock exec`
189
+ - malware using the SSH agent during an approval TTL window
190
+ - root-level compromise
191
+
192
+ Useful claim:
193
+
194
+ > Eldlock prevents secrets from sitting around passively stealable and requires
195
+ > local policy plus user presence before use.
196
+
197
+ Avoid claims like "impossible to steal" or "fully secure on a compromised
198
+ machine."
199
+
200
+ ## Develop
201
+
202
+ Repository layout:
203
+
204
+ ```text
205
+ eldlock-server/ Go daemon and security boundary
206
+ eldlock-cli/ TypeScript CLI/TUI frontend
207
+ docs/ architecture and threat model notes
208
+ examples/ example project configuration
209
+ ```
210
+
211
+ Common commands:
212
+
213
+ ```bash
214
+ # Build production artifacts into ./dist/eldlock
215
+ npm run build:prod
216
+
217
+ # Install eldlock for the whole machine at ~/.local/bin/eldlock
218
+ npm run install:local
219
+
220
+ # Local-only release build; requires an enrolled release YubiKey
221
+ npm run release
222
+
223
+ # First-time release YubiKey enrollment
224
+ npm run release -- --enroll
225
+
226
+ # Dry-run npm publish through eldlock_secrets/NODE_AUTH_TOKEN
227
+ npm run release -- --publish-dry-run
228
+
229
+ # Publish to npm through eldlock_secrets/NODE_AUTH_TOKEN
230
+ npm run release -- --publish
231
+
232
+ # Choose production install locations
233
+ node scripts/build-production.mjs \
234
+ --install-dir "$HOME/.local/share/eldlock" \
235
+ --bin-dir "$HOME/.local/bin"
236
+
237
+ # Server checks
238
+ cd eldlock-server
239
+ go run ./cmd/eldlock-server version
240
+ go test -mod=vendor ./...
241
+
242
+ # CLI checks
243
+ cd eldlock-cli
244
+ npm run typecheck
245
+ npm run build
246
+ ```
247
+
248
+ Vendored dependencies keep normal local development off live package registries:
249
+
250
+ - Go server dependencies live in `eldlock-server/vendor/`; server builds use
251
+ `-mod=vendor`.
252
+ - The patched `go-libfido2` binding lives in `eldlock-server/internal/libfido2/`.
253
+ - CLI npm tarballs live in `eldlock-cli/vendor/npm/`.
254
+ - `eldlock-cli/.npmrc` keeps npm offline for this package.
255
+
256
+ Npm releases are intentionally local-only. The package publishes as
257
+ `@reegaviljoen/eldlock` because npm rejected the unscoped `eldlock` name as too
258
+ similar to an existing package. Before publishing, install the
259
+ machine-wide command with `npm run install:local`, enroll the release YubiKey
260
+ with `npm run release -- --enroll`, then create an Eldlock vault named
261
+ `eldlock_secrets` containing the standard npm env secret `NODE_AUTH_TOKEN`.
262
+ The release script builds and verifies Eldlock locally, authenticates with the
263
+ release YubiKey, then runs normal `npm publish --access public` through
264
+ `eldlock exec --vault eldlock_secrets`. Use an npm automation token, or a
265
+ granular token with package publish access and 2FA bypass enabled, as
266
+ `NODE_AUTH_TOKEN`.
267
+
268
+ To verify env injection without printing the token, run:
269
+
270
+ ```bash
271
+ eldlock exec --vault eldlock_secrets -- 'test -n "$NODE_AUTH_TOKEN" && echo NODE_AUTH_TOKEN is set'
272
+ ```
273
+
274
+ If the secret is not already set in your outer shell, quote shell variables in
275
+ one command string, such as `eldlock exec -- 'echo "$NODE_AUTH_TOKEN"'`.
276
+ Unquoted variables are expanded by your outer shell before Eldlock starts.
277
+
278
+ Storage note: the 0.1 preview uses an encrypted JSON envelope. Eldlock should
279
+ avoid SQL/SQLite for vault storage so SQL injection is not part of the storage
280
+ threat model.
281
+
282
+ The deeper docs are intentionally more detailed:
283
+
284
+ - [Architecture](docs/architecture.md)
285
+ - [Threat model](docs/threat-model.md)
package/bin/eldlock ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env sh
2
+ SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
3
+ if [ "${1:-}" = "" ] || [ "${1:-}" = "tui" ]; then
4
+ if [ -n "${ELDLOCK_TUI_RUNTIME:-}" ]; then
5
+ exec "$ELDLOCK_TUI_RUNTIME" "$SCRIPT_DIR/../eldlock-cli/dist/main.js" "$@"
6
+ fi
7
+ if command -v bun >/dev/null 2>&1; then
8
+ exec bun "$SCRIPT_DIR/../eldlock-cli/dist/main.js" "$@"
9
+ fi
10
+ fi
11
+ exec node "$SCRIPT_DIR/../eldlock-cli/dist/main.js" "$@"
@@ -0,0 +1,164 @@
1
+ # Eldlock Architecture
2
+
3
+ Eldlock is a local daemon plus a bundled CLI/TUI frontend.
4
+
5
+ The daemon owns all security-sensitive behavior:
6
+
7
+ - secret storage
8
+ - encryption and decryption
9
+ - YubiKey unlock or wrapping
10
+ - policy decisions
11
+ - approvals
12
+ - SSH signing
13
+ - env injection
14
+ - audit logging
15
+
16
+ The CLI/TUI is intentionally thin. It asks the daemon to do things; it does not decide whether those things are allowed.
17
+
18
+ ## Components
19
+
20
+ ```text
21
+ ┌────────────────────┐
22
+ │ eldlock-cli / TUI │
23
+ │ frontend only │
24
+ └─────────┬──────────┘
25
+
26
+ │ Unix socket API
27
+ v
28
+ ┌──────────────────────────────────────────────────────┐
29
+ │ eldlock-server local daemon │
30
+ │ │
31
+ │ ┌──────────────┐ ┌──────────────┐ ┌─────────────┐ │
32
+ │ │ policy │ │ approval │ │ audit log │ │
33
+ │ └──────┬───────┘ └──────┬───────┘ └──────┬──────┘ │
34
+ │ │ │ │ │
35
+ │ ┌──────v───────┐ ┌──────v───────┐ ┌──────v──────┐ │
36
+ │ │ crypto │ │ YubiKey │ │ caller ID │ │
37
+ │ └──────┬───────┘ └──────────────┘ └─────────────┘ │
38
+ │ │ │
39
+ │ ┌──────v─────────────────────────────────────────┐ │
40
+ │ │ local encrypted vault │ │
41
+ │ └────────────────────────────────────────────────┘ │
42
+ │ │
43
+ │ Interfaces: SSH agent, exec launcher, shell hooks │
44
+ └──────────────────────────────────────────────────────┘
45
+ ```
46
+
47
+ ## Local API
48
+
49
+ The daemon should listen on a local Unix domain socket, for example:
50
+
51
+ ```text
52
+ $XDG_RUNTIME_DIR/eldlock/daemon.sock
53
+ ```
54
+
55
+ or on macOS:
56
+
57
+ ```text
58
+ $HOME/Library/Application Support/Eldlock/daemon.sock
59
+ ```
60
+
61
+ The local API should never be treated as trusted just because it is local. The daemon must inspect the peer process and apply policy before releasing secrets or signing anything.
62
+
63
+ Important caller signals:
64
+
65
+ - UID/GID
66
+ - PID
67
+ - executable path
68
+ - command line
69
+ - cwd
70
+ - parent process
71
+ - attached TTY/session
72
+ - requested secret
73
+ - requested action
74
+ - approval TTL state
75
+
76
+ On Linux, the daemon can use Unix socket peer credentials such as `SO_PEERCRED`. macOS has different peer credential APIs and needs its own implementation path.
77
+
78
+ ## SSH Agent
79
+
80
+ Eldlock should expose an OpenSSH-compatible agent socket:
81
+
82
+ ```bash
83
+ export SSH_AUTH_SOCK="$HOME/.eldlock/ssh-agent.sock"
84
+ ```
85
+
86
+ Normal tools should keep working:
87
+
88
+ ```bash
89
+ ssh server
90
+ git clone git@github.com:org/repo.git
91
+ git pull
92
+ ```
93
+
94
+ The private key should not be exposed to the SSH client. The client asks the agent to sign a challenge. Eldlock checks policy, requires approval when needed, decrypts the key in memory, signs, and clears plaintext material as quickly as possible.
95
+
96
+ ## Env Injection
97
+
98
+ Env vars cannot be lazily fetched after a process starts. Eldlock should launch the process with the required env vars:
99
+
100
+ ```bash
101
+ eldlock exec -- bin/dev
102
+ ```
103
+
104
+ Later, shell hooks can make this feel natural:
105
+
106
+ ```bash
107
+ bin/dev
108
+ ```
109
+
110
+ The shell hook can detect project config and route the command through `eldlock exec`.
111
+
112
+ ## Storage
113
+
114
+ The 0.1 preview uses an encrypted JSON envelope stored on the local machine.
115
+ The envelope uses established primitives through the Go implementation, with
116
+ key material requested from the configured passkey provider for vault create,
117
+ read, add, list, and remove operations.
118
+
119
+ Eldlock should avoid SQL/SQLite for vault storage so SQL injection is not part
120
+ of the storage threat model. Do not invent custom crypto.
121
+
122
+ Conceptual record model:
123
+
124
+ ```text
125
+ secrets
126
+ id
127
+ name
128
+ type
129
+ encrypted_blob
130
+ metadata_json
131
+ created_at
132
+ updated_at
133
+
134
+ policies
135
+ id
136
+ secret_id
137
+ allowed_cwd
138
+ allowed_process
139
+ approval_mode
140
+ ttl_seconds
141
+ require_touch
142
+
143
+ audit_events
144
+ id
145
+ event_type
146
+ secret_id
147
+ caller_pid
148
+ caller_exe
149
+ caller_cwd
150
+ decision
151
+ created_at
152
+ ```
153
+
154
+ Potential encryption model:
155
+
156
+ ```text
157
+ YubiKey-backed wrapping provider
158
+ ↓ unwraps
159
+ local master key
160
+ ↓ decrypts
161
+ per-secret encryption keys or secret blobs
162
+ ```
163
+
164
+ The YubiKey must be part of unwrapping key material, not just a cosmetic approval check.
@@ -0,0 +1,47 @@
1
+ # Threat Model
2
+
3
+ Eldlock is not a magic shield for compromised machines. It is designed to reduce passive secret theft and make secret use require local policy plus user presence.
4
+
5
+ ## Protects Against
6
+
7
+ Eldlock should materially help against:
8
+
9
+ - dependency install scripts scraping `~/.ssh`, `.env`, and common token files
10
+ - local token grabbers scanning developer directories
11
+ - accidental commits of `.env` files
12
+ - stolen laptops where the attacker only has disk access
13
+ - silent theft of SSH private keys
14
+ - tools that need standard env vars or normal OpenSSH agent behavior
15
+
16
+ ## Does Not Fully Protect Against
17
+
18
+ Eldlock cannot fully protect against:
19
+
20
+ - malware running as the user during an approved secret release
21
+ - malware modifying shell hooks
22
+ - malware replacing binaries like `git`, `ssh`, `rails`, or `npm`
23
+ - malware reading child process memory
24
+ - malware scraping environment variables after `eldlock exec`
25
+ - malware using the SSH agent during an approval TTL window
26
+ - root-level compromise
27
+
28
+ ## Design Implication
29
+
30
+ The daemon should assume local callers may be hostile. A command like this must not be automatically safe:
31
+
32
+ ```bash
33
+ eldlock secret read personal/openai/api_key
34
+ ```
35
+
36
+ Every request should go through policy checks, caller inspection, approval, and audit logging.
37
+
38
+ ## Useful Claim
39
+
40
+ Good:
41
+
42
+ > Eldlock prevents secrets from sitting around passively stealable and requires local policy plus user presence before use.
43
+
44
+ Bad:
45
+
46
+ > Eldlock makes secrets impossible to steal.
47
+
@@ -0,0 +1,56 @@
1
+ # eldlock-cli
2
+
3
+ `eldlock-cli` is the bundled command-line and TUI frontend for Eldlock.
4
+
5
+ It is intentionally not the trust boundary. It talks to the local `eldlock-server` daemon over a Unix socket.
6
+
7
+ Security-critical logic belongs in `eldlock-server`, including:
8
+
9
+ - policy decisions
10
+ - encryption and decryption
11
+ - YubiKey unlock
12
+ - SSH signing
13
+ - env injection
14
+ - audit logging
15
+
16
+ ## TUI Direction
17
+
18
+ The intended TUI direction is OpenTUI-style: a rich terminal frontend similar in feel to OpenCode.
19
+
20
+ The TUI should render state and collect user intent. The daemon decides what is allowed.
21
+
22
+ ## Prototype Secret Commands
23
+
24
+ Initialize the vault:
25
+
26
+ ```bash
27
+ export ELDLOCK_STUB_PASSKEY="local-test-passkey-change-me"
28
+ npm run dev -- init
29
+ ```
30
+
31
+ Start the daemon:
32
+
33
+ ```bash
34
+ export ELDLOCK_SERVER_PATH="../eldlock-server/bin/eldlock-server-dev"
35
+ npm run dev -- start
36
+ npm run dev -- status
37
+ ```
38
+
39
+ The public CLI does not require Go or mise at runtime. `eldlock start` launches the binary at `ELDLOCK_SERVER_PATH`, or finds `eldlock-server` on `PATH`.
40
+
41
+ In another terminal, add and read an env secret:
42
+
43
+ ```bash
44
+ npm run dev -- secret add demo/API_KEY=test-secret
45
+ npm run dev -- secret read demo/API_KEY
46
+ npm run dev -- secret read demo/API_KEY --plain
47
+ npm run dev -- secret remove demo/API_KEY
48
+ ```
49
+
50
+ Stop the daemon:
51
+
52
+ ```bash
53
+ npm run dev -- stop
54
+ ```
55
+
56
+ The CLI sends requests to the daemon over the Unix socket. Clipboard writes happen in the daemon, not in TypeScript.
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env sh
2
+ SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
3
+ exec node "$SCRIPT_DIR/../dist/main.js" "$@"