Skip to content

Commit 968dfd5

Browse files
guo-yuclaude
andcommitted
fix: return error details for sync failures instead of silently skipping
- Report read failures with descriptive error messages - Return failed items as { name, error } objects instead of bare strings - Bump shipkey to 0.3.8 (already tagged) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent db4ea76 commit 968dfd5

1 file changed

Lines changed: 50 additions & 48 deletions

File tree

src/commands/setup.ts

Lines changed: 50 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -333,69 +333,68 @@ async function handleSync(
333333
}
334334

335335
const refMap = buildSecretRefMap(config, backend, env);
336-
const results: { destination: string; synced: string[]; failed: string[] }[] = [];
336+
const results: { destination: string; synced: string[]; failed: { name: string; error: string }[] }[] = [];
337337

338338
for (const [destination, secretRefs] of Object.entries(targetConfig)) {
339339
const secrets: { name: string; value: string }[] = [];
340+
const readFailed: { name: string; error: string }[] = [];
341+
342+
const readSecret = async (envKey: string) => {
343+
const inlineRef = refMap.get(envKey);
344+
if (inlineRef && "readRaw" in backend) {
345+
try {
346+
const value = await (backend as any).readRaw(inlineRef);
347+
secrets.push({ name: envKey, value });
348+
return;
349+
} catch {
350+
// fall through to standard read
351+
}
352+
}
353+
try {
354+
const providerEntry = Object.entries(config.providers || {}).find(
355+
([, p]) => p.fields.includes(envKey)
356+
);
357+
if (!providerEntry) {
358+
readFailed.push({ name: envKey, error: "No provider found for this key" });
359+
return;
360+
}
361+
const value = await backend.read({
362+
vault: config.vault,
363+
provider: providerEntry[0],
364+
project: config.project,
365+
env,
366+
field: envKey,
367+
});
368+
secrets.push({ name: envKey, value });
369+
} catch (err) {
370+
readFailed.push({ name: envKey, error: "Key not found in password manager — store it first" });
371+
}
372+
};
340373

341374
if (Array.isArray(secretRefs)) {
342375
for (const envKey of secretRefs) {
343-
const inlineRef = refMap.get(envKey);
344-
if (inlineRef && "readRaw" in backend) {
345-
try {
346-
const value = await (backend as any).readRaw(inlineRef);
347-
secrets.push({ name: envKey, value });
348-
} catch {
349-
// skip unresolvable
350-
}
351-
} else {
352-
// Try reading via the standard read() path
353-
try {
354-
// Build a SecretRef from config
355-
const providerEntry = Object.entries(config.providers || {}).find(
356-
([, p]) => p.fields.includes(envKey)
357-
);
358-
if (!providerEntry) continue;
359-
const value = await backend.read({
360-
vault: config.vault,
361-
provider: providerEntry[0],
362-
project: config.project,
363-
env,
364-
field: envKey,
365-
});
366-
secrets.push({ name: envKey, value });
367-
} catch {
368-
// skip unresolvable
369-
}
370-
}
376+
await readSecret(envKey);
371377
}
372378
} else {
373379
for (const [name, ref] of Object.entries(secretRefs)) {
374-
try {
375-
if (ref.startsWith("op://") && "readRaw" in backend) {
380+
if (typeof ref === "string" && ref.startsWith("op://") && "readRaw" in backend) {
381+
try {
376382
const value = await (backend as any).readRaw(ref);
377383
secrets.push({ name, value });
378-
} else {
379-
// Try resolving through config
380-
const providerEntry = Object.entries(config.providers || {}).find(
381-
([, p]) => p.fields.includes(name)
382-
);
383-
if (!providerEntry) continue;
384-
const value = await backend.read({
385-
vault: config.vault,
386-
provider: providerEntry[0],
387-
project: config.project,
388-
env,
389-
field: name,
390-
});
391-
secrets.push({ name, value });
384+
} catch {
385+
readFailed.push({ name, error: "Key not found in password manager — store it first" });
392386
}
393-
} catch {
394-
// skip unresolvable
387+
} else {
388+
await readSecret(name);
395389
}
396390
}
397391
}
398392

393+
if (secrets.length === 0 && readFailed.length > 0) {
394+
results.push({ destination, synced: [], failed: readFailed });
395+
continue;
396+
}
397+
399398
if (secrets.length === 0) {
400399
results.push({ destination, synced: [], failed: [] });
401400
continue;
@@ -405,7 +404,10 @@ async function handleSync(
405404
results.push({
406405
destination,
407406
synced: result.success,
408-
failed: result.failed.map((f) => f.name),
407+
failed: [
408+
...readFailed,
409+
...result.failed.map((f) => ({ name: f.name, error: f.error })),
410+
],
409411
});
410412
}
411413

0 commit comments

Comments
 (0)