feat: fixed eslint and resolved all eslint issues

This commit is contained in:
Akhil Mohan
2024-01-30 22:30:42 +05:30
parent 7c4dd5000f
commit 5855cc660a
147 changed files with 1165 additions and 938 deletions
@@ -59,8 +59,8 @@ const getAppsGCPSecretManager = async ({ accessToken }: { accessToken: string })
...(pageToken ? { pageToken } : {})
});
const res: GCPGetProjectsRes = (
await request.get(`${IntegrationUrls.GCP_API_URL}/v1/projects`, {
const res = (
await request.get<GCPGetProjectsRes>(`${IntegrationUrls.GCP_API_URL}/v1/projects`, {
params,
headers: {
Authorization: `Bearer ${accessToken}`,
@@ -81,8 +81,8 @@ const getAppsGCPSecretManager = async ({ accessToken }: { accessToken: string })
// eslint-disable-next-line
for await (const gcpApp of gcpApps) {
try {
const res: GCPGetServiceRes = (
await request.get(
const res = (
await request.get<GCPGetServiceRes>(
`${IntegrationUrls.GCP_SERVICE_USAGE_URL}/v1/projects/${gcpApp.projectId}/services/${IntegrationUrls.GCP_SECRET_MANAGER_SERVICE_NAME}`,
{
headers: {
@@ -113,7 +113,7 @@ const getAppsGCPSecretManager = async ({ accessToken }: { accessToken: string })
*/
const getAppsHeroku = async ({ accessToken }: { accessToken: string }) => {
const res = (
await request.get(`${IntegrationUrls.HEROKU_API_URL}/apps`, {
await request.get<{ name: string }[]>(`${IntegrationUrls.HEROKU_API_URL}/apps`, {
headers: {
Accept: "application/vnd.heroku+json; version=3",
Authorization: `Bearer ${accessToken}`
@@ -121,7 +121,7 @@ const getAppsHeroku = async ({ accessToken }: { accessToken: string }) => {
})
).data;
const apps = res.map((a: any) => ({
const apps = res.map((a) => ({
name: a.name
}));
@@ -139,22 +139,25 @@ const getAppsVercel = async ({
accessToken: string;
}) => {
const res = (
await request.get(`${IntegrationUrls.VERCEL_API_URL}/v9/projects`, {
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
},
...(teamId
? {
params: {
teamId
await request.get<{ projects: { name: string; id: string }[] }>(
`${IntegrationUrls.VERCEL_API_URL}/v9/projects`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
},
...(teamId
? {
params: {
teamId
}
}
}
: {})
})
: {})
}
)
).data;
const apps = res.projects.map((a: any) => ({
const apps = res.projects.map((a) => ({
name: a.name,
appId: a.id
}));
@@ -166,7 +169,7 @@ const getAppsVercel = async ({
* Return list of sites for Netlify integration
*/
const getAppsNetlify = async ({ accessToken }: { accessToken: string }) => {
const apps: any = [];
const apps: Array<{ name: string; appId: string }> = [];
let page = 1;
const perPage = 10;
let hasMorePages = true;
@@ -179,15 +182,18 @@ const getAppsNetlify = async ({ accessToken }: { accessToken: string }) => {
filter: "all"
});
const { data } = await request.get(`${IntegrationUrls.NETLIFY_API_URL}/api/v1/sites`, {
params,
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
const { data } = await request.get<{ name: string; site_id: string }[]>(
`${IntegrationUrls.NETLIFY_API_URL}/api/v1/sites`,
{
params,
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
}
}
});
);
data.forEach((a: any) => {
data.forEach((a) => {
apps.push({
name: a.name,
appId: a.site_id
@@ -238,8 +244,8 @@ const getAppsGithub = async ({ accessToken }: { accessToken: string }) => {
}
);
if (response.data.length > 0) {
repos = repos.concat(response.data);
if ((response.data as GitHubApp[]).length > 0) {
repos = repos.concat(response.data as GitHubApp[]);
page += 1;
} else {
hasMore = false;
@@ -267,16 +273,19 @@ const getAppsGithub = async ({ accessToken }: { accessToken: string }) => {
*/
const getAppsRender = async ({ accessToken }: { accessToken: string }) => {
const res = (
await request.get(`${IntegrationUrls.RENDER_API_URL}/v1/services`, {
headers: {
Authorization: `Bearer ${accessToken}`,
Accept: "application/json",
"Accept-Encoding": "application/json"
await request.get<{ service: { name: string; id: string } }[]>(
`${IntegrationUrls.RENDER_API_URL}/v1/services`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
Accept: "application/json",
"Accept-Encoding": "application/json"
}
}
})
)
).data;
const apps = res.map((a: any) => ({
const apps = res.map((a) => ({
name: a.service.name,
appId: a.service.id
}));
@@ -309,7 +318,9 @@ const getAppsRailway = async ({ accessToken }: { accessToken: string }) => {
projects: { edges }
}
}
} = await request.post(
} = await request.post<{
data: { projects: { edges: { node: { name: string; id: string } }[] } };
}>(
IntegrationUrls.RAILWAY_API_URL,
{
query,
@@ -324,7 +335,7 @@ const getAppsRailway = async ({ accessToken }: { accessToken: string }) => {
}
);
const apps = edges.map((e: any) => ({
const apps = edges.map((e) => ({
name: e.node.name,
appId: e.node.id
}));
@@ -343,16 +354,19 @@ const getAppsLaravelForge = async ({
serverId?: string;
}) => {
const res = (
await request.get(`${IntegrationUrls.LARAVELFORGE_API_URL}/api/v1/servers/${serverId}/sites`, {
headers: {
Authorization: `Bearer ${accessToken}`,
Accept: "application/json",
"Content-Type": "application/json"
await request.get<{ sites: { name: string; id: string }[] }>(
`${IntegrationUrls.LARAVELFORGE_API_URL}/api/v1/servers/${serverId}/sites`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
Accept: "application/json",
"Content-Type": "application/json"
}
}
})
)
).data.sites;
const apps = res.map((a: any) => ({
const apps = res.map((a) => ({
name: a.name,
appId: a.id
}));
@@ -382,8 +396,8 @@ const getAppsFlyio = async ({ accessToken }: { accessToken: string }) => {
}
`;
const res: FlyioApp[] = (
await request.post(
const res = (
await request.post<{ data: { apps: { nodes: FlyioApp[] } } }>(
IntegrationUrls.FLYIO_API_URL,
{
query,
@@ -401,7 +415,7 @@ const getAppsFlyio = async ({ accessToken }: { accessToken: string }) => {
)
).data.data.apps.nodes;
const apps = res.map((a: FlyioApp) => ({
const apps = res.map((a) => ({
name: a.name,
appId: a.id
}));
@@ -414,7 +428,7 @@ const getAppsFlyio = async ({ accessToken }: { accessToken: string }) => {
*/
const getAppsCircleCI = async ({ accessToken }: { accessToken: string }) => {
const res = (
await request.get(`${IntegrationUrls.CIRCLECI_API_URL}/v1.1/projects`, {
await request.get<{ reponame: string }[]>(`${IntegrationUrls.CIRCLECI_API_URL}/v1.1/projects`, {
headers: {
"Circle-Token": accessToken,
"Accept-Encoding": "application/json"
@@ -422,7 +436,7 @@ const getAppsCircleCI = async ({ accessToken }: { accessToken: string }) => {
})
).data;
const apps = res?.map((a: any) => ({
const apps = res?.map((a) => ({
name: a?.reponame
}));
@@ -431,7 +445,7 @@ const getAppsCircleCI = async ({ accessToken }: { accessToken: string }) => {
const getAppsTravisCI = async ({ accessToken }: { accessToken: string }) => {
const res = (
await request.get(`${IntegrationUrls.TRAVISCI_API_URL}/repos`, {
await request.get<{ id: string; slug: string }[]>(`${IntegrationUrls.TRAVISCI_API_URL}/repos`, {
headers: {
Authorization: `token ${accessToken}`,
"Accept-Encoding": "application/json"
@@ -439,7 +453,7 @@ const getAppsTravisCI = async ({ accessToken }: { accessToken: string }) => {
})
).data;
const apps = res?.map((a: any) => ({
const apps = res?.map((a) => ({
name: a?.slug?.split("/")[1],
appId: a?.id
}));
@@ -458,7 +472,7 @@ const getAppsTerraformCloud = async ({
workspacesId?: string;
}) => {
const res = (
await request.get(
await request.get<{ data: { attributes: { name: string }; id: string } }>(
`${IntegrationUrls.TERRAFORM_CLOUD_API_URL}/api/v2/workspaces/${workspacesId}`,
{
headers: {
@@ -510,15 +524,18 @@ const getAppsGitlab = async ({
per_page: String(perPage)
});
const { data } = await request.get(`${gitLabApiUrl}/v4/groups/${teamId}/projects`, {
params,
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
const { data } = await request.get<{ name: string; id: string }[]>(
`${gitLabApiUrl}/v4/groups/${teamId}/projects`,
{
params,
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
}
}
});
);
data.forEach((a: any) => {
data.forEach((a) => {
apps.push({
name: a.name,
appId: a.id
@@ -535,7 +552,7 @@ const getAppsGitlab = async ({
// case: fetch projects for individual in GitLab
const { id } = (
await request.get(`${gitLabApiUrl}/v4/user`, {
await request.get<{ id: string }>(`${gitLabApiUrl}/v4/user`, {
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
@@ -549,15 +566,18 @@ const getAppsGitlab = async ({
per_page: String(perPage)
});
const { data } = await request.get(`${gitLabApiUrl}/v4/users/${id}/projects`, {
params,
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
const { data } = await request.get<{ name: string; id: string }[]>(
`${gitLabApiUrl}/v4/users/${id}/projects`,
{
params,
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
}
}
});
);
data.forEach((a: any) => {
data.forEach((a) => {
apps.push({
name: a.name,
appId: a.id
@@ -580,7 +600,7 @@ const getAppsGitlab = async ({
*/
const getAppsTeamCity = async ({ accessToken, url }: { url: string; accessToken: string }) => {
const res = (
await request.get(`${url}/app/rest/projects`, {
await request.get<{ project: { name: string; id: string }[] }>(`${url}/app/rest/projects`, {
headers: {
Authorization: `Bearer ${accessToken}`,
Accept: "application/json"
@@ -588,7 +608,7 @@ const getAppsTeamCity = async ({ accessToken, url }: { url: string; accessToken:
})
).data.project.slice(1);
const apps = res.map((a: any) => ({
const apps = res.map((a) => ({
name: a.name,
appId: a.id
}));
@@ -600,14 +620,17 @@ const getAppsTeamCity = async ({ accessToken, url }: { url: string; accessToken:
* Return list of projects for Supabase integration
*/
const getAppsSupabase = async ({ accessToken }: { accessToken: string }) => {
const { data } = await request.get(`${IntegrationUrls.SUPABASE_API_URL}/v1/projects`, {
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
const { data } = await request.get<{ name: string; id: string }[]>(
`${IntegrationUrls.SUPABASE_API_URL}/v1/projects`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
}
}
});
);
const apps = data.map((a: any) => ({
const apps = data.map((a) => ({
name: a.name,
appId: a.id
}));
@@ -619,14 +642,17 @@ const getAppsSupabase = async ({ accessToken }: { accessToken: string }) => {
* Return list of accounts for the Checkly integration
*/
const getAppsCheckly = async ({ accessToken }: { accessToken: string }) => {
const { data } = await request.get(`${IntegrationUrls.CHECKLY_API_URL}/v1/accounts`, {
headers: {
Authorization: `Bearer ${accessToken}`,
Accept: "application/json"
const { data } = await request.get<{ name: string; id: string }[]>(
`${IntegrationUrls.CHECKLY_API_URL}/v1/accounts`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
Accept: "application/json"
}
}
});
);
const apps = data.map((a: any) => ({
const apps = data.map((a) => ({
name: a.name,
appId: a.id
}));
@@ -644,7 +670,7 @@ const getAppsCloudflarePages = async ({
accessToken: string;
accountId?: string;
}) => {
const { data } = await request.get(
const { data } = await request.get<{ result: { name: string; id: string }[] }>(
`${IntegrationUrls.CLOUDFLARE_PAGES_API_URL}/client/v4/accounts/${accountId}/pages/projects`,
{
headers: {
@@ -654,7 +680,7 @@ const getAppsCloudflarePages = async ({
}
);
const apps = data.result.map((a: any) => ({
const apps = data.result.map((a) => ({
name: a.name,
appId: a.id
}));
@@ -671,7 +697,7 @@ const getAppsCloudflareWorkers = async ({
accessToken: string;
accountId?: string;
}) => {
const { data } = await request.get(
const { data } = await request.get<{ result: { id: string }[] }>(
`${IntegrationUrls.CLOUDFLARE_WORKERS_API_URL}/client/v4/accounts/${accountId}/workers/services`,
{
headers: {
@@ -681,7 +707,7 @@ const getAppsCloudflareWorkers = async ({
}
);
const apps = data.result.map((a: any) => ({
const apps = data.result.map((a) => ({
name: a.id,
appId: a.id
}));
@@ -759,14 +785,17 @@ const getAppsNorthflank = async ({ accessToken }: { accessToken: string }) => {
data: {
data: { projects }
}
} = await request.get(`${IntegrationUrls.NORTHFLANK_API_URL}/v1/projects`, {
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
} = await request.get<{ data: { projects: { name: string; id: string }[] } }>(
`${IntegrationUrls.NORTHFLANK_API_URL}/v1/projects`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
}
}
});
);
const apps = projects.map((a: any) => ({
const apps = projects.map((a) => ({
name: a.name,
appId: a.id
}));
@@ -779,15 +808,18 @@ const getAppsNorthflank = async ({ accessToken }: { accessToken: string }) => {
*/
const getAppsCodefresh = async ({ accessToken }: { accessToken: string }) => {
const res = (
await request.get(`${IntegrationUrls.CODEFRESH_API_URL}/projects`, {
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
await request.get<{ projects: { projectName: string; id: string }[] }>(
`${IntegrationUrls.CODEFRESH_API_URL}/projects`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
}
}
})
)
).data;
const apps = res.projects.map((a: any) => ({
const apps = res.projects.map((a) => ({
name: a.projectName,
appId: a.id
}));
@@ -799,20 +831,23 @@ const getAppsCodefresh = async ({ accessToken }: { accessToken: string }) => {
* Return list of projects for Windmill integration
*/
const getAppsWindmill = async ({ accessToken }: { accessToken: string }) => {
const { data } = await request.get(`${IntegrationUrls.WINDMILL_API_URL}/workspaces/list`, {
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
const { data } = await request.get<{ id: string; name: string }[]>(
`${IntegrationUrls.WINDMILL_API_URL}/workspaces/list`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
}
}
});
);
// check for write access of secrets in windmill workspaces
const writeAccessCheck = data.map(async (app: any) => {
const writeAccessCheck = data.map(async (app) => {
try {
const userPath = "u/user/variable";
const folderPath = "f/folder/variable";
const { data: writeUser } = await request.post(
const { data: writeUser } = await request.post<object>(
`${IntegrationUrls.WINDMILL_API_URL}/w/${app.id}/variables/create`,
{
path: userPath,
@@ -828,7 +863,7 @@ const getAppsWindmill = async ({ accessToken }: { accessToken: string }) => {
}
);
const { data: writeFolder } = await request.post(
const { data: writeFolder } = await request.post<object>(
`${IntegrationUrls.WINDMILL_API_URL}/w/${app.id}/variables/create`,
{
path: folderPath,
@@ -869,15 +904,17 @@ const getAppsWindmill = async ({ accessToken }: { accessToken: string }) => {
return app;
}
return { error: "cannot write secret" };
} catch (err: any) {
return { error: err.message };
} catch (err) {
return { error: (err as Error).message };
}
});
const appsWriteResponses = await Promise.all(writeAccessCheck);
const appsWithWriteAccess = appsWriteResponses.filter((appRes: any) => !appRes.error);
const appsWithWriteAccess = appsWriteResponses.filter(
(appRes) => !(appRes as { error: string })?.error
);
const apps = appsWithWriteAccess.map((a: any) => ({
const apps = (appsWithWriteAccess as { id: string; name: string }[]).map((a) => ({
name: a.name,
appId: a.id
}));
@@ -908,22 +945,27 @@ const getAppsDigitalOceanAppPlatform = async ({ accessToken }: { accessToken: st
}
const res = (
await request.get(`${IntegrationUrls.DIGITAL_OCEAN_API_URL}/v2/apps`, {
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
await request.get<{ apps: DigitalOceanApp[] }>(
`${IntegrationUrls.DIGITAL_OCEAN_API_URL}/v2/apps`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
}
}
})
)
).data;
return (res.apps ?? []).map((a: DigitalOceanApp) => ({
return (res.apps ?? []).map((a) => ({
name: a.spec.name,
appId: a.id
}));
};
const getAppsHasuraCloud = async ({ accessToken }: { accessToken: string }) => {
const res = await request.post(
const res = await request.post<{
data: { projects: { name: string; tenant: { id: string } }[] };
}>(
IntegrationUrls.HASURA_CLOUD_API_URL,
{
query: "query MyQuery { projects { name tenant { id } } }"
@@ -936,19 +978,15 @@ const getAppsHasuraCloud = async ({ accessToken }: { accessToken: string }) => {
}
);
const data = (res?.data?.data?.projects ?? []).map(
({ name, tenant: { id: appId } }: { name: string; tenant: { id: string } }) => ({ name, appId })
);
const data = (res?.data?.data?.projects ?? []).map(({ name, tenant: { id: appId } }) => ({
name,
appId
}));
return data;
};
/**
* Return list of applications for Cloud66 integration
* @param {Object} obj
* @param {String} obj.accessToken - personal access token for Cloud66 API
* @returns {Object[]} apps - Cloud66 apps
* @returns {String} apps.name - name of Cloud66 app
* @returns {String} apps.appId - uid of Cloud66 app
*/
const getAppsCloud66 = async ({ accessToken }: { accessToken: string }) => {
interface Cloud66Apps {
@@ -979,19 +1017,19 @@ const getAppsCloud66 = async ({ accessToken }: { accessToken: string }) => {
account_name: string;
is_cluster: boolean;
is_inside_cluster: boolean;
cluster_name: any;
cluster_name: string;
application_address: string;
configstore_namespace: string;
}
const stacks = (
await request.get(`${IntegrationUrls.CLOUD_66_API_URL}/3/stacks`, {
await request.get<{ response: Cloud66Apps[] }>(`${IntegrationUrls.CLOUD_66_API_URL}/3/stacks`, {
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
}
})
).data.response as Cloud66Apps[];
).data.response;
const apps = stacks.map((app) => ({
name: app.name,
@@ -1016,7 +1054,7 @@ export const getApps = async ({
workspaceSlug?: string;
url?: string | null;
}): Promise<App[]> => {
switch (integration) {
switch (integration as Integrations) {
case Integrations.GCP_SECRET_MANAGER:
return getAppsGCPSecretManager({
accessToken
@@ -906,7 +906,7 @@ export const integrationAuthServiceFactory = ({
}
);
secrets.forEach((a: any) => {
secrets.forEach((a) => {
secretGroups.push({
name: a.name,
groupId: a.id
@@ -67,6 +67,7 @@ export enum IntegrationUrls {
QOVERY_API_URL = "https://api.qovery.com",
TERRAFORM_CLOUD_API_URL = "https://app.terraform.io",
CLOUDFLARE_PAGES_API_URL = "https://api.cloudflare.com",
// eslint-disable-next-line
CLOUDFLARE_WORKERS_API_URL = "https://api.cloudflare.com",
BITBUCKET_API_URL = "https://api.bitbucket.org",
CODEFRESH_API_URL = "https://g.codefresh.io/api",
@@ -1,4 +1,11 @@
/* eslint-disable @typescript-eslint/no-unsafe-return */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-argument */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable no-param-reassign,no-await-in-loop */
// Taken from old code and too much work at present thus disabling the above any rules
// resolve it later: akhilmhdh - TODO
import {
CreateSecretCommand,
GetSecretValueCommand,
@@ -8,6 +15,7 @@ import {
} from "@aws-sdk/client-secrets-manager";
import { Octokit } from "@octokit/rest";
import AWS from "aws-sdk";
import { AxiosError } from "axios";
import sodium from "libsodium-wrappers";
import isEqual from "lodash.isequal";
import { z } from "zod";
@@ -87,8 +95,8 @@ const syncSecretsGCPSecretManager = async ({
...(pageToken ? { pageToken } : {})
});
const res: GCPSMListSecretsRes = (
await request.get(
const res = (
await request.get<GCPSMListSecretsRes>(
`${IntegrationUrls.GCP_SECRET_MANAGER_URL}/v1/projects/${integration.appId}/secrets${filterParam}`,
{
params,
@@ -309,7 +317,7 @@ const syncSecretsAzureKeyVault = async ({
})
)
).reduce(
(obj: any, secret: any) => ({
(obj, secret) => ({
...obj,
[secret.key]: secret
}),
@@ -378,8 +386,9 @@ const syncSecretsAzureKeyVault = async ({
isSecretSet = true;
} catch (err) {
const error: any = err;
if (error?.response?.data?.error?.innererror?.code === "ObjectIsDeletedButRecoverable") {
const error = err as AxiosError;
// eslint-disable-next-line
if ((error?.response?.data as any)?.error?.innererror?.code === "ObjectIsDeletedButRecoverable") {
await request.post(
`${azIntegration.app}/deletedsecrets/${key}/recover?api-version=7.3`,
{},
@@ -405,7 +414,7 @@ const syncSecretsAzureKeyVault = async ({
// Sync/push set secrets
for await (const setSecret of setSecrets) {
const { key, value } = setSecret;
setSecretAzureKeyVault({
await setSecretAzureKeyVault({
key,
value,
integration,
@@ -425,11 +434,6 @@ const syncSecretsAzureKeyVault = async ({
/**
* Sync/push [secrets] to AWS parameter store
* @param {Object} obj
* @param {TIntegrations} obj.integration - integration details
* @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values)
* @param {String} obj.accessId - access id for AWS parameter store integration
* @param {String} obj.accessToken - access token for AWS parameter store integration
*/
const syncSecretsAWSParameterStore = async ({
integration,
@@ -463,60 +467,60 @@ const syncSecretsAWSParameterStore = async ({
const parameterList = (await ssm.getParametersByPath(params).promise()).Parameters;
let awsParameterStoreSecretsObj: {
[key: string]: any;
} = {};
if (parameterList) {
awsParameterStoreSecretsObj = parameterList.reduce(
(obj: any, secret: any) => ({
const awsParameterStoreSecretsObj = (parameterList || [])
.filter(({ Name }) => Boolean(Name))
.reduce(
(obj, secret) => ({
...obj,
[secret.Name.substring((integration.path as string).length)]: secret
[(secret.Name as string).substring((integration.path as string).length)]: secret
}),
{}
{} as Record<string, AWS.SSM.Parameter>
);
}
// Identify secrets to create
Object.keys(secrets).map(async (key) => {
if (!(key in awsParameterStoreSecretsObj)) {
// case: secret does not exist in AWS parameter store
// -> create secret
await ssm
.putParameter({
Name: `${integration.path}${key}`,
Type: "SecureString",
Value: secrets[key].value,
Overwrite: true
})
.promise();
// case: secret exists in AWS parameter store
} else if (awsParameterStoreSecretsObj[key].Value !== secrets[key].value) {
// case: secret value doesn't match one in AWS parameter store
// -> update secret
await ssm
.putParameter({
Name: `${integration.path}${key}`,
Type: "SecureString",
Value: secrets[key].value,
Overwrite: true
})
.promise();
}
});
await Promise.all(
Object.keys(secrets).map(async (key) => {
if (!(key in awsParameterStoreSecretsObj)) {
// case: secret does not exist in AWS parameter store
// -> create secret
await ssm
.putParameter({
Name: `${integration.path}${key}`,
Type: "SecureString",
Value: secrets[key].value,
Overwrite: true
})
.promise();
// case: secret exists in AWS parameter store
} else if (awsParameterStoreSecretsObj[key].Value !== secrets[key].value) {
// case: secret value doesn't match one in AWS parameter store
// -> update secret
await ssm
.putParameter({
Name: `${integration.path}${key}`,
Type: "SecureString",
Value: secrets[key].value,
Overwrite: true
})
.promise();
}
})
);
// Identify secrets to delete
Object.keys(awsParameterStoreSecretsObj).map(async (key) => {
if (!(key in secrets)) {
// case:
// -> delete secret
await ssm
.deleteParameter({
Name: awsParameterStoreSecretsObj[key].Name
})
.promise();
}
});
await Promise.all(
Object.keys(awsParameterStoreSecretsObj).map(async (key) => {
if (!(key in secrets)) {
// case:
// -> delete secret
await ssm
.deleteParameter({
Name: awsParameterStoreSecretsObj[key].Name as string
})
.promise();
}
})
);
AWS.config.update({
region: undefined,
@@ -564,7 +568,7 @@ const syncSecretsAWSSecretManager = async ({
})
);
let awsSecretManagerSecretObj: { [key: string]: any } = {};
let awsSecretManagerSecretObj: { [key: string]: AWS.SecretsManager } = {};
if (awsSecretManagerSecret?.SecretString) {
awsSecretManagerSecretObj = JSON.parse(awsSecretManagerSecret.SecretString);
@@ -680,15 +684,18 @@ const syncSecretsVercel = async ({
: {})
};
const vercelSecrets: VercelSecret[] = (
await request.get(`${IntegrationUrls.VERCEL_API_URL}/v9/projects/${integration.app}/env`, {
params,
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
const vercelSecrets = (
await request.get<{ envs: VercelSecret[] }>(
`${IntegrationUrls.VERCEL_API_URL}/v9/projects/${integration.app}/env`,
{
params,
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
}
}
})
).data.envs.filter((secret: VercelSecret) => {
)
).data.envs.filter((secret) => {
if (!secret.target.includes(integration.targetEnvironment as string)) {
// case: secret does not have the same target environment
return false;
@@ -866,7 +873,7 @@ const syncSecretsNetlify = async ({
});
const res = (
await request.get(
await request.get<NetlifySecret[]>(
`${IntegrationUrls.NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env`,
{
params: getParams,
@@ -877,11 +884,11 @@ const syncSecretsNetlify = async ({
}
)
).data.reduce(
(obj: any, secret: any) => ({
(obj, secret) => ({
...obj,
[secret.key]: secret
}),
{}
{} as Record<string, NetlifySecret>
);
const newSecrets: NetlifySecret[] = []; // createEnvVars
@@ -905,16 +912,16 @@ const syncSecretsNetlify = async ({
} else {
// case: Infisical secret exists in Netlify
const contexts = res[key].values.reduce(
(obj: any, value: NetlifyValue) => ({
(obj, value) => ({
...obj,
[value.context]: value
}),
{}
{} as Record<string, NetlifyValue>
);
if ((integration.targetEnvironment as string) in contexts) {
// case: Netlify secret value exists in integration context
if (secrets[key] !== contexts[integration.targetEnvironment as string].value) {
if (secrets[key].value !== contexts[integration.targetEnvironment as string].value) {
// case: Infisical and Netlify secret values are different
// -> update Netlify secret context and value
updateSecrets.push({
@@ -994,62 +1001,63 @@ const syncSecretsNetlify = async ({
}
if (updateSecrets.length > 0) {
updateSecrets.forEach(async (secret: NetlifySecret) => {
await request.patch(
`${IntegrationUrls.NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${secret.key}`,
{
context: secret.values[0].context,
value: secret.values[0].value
},
{
params: syncParams,
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
await Promise.all(
updateSecrets.map(async (secret: NetlifySecret) => {
await request.patch(
`${IntegrationUrls.NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${secret.key}`,
{
context: secret.values[0].context,
value: secret.values[0].value
},
{
params: syncParams,
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
}
}
}
);
});
);
})
);
}
if (deleteSecrets.length > 0) {
deleteSecrets.forEach(async (key: string) => {
await request.delete(
`${IntegrationUrls.NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${key}`,
{
params: syncParams,
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
await Promise.all(
deleteSecrets.map(async (key: string) => {
await request.delete(
`${IntegrationUrls.NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${key}`,
{
params: syncParams,
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
}
}
}
);
});
);
})
);
}
if (deleteSecretValues.length > 0) {
deleteSecretValues.forEach(async (secret: NetlifySecret) => {
await request.delete(
`${IntegrationUrls.NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${secret.key}/value/${secret.values[0].id}`,
{
params: syncParams,
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
await Promise.all(
deleteSecretValues.map(async (secret: NetlifySecret) => {
await request.delete(
`${IntegrationUrls.NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${secret.key}/value/${secret.values[0].id}`,
{
params: syncParams,
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
}
}
}
);
});
);
})
);
}
};
/**
* Sync/push [secrets] to GitHub repo with name [integration.app]
* @param {Object} obj
* @param {TIntegrations} obj.integration - integration details
* @param {TIntegrationAuth} obj.integrationAuth - integration auth details
* @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values)
* @param {String} obj.accessToken - access token for GitHub integration
*/
const syncSecretsGitHub = async ({
integration,
@@ -1096,7 +1104,7 @@ const syncSecretsGitHub = async ({
repo: integration.app as string
})
).data.secrets.reduce(
(obj: any, secret: any) => ({
(obj, secret) => ({
...obj,
[secret.name]: secret
}),
@@ -1121,46 +1129,46 @@ const syncSecretsGitHub = async ({
{}
);
Object.keys(encryptedSecrets).map(async (key) => {
if (!(key in secrets)) {
await octokit.request("DELETE /repos/{owner}/{repo}/actions/secrets/{secret_name}", {
owner: integration.owner as string,
repo: integration.app as string,
secret_name: key
await Promise.all(
Object.keys(encryptedSecrets).map(async (key) => {
if (!(key in secrets)) {
return octokit.request("DELETE /repos/{owner}/{repo}/actions/secrets/{secret_name}", {
owner: integration.owner as string,
repo: integration.app as string,
secret_name: key
});
}
})
);
await Promise.all(
Object.keys(secrets).map((key) => {
// let encryptedSecret;
return sodium.ready.then(async () => {
// convert secret & base64 key to Uint8Array.
const binkey = sodium.from_base64(repoPublicKey.key, sodium.base64_variants.ORIGINAL);
const binsec = sodium.from_string(secrets[key].value);
// encrypt secret using libsodium
const encBytes = sodium.crypto_box_seal(binsec, binkey);
// convert encrypted Uint8Array to base64
const encryptedSecret = sodium.to_base64(encBytes, sodium.base64_variants.ORIGINAL);
await octokit.request("PUT /repos/{owner}/{repo}/actions/secrets/{secret_name}", {
owner: integration.owner as string,
repo: integration.app as string,
secret_name: key,
encrypted_value: encryptedSecret,
key_id: repoPublicKey.key_id
});
});
}
});
Object.keys(secrets).forEach((key) => {
// let encryptedSecret;
sodium.ready.then(async () => {
// convert secret & base64 key to Uint8Array.
const binkey = sodium.from_base64(repoPublicKey.key, sodium.base64_variants.ORIGINAL);
const binsec = sodium.from_string(secrets[key].value);
// encrypt secret using libsodium
const encBytes = sodium.crypto_box_seal(binsec, binkey);
// convert encrypted Uint8Array to base64
const encryptedSecret = sodium.to_base64(encBytes, sodium.base64_variants.ORIGINAL);
await octokit.request("PUT /repos/{owner}/{repo}/actions/secrets/{secret_name}", {
owner: integration.owner as string,
repo: integration.app as string,
secret_name: key,
encrypted_value: encryptedSecret,
key_id: repoPublicKey.key_id
});
});
});
})
);
};
/**
* Sync/push [secrets] to Render service with id [integration.appId]
* @param {Object} obj
* @param {TIntegrations} obj.integration - integration details
* @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values)
* @param {String} obj.accessToken - access token for Render integration
*/
const syncSecretsRender = async ({
integration,
@@ -1188,10 +1196,6 @@ const syncSecretsRender = async ({
/**
* Sync/push [secrets] to Laravel Forge sites with id [integration.appId]
* @param {Object} obj
* @param {TIntegrations} obj.integration - integration details
* @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values)
* @param {String} obj.accessToken - access token for Laravel Forge integration
*/
const syncSecretsLaravelForge = async ({
integration,
@@ -1204,13 +1208,11 @@ const syncSecretsLaravelForge = async ({
accessId: string | null;
accessToken: string;
}) => {
function transformObjectToString(obj: any) {
function transformObjectToString(obj: Record<string, { value: string }>) {
let result = "";
for (const key in obj) {
if (obj.hasOwnPropery(key)) {
result += `${key}=${obj[key].value}\n`;
}
}
Object.keys(obj).forEach((key) => {
result += `${key}=${obj[key].value}\n`;
});
return result;
}
@@ -1231,10 +1233,6 @@ const syncSecretsLaravelForge = async ({
/**
* Sync/push [secrets] to Railway project with id [integration.appId]
* @param {Object} obj
* @param {TIntegrations} obj.integration - integration details
* @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values)
* @param {String} obj.accessToken - access token for Railway integration
*/
const syncSecretsRailway = async ({
integration,
@@ -1279,10 +1277,6 @@ const syncSecretsRailway = async ({
/**
* Sync/push [secrets] to Fly.io app
* @param {Object} obj
* @param {TIntegrations} obj.integration - integration details
* @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values)
* @param {String} obj.accessToken - access token for Render integration
*/
const syncSecretsFlyio = async ({
integration,
@@ -1354,7 +1348,7 @@ const syncSecretsFlyio = async ({
}`;
const getSecretsRes = (
await request.post(
await request.post<{ data: { app: { secrets: FlyioSecret[] } } }>(
IntegrationUrls.FLYIO_API_URL,
{
query: GetSecrets,
@@ -1373,8 +1367,8 @@ const syncSecretsFlyio = async ({
).data.data.app.secrets;
const deleteSecretsKeys = getSecretsRes
.filter((secret: FlyioSecret) => !(secret.name in secrets))
.map((secret: FlyioSecret) => secret.name);
.filter((secret) => !(secret.name in secrets))
.map((secret) => secret.name);
// unset (delete) secrets
const DeleteSecrets = `mutation($input: UnsetSecretsInput!) {
@@ -1460,7 +1454,7 @@ const syncSecretsCircleCI = async ({
// get secrets from CircleCI
const getSecretsRes = (
await request.get(
await request.get<{ items: { name: string }[] }>(
`${IntegrationUrls.CIRCLECI_API_URL}/v2/project/${slug}/${integration.app}/envvar`,
{
headers: {
@@ -1472,19 +1466,21 @@ const syncSecretsCircleCI = async ({
).data?.items;
// delete secrets from CircleCI
getSecretsRes.forEach(async (sec: any) => {
if (!(sec.name in secrets)) {
await request.delete(
`${IntegrationUrls.CIRCLECI_API_URL}/v2/project/${slug}/${integration.app}/envvar/${sec.name}`,
{
headers: {
"Circle-Token": accessToken,
"Content-Type": "application/json"
await Promise.all(
getSecretsRes.map(async (sec) => {
if (!(sec.name in secrets)) {
return request.delete(
`${IntegrationUrls.CIRCLECI_API_URL}/v2/project/${slug}/${integration.app}/envvar/${sec.name}`,
{
headers: {
"Circle-Token": accessToken,
"Content-Type": "application/json"
}
}
}
);
}
});
);
}
})
);
};
/**
@@ -1501,21 +1497,20 @@ const syncSecretsTravisCI = async ({
}) => {
// get secrets from travis-ci
const getSecretsRes = (
await request.get(
`${IntegrationUrls.TRAVISCI_API_URL}/settings/env_vars?repository_id=${integration.appId}`,
{
headers: {
Authorization: `token ${accessToken}`,
"Accept-Encoding": "application/json"
}
await request.get<{
env_vars: { name: string; value: string; repository_id: string; id: string }[];
}>(`${IntegrationUrls.TRAVISCI_API_URL}/settings/env_vars?repository_id=${integration.appId}`, {
headers: {
Authorization: `token ${accessToken}`,
"Accept-Encoding": "application/json"
}
)
})
).data?.env_vars.reduce(
(obj: any, secret: any) => ({
(obj, secret) => ({
...obj,
[secret.name]: secret
}),
{}
{} as Record<string, { name: string; value: string; repository_id: string; id: string }>
);
// add secrets
@@ -1614,10 +1609,10 @@ const syncSecretsGitLab = async ({
`${gitLabApiUrl}/v4/projects/${integrationAppId}/variables?per_page=100`;
while (url) {
const response: any = await request.get(url, { headers });
const response = await request.get(url, { headers });
allEnvVariables = [...allEnvVariables, ...response.data];
const linkHeader = response.headers.link;
const linkHeader = response.headers.link as string;
const nextLink = linkHeader?.split(",").find((part: string) => part.includes('rel="next"'));
if (nextLink) {
@@ -1649,7 +1644,7 @@ const syncSecretsGitLab = async ({
});
for await (const key of Object.keys(secrets)) {
const existingSecret = getSecretsRes.find((s: any) => s.key === key);
const existingSecret = getSecretsRes.find((s) => s.key === key);
if (!existingSecret) {
await request.post(
`${gitLabApiUrl}/v4/projects/${integration?.appId}/variables`,
@@ -1714,7 +1709,7 @@ const syncSecretsSupabase = async ({
secrets: Record<string, { value: string; comment?: string }>;
accessToken: string;
}) => {
const { data: getSecretsRes } = await request.get(
const { data: getSecretsRes } = await request.get<{ name: string; value: string }[]>(
`${IntegrationUrls.SUPABASE_API_URL}/v1/projects/${integration.appId}/secrets`,
{
headers: {
@@ -1741,8 +1736,7 @@ const syncSecretsSupabase = async ({
}
);
const secretsToDelete: any = [];
getSecretsRes?.forEach((secretObj: any) => {
const secretsToDelete = getSecretsRes?.flatMap((secretObj) => {
if (
!(secretObj.name in secrets) &&
// supbase reserved secret ref: https://supabase.com/docs/guides/functions/secrets#default-secrets
@@ -1753,8 +1747,9 @@ const syncSecretsSupabase = async ({
"SUPABASE_URL"
].includes(secretObj.name)
) {
secretsToDelete.push(secretObj.name);
return secretObj.name;
}
return [];
});
await request.delete(
@@ -1788,7 +1783,7 @@ const syncSecretsCheckly = async ({
// sync secrets to checkly group envars
let getGroupSecretsRes = (
await request.get(
await request.get<{ environmentVariables: { key: string; value: string }[] }>(
`${IntegrationUrls.CHECKLY_API_URL}/v1/check-groups/${integration.targetServiceId}`,
{
headers: {
@@ -1799,11 +1794,11 @@ const syncSecretsCheckly = async ({
}
)
).data.environmentVariables.reduce(
(obj: any, secret: any) => ({
(obj, secret) => ({
...obj,
[secret.key]: secret.value
}),
{}
{} as Record<string, string>
);
getGroupSecretsRes = Object.keys(getGroupSecretsRes).reduce(
@@ -1846,19 +1841,22 @@ const syncSecretsCheckly = async ({
// sync secrets to checkly global envars
let getSecretsRes = (
await request.get(`${IntegrationUrls.CHECKLY_API_URL}/v1/variables`, {
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json",
"X-Checkly-Account": integration.appId
await request.get<{ key: string; value: string }[]>(
`${IntegrationUrls.CHECKLY_API_URL}/v1/variables`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json",
"X-Checkly-Account": integration.appId
}
}
})
)
).data.reduce(
(obj: any, secret: any) => ({
(obj, secret) => ({
...obj,
[secret.key]: secret.value
}),
{}
{} as Record<string, string>
);
getSecretsRes = Object.keys(getSecretsRes).reduce(
@@ -1901,7 +1899,7 @@ const syncSecretsCheckly = async ({
);
// case: secret exists in checkly
// -> update/set secret
} else if (secrets[key] !== getSecretsRes[key]) {
} else if (secrets[key].value !== getSecretsRes[key]) {
await request.put(
`${IntegrationUrls.CHECKLY_API_URL}/v1/variables/${key}`,
{
@@ -1951,7 +1949,7 @@ const syncSecretsQovery = async ({
accessToken: string;
}) => {
const getSecretsRes = (
await request.get(
await request.get<{ results: { id: string; value: string; key: string }[] }>(
`${IntegrationUrls.QOVERY_API_URL}/${integration.scope}/${integration.appId}/environmentVariable`,
{
headers: {
@@ -1961,11 +1959,11 @@ const syncSecretsQovery = async ({
}
)
).data.results.reduce(
(obj: any, secret: any) => ({
(obj, secret) => ({
...obj,
[secret.key]: { id: secret.id, value: secret.value }
}),
{}
{} as Record<string, { id: string; value: string }>
);
// add secrets
@@ -2042,7 +2040,7 @@ const syncSecretsTerraformCloud = async ({
}) => {
// get secrets from Terraform Cloud
const getSecretsRes = (
await request.get(
await request.get<{ data: { attributes: { key: string; value: string }; id: string }[] }>(
`${IntegrationUrls.TERRAFORM_CLOUD_API_URL}/api/v2/workspaces/${integration.appId}/vars`,
{
headers: {
@@ -2052,11 +2050,11 @@ const syncSecretsTerraformCloud = async ({
}
)
).data.data.reduce(
(obj: any, secret: any) => ({
(obj, secret) => ({
...obj,
[secret.attributes.key]: secret
}),
{}
{} as Record<string, { attributes: { key: string; value: string }; id: string }>
);
// create or update secrets on Terraform Cloud
@@ -2138,7 +2136,7 @@ const syncSecretsTeamCity = async ({
}: {
integrationAuth: TIntegrationAuths;
integration: TIntegrations;
secrets: any;
secrets: Record<string, { value: string; comment?: string }>;
accessToken: string;
}) => {
interface TeamCitySecret {
@@ -2171,13 +2169,16 @@ const syncSecretsTeamCity = async ({
)
).data.property
.filter((parameter) => !parameter.inherited)
.reduce((obj: any, secret: TeamCitySecret) => {
const secretName = secret.name.replace(/^env\./, "");
return {
...obj,
[secretName]: secret.value
};
}, {});
.reduce(
(obj, secret) => {
const secretName = secret.name.replace(/^env\./, "");
return {
...obj,
[secretName]: secret.value
};
},
{} as Record<string, string>
);
for await (const key of Object.keys(secrets)) {
if (!(key in res) || (key in res && secrets[key].value !== res[key])) {
@@ -2216,7 +2217,7 @@ const syncSecretsTeamCity = async ({
} else {
// case: sync to TeamCity project
const res = (
await request.get(
await request.get<{ property: TeamCitySecret[] }>(
`${integrationAuth.url}/app/rest/projects/id:${integration.appId}/parameters`,
{
headers: {
@@ -2225,16 +2226,19 @@ const syncSecretsTeamCity = async ({
}
}
)
).data.property.reduce((obj: any, secret: TeamCitySecret) => {
const secretName = secret.name.replace(/^env\./, "");
return {
...obj,
[secretName]: secret.value
};
}, {});
).data.property.reduce(
(obj, secret) => {
const secretName = secret.name.replace(/^env\./, "");
return {
...obj,
[secretName]: secret.value
};
},
{} as Record<string, string>
);
for await (const key of Object.keys(secrets)) {
if (!(key in res) || (key in res && secrets[key] !== res[key])) {
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 request.post(
@@ -2347,7 +2351,9 @@ const syncSecretsCloudflarePages = async ({
}) => {
// get secrets from cloudflare pages
const getSecretsRes = (
await request.get(
await request.get<{
result: { deployment_configs: Record<string, { env_vars: Record<string, unknown> }> };
}>(
`${IntegrationUrls.CLOUDFLARE_PAGES_API_URL}/client/v4/accounts/${accessId}/pages/projects/${integration.app}`,
{
headers: {
@@ -2359,21 +2365,12 @@ const syncSecretsCloudflarePages = async ({
).data.result.deployment_configs[integration.targetEnvironment as string].env_vars;
// copy the secrets object, so we can set deleted keys to null
const secretsObj: any = getSecretKeyValuePair(secrets);
for (const [key, val] of Object.entries(secretsObj)) {
secretsObj[key] = { type: "secret_text", value: val };
}
if (getSecretsRes) {
for await (const key of Object.keys(getSecretsRes)) {
if (!(key in secrets)) {
// case: secret does not exist in infisical
// -> delete secret from cloudflare pages
secretsObj[key] = null;
}
}
}
const secretsObj = Object.fromEntries(
Object.entries(getSecretKeyValuePair(secrets)).map(([key, val]) => [
key,
key in Object.keys(getSecretsRes) ? { type: "secret_text", value: val } : null
])
);
const data = {
deployment_configs: {
@@ -2411,7 +2408,7 @@ const syncSecretsCloudflareWorkers = async ({
}) => {
// get secrets from cloudflare workers
const getSecretsRes = (
await request.get(
await request.get<{ result: { name: string }[] }>(
`${IntegrationUrls.CLOUDFLARE_WORKERS_API_URL}/client/v4/accounts/${accessId}/workers/scripts/${integration.app}/secrets`,
{
headers: {
@@ -2422,33 +2419,36 @@ const syncSecretsCloudflareWorkers = async ({
)
).data.result;
const secretsObj: any = getSecretKeyValuePair(secrets);
for (const [key, val] of Object.entries(secretsObj)) {
secretsObj[key] = { type: "secret_text", value: val };
}
const secretsObj = Object.fromEntries(
Object.entries(getSecretKeyValuePair(secrets)).map(([key, val]) => [
key,
{ type: "secret_text", value: val }
])
);
// get deleted secrets list
const deletedSecretKeys: string[] = [];
if (getSecretsRes) {
getSecretsRes.forEach((secretRes: any) => {
getSecretsRes.forEach((secretRes) => {
if (!Object.keys(secrets).includes(secretRes.name)) {
deletedSecretKeys.push(secretRes.name);
}
});
}
deletedSecretKeys.forEach(async (secretKey) => {
await request.delete(
`${IntegrationUrls.CLOUDFLARE_WORKERS_API_URL}/client/v4/accounts/${accessId}/workers/scripts/${integration.app}/secrets/${secretKey}`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
Accept: "application/json"
await Promise.all(
deletedSecretKeys.map(async (secretKey) => {
return request.delete(
`${IntegrationUrls.CLOUDFLARE_WORKERS_API_URL}/client/v4/accounts/${accessId}/workers/scripts/${integration.app}/secrets/${secretKey}`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
Accept: "application/json"
}
}
}
);
});
);
})
);
interface ConvertedSecret {
name: string;
@@ -2471,27 +2471,24 @@ const syncSecretsCloudflareWorkers = async ({
})
);
data.forEach(async (secret) => {
await request.put(
`${IntegrationUrls.CLOUDFLARE_WORKERS_API_URL}/client/v4/accounts/${accessId}/workers/scripts/${integration.app}/secrets`,
secret,
{
headers: {
Authorization: `Bearer ${accessToken}`,
Accept: "application/json"
await Promise.all(
data.map(async (secret) => {
return request.put(
`${IntegrationUrls.CLOUDFLARE_WORKERS_API_URL}/client/v4/accounts/${accessId}/workers/scripts/${integration.app}/secrets`,
secret,
{
headers: {
Authorization: `Bearer ${accessToken}`,
Accept: "application/json"
}
}
}
);
});
);
})
);
};
/**
* Sync/push [secrets] to BitBucket repo with name [integration.app]
* @param {Object} obj
* @param {TIntegrations} obj.integration - integration details
* @param {TIntegrationAuth} obj.integrationAuth - integration auth details
* @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values)
* @param {String} obj.accessToken - access token for BitBucket integration
*/
const syncSecretsBitBucket = async ({
integration,
@@ -2700,18 +2697,21 @@ const syncSecretsWindmill = async ({
// get secrets stored in windmill workspace
const res = (
await request.get(`${IntegrationUrls.WINDMILL_API_URL}/w/${integration.appId}/variables/list`, {
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
await request.get<WindmillSecret[]>(
`${IntegrationUrls.WINDMILL_API_URL}/w/${integration.appId}/variables/list`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
}
}
})
)
).data.reduce(
(obj: any, secret: WindmillSecret) => ({
(obj, secret) => ({
...obj,
[secret.path]: secret
}),
{}
{} as Record<string, WindmillSecret>
);
// eslint-disable-next-line
@@ -2778,11 +2778,6 @@ const syncSecretsWindmill = async ({
/**
* Sync/push [secrets] to Cloud66 application with name [integration.app]
* @param {Object} obj
* @param {TIntegrations} obj.integration - integration details
* @param {TIntegrationAuth} obj.integrationAuth - integration auth details
* @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values)
* @param {String} obj.accessToken - access token for Cloud66 integration
*/
const syncSecretsCloud66 = async ({
integration,
@@ -2802,12 +2797,12 @@ const syncSecretsCloud66 = async ({
updated_at: string;
is_password: boolean;
is_generated: boolean;
history: any[];
history: unknown[];
}
// get all current secrets
const res = (
await request.get(
await request.get<{ response: Cloud66Secret[] }>(
`${IntegrationUrls.CLOUD_66_API_URL}/3/stacks/${integration.appId}/environments`,
{
headers: {
@@ -2817,9 +2812,9 @@ const syncSecretsCloud66 = async ({
}
)
).data.response
.filter((secret: Cloud66Secret) => !secret.readonly || !secret.is_generated)
.filter((secret) => !secret.readonly || !secret.is_generated)
.reduce(
(obj: any, secret: any) => ({
(obj, secret) => ({
...obj,
[secret.key]: secret
}),
@@ -1,7 +1,7 @@
import { request } from "@app/lib/config/request";
import { BadRequestError } from "@app/lib/errors";
import { Integrations,IntegrationUrls } from "./integration-list";
import { Integrations, IntegrationUrls } from "./integration-list";
type Team = {
name: string;
@@ -12,7 +12,7 @@ const getTeamsGitLab = async ({ url, accessToken }: { url: string; accessToken:
let teams: Team[] = [];
const res = (
await request.get(`${gitLabApiUrl}/v4/groups`, {
await request.get<{ name: string; id: string }[]>(`${gitLabApiUrl}/v4/groups`, {
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
@@ -20,7 +20,7 @@ const getTeamsGitLab = async ({ url, accessToken }: { url: string; accessToken:
})
).data;
teams = res.map((t: any) => ({
teams = res.map((t) => ({
name: t.name,
teamId: t.id
}));
@@ -80,8 +80,8 @@ const exchangeCodeGCP = async ({ code }: { code: string }) => {
throw new BadRequestError({ message: "Missing client id and client secret" });
}
const res: ExchangeCodeGCPResponse = (
await request.post(
const res = (
await request.post<ExchangeCodeGCPResponse>(
IntegrationUrls.GCP_TOKEN_URL,
new URLSearchParams({
grant_type: "authorization_code",
@@ -108,8 +108,8 @@ const exchangeCodeAzure = async ({ code }: { code: string }) => {
if (!appCfg.CLIENT_ID_AZURE || !appCfg.CLIENT_SECRET_AZURE) {
throw new BadRequestError({ message: "Missing client id and client secret" });
}
const res: ExchangeCodeAzureResponse = (
await request.post(
const res = (
await request.post<ExchangeCodeAzureResponse>(
IntegrationUrls.AZURE_TOKEN_URL,
new URLSearchParams({
grant_type: "authorization_code",
@@ -118,7 +118,7 @@ const exchangeCodeAzure = async ({ code }: { code: string }) => {
client_id: appCfg.CLIENT_ID_AZURE,
client_secret: appCfg.CLIENT_SECRET_AZURE,
redirect_uri: `${appCfg.SITE_URL}/integrations/azure-key-vault/oauth2/callback`
} as any)
})
)
).data;
@@ -138,8 +138,8 @@ const exchangeCodeHeroku = async ({ code }: { code: string }) => {
throw new BadRequestError({ message: "Missing client id and client secret" });
}
const res: ExchangeCodeHerokuResponse = (
await request.post(
const res = (
await request.post<ExchangeCodeHerokuResponse>(
IntegrationUrls.HEROKU_TOKEN_URL,
new URLSearchParams({
grant_type: "authorization_code",
@@ -160,12 +160,6 @@ const exchangeCodeHeroku = async ({ code }: { code: string }) => {
/**
* Return [accessToken], [accessExpiresAt], and [refreshToken] for Vercel
* code-token exchange
* @param {Object} obj1
* @param {Object} obj1.code - code for code-token exchange
* @returns {Object} obj2
* @returns {String} obj2.accessToken - access token for Heroku API
* @returns {String} obj2.refreshToken - refresh token for Heroku API
* @returns {Date} obj2.accessExpiresAt - date of expiration for access token
*/
const exchangeCodeVercel = async ({ code }: { code: string }) => {
const appCfg = getConfig();
@@ -173,15 +167,15 @@ const exchangeCodeVercel = async ({ code }: { code: string }) => {
throw new BadRequestError({ message: "Missing client id and client secret" });
}
const res: ExchangeCodeVercelResponse = (
await request.post(
const res = (
await request.post<ExchangeCodeVercelResponse>(
IntegrationUrls.VERCEL_TOKEN_URL,
new URLSearchParams({
code,
client_id: appCfg.CLIENT_ID_VERCEL,
client_secret: appCfg.CLIENT_SECRET_VERCEL,
redirect_uri: `${appCfg.SITE_URL}/integrations/vercel/oauth2/callback`
} as any)
})
)
).data;
@@ -196,12 +190,6 @@ const exchangeCodeVercel = async ({ code }: { code: string }) => {
/**
* Return [accessToken], [accessExpiresAt], and [refreshToken] for Vercel
* code-token exchange
* @param {Object} obj1
* @param {Object} obj1.code - code for code-token exchange
* @returns {Object} obj2
* @returns {String} obj2.accessToken - access token for Heroku API
* @returns {String} obj2.refreshToken - refresh token for Heroku API
* @returns {Date} obj2.accessExpiresAt - date of expiration for access token
*/
const exchangeCodeNetlify = async ({ code }: { code: string }) => {
const appCfg = getConfig();
@@ -209,8 +197,8 @@ const exchangeCodeNetlify = async ({ code }: { code: string }) => {
throw new BadRequestError({ message: "Missing client id and client secret" });
}
const res: ExchangeCodeNetlifyResponse = (
await request.post(
const res = (
await request.post<ExchangeCodeNetlifyResponse>(
IntegrationUrls.NETLIFY_TOKEN_URL,
new URLSearchParams({
grant_type: "authorization_code",
@@ -218,7 +206,7 @@ const exchangeCodeNetlify = async ({ code }: { code: string }) => {
client_id: appCfg.CLIENT_ID_NETLIFY,
client_secret: appCfg.CLIENT_SECRET_NETLIFY,
redirect_uri: `${appCfg.SITE_URL}/integrations/netlify/oauth2/callback`
} as any)
})
)
).data;
@@ -230,7 +218,7 @@ const exchangeCodeNetlify = async ({ code }: { code: string }) => {
// });
const res3 = (
await request.get("https://api.netlify.com/api/v1/accounts", {
await request.get<Array<{ id: string }>>("https://api.netlify.com/api/v1/accounts", {
headers: {
Authorization: `Bearer ${res.access_token}`
}
@@ -252,8 +240,8 @@ const exchangeCodeGithub = async ({ code }: { code: string }) => {
throw new BadRequestError({ message: "Missing client id and client secret" });
}
const res: ExchangeCodeGithubResponse = (
await request.get(IntegrationUrls.GITHUB_TOKEN_URL, {
const res = (
await request.get<ExchangeCodeGithubResponse>(IntegrationUrls.GITHUB_TOKEN_URL, {
params: {
client_id: appCfg.CLIENT_ID_GITHUB,
client_secret: appCfg.CLIENT_SECRET_GITHUB,
@@ -285,8 +273,8 @@ const exchangeCodeGitlab = async ({ code, url }: { code: string; url?: string })
throw new BadRequestError({ message: "Missing client id and client secret" });
}
const res: ExchangeCodeGitlabResponse = (
await request.post(
const res = (
await request.post<ExchangeCodeGitlabResponse>(
url ? `${url}/oauth/token` : IntegrationUrls.GITLAB_TOKEN_URL,
new URLSearchParams({
grant_type: "authorization_code",
@@ -294,7 +282,7 @@ const exchangeCodeGitlab = async ({ code, url }: { code: string; url?: string })
client_id: appCfg.CLIENT_ID_GITLAB,
client_secret: appCfg.CLIENT_SECRET_GITLAB,
redirect_uri: `${appCfg.SITE_URL}/integrations/gitlab/oauth2/callback`
} as any),
}),
{
headers: {
"Accept-Encoding": "application/json"
@@ -324,8 +312,8 @@ const exchangeCodeBitBucket = async ({ code }: { code: string }) => {
throw new BadRequestError({ message: "Missing client id and client secret" });
}
const res: ExchangeCodeBitBucketResponse = (
await request.post(
const res = (
await request.post<ExchangeCodeBitBucketResponse>(
IntegrationUrls.BITBUCKET_TOKEN_URL,
new URLSearchParams({
grant_type: "authorization_code",
@@ -333,7 +321,7 @@ const exchangeCodeBitBucket = async ({ code }: { code: string }) => {
client_id: appCfg.CLIENT_ID_BITBUCKET,
client_secret: appCfg.CLIENT_SECRET_BITBUCKET,
redirect_uri: `${appCfg.SITE_URL}/integrations/bitbucket/oauth2/callback`
} as any),
}),
{
headers: {
"Accept-Encoding": "application/json"
@@ -593,7 +581,7 @@ const exchangeRefreshBitBucket = async ({ refreshToken }: { refreshToken: string
client_id: appCfg.CLIENT_ID_BITBUCKET,
client_secret: appCfg.CLIENT_SECRET_BITBUCKET,
redirect_uri: `${appCfg.SITE_URL}/integrations/bitbucket/oauth2/callback`
} as any),
}),
{
headers: {
"Accept-Encoding": "application/json"
@@ -624,7 +612,11 @@ const exchangeRefreshGCPSecretManager = async ({
const accessExpiresAt = new Date();
if (metadata?.authMethod === "serviceAccount") {
const serviceAccount = JSON.parse(refreshToken);
const serviceAccount = JSON.parse(refreshToken) as {
client_email: string;
token_uri: string;
private_key: string;
};
const payload = {
iss: serviceAccount.client_email,
@@ -663,14 +655,14 @@ const exchangeRefreshGCPSecretManager = async ({
if (!appCfg.CLIENT_SECRET_GCP_SECRET_MANAGER || !appCfg.CLIENT_ID_GCP_SECRET_MANAGER) {
throw new BadRequestError({ message: "Missing client id and client secret" });
}
const { data }: { data: RefreshTokenGCPSecretManagerResponse } = await request.post(
const { data } = await request.post<RefreshTokenGCPSecretManagerResponse>(
IntegrationUrls.GCP_TOKEN_URL,
new URLSearchParams({
client_id: appCfg.CLIENT_ID_GCP_SECRET_MANAGER,
client_secret: appCfg.CLIENT_SECRET_GCP_SECRET_MANAGER,
refresh_token: refreshToken,
grant_type: "refresh_token"
} as any)
})
);
accessExpiresAt.setSeconds(accessExpiresAt.getSeconds() + data.expires_in);