diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f369c4a..4b5c60f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,10 @@ and this project adheres to # Unreleased +- runtime: treat a blank `CA_CERTIFICATE` / `DISABLE_TLS_VERIFICATION` as unset + when the integration did not declare the field, so an empty value written by + the platform cannot abort the run + # 17.6.0 - 2026-08-18 - runtime: always expose `caCertificate` and `disableTlsVerification` from the diff --git a/packages/integration-sdk-runtime/src/execution/__tests__/config.test.ts b/packages/integration-sdk-runtime/src/execution/__tests__/config.test.ts index ce914ca7..0327c423 100644 --- a/packages/integration-sdk-runtime/src/execution/__tests__/config.test.ts +++ b/packages/integration-sdk-runtime/src/execution/__tests__/config.test.ts @@ -155,6 +155,65 @@ test('respects integration-declared caCertificate / disableTlsVerification over expect(config).toEqual({ caCertificate: 'cert-value' }); }); +test('a declared caCertificate replaces the implicit one, so it is no longer optional', () => { + // The implicit definition is optional, so an unset CA_CERTIFICATE would + // resolve to undefined. Declaring the field without `optional` has to win, + // which is only observable when the environment variable is missing. + const instanceConfigFields: IntegrationInstanceConfigFieldMap< + Record<'caCertificate', IntegrationInstanceConfigField> + > = { + caCertificate: { + type: 'string', + }, + }; + + expect(() => + loadConfigFromEnvironmentVariables(instanceConfigFields), + ).toThrow( + 'Expected environment variable "CA_CERTIFICATE" for config field "caCertificate" to be set.', + ); +}); + +test('treats a blank implicit agent-configuration variable as unset', () => { + // The platform writes these for every integration, none of which declared + // them. A blank value must not fail the boolean conversion and abort the run. + process.env.CA_CERTIFICATE = ''; + process.env.DISABLE_TLS_VERIFICATION = ''; + + const config = loadConfigFromEnvironmentVariables({}); + + expect(config).toEqual({}); +}); + +test('treats a whitespace-only implicit agent-configuration variable as unset', () => { + process.env.CA_CERTIFICATE = ' '; + process.env.DISABLE_TLS_VERIFICATION = ' '; + + const config = loadConfigFromEnvironmentVariables({}); + + expect(config).toEqual({}); +}); + +test('still rejects a blank value for an agent-configuration field the integration declared', () => { + // Once the integration declares the field it owns it, and a value the + // integration cannot parse stays an error rather than being ignored. + process.env.DISABLE_TLS_VERIFICATION = ''; + const instanceConfigFields: IntegrationInstanceConfigFieldMap< + Record<'disableTlsVerification', IntegrationInstanceConfigField> + > = { + disableTlsVerification: { + type: 'boolean', + optional: true, + }, + }; + + expect(() => + loadConfigFromEnvironmentVariables(instanceConfigFields), + ).toThrow( + 'Expected boolean value for field "disableTlsVerification" but received "".', + ); +}); + test('loads environment variables from .env', () => { vol.fromJSON({ [path.join(process.cwd(), '.env')]: 'MY_ENV_VAR=mochi', diff --git a/packages/integration-sdk-runtime/src/execution/config.ts b/packages/integration-sdk-runtime/src/execution/config.ts index 6636e16b..c7800393 100644 --- a/packages/integration-sdk-runtime/src/execution/config.ts +++ b/packages/integration-sdk-runtime/src/execution/config.ts @@ -48,7 +48,19 @@ export function loadConfigFromEnvironmentVariables< const environmentVariableValue = process.env[environmentVariableName]; - if (environmentVariableValue === undefined) { + // An implicit field is present only because the platform may have written + // it into the environment; the integration never asked for it. A blank + // value there means "not configured", not "malformed" — without this, a + // stray `DISABLE_TLS_VERIFICATION=` would fail the boolean conversion and + // abort the run of every integration rather than only the ones that + // declared the field. + const isUndeclaredImplicitField = + field in IMPLICIT_AGENT_CONFIG_FIELDS && !(field in configMap); + + if ( + environmentVariableValue === undefined || + (isUndeclaredImplicitField && environmentVariableValue.trim() === '') + ) { if (config.optional) { return [field, undefined]; } else {