create-op-node 0.10.0 → 0.10.1

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/dist/cli.js CHANGED
@@ -289,7 +289,7 @@ async function saveSecret(coords, value) {
289
289
  return {
290
290
  written: false,
291
291
  updated,
292
- reason: `security add-generic-password failed (${res.exitCode ?? "signal"}): ${res.stderr || res.stdout}`
292
+ reason: `security add-generic-password failed (${res.exitCode ?? "signal"}): ${res.stderr || res.stdout}${formatKeychainHint(res.exitCode)}`
293
293
  };
294
294
  }
295
295
  return { written: true, updated };
@@ -309,6 +309,47 @@ async function readSecret(coords) {
309
309
  const value = res.stdout.trim();
310
310
  return value.length > 0 ? value : null;
311
311
  }
312
+ var ERR_SEC_INTERACTION_NOT_ALLOWED = 36;
313
+ function formatKeychainHint(exitCode) {
314
+ if (exitCode === ERR_SEC_INTERACTION_NOT_ALLOWED) {
315
+ return `
316
+ Hint: the login keychain is locked (SSH sessions don't auto-unlock it).
317
+ Run \`security unlock-keychain ~/Library/Keychains/login.keychain-db\` and re-run bootstrap.`;
318
+ }
319
+ return "";
320
+ }
321
+ async function isKeychainLocked() {
322
+ const res = await safeExeca("security", [
323
+ "find-generic-password",
324
+ "-s",
325
+ `${SERVICE_PREFIX}.__op_node_lock_probe__`,
326
+ "-a",
327
+ "__nothing_here__"
328
+ ]);
329
+ if (res === null) return false;
330
+ return res.exitCode === ERR_SEC_INTERACTION_NOT_ALLOWED;
331
+ }
332
+ async function unlockKeychain(password3) {
333
+ const res = await safeExeca("security", [
334
+ "unlock-keychain",
335
+ "-p",
336
+ password3,
337
+ // Default keychain path — same as the operator's GUI login keychain
338
+ // on a stock macOS install. Lets us avoid a homedir lookup here.
339
+ `${process.env["HOME"] ?? ""}/Library/Keychains/login.keychain-db`
340
+ ]);
341
+ if (res === null) return { ok: false, reason: "`security` CLI not on PATH" };
342
+ if (res.exitCode !== 0) {
343
+ return {
344
+ ok: false,
345
+ reason: `security unlock-keychain failed (${res.exitCode ?? "signal"}): ${res.stderr || res.stdout}`
346
+ };
347
+ }
348
+ return { ok: true };
349
+ }
350
+ function isSshSession(env = process.env) {
351
+ return Boolean(env["SSH_CONNECTION"] ?? env["SSH_TTY"]);
352
+ }
312
353
  function unwrap(value) {
313
354
  if (p3.isCancel(value)) {
314
355
  p3.cancel("Cancelled.");
@@ -2093,6 +2134,31 @@ var bootstrapCommand = new Command("bootstrap").description(
2093
2134
  );
2094
2135
  process.exit(1);
2095
2136
  }
2137
+ if (isSshSession() && await isKeychainLocked()) {
2138
+ p3.note(
2139
+ [
2140
+ "SSH session detected with a locked login keychain.",
2141
+ "macOS keychain operations require an unlocked keychain \u2014 your",
2142
+ "login password will be used once to unlock it for this session.",
2143
+ "The keychain remains unlocked until the session ends or it",
2144
+ "idle-locks. To skip and unlock manually, press Ctrl+C and run",
2145
+ "`security unlock-keychain` yourself."
2146
+ ].join("\n"),
2147
+ "Keychain unlock required"
2148
+ );
2149
+ const pw = unwrap(
2150
+ await p3.password({
2151
+ message: "macOS login password (for `security unlock-keychain`):",
2152
+ validate: (v) => v && v.length > 0 ? void 0 : "password required"
2153
+ })
2154
+ );
2155
+ const unlock = await unlockKeychain(pw);
2156
+ if (!unlock.ok) {
2157
+ p3.cancel(unlock.reason ?? "security unlock-keychain failed.");
2158
+ process.exit(1);
2159
+ }
2160
+ p3.note(`${pc2.green("\u2713")} Keychain unlocked for this session.`, "Keychain");
2161
+ }
2096
2162
  const pgsodiumKey = await loadSecret({
2097
2163
  region,
2098
2164
  account: "pgsodium-root-key",
@@ -4334,7 +4400,7 @@ async function looksLikeRegionsRepo(dir) {
4334
4400
  }
4335
4401
 
4336
4402
  // src/cli.ts
4337
- var VERSION = "0.10.0";
4403
+ var VERSION = "0.10.1";
4338
4404
  var program = new Command();
4339
4405
  program.name("create-op-node").description(
4340
4406
  "Interactive bootstrap for an Opus Populi federation node.\nCloudflare infrastructure \u2192 Mac Studio \u2192 live public API."