mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 12:27:28 +00:00
Finish adding support for build-configuration level syncs for TeamCity integration
This commit is contained in:
@@ -547,6 +547,57 @@ export const getIntegrationAuthNorthflankSecretGroups = async (req: Request, res
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return list of build configs for TeamCity project with id [appId]
|
||||
* @param req
|
||||
* @param res
|
||||
* @returns
|
||||
*/
|
||||
export const getIntegrationAuthTeamCityBuildConfigs = async (req: Request, res: Response) => {
|
||||
const appId = req.query.appId as string;
|
||||
|
||||
interface TeamCityBuildConfig {
|
||||
id: string;
|
||||
name: string;
|
||||
projectName: string;
|
||||
projectId: string;
|
||||
href: string;
|
||||
webUrl: string;
|
||||
}
|
||||
|
||||
interface GetTeamCityBuildConfigsRes {
|
||||
count: number;
|
||||
href: string;
|
||||
buildType: TeamCityBuildConfig[];
|
||||
}
|
||||
|
||||
|
||||
if (appId && appId !== "") {
|
||||
const { data: { buildType } } = (
|
||||
await standardRequest.get<GetTeamCityBuildConfigsRes>(`${req.integrationAuth.url}/app/rest/buildTypes`, {
|
||||
params: {
|
||||
locator: `project:${appId}`
|
||||
},
|
||||
headers: {
|
||||
Authorization: `Bearer ${req.accessToken}`,
|
||||
Accept: "application/json",
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
return res.status(200).send({
|
||||
buildConfigs: buildType.map((buildConfig) => ({
|
||||
name: buildConfig.name,
|
||||
buildConfigId: buildConfig.id
|
||||
}))
|
||||
});
|
||||
}
|
||||
|
||||
return res.status(200).send({
|
||||
buildConfigs: []
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete integration authorization with id [integrationAuthId]
|
||||
* @param req
|
||||
|
||||
@@ -236,7 +236,7 @@ export const batchSecrets = async (req: Request, res: Response) => {
|
||||
version: 1
|
||||
},
|
||||
$unset: {
|
||||
'metadata.source': true as true
|
||||
"metadata.source": true as const
|
||||
},
|
||||
...u,
|
||||
_id: new Types.ObjectId(u._id)
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
INTEGRATION_VERCEL
|
||||
} from "../variables";
|
||||
import { UnauthorizedRequestError } from "../utils/errors";
|
||||
import { syncSecretsToActiveIntegrationsQueue } from "../queues/integrations/syncSecretsToThirdPartyServices"
|
||||
|
||||
interface Update {
|
||||
workspace: string;
|
||||
|
||||
@@ -850,7 +850,7 @@ const getAppsTeamCity = async ({
|
||||
},
|
||||
})
|
||||
).data.project.slice(1);
|
||||
|
||||
|
||||
const apps = res.map((a: any) => {
|
||||
return {
|
||||
name: a.name,
|
||||
|
||||
@@ -4,6 +4,8 @@ import {
|
||||
INTEGRATION_AZURE_TOKEN_URL,
|
||||
INTEGRATION_BITBUCKET,
|
||||
INTEGRATION_BITBUCKET_TOKEN_URL,
|
||||
INTEGRATION_GCP_SECRET_MANAGER,
|
||||
INTEGRATION_GCP_TOKEN_URL,
|
||||
INTEGRATION_GITHUB,
|
||||
INTEGRATION_GITHUB_TOKEN_URL,
|
||||
INTEGRATION_GITLAB,
|
||||
@@ -13,21 +15,19 @@ import {
|
||||
INTEGRATION_NETLIFY,
|
||||
INTEGRATION_NETLIFY_TOKEN_URL,
|
||||
INTEGRATION_VERCEL,
|
||||
INTEGRATION_VERCEL_TOKEN_URL,
|
||||
INTEGRATION_GCP_SECRET_MANAGER,
|
||||
INTEGRATION_GCP_TOKEN_URL
|
||||
INTEGRATION_VERCEL_TOKEN_URL
|
||||
} from "../variables";
|
||||
import {
|
||||
getClientIdGCPSecretManager,
|
||||
getClientSecretGCPSecretManager,
|
||||
getClientIdAzure,
|
||||
getClientIdBitBucket,
|
||||
getClientIdGCPSecretManager,
|
||||
getClientIdGitHub,
|
||||
getClientIdGitLab,
|
||||
getClientIdNetlify,
|
||||
getClientIdVercel,
|
||||
getClientSecretAzure,
|
||||
getClientSecretBitBucket,
|
||||
getClientSecretGCPSecretManager,
|
||||
getClientSecretGitHub,
|
||||
getClientSecretGitLab,
|
||||
getClientSecretHeroku,
|
||||
|
||||
@@ -2185,7 +2185,7 @@ const syncSecretsTerraformCloud = async ({
|
||||
};
|
||||
|
||||
/**
|
||||
* Sync/push [secrets] to TeamCity project
|
||||
* Sync/push [secrets] to TeamCity project (and optionally build config)
|
||||
* @param {Object} obj
|
||||
* @param {IIntegration} obj.integration - integration details
|
||||
* @param {Object} obj.secrets - secrets to push to integration
|
||||
@@ -2207,57 +2207,124 @@ const syncSecretsTeamCity = async ({
|
||||
value: string;
|
||||
}
|
||||
|
||||
// get secrets from Teamcity
|
||||
const res = (
|
||||
await standardRequest.get(
|
||||
`${integrationAuth.url}/app/rest/projects/id:${integration.appId}/parameters`,
|
||||
interface TeamCityBuildConfigParameter {
|
||||
name: string;
|
||||
value: string;
|
||||
inherited: boolean;
|
||||
}
|
||||
interface GetTeamCityBuildConfigParametersRes {
|
||||
href: string;
|
||||
count: number;
|
||||
property: TeamCityBuildConfigParameter[];
|
||||
}
|
||||
|
||||
if (integration.targetEnvironment && integration.targetEnvironmentId) {
|
||||
// case: sync to specific build-config in TeamCity project
|
||||
const res = (await standardRequest.get<GetTeamCityBuildConfigParametersRes>(
|
||||
`${integrationAuth.url}/app/rest/buildTypes/${integration.targetEnvironmentId}/parameters`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
Accept: "application/json"
|
||||
}
|
||||
Accept: "application/json",
|
||||
},
|
||||
}
|
||||
)
|
||||
).data.property.reduce((obj: any, secret: TeamCitySecret) => {
|
||||
const secretName = secret.name.replace(/^env\./, "");
|
||||
return {
|
||||
...obj,
|
||||
[secretName]: secret.value
|
||||
};
|
||||
}, {});
|
||||
|
||||
for await (const key of Object.keys(secrets)) {
|
||||
if (!(key in res) || (key in res && secrets[key] !== res[key])) {
|
||||
// case: secret does not exist in TeamCity or secret value has changed
|
||||
// -> create/update secret
|
||||
await standardRequest.post(
|
||||
`${integrationAuth.url}/app/rest/projects/id:${integration.appId}/parameters`,
|
||||
))
|
||||
.data
|
||||
.property
|
||||
.filter((parameter) => !parameter.inherited)
|
||||
.reduce((obj: any, secret: TeamCitySecret) => {
|
||||
const secretName = secret.name.replace(/^env\./, "");
|
||||
return {
|
||||
...obj,
|
||||
[secretName]: secret.value
|
||||
};
|
||||
}, {});
|
||||
|
||||
for await (const key of Object.keys(secrets)) {
|
||||
if (!(key in res) || (key in res && secrets[key].value !== res[key])) {
|
||||
// case: secret does not exist in TeamCity or secret value has changed
|
||||
// -> create/update secret
|
||||
await standardRequest.post(`${integrationAuth.url}/app/rest/buildTypes/${integration.targetEnvironmentId}/parameters`,
|
||||
{
|
||||
name: `env.${key}`,
|
||||
name:`env.${key}`,
|
||||
value: secrets[key].value
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
Accept: "application/json"
|
||||
}
|
||||
}
|
||||
);
|
||||
Accept: "application/json",
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for await (const key of Object.keys(res)) {
|
||||
if (!(key in secrets)) {
|
||||
// delete secret
|
||||
await standardRequest.delete(
|
||||
`${integrationAuth.url}/app/rest/projects/id:${integration.appId}/parameters/env.${key}`,
|
||||
for await (const key of Object.keys(res)) {
|
||||
if (!(key in secrets)) {
|
||||
// delete secret
|
||||
await standardRequest.delete(
|
||||
`${integrationAuth.url}/app/rest/buildTypes/${integration.targetEnvironmentId}/parameters/env.${key}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
Accept: "application/json"
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// case: sync to TeamCity project
|
||||
const res = (
|
||||
await standardRequest.get(
|
||||
`${integrationAuth.url}/app/rest/projects/id:${integration.appId}/parameters`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
Accept: "application/json"
|
||||
}
|
||||
}
|
||||
);
|
||||
)
|
||||
).data.property.reduce((obj: any, secret: TeamCitySecret) => {
|
||||
const secretName = secret.name.replace(/^env\./, "");
|
||||
return {
|
||||
...obj,
|
||||
[secretName]: secret.value
|
||||
};
|
||||
}, {});
|
||||
|
||||
for await (const key of Object.keys(secrets)) {
|
||||
if (!(key in res) || (key in res && secrets[key] !== res[key])) {
|
||||
// case: secret does not exist in TeamCity or secret value has changed
|
||||
// -> create/update secret
|
||||
await standardRequest.post(
|
||||
`${integrationAuth.url}/app/rest/projects/id:${integration.appId}/parameters`,
|
||||
{
|
||||
name: `env.${key}`,
|
||||
value: secrets[key].value
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
Accept: "application/json"
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for await (const key of Object.keys(res)) {
|
||||
if (!(key in secrets)) {
|
||||
// delete secret
|
||||
await standardRequest.delete(
|
||||
`${integrationAuth.url}/app/rest/projects/id:${integration.appId}/parameters/env.${key}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
Accept: "application/json"
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
INTEGRATION_CODEFRESH,
|
||||
INTEGRATION_DIGITAL_OCEAN_APP_PLATFORM,
|
||||
INTEGRATION_FLYIO,
|
||||
INTEGRATION_GCP_SECRET_MANAGER,
|
||||
INTEGRATION_GITHUB,
|
||||
INTEGRATION_GITLAB,
|
||||
INTEGRATION_HASHICORP_VAULT,
|
||||
@@ -24,8 +25,7 @@ import {
|
||||
INTEGRATION_TERRAFORM_CLOUD,
|
||||
INTEGRATION_TRAVISCI,
|
||||
INTEGRATION_VERCEL,
|
||||
INTEGRATION_WINDMILL,
|
||||
INTEGRATION_GCP_SECRET_MANAGER
|
||||
INTEGRATION_WINDMILL
|
||||
} from "../variables";
|
||||
import { Schema, Types, model } from "mongoose";
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
INTEGRATION_CODEFRESH,
|
||||
INTEGRATION_DIGITAL_OCEAN_APP_PLATFORM,
|
||||
INTEGRATION_FLYIO,
|
||||
INTEGRATION_GCP_SECRET_MANAGER,
|
||||
INTEGRATION_GITHUB,
|
||||
INTEGRATION_GITLAB,
|
||||
INTEGRATION_HASHICORP_VAULT,
|
||||
@@ -26,8 +27,7 @@ import {
|
||||
INTEGRATION_TERRAFORM_CLOUD,
|
||||
INTEGRATION_TRAVISCI,
|
||||
INTEGRATION_VERCEL,
|
||||
INTEGRATION_WINDMILL,
|
||||
INTEGRATION_GCP_SECRET_MANAGER
|
||||
INTEGRATION_WINDMILL
|
||||
} from "../variables";
|
||||
import { Document, Schema, Types, model } from "mongoose";
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import Queue, { Job } from "bull";
|
||||
import { ProbotOctokit } from "probot"
|
||||
import { Commit, Committer, Repository } from "@octokit/webhooks-types";
|
||||
import { Commit } from "@octokit/webhooks-types";
|
||||
import TelemetryService from "../../services/TelemetryService";
|
||||
import { sendMail } from "../../helpers";
|
||||
import GitRisks from "../../ee/models/gitRisks";
|
||||
import { MembershipOrg, User } from "../../models";
|
||||
import { OWNER, ADMIN } from "../../variables";
|
||||
import { ADMIN, OWNER } from "../../variables";
|
||||
import { convertKeysToLowercase, scanContentAndGetFindings } from "../../ee/services/GithubSecretScanning/helper";
|
||||
import { getSecretScanningGitAppId, getSecretScanningPrivateKey } from "../../config";
|
||||
import { SecretMatch } from "../../ee/services/GithubSecretScanning/types";
|
||||
|
||||
export const githubPushEventSecretScan = new Queue('github-push-event-secret-scanning', 'redis://redis:6379');
|
||||
export const githubPushEventSecretScan = new Queue("github-push-event-secret-scanning", "redis://redis:6379");
|
||||
|
||||
type TScanPushEventQueueDetails = {
|
||||
organizationId: string,
|
||||
|
||||
@@ -89,4 +89,4 @@ router.post(
|
||||
integrationController.manualSync
|
||||
);
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
@@ -168,6 +168,20 @@ router.get(
|
||||
integrationAuthController.getIntegrationAuthNorthflankSecretGroups
|
||||
);
|
||||
|
||||
router.get(
|
||||
"/:integrationAuthId/teamcity/build-configs",
|
||||
requireAuth({
|
||||
acceptedAuthModes: [AuthMode.JWT],
|
||||
}),
|
||||
requireIntegrationAuthorizationAuth({
|
||||
acceptedRoles: [ADMIN, MEMBER],
|
||||
}),
|
||||
param("integrationAuthId").exists().isString(),
|
||||
query("appId").exists().isString(),
|
||||
validateRequest,
|
||||
integrationAuthController.getIntegrationAuthTeamCityBuildConfigs
|
||||
);
|
||||
|
||||
router.delete(
|
||||
"/:integrationAuthId",
|
||||
requireAuth({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import express, { Request, Response } from "express";
|
||||
import express from "express";
|
||||
const router = express.Router();
|
||||
import { requireAuth, requireWorkspaceAuth, validateRequest } from "../../middleware";
|
||||
import { body, param, query } from "express-validator";
|
||||
|
||||
Reference in New Issue
Block a user