mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
feat(secret-sync): Add Azure Devops PR suggestions
This commit is contained in:
@@ -225,7 +225,6 @@ export const getAppConnectionMethodName = (method: TAppConnection["method"]) =>
|
|||||||
case TerraformCloudConnectionMethod.ApiToken:
|
case TerraformCloudConnectionMethod.ApiToken:
|
||||||
case VercelConnectionMethod.ApiToken:
|
case VercelConnectionMethod.ApiToken:
|
||||||
case OnePassConnectionMethod.ApiToken:
|
case OnePassConnectionMethod.ApiToken:
|
||||||
case AzureDevOpsConnectionMethod.ApiToken:
|
|
||||||
return "API Token";
|
return "API Token";
|
||||||
case PostgresConnectionMethod.UsernameAndPassword:
|
case PostgresConnectionMethod.UsernameAndPassword:
|
||||||
case MsSqlConnectionMethod.UsernameAndPassword:
|
case MsSqlConnectionMethod.UsernameAndPassword:
|
||||||
@@ -234,6 +233,7 @@ export const getAppConnectionMethodName = (method: TAppConnection["method"]) =>
|
|||||||
case WindmillConnectionMethod.AccessToken:
|
case WindmillConnectionMethod.AccessToken:
|
||||||
case HCVaultConnectionMethod.AccessToken:
|
case HCVaultConnectionMethod.AccessToken:
|
||||||
case TeamCityConnectionMethod.AccessToken:
|
case TeamCityConnectionMethod.AccessToken:
|
||||||
|
case AzureDevOpsConnectionMethod.AccessToken:
|
||||||
return "Access Token";
|
return "Access Token";
|
||||||
case Auth0ConnectionMethod.ClientCredentials:
|
case Auth0ConnectionMethod.ClientCredentials:
|
||||||
return "Client Credentials";
|
return "Client Credentials";
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export enum AzureDevOpsConnectionMethod {
|
export enum AzureDevOpsConnectionMethod {
|
||||||
OAuth = "oauth",
|
OAuth = "oauth",
|
||||||
ApiToken = "api-token"
|
AccessToken = "access-token"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,13 +30,13 @@ export const getAzureDevopsConnectionListItem = () => {
|
|||||||
app: AppConnection.AzureDevOps as const,
|
app: AppConnection.AzureDevOps as const,
|
||||||
methods: Object.values(AzureDevOpsConnectionMethod) as [
|
methods: Object.values(AzureDevOpsConnectionMethod) as [
|
||||||
AzureDevOpsConnectionMethod.OAuth,
|
AzureDevOpsConnectionMethod.OAuth,
|
||||||
AzureDevOpsConnectionMethod.ApiToken
|
AzureDevOpsConnectionMethod.AccessToken
|
||||||
],
|
],
|
||||||
oauthClientId: INF_APP_CONNECTION_AZURE_CLIENT_ID
|
oauthClientId: INF_APP_CONNECTION_AZURE_CLIENT_ID
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getAzureDevopsConnectionAccessToken = async (
|
export const getAzureDevopsConnection = async (
|
||||||
connectionId: string,
|
connectionId: string,
|
||||||
appConnectionDAL: Pick<TAppConnectionDALFactory, "findById" | "updateById">,
|
appConnectionDAL: Pick<TAppConnectionDALFactory, "findById" | "updateById">,
|
||||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">
|
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">
|
||||||
@@ -104,12 +104,12 @@ export const getAzureDevopsConnectionAccessToken = async (
|
|||||||
|
|
||||||
return data.access_token;
|
return data.access_token;
|
||||||
|
|
||||||
case AzureDevOpsConnectionMethod.ApiToken:
|
case AzureDevOpsConnectionMethod.AccessToken:
|
||||||
if (!("apiKey" in credentials)) {
|
if (!("accessToken" in credentials)) {
|
||||||
throw new BadRequestError({ message: "Invalid API token credentials" });
|
throw new BadRequestError({ message: "Invalid API token credentials" });
|
||||||
}
|
}
|
||||||
// For API token, return the basic auth token directly
|
// For API token, return the basic auth token directly
|
||||||
return credentials.apiKey as string;
|
return credentials.accessToken;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new BadRequestError({ message: `Unsupported connection method` });
|
throw new BadRequestError({ message: `Unsupported connection method` });
|
||||||
@@ -188,17 +188,17 @@ export const validateAzureDevOpsConnectionCredentials = async (config: TAzureDev
|
|||||||
expiresAt: Date.now() + tokenResp.data.expires_in * 1000
|
expiresAt: Date.now() + tokenResp.data.expires_in * 1000
|
||||||
};
|
};
|
||||||
|
|
||||||
case AzureDevOpsConnectionMethod.ApiToken:
|
case AzureDevOpsConnectionMethod.AccessToken:
|
||||||
const apiTokenCredentials = inputCredentials as { apiKey: string; orgName?: string };
|
const apiTokenCredentials = inputCredentials as { accessToken: string; orgName?: string };
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (apiTokenCredentials.orgName) {
|
if (apiTokenCredentials.orgName) {
|
||||||
// Validate against specific organization
|
// Validate against specific organization
|
||||||
const response = await request.get(
|
const response = await request.get(
|
||||||
`${IntegrationUrls.AZURE_DEVOPS_API_URL}/${apiTokenCredentials.orgName}/_apis/projects?api-version=7.2-preview.2&$top=1`,
|
`${IntegrationUrls.AZURE_DEVOPS_API_URL}/${encodeURIComponent(apiTokenCredentials.orgName)}/_apis/projects?api-version=7.2-preview.2&$top=1`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Basic ${Buffer.from(`:${apiTokenCredentials.apiKey}`).toString("base64")}`
|
Authorization: `Basic ${Buffer.from(`:${apiTokenCredentials.accessToken}`).toString("base64")}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -210,7 +210,7 @@ export const validateAzureDevOpsConnectionCredentials = async (config: TAzureDev
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
apiKey: apiTokenCredentials.apiKey,
|
accessToken: apiTokenCredentials.accessToken,
|
||||||
orgName: apiTokenCredentials.orgName
|
orgName: apiTokenCredentials.orgName
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -219,7 +219,7 @@ export const validateAzureDevOpsConnectionCredentials = async (config: TAzureDev
|
|||||||
`https://app.vssps.visualstudio.com/_apis/profile/profiles/me?api-version=7.1`,
|
`https://app.vssps.visualstudio.com/_apis/profile/profiles/me?api-version=7.1`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Basic ${Buffer.from(`:${apiTokenCredentials.apiKey}`).toString("base64")}`
|
Authorization: `Basic ${Buffer.from(`:${apiTokenCredentials.accessToken}`).toString("base64")}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -230,7 +230,7 @@ export const validateAzureDevOpsConnectionCredentials = async (config: TAzureDev
|
|||||||
value: Array<{ accountId: string; accountName: string; accountUri: string }>;
|
value: Array<{ accountId: string; accountName: string; accountUri: string }>;
|
||||||
}>(`https://app.vssps.visualstudio.com/_apis/accounts?api-version=7.1`, {
|
}>(`https://app.vssps.visualstudio.com/_apis/accounts?api-version=7.1`, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Basic ${Buffer.from(`:${apiTokenCredentials.apiKey}`).toString("base64")}`
|
Authorization: `Basic ${Buffer.from(`:${apiTokenCredentials.accessToken}`).toString("base64")}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
organizations = orgsResponse.data.value || [];
|
organizations = orgsResponse.data.value || [];
|
||||||
@@ -239,7 +239,7 @@ export const validateAzureDevOpsConnectionCredentials = async (config: TAzureDev
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
apiKey: apiTokenCredentials.apiKey,
|
accessToken: apiTokenCredentials.accessToken,
|
||||||
userDisplayName: profileResponse.data.displayName,
|
userDisplayName: profileResponse.data.displayName,
|
||||||
organizations: organizations.map((org) => ({
|
organizations: organizations.map((org) => ({
|
||||||
accountId: org.accountId,
|
accountId: org.accountId,
|
||||||
|
|||||||
@@ -29,12 +29,12 @@ export const AzureDevOpsConnectionOAuthOutputCredentialsSchema = z.object({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const AzureDevOpsConnectionApiTokenInputCredentialsSchema = z.object({
|
export const AzureDevOpsConnectionApiTokenInputCredentialsSchema = z.object({
|
||||||
apiKey: z.string().trim().min(1, "API Key required"),
|
accessToken: z.string().trim().min(1, "Access Token required"),
|
||||||
orgName: z.string().trim().min(1, "Organization name required")
|
orgName: z.string().trim().min(1, "Organization name required")
|
||||||
});
|
});
|
||||||
|
|
||||||
export const AzureDevOpsConnectionApiTokenOutputCredentialsSchema = z.object({
|
export const AzureDevOpsConnectionApiTokenOutputCredentialsSchema = z.object({
|
||||||
apiKey: z.string(),
|
accessToken: z.string(),
|
||||||
orgName: z.string()
|
orgName: z.string()
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ export const ValidateAzureDevOpsConnectionCredentialsSchema = z.discriminatedUni
|
|||||||
}),
|
}),
|
||||||
z.object({
|
z.object({
|
||||||
method: z
|
method: z
|
||||||
.literal(AzureDevOpsConnectionMethod.ApiToken)
|
.literal(AzureDevOpsConnectionMethod.AccessToken)
|
||||||
.describe(AppConnections.CREATE(AppConnection.AzureDevOps).method),
|
.describe(AppConnections.CREATE(AppConnection.AzureDevOps).method),
|
||||||
credentials: AzureDevOpsConnectionApiTokenInputCredentialsSchema.describe(
|
credentials: AzureDevOpsConnectionApiTokenInputCredentialsSchema.describe(
|
||||||
AppConnections.CREATE(AppConnection.AzureDevOps).credentials
|
AppConnections.CREATE(AppConnection.AzureDevOps).credentials
|
||||||
@@ -82,7 +82,7 @@ export const AzureDevOpsConnectionSchema = z.intersection(
|
|||||||
credentials: AzureDevOpsConnectionOAuthOutputCredentialsSchema
|
credentials: AzureDevOpsConnectionOAuthOutputCredentialsSchema
|
||||||
}),
|
}),
|
||||||
z.object({
|
z.object({
|
||||||
method: z.literal(AzureDevOpsConnectionMethod.ApiToken),
|
method: z.literal(AzureDevOpsConnectionMethod.AccessToken),
|
||||||
credentials: AzureDevOpsConnectionApiTokenOutputCredentialsSchema
|
credentials: AzureDevOpsConnectionApiTokenOutputCredentialsSchema
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
@@ -97,7 +97,7 @@ export const SanitizedAzureDevOpsConnectionSchema = z.discriminatedUnion("method
|
|||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
BaseAzureDevOpsConnectionSchema.extend({
|
BaseAzureDevOpsConnectionSchema.extend({
|
||||||
method: z.literal(AzureDevOpsConnectionMethod.ApiToken),
|
method: z.literal(AzureDevOpsConnectionMethod.AccessToken),
|
||||||
credentials: AzureDevOpsConnectionApiTokenOutputCredentialsSchema.pick({
|
credentials: AzureDevOpsConnectionApiTokenOutputCredentialsSchema.pick({
|
||||||
orgName: true
|
orgName: true
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { IntegrationUrls } from "@app/services/integration-auth/integration-list
|
|||||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||||
|
|
||||||
import { AzureDevOpsConnectionMethod } from "./azure-devops-enums";
|
import { AzureDevOpsConnectionMethod } from "./azure-devops-enums";
|
||||||
import { getAzureDevopsConnectionAccessToken } from "./azure-devops-fns";
|
import { getAzureDevopsConnection } from "./azure-devops-fns";
|
||||||
import { TAzureDevOpsConnection } from "./azure-devops-types";
|
import { TAzureDevOpsConnection } from "./azure-devops-types";
|
||||||
|
|
||||||
type TGetAppConnectionFunc = (
|
type TGetAppConnectionFunc = (
|
||||||
@@ -45,7 +45,7 @@ const getAuthHeaders = (appConnection: TAzureDevOpsConnection, accessToken: stri
|
|||||||
Authorization: `Bearer ${accessToken}`,
|
Authorization: `Bearer ${accessToken}`,
|
||||||
Accept: "application/json"
|
Accept: "application/json"
|
||||||
};
|
};
|
||||||
case AzureDevOpsConnectionMethod.ApiToken:
|
case AzureDevOpsConnectionMethod.AccessToken:
|
||||||
// For API token, create Basic auth header
|
// For API token, create Basic auth header
|
||||||
const basicAuthToken = Buffer.from(`user:${accessToken}`).toString("base64");
|
const basicAuthToken = Buffer.from(`user:${accessToken}`).toString("base64");
|
||||||
return {
|
return {
|
||||||
@@ -62,7 +62,7 @@ const listAzureDevOpsProjects = async (
|
|||||||
appConnectionDAL: Pick<TAppConnectionDALFactory, "findById" | "update" | "updateById">,
|
appConnectionDAL: Pick<TAppConnectionDALFactory, "findById" | "update" | "updateById">,
|
||||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">
|
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">
|
||||||
): Promise<TAzureDevOpsProject[]> => {
|
): Promise<TAzureDevOpsProject[]> => {
|
||||||
const accessToken = await getAzureDevopsConnectionAccessToken(appConnection.id, appConnectionDAL, kmsService);
|
const accessToken = await getAzureDevopsConnection(appConnection.id, appConnectionDAL, kmsService);
|
||||||
|
|
||||||
// Both OAuth and API Token methods use organization name from credentials
|
// Both OAuth and API Token methods use organization name from credentials
|
||||||
const credentials = appConnection.credentials as { orgName: string };
|
const credentials = appConnection.credentials as { orgName: string };
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { request } from "@app/lib/config/request";
|
|||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
import { TAppConnectionDALFactory } from "@app/services/app-connection/app-connection-dal";
|
import { TAppConnectionDALFactory } from "@app/services/app-connection/app-connection-dal";
|
||||||
import { AzureDevOpsConnectionMethod } from "@app/services/app-connection/azure-devops/azure-devops-enums";
|
import { AzureDevOpsConnectionMethod } from "@app/services/app-connection/azure-devops/azure-devops-enums";
|
||||||
import { getAzureDevopsConnectionAccessToken } from "@app/services/app-connection/azure-devops/azure-devops-fns";
|
import { getAzureDevopsConnection } from "@app/services/app-connection/azure-devops/azure-devops-fns";
|
||||||
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
|
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
|
||||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||||
import { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
|
import { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
|
||||||
@@ -44,7 +44,7 @@ export const azureDevOpsSyncFactory = ({ kmsService, appConnectionDAL }: TAzureD
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const accessToken = await getAzureDevopsConnectionAccessToken(
|
const accessToken = await getAzureDevopsConnection(
|
||||||
secretSync.connectionId,
|
secretSync.connectionId,
|
||||||
appConnectionDAL,
|
appConnectionDAL,
|
||||||
kmsService
|
kmsService
|
||||||
@@ -115,7 +115,7 @@ export const azureDevOpsSyncFactory = ({ kmsService, appConnectionDAL }: TAzureD
|
|||||||
|
|
||||||
if (!groupId) {
|
if (!groupId) {
|
||||||
// Create new variable group - API endpoint is organization-level
|
// Create new variable group - API endpoint is organization-level
|
||||||
const url = `${IntegrationUrls.AZURE_DEVOPS_API_URL}/${orgName}/_apis/distributedtask/variablegroups?api-version=7.1`;
|
const url = `${IntegrationUrls.AZURE_DEVOPS_API_URL}/${encodeURIComponent(orgName)}/_apis/distributedtask/variablegroups?api-version=7.1`;
|
||||||
|
|
||||||
await request.post(
|
await request.post(
|
||||||
url,
|
url,
|
||||||
@@ -143,7 +143,7 @@ export const azureDevOpsSyncFactory = ({ kmsService, appConnectionDAL }: TAzureD
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const url = `${IntegrationUrls.AZURE_DEVOPS_API_URL}/${orgName}/_apis/distributedtask/variablegroups/${groupId}?api-version=7.1`;
|
const url = `${IntegrationUrls.AZURE_DEVOPS_API_URL}/${encodeURIComponent(orgName)}/_apis/distributedtask/variablegroups/${groupId}?api-version=7.1`;
|
||||||
|
|
||||||
await request.put(
|
await request.put(
|
||||||
url,
|
url,
|
||||||
@@ -186,7 +186,7 @@ export const azureDevOpsSyncFactory = ({ kmsService, appConnectionDAL }: TAzureD
|
|||||||
|
|
||||||
if (groupId) {
|
if (groupId) {
|
||||||
// Delete the variable group entirely using the DELETE API
|
// Delete the variable group entirely using the DELETE API
|
||||||
const deleteUrl = `${IntegrationUrls.AZURE_DEVOPS_API_URL}/${orgName}/_apis/distributedtask/variablegroups/${groupId}?projectIds=${secretSync.destinationConfig.devopsProjectId}&api-version=7.1`;
|
const deleteUrl = `${IntegrationUrls.AZURE_DEVOPS_API_URL}/${encodeURIComponent(orgName)}/_apis/distributedtask/variablegroups/${groupId}?projectIds=${secretSync.destinationConfig.devopsProjectId}&api-version=7.1`;
|
||||||
|
|
||||||
await request.delete(deleteUrl, {
|
await request.delete(deleteUrl, {
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ title: "Azure DevOps Connection"
|
|||||||
description: "Learn how to configure an Azure DevOps Connection for Infisical."
|
description: "Learn how to configure an Azure DevOps Connection for Infisical."
|
||||||
---
|
---
|
||||||
|
|
||||||
Infisical currently supports two methods for connecting to Azure DevOps, which are OAuth and Azure DevOps API Token.
|
Infisical currently supports two methods for connecting to Azure DevOps, which are OAuth and Azure DevOps Personal Access Token.
|
||||||
|
|
||||||
<Accordion title="Self-Hosted Instance">
|
<Accordion title="Azure OAuth on a Self-Hosted Instance">
|
||||||
Using the Azure DevOps OAuth connection on a self-hosted instance of Infisical requires configuring an application in Azure
|
Using the Azure DevOps <b>OAuth connection</b> on a self-hosted instance of Infisical requires configuring an application in Azure
|
||||||
and registering your instance with it.
|
and registering your instance with it.
|
||||||
|
|
||||||
**Prerequisites:**
|
**Prerequisites:**
|
||||||
@@ -67,7 +67,7 @@ Infisical currently supports two methods for connecting to Azure DevOps, which a
|
|||||||
|
|
||||||
<Accordion title="Azure DevOps personal access token (PAT)">
|
<Accordion title="Azure DevOps personal access token (PAT)">
|
||||||
#### Create a new Azure DevOps personal access token (PAT)
|
#### Create a new Azure DevOps personal access token (PAT)
|
||||||
You'll need to create a new personal access token (PAT) in order to authenticate Infisical with Azure DevOps.
|
When using the Azure DevOps <b>Access Token connection</b> you'll need to create a new personal access token (PAT) in order to authenticate Infisical with Azure DevOps.
|
||||||
<Steps>
|
<Steps>
|
||||||
<Step title="Navigate to Azure DevOps">
|
<Step title="Navigate to Azure DevOps">
|
||||||

|

|
||||||
@@ -100,10 +100,10 @@ Infisical currently supports two methods for connecting to Azure DevOps, which a
|
|||||||
|
|
||||||
<Step title="Create Connection">
|
<Step title="Create Connection">
|
||||||
<Tabs>
|
<Tabs>
|
||||||
<Tab title="Infisical UI">
|
<Tab title="OAuth">
|
||||||
<Steps>
|
<Steps>
|
||||||
<Step title="Fill in Connection Details">
|
<Step title="Fill in Connection Details">
|
||||||
Fill in the **Tenant ID** field with the Directory (Tenant) ID you obtained in the previous step. Also fill in the organization name of the Azure DevOps organization you want to connect to.
|
Fill in the **Tenant ID** field with the Directory (Tenant) ID you obtained in the previous [step](#azure-oauth-on-a-self-hosted-instance). Also fill in the organization name of the Azure DevOps organization you want to connect to.
|
||||||

|

|
||||||
|
|
||||||
<Tip>
|
<Tip>
|
||||||
@@ -117,10 +117,10 @@ Infisical currently supports two methods for connecting to Azure DevOps, which a
|
|||||||
</Step>
|
</Step>
|
||||||
</Steps>
|
</Steps>
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab title="API">
|
<Tab title="Access Token">
|
||||||
<Steps>
|
<Steps>
|
||||||
<Step title="Fill in Connection Details">
|
<Step title="Fill in Connection Details">
|
||||||
Fill in the **API Key** field with the API key you obtained in the previous step. And the organization name of the Azure DevOps organization you want to connect to.
|
Fill in the **Access Token** field with the Access Token you obtained in the previous step. And the organization name of the Azure DevOps organization you want to connect to.
|
||||||

|

|
||||||
|
|
||||||
<Tip>
|
<Tip>
|
||||||
|
|||||||
@@ -113,28 +113,28 @@ description: "Learn how to configure a Azure DevOps Sync for Infisical."
|
|||||||
"lastRemoveMessage": null,
|
"lastRemoveMessage": null,
|
||||||
"lastRemovedAt": null,
|
"lastRemovedAt": null,
|
||||||
"syncOptions": {
|
"syncOptions": {
|
||||||
"initialSyncBehavior": "overwrite-destination",
|
"initialSyncBehavior": "overwrite-destination",
|
||||||
"keySchema": "PIPELINE_${secretKey}",
|
"keySchema": "PIPELINE_${secretKey}",
|
||||||
"disableSecretDeletion": true
|
"disableSecretDeletion": true
|
||||||
},
|
},
|
||||||
"connection": {
|
"connection": {
|
||||||
"app": "azure-devops",
|
"app": "azure-devops",
|
||||||
"name": "Production DevOps Organization",
|
"name": "Production DevOps Organization",
|
||||||
"id": "8b92f5cc-3g77-5e80-6666-6ff57069385d"
|
"id": "8b92f5cc-3g77-5e80-6666-6ff57069385d"
|
||||||
},
|
},
|
||||||
"environment": {
|
"environment": {
|
||||||
"slug": "production",
|
"slug": "production",
|
||||||
"name": "Production Environment",
|
"name": "Production Environment",
|
||||||
"id": "4f16j9gg-7k11-9i23-2222-2jj91403729h"
|
"id": "4f16j9gg-7k11-9i23-2222-2jj91403729h"
|
||||||
},
|
},
|
||||||
"folder": {
|
"folder": {
|
||||||
"id": "5a71e8dd-2f66-4d70-7777-7cc46958274c",
|
"id": "5a71e8dd-2f66-4d70-7777-7cc46958274c",
|
||||||
"path": "/devops/pipeline-secrets"
|
"path": "/devops/pipeline-secrets"
|
||||||
},
|
},
|
||||||
"destination": "azure-devops",
|
"destination": "azure-devops",
|
||||||
"destinationConfig": {
|
"destinationConfig": {
|
||||||
"devopsProjectId": "12345678-90ab-cdef-1234-567890abcdef",
|
"devopsProjectId": "12345678-90ab-cdef-1234-567890abcdef",
|
||||||
"devopsProjectName": "example-project"
|
"devopsProjectName": "example-project"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,7 +105,6 @@ export const getAppConnectionMethodDetails = (method: TAppConnection["method"])
|
|||||||
case TerraformCloudConnectionMethod.ApiToken:
|
case TerraformCloudConnectionMethod.ApiToken:
|
||||||
case VercelConnectionMethod.ApiToken:
|
case VercelConnectionMethod.ApiToken:
|
||||||
case OnePassConnectionMethod.ApiToken:
|
case OnePassConnectionMethod.ApiToken:
|
||||||
case AzureDevOpsConnectionMethod.ApiToken:
|
|
||||||
return { name: "API Token", icon: faKey };
|
return { name: "API Token", icon: faKey };
|
||||||
case PostgresConnectionMethod.UsernameAndPassword:
|
case PostgresConnectionMethod.UsernameAndPassword:
|
||||||
case MsSqlConnectionMethod.UsernameAndPassword:
|
case MsSqlConnectionMethod.UsernameAndPassword:
|
||||||
@@ -113,6 +112,7 @@ export const getAppConnectionMethodDetails = (method: TAppConnection["method"])
|
|||||||
return { name: "Username & Password", icon: faLock };
|
return { name: "Username & Password", icon: faLock };
|
||||||
case HCVaultConnectionMethod.AccessToken:
|
case HCVaultConnectionMethod.AccessToken:
|
||||||
case TeamCityConnectionMethod.AccessToken:
|
case TeamCityConnectionMethod.AccessToken:
|
||||||
|
case AzureDevOpsConnectionMethod.AccessToken:
|
||||||
case WindmillConnectionMethod.AccessToken:
|
case WindmillConnectionMethod.AccessToken:
|
||||||
return { name: "Access Token", icon: faKey };
|
return { name: "Access Token", icon: faKey };
|
||||||
case Auth0ConnectionMethod.ClientCredentials:
|
case Auth0ConnectionMethod.ClientCredentials:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { TRootAppConnection } from "@app/hooks/api/appConnections/types/root-con
|
|||||||
|
|
||||||
export enum AzureDevOpsConnectionMethod {
|
export enum AzureDevOpsConnectionMethod {
|
||||||
OAuth = "oauth",
|
OAuth = "oauth",
|
||||||
ApiToken = "api-token"
|
AccessToken = "access-token"
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TAzureDevOpsConnection = TRootAppConnection & {
|
export type TAzureDevOpsConnection = TRootAppConnection & {
|
||||||
@@ -18,9 +18,9 @@ export type TAzureDevOpsConnection = TRootAppConnection & {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
method: AzureDevOpsConnectionMethod.ApiToken;
|
method: AzureDevOpsConnectionMethod.AccessToken;
|
||||||
credentials: {
|
credentials: {
|
||||||
apiKey: string;
|
accessToken: string;
|
||||||
orgName: string;
|
orgName: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,9 +42,9 @@ const oauthSchema = baseSchema.extend({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const apiTokenSchema = baseSchema.extend({
|
const apiTokenSchema = baseSchema.extend({
|
||||||
method: z.literal(AzureDevOpsConnectionMethod.ApiToken),
|
method: z.literal(AzureDevOpsConnectionMethod.AccessToken),
|
||||||
credentials: z.object({
|
credentials: z.object({
|
||||||
apiKey: z.string().trim().min(1, "API Key is required"),
|
accessToken: z.string().trim().min(1, "Access Token is required"),
|
||||||
orgName: z.string().trim().min(1, "Organization name is required")
|
orgName: z.string().trim().min(1, "Organization name is required")
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
@@ -81,13 +81,13 @@ const getDefaultValues = (appConnection?: TAzureDevOpsConnection): Partial<FormD
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AzureDevOpsConnectionMethod.ApiToken:
|
case AzureDevOpsConnectionMethod.AccessToken:
|
||||||
if ("apiKey" in credentials && "orgName" in credentials) {
|
if ("accessToken" in credentials && "orgName" in credentials) {
|
||||||
return {
|
return {
|
||||||
...base,
|
...base,
|
||||||
method: AzureDevOpsConnectionMethod.ApiToken,
|
method: AzureDevOpsConnectionMethod.AccessToken,
|
||||||
credentials: {
|
credentials: {
|
||||||
apiKey: credentials.apiKey,
|
accessToken: credentials.accessToken,
|
||||||
orgName: credentials.orgName
|
orgName: credentials.orgName
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -139,7 +139,7 @@ export const AzureDevOpsConnectionForm = ({ appConnection, onSubmit }: Props) =>
|
|||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AzureDevOpsConnectionMethod.ApiToken:
|
case AzureDevOpsConnectionMethod.AccessToken:
|
||||||
onSubmit(formData);
|
onSubmit(formData);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -231,16 +231,16 @@ export const AzureDevOpsConnectionForm = ({ appConnection, onSubmit }: Props) =>
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* API Token-specific fields */}
|
{/* API Token-specific fields */}
|
||||||
{selectedMethod === AzureDevOpsConnectionMethod.ApiToken && (
|
{selectedMethod === AzureDevOpsConnectionMethod.AccessToken && (
|
||||||
<>
|
<>
|
||||||
<Controller
|
<Controller
|
||||||
name="credentials.apiKey"
|
name="credentials.accessToken"
|
||||||
control={control}
|
control={control}
|
||||||
render={({ field, fieldState: { error } }) => (
|
render={({ field, fieldState: { error } }) => (
|
||||||
<FormControl
|
<FormControl
|
||||||
tooltipText="Personal Access Token from Azure DevOps."
|
tooltipText="Personal Access Token from Azure DevOps."
|
||||||
isError={Boolean(error?.message)}
|
isError={Boolean(error?.message)}
|
||||||
label="API Key"
|
label="Access Token"
|
||||||
errorText={error?.message}
|
errorText={error?.message}
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ type OAuthCredentials = Extract<
|
|||||||
>["credentials"];
|
>["credentials"];
|
||||||
type ApiTokenCredentials = Extract<
|
type ApiTokenCredentials = Extract<
|
||||||
TAzureDevOpsConnection,
|
TAzureDevOpsConnection,
|
||||||
{ method: AzureDevOpsConnectionMethod.ApiToken }
|
{ method: AzureDevOpsConnectionMethod.AccessToken }
|
||||||
>["credentials"];
|
>["credentials"];
|
||||||
|
|
||||||
type AzureDevOpsFormData = BaseFormData &
|
type AzureDevOpsFormData = BaseFormData &
|
||||||
|
|||||||
Reference in New Issue
Block a user