mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 17:27:40 +00:00
review fixes
This commit is contained in:
@@ -3,6 +3,7 @@ import { AxiosError } from "axios";
|
|||||||
import { request } from "@app/lib/config/request";
|
import { request } from "@app/lib/config/request";
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
import { removeTrailingSlash } from "@app/lib/fn";
|
import { removeTrailingSlash } from "@app/lib/fn";
|
||||||
|
import { blockLocalAndPrivateIpAddresses } from "@app/lib/validator";
|
||||||
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||||
|
|
||||||
import { TeamCityConnectionMethod } from "./teamcity-connection-enums";
|
import { TeamCityConnectionMethod } from "./teamcity-connection-enums";
|
||||||
@@ -12,6 +13,14 @@ import {
|
|||||||
TTeamCityListProjectsResponse
|
TTeamCityListProjectsResponse
|
||||||
} from "./teamcity-connection-types";
|
} from "./teamcity-connection-types";
|
||||||
|
|
||||||
|
export const getTeamCityInstanceUrl = async (config: TTeamCityConnectionConfig) => {
|
||||||
|
const instanceUrl = removeTrailingSlash(config.credentials.instanceUrl);
|
||||||
|
|
||||||
|
await blockLocalAndPrivateIpAddresses(instanceUrl);
|
||||||
|
|
||||||
|
return instanceUrl;
|
||||||
|
};
|
||||||
|
|
||||||
export const getTeamCityConnectionListItem = () => {
|
export const getTeamCityConnectionListItem = () => {
|
||||||
return {
|
return {
|
||||||
name: "TeamCity" as const,
|
name: "TeamCity" as const,
|
||||||
@@ -21,7 +30,8 @@ export const getTeamCityConnectionListItem = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const validateTeamCityConnectionCredentials = async (config: TTeamCityConnectionConfig) => {
|
export const validateTeamCityConnectionCredentials = async (config: TTeamCityConnectionConfig) => {
|
||||||
const instanceUrl = removeTrailingSlash(config.credentials.instanceUrl);
|
const instanceUrl = await getTeamCityInstanceUrl(config);
|
||||||
|
|
||||||
const { accessToken } = config.credentials;
|
const { accessToken } = config.credentials;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -46,7 +56,7 @@ export const validateTeamCityConnectionCredentials = async (config: TTeamCityCon
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const listTeamCityProjects = async (appConnection: TTeamCityConnection) => {
|
export const listTeamCityProjects = async (appConnection: TTeamCityConnection) => {
|
||||||
const instanceUrl = removeTrailingSlash(appConnection.credentials.instanceUrl);
|
const instanceUrl = await getTeamCityInstanceUrl(appConnection);
|
||||||
const { accessToken } = appConnection.credentials;
|
const { accessToken } = appConnection.credentials;
|
||||||
|
|
||||||
const resp = await request.get<TTeamCityListProjectsResponse>(
|
const resp = await request.get<TTeamCityListProjectsResponse>(
|
||||||
|
|||||||
@@ -145,7 +145,9 @@ export const SecretSyncFns = {
|
|||||||
case SecretSync.TeamCity:
|
case SecretSync.TeamCity:
|
||||||
return TeamCitySyncFns.syncSecrets(secretSync, secretMap);
|
return TeamCitySyncFns.syncSecrets(secretSync, secretMap);
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unhandled sync destination for sync secrets fns: ${secretSync.destination}`);
|
throw new Error(
|
||||||
|
`Unhandled sync destination for sync secrets fns: ${(secretSync as TSecretSyncWithCredentials).destination}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getSecrets: async (
|
getSecrets: async (
|
||||||
@@ -205,7 +207,9 @@ export const SecretSyncFns = {
|
|||||||
secretMap = await TeamCitySyncFns.getSecrets(secretSync);
|
secretMap = await TeamCitySyncFns.getSecrets(secretSync);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unhandled sync destination for get secrets fns: ${secretSync.destination}`);
|
throw new Error(
|
||||||
|
`Unhandled sync destination for get secrets fns: ${(secretSync as TSecretSyncWithCredentials).destination}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return secretMap;
|
return secretMap;
|
||||||
@@ -258,7 +262,9 @@ export const SecretSyncFns = {
|
|||||||
case SecretSync.TeamCity:
|
case SecretSync.TeamCity:
|
||||||
return TeamCitySyncFns.removeSecrets(secretSync, secretMap);
|
return TeamCitySyncFns.removeSecrets(secretSync, secretMap);
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unhandled sync destination for remove secrets fns: ${secretSync.destination}`);
|
throw new Error(
|
||||||
|
`Unhandled sync destination for remove secrets fns: ${(secretSync as TSecretSyncWithCredentials).destination}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { request } from "@app/lib/config/request";
|
import { request } from "@app/lib/config/request";
|
||||||
import { removeTrailingSlash } from "@app/lib/fn";
|
import { getTeamCityInstanceUrl } from "@app/services/app-connection/teamcity";
|
||||||
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
||||||
import { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
|
import { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
|
||||||
import {
|
import {
|
||||||
@@ -89,7 +89,7 @@ export const TeamCitySyncFns = {
|
|||||||
destinationConfig: { project, buildConfig }
|
destinationConfig: { project, buildConfig }
|
||||||
} = secretSync;
|
} = secretSync;
|
||||||
|
|
||||||
const instanceUrl = removeTrailingSlash(connection.credentials.instanceUrl);
|
const instanceUrl = await getTeamCityInstanceUrl(connection);
|
||||||
const { accessToken } = connection.credentials;
|
const { accessToken } = connection.credentials;
|
||||||
|
|
||||||
for await (const entry of Object.entries(secretMap)) {
|
for await (const entry of Object.entries(secretMap)) {
|
||||||
@@ -145,7 +145,7 @@ export const TeamCitySyncFns = {
|
|||||||
destinationConfig: { project, buildConfig }
|
destinationConfig: { project, buildConfig }
|
||||||
} = secretSync;
|
} = secretSync;
|
||||||
|
|
||||||
const instanceUrl = removeTrailingSlash(connection.credentials.instanceUrl);
|
const instanceUrl = await getTeamCityInstanceUrl(connection);
|
||||||
const { accessToken } = connection.credentials;
|
const { accessToken } = connection.credentials;
|
||||||
|
|
||||||
const variables = await listTeamCityVariables({ instanceUrl, accessToken, project, buildConfig });
|
const variables = await listTeamCityVariables({ instanceUrl, accessToken, project, buildConfig });
|
||||||
@@ -175,7 +175,7 @@ export const TeamCitySyncFns = {
|
|||||||
destinationConfig: { project, buildConfig }
|
destinationConfig: { project, buildConfig }
|
||||||
} = secretSync;
|
} = secretSync;
|
||||||
|
|
||||||
const instanceUrl = removeTrailingSlash(connection.credentials.instanceUrl);
|
const instanceUrl = await getTeamCityInstanceUrl(connection);
|
||||||
const { accessToken } = connection.credentials;
|
const { accessToken } = connection.credentials;
|
||||||
|
|
||||||
return listTeamCityVariables({ instanceUrl, accessToken, project, buildConfig });
|
return listTeamCityVariables({ instanceUrl, accessToken, project, buildConfig });
|
||||||
|
|||||||
@@ -18,17 +18,28 @@ Infisical supports connecting to TeamCity using an Access Token to securely sync
|
|||||||
</Step>
|
</Step>
|
||||||
<Step title="Create the Access Token">
|
<Step title="Create the Access Token">
|
||||||
Click the **Create access token** button and provide a name for your token (e.g., "Infisical Integration"). You may set an expiration date or leave it blank for no expiry.
|
Click the **Create access token** button and provide a name for your token (e.g., "Infisical Integration"). You may set an expiration date or leave it blank for no expiry.
|
||||||
The permission scope can either be **Same as current user** or **Limit per project**. If you're choosing **Limit per project**, make sure you select the relevant project and enable the **View build configuration settings** and **Edit project** permissions.
|
The permission scope can either be **Same as current user** or **Limit per project**.
|
||||||
|
|
||||||
|
If you're choosing **Limit per project**, make sure you select the relevant project and enable the permissions relevant to your use case:
|
||||||
|
|
||||||
|
<Tabs>
|
||||||
|
<Tab title="Secret Sync Permissions">
|
||||||
|
- View build configuration settings
|
||||||
|
- Edit project
|
||||||
|
</Tab>
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
<Note>
|
<Note>
|
||||||
Setting your permission scope to **Same as current user** will allow your integration to access multiple projects as long as the current user has read and write access to them.
|
Setting your permission scope to **Same as current user** will allow your integration to access multiple projects as long as the current user has read and write access to them.
|
||||||
</Note>
|
</Note>
|
||||||
<Note>
|
<Note>
|
||||||
Setting your permission scope to **Limit per project** requires the **View build configuration settings** and **Edit project** permissions.
|
If you configure an expiry date for your access token, you must manually rotate to a new token before the expiration date to prevent service interruption.
|
||||||
</Note>
|
</Note>
|
||||||

|
|
||||||
</Step>
|
</Step>
|
||||||
<Step title="Copy the Access Token">
|
<Step title="Copy the Access Token">
|
||||||
After creation, a modal with the API token will be displayed. Copy this token immediately and store it securely, as you won't be able to view it again after closing this dialog.
|
After creation, a modal with the Access Token will be displayed. Copy this token immediately and store it securely, as you won't be able to view it again after closing this dialog.
|
||||||

|

|
||||||
</Step>
|
</Step>
|
||||||
<Step title="Token Created">
|
<Step title="Token Created">
|
||||||
|
|||||||
+30
-30
@@ -434,10 +434,10 @@
|
|||||||
"integrations/app-connections/humanitec",
|
"integrations/app-connections/humanitec",
|
||||||
"integrations/app-connections/mssql",
|
"integrations/app-connections/mssql",
|
||||||
"integrations/app-connections/postgres",
|
"integrations/app-connections/postgres",
|
||||||
|
"integrations/app-connections/teamcity",
|
||||||
"integrations/app-connections/terraform-cloud",
|
"integrations/app-connections/terraform-cloud",
|
||||||
"integrations/app-connections/vercel",
|
"integrations/app-connections/vercel",
|
||||||
"integrations/app-connections/windmill",
|
"integrations/app-connections/windmill"
|
||||||
"integrations/app-connections/teamcity"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -458,10 +458,10 @@
|
|||||||
"integrations/secret-syncs/gcp-secret-manager",
|
"integrations/secret-syncs/gcp-secret-manager",
|
||||||
"integrations/secret-syncs/github",
|
"integrations/secret-syncs/github",
|
||||||
"integrations/secret-syncs/humanitec",
|
"integrations/secret-syncs/humanitec",
|
||||||
|
"integrations/secret-syncs/teamcity",
|
||||||
"integrations/secret-syncs/terraform-cloud",
|
"integrations/secret-syncs/terraform-cloud",
|
||||||
"integrations/secret-syncs/vercel",
|
"integrations/secret-syncs/vercel",
|
||||||
"integrations/secret-syncs/windmill",
|
"integrations/secret-syncs/windmill"
|
||||||
"integrations/secret-syncs/teamcity"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -1045,6 +1045,18 @@
|
|||||||
"api-reference/endpoints/app-connections/postgres/delete"
|
"api-reference/endpoints/app-connections/postgres/delete"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"group": "TeamCity",
|
||||||
|
"pages": [
|
||||||
|
"api-reference/endpoints/app-connections/teamcity/list",
|
||||||
|
"api-reference/endpoints/app-connections/teamcity/available",
|
||||||
|
"api-reference/endpoints/app-connections/teamcity/get-by-id",
|
||||||
|
"api-reference/endpoints/app-connections/teamcity/get-by-name",
|
||||||
|
"api-reference/endpoints/app-connections/teamcity/create",
|
||||||
|
"api-reference/endpoints/app-connections/teamcity/update",
|
||||||
|
"api-reference/endpoints/app-connections/teamcity/delete"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"group": "Terraform Cloud",
|
"group": "Terraform Cloud",
|
||||||
"pages": [
|
"pages": [
|
||||||
@@ -1080,18 +1092,6 @@
|
|||||||
"api-reference/endpoints/app-connections/windmill/update",
|
"api-reference/endpoints/app-connections/windmill/update",
|
||||||
"api-reference/endpoints/app-connections/windmill/delete"
|
"api-reference/endpoints/app-connections/windmill/delete"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"group": "TeamCity",
|
|
||||||
"pages": [
|
|
||||||
"api-reference/endpoints/app-connections/teamcity/list",
|
|
||||||
"api-reference/endpoints/app-connections/teamcity/available",
|
|
||||||
"api-reference/endpoints/app-connections/teamcity/get-by-id",
|
|
||||||
"api-reference/endpoints/app-connections/teamcity/get-by-name",
|
|
||||||
"api-reference/endpoints/app-connections/teamcity/create",
|
|
||||||
"api-reference/endpoints/app-connections/teamcity/update",
|
|
||||||
"api-reference/endpoints/app-connections/teamcity/delete"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -1222,6 +1222,20 @@
|
|||||||
"api-reference/endpoints/secret-syncs/humanitec/remove-secrets"
|
"api-reference/endpoints/secret-syncs/humanitec/remove-secrets"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"group": "TeamCity",
|
||||||
|
"pages": [
|
||||||
|
"api-reference/endpoints/secret-syncs/teamcity/list",
|
||||||
|
"api-reference/endpoints/secret-syncs/teamcity/get-by-id",
|
||||||
|
"api-reference/endpoints/secret-syncs/teamcity/get-by-name",
|
||||||
|
"api-reference/endpoints/secret-syncs/teamcity/create",
|
||||||
|
"api-reference/endpoints/secret-syncs/teamcity/update",
|
||||||
|
"api-reference/endpoints/secret-syncs/teamcity/delete",
|
||||||
|
"api-reference/endpoints/secret-syncs/teamcity/sync-secrets",
|
||||||
|
"api-reference/endpoints/secret-syncs/teamcity/import-secrets",
|
||||||
|
"api-reference/endpoints/secret-syncs/teamcity/remove-secrets"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"group": "Terraform Cloud",
|
"group": "Terraform Cloud",
|
||||||
"pages": [
|
"pages": [
|
||||||
@@ -1262,20 +1276,6 @@
|
|||||||
"api-reference/endpoints/secret-syncs/windmill/import-secrets",
|
"api-reference/endpoints/secret-syncs/windmill/import-secrets",
|
||||||
"api-reference/endpoints/secret-syncs/windmill/remove-secrets"
|
"api-reference/endpoints/secret-syncs/windmill/remove-secrets"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"group": "TeamCity",
|
|
||||||
"pages": [
|
|
||||||
"api-reference/endpoints/secret-syncs/teamcity/list",
|
|
||||||
"api-reference/endpoints/secret-syncs/teamcity/get-by-id",
|
|
||||||
"api-reference/endpoints/secret-syncs/teamcity/get-by-name",
|
|
||||||
"api-reference/endpoints/secret-syncs/teamcity/create",
|
|
||||||
"api-reference/endpoints/secret-syncs/teamcity/update",
|
|
||||||
"api-reference/endpoints/secret-syncs/teamcity/delete",
|
|
||||||
"api-reference/endpoints/secret-syncs/teamcity/sync-secrets",
|
|
||||||
"api-reference/endpoints/secret-syncs/teamcity/import-secrets",
|
|
||||||
"api-reference/endpoints/secret-syncs/teamcity/remove-secrets"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
+13
-3
@@ -90,9 +90,15 @@ export const TeamCitySyncFields = () => {
|
|||||||
isOptional
|
isOptional
|
||||||
label="Build Configuration"
|
label="Build Configuration"
|
||||||
helperText={
|
helperText={
|
||||||
<span>
|
<Tooltip
|
||||||
Not selecting a Build Configuration will sync your secrets with the entire project.
|
className="max-w-md"
|
||||||
</span>
|
content='Ensure the configuration exists in the selected project and that your Access Token has the "View build configuration settings" permission.'
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<span>Don't see the configuration you're looking for?</span>{" "}
|
||||||
|
<FontAwesomeIcon icon={faCircleInfo} className="text-mineshaft-400" />
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<FilterableSelect
|
<FilterableSelect
|
||||||
@@ -113,6 +119,10 @@ export const TeamCitySyncFields = () => {
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<span className="text-sm text-bunker-300">
|
||||||
|
Not selecting a Build Configuration will sync your secrets to the entire project.
|
||||||
|
</span>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,6 +9,6 @@ export type TTeamCityConnection = TRootAppConnection & { app: AppConnection.Team
|
|||||||
method: TeamCityConnectionMethod.AccessToken;
|
method: TeamCityConnectionMethod.AccessToken;
|
||||||
credentials: {
|
credentials: {
|
||||||
accessToken: string;
|
accessToken: string;
|
||||||
instanceUrl?: string;
|
instanceUrl: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
+1
-8
@@ -34,14 +34,7 @@ const formSchema = z.discriminatedUnion("method", [
|
|||||||
method: z.literal(TeamCityConnectionMethod.AccessToken),
|
method: z.literal(TeamCityConnectionMethod.AccessToken),
|
||||||
credentials: z.object({
|
credentials: z.object({
|
||||||
accessToken: z.string().trim().min(1, "Access Token required"),
|
accessToken: z.string().trim().min(1, "Access Token required"),
|
||||||
instanceUrl: z
|
instanceUrl: z.string().trim().url("Invalid Instance URL")
|
||||||
.string()
|
|
||||||
.trim()
|
|
||||||
.transform((value) => value || undefined)
|
|
||||||
.refine((value) => (!value ? true : z.string().url().safeParse(value).success), {
|
|
||||||
message: "Invalid instance URL"
|
|
||||||
})
|
|
||||||
.optional()
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
|
|||||||
Reference in New Issue
Block a user