@backstage/integration
Version:
Helpers for managing integrations towards external systems
161 lines (157 loc) • 5.98 kB
JavaScript
;
var helpers = require('../helpers.cjs.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 (!helpers.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;
}
exports.readAzureIntegrationConfig = readAzureIntegrationConfig;
exports.readAzureIntegrationConfigs = readAzureIntegrationConfigs;
//# sourceMappingURL=config.cjs.js.map