@theholocron/holocron-plugin-1password 2.0.0-alpha.1 → 2.0.0-alpha.5
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 +99 -27
- package/dist/index.d.mts +23 -1
- package/dist/index.mjs +54 -1
- package/package.json +6 -4
package/README.md
CHANGED
|
@@ -1,8 +1,49 @@
|
|
|
1
|
+
<!-- editorconfig-checker-disable-file -->
|
|
2
|
+
|
|
1
3
|
# `@theholocron/holocron-plugin-1password`
|
|
2
4
|
|
|
3
|
-
1Password plugin for [Holocron](../cli). Implements the
|
|
4
|
-
|
|
5
|
-
(<https://developer.1password.com/docs/cli>).
|
|
5
|
+
1Password plugin for [Holocron](../cli). Implements the `vault`
|
|
6
|
+
capability via shell-out to the `op` CLI
|
|
7
|
+
(<https://developer.1password.com/docs/cli>). Also exports
|
|
8
|
+
`verifyToken` + `AUTH_HINT` for use by `holocron auth`.
|
|
9
|
+
|
|
10
|
+
## One of several vault providers
|
|
11
|
+
|
|
12
|
+
`vault` is a REQUIRED capability, but 1Password is one of several
|
|
13
|
+
providers you can pick — the capability/provider model is designed
|
|
14
|
+
so you can swap by editing one config line. Peer plugins:
|
|
15
|
+
|
|
16
|
+
- **[`@theholocron/holocron-plugin-doppler`](../holocron-plugin-doppler)**
|
|
17
|
+
— REST-transport, Doppler-CLI-managed auth via the OS keychain
|
|
18
|
+
(`doppler login` → `holocron auth set doppler …`). This repo's
|
|
19
|
+
own default since `2.0.0-alpha.4`.
|
|
20
|
+
- **`@theholocron/holocron-plugin-infisical`** — planned (see [#97](https://github.com/theholocron/holocron/issues/97)),
|
|
21
|
+
will use the same REST + keyring shape.
|
|
22
|
+
|
|
23
|
+
### When to choose 1Password
|
|
24
|
+
|
|
25
|
+
Reach for this plugin if:
|
|
26
|
+
|
|
27
|
+
- Your existing personal / team secrets already live in 1Password
|
|
28
|
+
and adding another vault provider is real friction.
|
|
29
|
+
- You value 1Password's biometric-first UX for laptop workflows
|
|
30
|
+
over the "REST + keyring" ergonomic set that the other plugins
|
|
31
|
+
offer.
|
|
32
|
+
- You're comfortable running the `op` CLI on every machine that
|
|
33
|
+
needs to reach your secrets — including CI, where you'd set
|
|
34
|
+
`OP_SERVICE_ACCOUNT_TOKEN` instead of the biometric flow.
|
|
35
|
+
|
|
36
|
+
Reach for one of the REST plugins (Doppler / Infisical) instead
|
|
37
|
+
when you want:
|
|
38
|
+
|
|
39
|
+
- Zero desktop-app dependency (Doppler-CLI on the laptop still
|
|
40
|
+
needed; nothing on CI beyond a bearer token).
|
|
41
|
+
- 100% REST transport across every capability call (this plugin
|
|
42
|
+
shells out per operation).
|
|
43
|
+
- A vault whose API you can reach without unlocking anything.
|
|
44
|
+
|
|
45
|
+
Both patterns are fully supported — switch by editing
|
|
46
|
+
`holocron.config.json`.
|
|
6
47
|
|
|
7
48
|
## Install
|
|
8
49
|
|
|
@@ -10,21 +51,23 @@
|
|
|
10
51
|
pnpm add -D @theholocron/holocron-plugin-1password@alpha
|
|
11
52
|
```
|
|
12
53
|
|
|
13
|
-
Requires the `op` binary on PATH (see [Prerequisite](#prerequisite)
|
|
54
|
+
Requires the `op` binary on PATH (see [Prerequisite](#prerequisite)).
|
|
14
55
|
|
|
15
56
|
## Why shell-out, not REST
|
|
16
57
|
|
|
17
58
|
1Password's "REST API" is the **Connect server** — a Docker container
|
|
18
|
-
you have to run yourself (or pay for the cloud-hosted version). For
|
|
19
|
-
solo / small-team workflow, that's overkill. The `op` CLI is what
|
|
20
|
-
developer already has installed and uses for hand-debugging
|
|
59
|
+
you have to run yourself (or pay for the cloud-hosted version). For
|
|
60
|
+
a solo / small-team workflow, that's overkill. The `op` CLI is what
|
|
61
|
+
every developer already has installed and uses for hand-debugging
|
|
62
|
+
anyway, so:
|
|
21
63
|
|
|
22
|
-
- **Local dev
|
|
23
|
-
|
|
24
|
-
- **CI
|
|
25
|
-
- **Either way
|
|
64
|
+
- **Local dev**: developer's signed-in `op` CLI (biometric unlock
|
|
65
|
+
via the desktop app).
|
|
66
|
+
- **CI**: `OP_SERVICE_ACCOUNT_TOKEN` env var; `op` auto-detects it.
|
|
67
|
+
- **Either way**: same binary, same commands, same code path.
|
|
26
68
|
|
|
27
|
-
The plugin's job is just to drive the CLI; auth handling is the
|
|
69
|
+
The plugin's job is just to drive the CLI; auth handling is the
|
|
70
|
+
CLI's.
|
|
28
71
|
|
|
29
72
|
## Prerequisite
|
|
30
73
|
|
|
@@ -38,6 +81,19 @@ brew install 1password-cli # macOS
|
|
|
38
81
|
The plugin throws a clear error at construction time if `op` isn't
|
|
39
82
|
found.
|
|
40
83
|
|
|
84
|
+
## Auth
|
|
85
|
+
|
|
86
|
+
This plugin does NOT store a bearer token — the `op` CLI manages
|
|
87
|
+
its own auth via the 1Password desktop app (biometric unlock on
|
|
88
|
+
laptops) or `OP_SERVICE_ACCOUNT_TOKEN` on CI. `holocron auth set
|
|
89
|
+
1password` will accept a token, but since the plugin doesn't read
|
|
90
|
+
the keyring, storing one has no runtime effect. The `AUTH_HINT`
|
|
91
|
+
export makes this explicit in `holocron auth` output.
|
|
92
|
+
|
|
93
|
+
`holocron auth check 1password` runs `op whoami --format=json` to
|
|
94
|
+
confirm you're signed in — a useful sanity check independent of
|
|
95
|
+
holocron.
|
|
96
|
+
|
|
41
97
|
## Config
|
|
42
98
|
|
|
43
99
|
```jsonc
|
|
@@ -55,27 +111,43 @@ found.
|
|
|
55
111
|
```
|
|
56
112
|
|
|
57
113
|
- `vault` (required) — the 1Password vault name items live in.
|
|
58
|
-
- `account` (optional) — 1P account UUID. Passes `--account <UUID>`
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
114
|
+
- `account` (optional) — 1P account UUID. Passes `--account <UUID>`
|
|
115
|
+
on every `op` call so the integration targets a specific account
|
|
116
|
+
even when the developer has multiple signed in (e.g., work +
|
|
117
|
+
personal). Find via `op account list`.
|
|
62
118
|
|
|
63
119
|
## What's implemented
|
|
64
120
|
|
|
65
|
-
| Method
|
|
66
|
-
|
|
|
67
|
-
| `read(reference)`
|
|
68
|
-
| `write(reference, v)`
|
|
69
|
-
| `list()`
|
|
70
|
-
| `environments()`
|
|
71
|
-
| `readEnvironment(id)`
|
|
72
|
-
|
|
121
|
+
| Method | What it does |
|
|
122
|
+
| --------------------- | ---------------------------------------------------------------------------------- |
|
|
123
|
+
| `read(reference)` | `op read <reference>` — resolves `op://Vault/Item/field`. `--no-newline`. |
|
|
124
|
+
| `write(reference, v)` | Probe + `op item edit` if exists, else `op item create --category=API Credential`. |
|
|
125
|
+
| `list()` | `op item list --vault=<vault> --format=json` — names of items in the vault. |
|
|
126
|
+
| `environments()` | `op environment list --format=json` — names of 1P Environments. |
|
|
127
|
+
| `readEnvironment(id)` | `op environment read <id>` — parses `KEY=VALUE` lines into a record. |
|
|
128
|
+
|
|
129
|
+
Plugin-level exports (not capability methods, per the auth-bootstrap
|
|
130
|
+
convention):
|
|
131
|
+
|
|
132
|
+
| Export | Purpose |
|
|
133
|
+
| ------------- | ----------------------------------------------------------------------------------------------------------- |
|
|
134
|
+
| `verifyToken` | `op whoami --format=json` — token arg ignored (see [Auth](#auth)). Returns `ok: true` when signed in. |
|
|
135
|
+
| `AUTH_HINT` | Explains the `op signin` / `OP_SERVICE_ACCOUNT_TOKEN` model to operators — 1P has no bearer token to store. |
|
|
136
|
+
|
|
137
|
+
### Not implemented (deliberately)
|
|
138
|
+
|
|
139
|
+
`ensureProject` / `ensureEnvironment` — 1Password's data model
|
|
140
|
+
doesn't have projects with sub-configs the way Doppler / Infisical
|
|
141
|
+
do. The vault + item hierarchy is created via the 1P UI or `op item
|
|
142
|
+
create`, not via `holocron setup`. The methods are simply omitted;
|
|
143
|
+
`runSetup` skips them cleanly (see the [`Vault`
|
|
144
|
+
interface](../cli/src/capabilities/index.ts)).
|
|
73
145
|
|
|
74
146
|
## Status
|
|
75
147
|
|
|
76
|
-
**`v2.0.0-alpha.
|
|
77
|
-
|
|
78
|
-
|
|
148
|
+
**`v2.0.0-alpha.1`** (or later — check [releases](https://github.com/theholocron/holocron/releases)).
|
|
149
|
+
Published on npm under the `alpha` dist-tag. APIs may still shift
|
|
150
|
+
before stable v2.0.0.
|
|
79
151
|
|
|
80
152
|
Implementation note: the stdio shape (`['inherit', 'pipe', 'pipe']`)
|
|
81
153
|
is critical — it gives `op` a TTY signal so it can fire the desktop
|
package/dist/index.d.mts
CHANGED
|
@@ -60,6 +60,22 @@ declare class OpVault implements Vault {
|
|
|
60
60
|
readEnvironment(environmentId: string): Promise<Record<string, string>>;
|
|
61
61
|
}
|
|
62
62
|
//#endregion
|
|
63
|
+
//#region src/verify-token.d.ts
|
|
64
|
+
interface VerifyTokenSuccess {
|
|
65
|
+
ok: true;
|
|
66
|
+
subject: string;
|
|
67
|
+
}
|
|
68
|
+
interface VerifyTokenFailure {
|
|
69
|
+
ok: false;
|
|
70
|
+
message: string;
|
|
71
|
+
}
|
|
72
|
+
type VerifyTokenResult = VerifyTokenSuccess | VerifyTokenFailure;
|
|
73
|
+
interface VerifyTokenOptions {
|
|
74
|
+
spawn?: typeof spawnSync;
|
|
75
|
+
binary?: string;
|
|
76
|
+
}
|
|
77
|
+
declare function verifyToken(_token: string, opts?: VerifyTokenOptions): Promise<VerifyTokenResult>;
|
|
78
|
+
//#endregion
|
|
63
79
|
//#region src/index.d.ts
|
|
64
80
|
interface OpPluginOptions extends VerifyInput {
|
|
65
81
|
/** 1P vault name items live in. Required. */
|
|
@@ -79,5 +95,11 @@ declare function createPlugin(options: OpPluginOptions): {
|
|
|
79
95
|
vault: () => Vault;
|
|
80
96
|
};
|
|
81
97
|
};
|
|
98
|
+
/**
|
|
99
|
+
* One-line hint printed by `holocron auth set 1password` — 1P doesn't
|
|
100
|
+
* store a token in the holocron keyring; the `op` CLI manages its own
|
|
101
|
+
* auth. Directs the operator to the two paths that actually work.
|
|
102
|
+
*/
|
|
103
|
+
declare const AUTH_HINT: string;
|
|
82
104
|
//#endregion
|
|
83
|
-
export { AuthError, OpPluginOptions, OpShell, OpVault, PluginContext, VerifyInput, createContext, createPlugin, vault, verifyOpInstalled };
|
|
105
|
+
export { AUTH_HINT, AuthError, OpPluginOptions, OpShell, OpVault, PluginContext, VerifyInput, type VerifyTokenFailure, type VerifyTokenResult, type VerifyTokenSuccess, createContext, createPlugin, vault, verifyOpInstalled, verifyToken };
|
package/dist/index.mjs
CHANGED
|
@@ -211,6 +211,53 @@ var OpShell = class {
|
|
|
211
211
|
}
|
|
212
212
|
};
|
|
213
213
|
//#endregion
|
|
214
|
+
//#region src/verify-token.ts
|
|
215
|
+
/**
|
|
216
|
+
* `verifyToken` — plugin-level export used by `holocron auth check`.
|
|
217
|
+
*
|
|
218
|
+
* 1Password doesn't use a bearer token like the REST-transport plugins
|
|
219
|
+
* do — the `op` CLI manages its own auth via desktop-app biometric on
|
|
220
|
+
* laptops and `OP_SERVICE_ACCOUNT_TOKEN` env var in CI. So the token
|
|
221
|
+
* argument is intentionally IGNORED here. What we actually check is:
|
|
222
|
+
* is `op` installed AND signed in (i.e., can it answer `whoami`).
|
|
223
|
+
*
|
|
224
|
+
* If someone tries `holocron auth set 1password <token>`, the token
|
|
225
|
+
* will be stored in the keyring but never read by this plugin — the
|
|
226
|
+
* `AUTH_HINT` below explains that up front.
|
|
227
|
+
*/
|
|
228
|
+
async function verifyToken(_token, opts = {}) {
|
|
229
|
+
const spawnImpl = opts.spawn ?? spawnSync;
|
|
230
|
+
const binary = opts.binary ?? "op";
|
|
231
|
+
const result = spawnImpl(binary, ["whoami", "--format=json"], {
|
|
232
|
+
encoding: "utf-8",
|
|
233
|
+
stdio: [
|
|
234
|
+
"ignore",
|
|
235
|
+
"pipe",
|
|
236
|
+
"pipe"
|
|
237
|
+
]
|
|
238
|
+
});
|
|
239
|
+
if (result.error) return {
|
|
240
|
+
ok: false,
|
|
241
|
+
message: `1Password CLI (\`${binary}\`) not found on PATH. Install via \`brew install 1password-cli\`.`
|
|
242
|
+
};
|
|
243
|
+
if (result.status !== 0) return {
|
|
244
|
+
ok: false,
|
|
245
|
+
message: `\`${binary} whoami\` failed: ${(result.stderr ?? "").trim() || `exit ${result.status ?? "?"}`}`
|
|
246
|
+
};
|
|
247
|
+
try {
|
|
248
|
+
const parsed = JSON.parse(result.stdout ?? "{}");
|
|
249
|
+
return {
|
|
250
|
+
ok: true,
|
|
251
|
+
subject: `op: ${parsed.email ?? parsed.url ?? parsed.user_uuid ?? "signed in"}`
|
|
252
|
+
};
|
|
253
|
+
} catch {
|
|
254
|
+
return {
|
|
255
|
+
ok: true,
|
|
256
|
+
subject: "op: signed in"
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
//#endregion
|
|
214
261
|
//#region src/index.ts
|
|
215
262
|
function createContext(options) {
|
|
216
263
|
if (!options.vault) throw new Error("@theholocron/holocron-plugin-1password requires `vault` in options");
|
|
@@ -237,5 +284,11 @@ function createPlugin(options) {
|
|
|
237
284
|
capabilities: { vault: () => vault(ctx) }
|
|
238
285
|
};
|
|
239
286
|
}
|
|
287
|
+
/**
|
|
288
|
+
* One-line hint printed by `holocron auth set 1password` — 1P doesn't
|
|
289
|
+
* store a token in the holocron keyring; the `op` CLI manages its own
|
|
290
|
+
* auth. Directs the operator to the two paths that actually work.
|
|
291
|
+
*/
|
|
292
|
+
const AUTH_HINT = "1Password uses the `op` CLI for auth — no bearer token to store. On laptop: `op signin` (or the desktop app's biometric flow). In CI: set `OP_SERVICE_ACCOUNT_TOKEN` in the workflow env.";
|
|
240
293
|
//#endregion
|
|
241
|
-
export { AuthError, OpShell, OpVault, createContext, createPlugin, vault, verifyOpInstalled };
|
|
294
|
+
export { AUTH_HINT, AuthError, OpShell, OpVault, createContext, createPlugin, vault, verifyOpInstalled, verifyToken };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theholocron/holocron-plugin-1password",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.5",
|
|
4
4
|
"description": "Holocron plugin for 1Password. Implements the vault capability via shell-out to the `op` CLI (https://developer.1password.com/docs/cli).",
|
|
5
5
|
"homepage": "https://github.com/theholocron/holocron/tree/main/packages/holocron-plugin-1password#readme",
|
|
6
6
|
"bugs": "https://github.com/theholocron/holocron/issues",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
}
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {
|
|
24
|
-
"@theholocron/cli": "2.0.0-alpha.
|
|
24
|
+
"@theholocron/cli": "2.0.0-alpha.5"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@theholocron/tsconfig": "^4.1.0",
|
|
@@ -32,7 +32,8 @@
|
|
|
32
32
|
"typescript": "^5.9.3",
|
|
33
33
|
"vitest": "^3.2.6",
|
|
34
34
|
"tsdown": "^0.22.3",
|
|
35
|
-
"
|
|
35
|
+
"tsx": "^4.22.4",
|
|
36
|
+
"@theholocron/cli": "2.0.0-alpha.5"
|
|
36
37
|
},
|
|
37
38
|
"publishConfig": {
|
|
38
39
|
"access": "public"
|
|
@@ -47,7 +48,8 @@
|
|
|
47
48
|
"typecheck": "tsc --noEmit",
|
|
48
49
|
"test": "vitest run",
|
|
49
50
|
"test:watch": "vitest",
|
|
50
|
-
"test:coverage": "vitest run --coverage"
|
|
51
|
+
"test:coverage": "vitest run --coverage",
|
|
52
|
+
"validate": "tsx scripts/validate.mjs"
|
|
51
53
|
},
|
|
52
54
|
"types": "./dist/index.d.mts"
|
|
53
55
|
}
|