UNPKG

@backstage/integration

Version:

Helpers for managing integrations towards external systems

158 lines (155 loc) • 5.9 kB
import { isValidHost } from '../helpers.esm.js'; const AZURE_HOST = "dev.azure.com"; const AzureDevOpsCredentialFields = [ "clientId", "clientSecret", "managedIdentityClientId", "tenantId", "personalAccessToken" ]; const AzureDevopsCredentialFieldMap = /* @__PURE__ */ new Map([ ["ClientSecret", ["clientId", "clientSecret", "tenantId"]], ["ManagedIdentity", ["clientId"]], [ "ManagedIdentityClientAssertion", ["clientId", "managedIdentityClientId", "tenantId"] ], ["PersonalAccessToken", ["personalAccessToken"]] ]); function asAzureDevOpsCredential(credential) { for (const entry of AzureDevopsCredentialFieldMap.entries()) { const [kind, requiredFields] = entry; const forbiddenFields = AzureDevOpsCredentialFields.filter( (field) => !requiredFields.includes(field) ); if (requiredFields.every((field) => credential[field] !== void 0) && forbiddenFields.every((field) => credential[field] === void 0)) { return { kind, organizations: credential.organizations, ...requiredFields.reduce((acc, field) => { acc[field] = credential[field]; return acc; }, {}) }; } } throw new Error("is not a valid credential"); } function readAzureIntegrationConfig(config) { const host = config.getOptionalString("host") ?? AZURE_HOST; let credentialConfigs = config.getOptionalConfigArray("credentials")?.map((credential) => { const result = { organizations: credential.getOptionalStringArray("organizations"), personalAccessToken: credential.getOptionalString("personalAccessToken")?.trim(), tenantId: credential.getOptionalString("tenantId")?.trim(), clientId: credential.getOptionalString("clientId")?.trim(), clientSecret: credential.getOptionalString("clientSecret")?.trim(), managedIdentityClientId: credential.getOptionalString("managedIdentityClientId")?.trim() }; return result; }); const token = config.getOptionalString("token")?.trim(); if (config.getOptional("credential") !== void 0 && config.getOptional("credentials") !== void 0) { throw new Error( `Invalid Azure integration config, 'credential' and 'credentials' cannot be used together. Use 'credentials' instead.` ); } if (config.getOptional("token") !== void 0 && config.getOptional("credentials") !== void 0) { throw new Error( `Invalid Azure integration config, 'token' and 'credentials' cannot be used together. Use 'credentials' instead.` ); } if (token !== void 0) { const mapped = [{ personalAccessToken: token }]; credentialConfigs = credentialConfigs?.concat(mapped) ?? mapped; } if (config.getOptional("credential") !== void 0) { const mapped = [ { organizations: config.getOptionalStringArray( "credential.organizations" ), token: config.getOptionalString("credential.token")?.trim(), tenantId: config.getOptionalString("credential.tenantId"), clientId: config.getOptionalString("credential.clientId"), clientSecret: config.getOptionalString("credential.clientSecret")?.trim() } ]; credentialConfigs = credentialConfigs?.concat(mapped) ?? mapped; } if (!isValidHost(host)) { throw new Error( `Invalid Azure integration config, '${host}' is not a valid host` ); } let credentials = void 0; if (credentialConfigs !== void 0) { const errors = credentialConfigs?.reduce((acc, credentialConfig, index) => { let error = void 0; try { asAzureDevOpsCredential(credentialConfig); } catch (e) { error = e.message; } if (error !== void 0) { acc.push(`credential at position ${index + 1} ${error}`); } return acc; }, Array.of()).concat( Object.entries( credentialConfigs.filter( (credential) => credential.organizations !== void 0 && credential.organizations.length > 0 ).reduce((acc, credential, index) => { credential.organizations?.forEach((organization) => { if (!acc[organization]) { acc[organization] = []; } acc[organization].push(index + 1); }); return acc; }, {}) ).filter(([_, indexes]) => indexes.length > 1).reduce((acc, [org, indexes]) => { acc.push( `organization ${org} is specified multiple times in credentials at positions ${indexes.slice(0, indexes.length - 1).join(", ")} and ${indexes[indexes.length - 1]}` ); return acc; }, Array.of()) ); if (errors?.length > 0) { throw new Error( `Invalid Azure integration config for ${host}: ${errors.join("; ")}` ); } credentials = credentialConfigs.map( (credentialConfig) => asAzureDevOpsCredential(credentialConfig) ); if (credentials.some( (credential) => credential.kind !== "PersonalAccessToken" ) && host !== AZURE_HOST) { throw new Error( `Invalid Azure integration config for ${host}, only personal access tokens can be used with hosts other than ${AZURE_HOST}` ); } if (credentials.filter( (credential) => credential.organizations === void 0 || credential.organizations.length === 0 ).length > 1) { throw new Error( `Invalid Azure integration config for ${host}, you cannot specify multiple credentials without organizations` ); } } return { host, credentials, commitSigningKey: config.getOptionalString("commitSigningKey") }; } function readAzureIntegrationConfigs(configs) { const result = configs.map(readAzureIntegrationConfig); if (!result.some((c) => c.host === AZURE_HOST)) { result.push({ host: AZURE_HOST }); } return result; } export { readAzureIntegrationConfig, readAzureIntegrationConfigs }; //# sourceMappingURL=config.esm.js.map