diff --git a/src/secrets/resolve.test.ts b/src/secrets/resolve.test.ts index 902176a34b7b..4ce1411e96f9 100644 --- a/src/secrets/resolve.test.ts +++ b/src/secrets/resolve.test.ts @@ -45,6 +45,7 @@ describe("secret ref resolver", () => { let execPlainScriptPath = ""; let execProtocolV2ScriptPath = ""; let execMissingIdScriptPath = ""; + let execInheritedErrorScriptPath = ""; let execInvalidJsonScriptPath = ""; let execFastExitScriptPath = ""; @@ -152,6 +153,16 @@ describe("secret ref resolver", () => { 0o700, ); + execInheritedErrorScriptPath = path.join(sharedExecDir, "resolver-inherited-error.sh"); + await writeSecureFile( + execInheritedErrorScriptPath, + [ + "#!/bin/sh", + 'printf \'{"protocolVersion":1,"values":{"toString":"resolved"},"errors":{}}\'', + ].join("\n"), + 0o700, + ); + execInvalidJsonScriptPath = path.join(sharedExecDir, "resolver-invalid-json.sh"); await writeSecureFile( execInvalidJsonScriptPath, @@ -400,6 +411,40 @@ describe("secret ref resolver", () => { ); }); + itPosix("rejects exec refs when missing response id is inherited", async () => { + await expect( + resolveSecretRefValue( + { source: "exec", provider: "execmain", id: "toString" }, + { + config: { + secrets: { + providers: { + execmain: createExecProviderConfig(execMissingIdScriptPath), + }, + }, + }, + }, + ), + ).rejects.toThrow('response missing id "toString"'); + }); + + itPosix("ignores inherited exec response errors", async () => { + await expect( + resolveSecretRefValue( + { source: "exec", provider: "execmain", id: "toString" }, + { + config: { + secrets: { + providers: { + execmain: createExecProviderConfig(execInheritedErrorScriptPath), + }, + }, + }, + }, + ), + ).resolves.toBe("resolved"); + }); + itPosix("rejects exec refs with invalid JSON when jsonOnly is true", async () => { await expect(resolveExecSecret(execInvalidJsonScriptPath, { jsonOnly: true })).rejects.toThrow( "returned invalid JSON", diff --git a/src/secrets/resolve.ts b/src/secrets/resolve.ts index 8e963656169f..2200ec953eb6 100644 --- a/src/secrets/resolve.ts +++ b/src/secrets/resolve.ts @@ -664,7 +664,7 @@ function parseExecValues(params: { const responseErrors = isRecord(parsed.errors) ? parsed.errors : null; const out: Record = {}; for (const id of params.ids) { - if (responseErrors && id in responseErrors) { + if (responseErrors && Object.hasOwn(responseErrors, id)) { const entry = responseErrors[id]; if (isRecord(entry) && typeof entry.message === "string" && entry.message.trim()) { throw refResolutionError({ @@ -681,7 +681,7 @@ function parseExecValues(params: { message: `Exec provider "${params.providerName}" failed for id "${id}".`, }); } - if (!(id in responseValues)) { + if (!Object.hasOwn(responseValues, id)) { throw refResolutionError({ source: "exec", provider: params.providerName,