mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
feat: add sync
This commit is contained in:
@@ -32,6 +32,8 @@ import {
|
|||||||
INTEGRATION_GITLAB,
|
INTEGRATION_GITLAB,
|
||||||
INTEGRATION_GITLAB_API_URL,
|
INTEGRATION_GITLAB_API_URL,
|
||||||
INTEGRATION_HASHICORP_VAULT,
|
INTEGRATION_HASHICORP_VAULT,
|
||||||
|
INTEGRATION_HASURA_CLOUD,
|
||||||
|
INTEGRATION_HASURA_CLOUD_API_URL,
|
||||||
INTEGRATION_HEROKU,
|
INTEGRATION_HEROKU,
|
||||||
INTEGRATION_HEROKU_API_URL,
|
INTEGRATION_HEROKU_API_URL,
|
||||||
INTEGRATION_LARAVELFORGE,
|
INTEGRATION_LARAVELFORGE,
|
||||||
@@ -63,6 +65,7 @@ import { Octokit } from "@octokit/rest";
|
|||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import sodium from "libsodium-wrappers";
|
import sodium from "libsodium-wrappers";
|
||||||
import { standardRequest } from "../config/request";
|
import { standardRequest } from "../config/request";
|
||||||
|
import { ZGetTenantEnv } from "../validation/hasuraCloudIntegration";
|
||||||
|
|
||||||
const getSecretKeyValuePair = (
|
const getSecretKeyValuePair = (
|
||||||
secrets: Record<string, { value: string | null; comment?: string } | null>
|
secrets: Record<string, { value: string | null; comment?: string } | null>
|
||||||
@@ -95,7 +98,7 @@ const syncSecrets = async ({
|
|||||||
secrets: Record<string, { value: string; comment?: string }>;
|
secrets: Record<string, { value: string; comment?: string }>;
|
||||||
accessId: string | null;
|
accessId: string | null;
|
||||||
accessToken: string;
|
accessToken: string;
|
||||||
appendices?: { prefix: string, suffix: string };
|
appendices?: { prefix: string; suffix: string };
|
||||||
}) => {
|
}) => {
|
||||||
switch (integration.integration) {
|
switch (integration.integration) {
|
||||||
case INTEGRATION_GCP_SECRET_MANAGER:
|
case INTEGRATION_GCP_SECRET_MANAGER:
|
||||||
@@ -306,6 +309,14 @@ const syncSecrets = async ({
|
|||||||
accessToken
|
accessToken
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case INTEGRATION_HASURA_CLOUD:
|
||||||
|
await syncSecretsHasuraCloud({
|
||||||
|
integration,
|
||||||
|
secrets,
|
||||||
|
accessToken
|
||||||
|
});
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -963,8 +974,9 @@ const syncSecretsVercel = async ({
|
|||||||
: {}),
|
: {}),
|
||||||
...(integration?.path
|
...(integration?.path
|
||||||
? {
|
? {
|
||||||
gitBranch: integration?.path
|
gitBranch: integration?.path
|
||||||
} : {})
|
}
|
||||||
|
: {})
|
||||||
};
|
};
|
||||||
|
|
||||||
const vercelSecrets: VercelSecret[] = (
|
const vercelSecrets: VercelSecret[] = (
|
||||||
@@ -992,7 +1004,7 @@ const syncSecretsVercel = async ({
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
const res: { [key: string]: VercelSecret } = {};
|
const res: { [key: string]: VercelSecret } = {};
|
||||||
|
|
||||||
for await (const vercelSecret of vercelSecrets) {
|
for await (const vercelSecret of vercelSecrets) {
|
||||||
@@ -1352,7 +1364,7 @@ const syncSecretsGitHub = async ({
|
|||||||
integration: IIntegration;
|
integration: IIntegration;
|
||||||
secrets: Record<string, { value: string; comment?: string }>;
|
secrets: Record<string, { value: string; comment?: string }>;
|
||||||
accessToken: string;
|
accessToken: string;
|
||||||
appendices?: { prefix: string, suffix: string };
|
appendices?: { prefix: string; suffix: string };
|
||||||
}) => {
|
}) => {
|
||||||
interface GitHubRepoKey {
|
interface GitHubRepoKey {
|
||||||
key_id: string;
|
key_id: string;
|
||||||
@@ -1395,14 +1407,23 @@ const syncSecretsGitHub = async ({
|
|||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
|
|
||||||
encryptedSecrets = Object.keys(encryptedSecrets).reduce((result: {
|
encryptedSecrets = Object.keys(encryptedSecrets).reduce(
|
||||||
[key: string]: GitHubSecret;
|
(
|
||||||
}, key) => {
|
result: {
|
||||||
if ((appendices?.prefix !== undefined ? key.startsWith(appendices?.prefix) : true) && (appendices?.suffix !== undefined ? key.endsWith(appendices?.suffix) : true)) {
|
[key: string]: GitHubSecret;
|
||||||
result[key] = encryptedSecrets[key];
|
},
|
||||||
}
|
key
|
||||||
return result;
|
) => {
|
||||||
}, {});
|
if (
|
||||||
|
(appendices?.prefix !== undefined ? key.startsWith(appendices?.prefix) : true) &&
|
||||||
|
(appendices?.suffix !== undefined ? key.endsWith(appendices?.suffix) : true)
|
||||||
|
) {
|
||||||
|
result[key] = encryptedSecrets[key];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
Object.keys(encryptedSecrets).map(async (key) => {
|
Object.keys(encryptedSecrets).map(async (key) => {
|
||||||
if (!(key in secrets)) {
|
if (!(key in secrets)) {
|
||||||
@@ -2095,7 +2116,7 @@ const syncSecretsCheckly = async ({
|
|||||||
integration: IIntegration;
|
integration: IIntegration;
|
||||||
secrets: Record<string, { value: string; comment?: string }>;
|
secrets: Record<string, { value: string; comment?: string }>;
|
||||||
accessToken: string;
|
accessToken: string;
|
||||||
appendices?: { prefix: string, suffix: string };
|
appendices?: { prefix: string; suffix: string };
|
||||||
}) => {
|
}) => {
|
||||||
let getSecretsRes = (
|
let getSecretsRes = (
|
||||||
await standardRequest.get(`${INTEGRATION_CHECKLY_API_URL}/v1/variables`, {
|
await standardRequest.get(`${INTEGRATION_CHECKLY_API_URL}/v1/variables`, {
|
||||||
@@ -2113,14 +2134,23 @@ const syncSecretsCheckly = async ({
|
|||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
|
|
||||||
getSecretsRes = Object.keys(getSecretsRes).reduce((result: {
|
getSecretsRes = Object.keys(getSecretsRes).reduce(
|
||||||
[key: string]: string;
|
(
|
||||||
}, key) => {
|
result: {
|
||||||
if ((appendices?.prefix !== undefined ? key.startsWith(appendices?.prefix) : true) && (appendices?.suffix !== undefined ? key.endsWith(appendices?.suffix) : true)) {
|
[key: string]: string;
|
||||||
result[key] = getSecretsRes[key];
|
},
|
||||||
}
|
key
|
||||||
return result;
|
) => {
|
||||||
}, {});
|
if (
|
||||||
|
(appendices?.prefix !== undefined ? key.startsWith(appendices?.prefix) : true) &&
|
||||||
|
(appendices?.suffix !== undefined ? key.endsWith(appendices?.suffix) : true)
|
||||||
|
) {
|
||||||
|
result[key] = getSecretsRes[key];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
// add secrets
|
// add secrets
|
||||||
for await (const key of Object.keys(secrets)) {
|
for await (const key of Object.keys(secrets)) {
|
||||||
@@ -2195,18 +2225,20 @@ const syncSecretsQovery = async ({
|
|||||||
secrets: Record<string, { value: string; comment?: string }>;
|
secrets: Record<string, { value: string; comment?: string }>;
|
||||||
accessToken: string;
|
accessToken: string;
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
const getSecretsRes = (
|
const getSecretsRes = (
|
||||||
await standardRequest.get(`${INTEGRATION_QOVERY_API_URL}/${integration.scope}/${integration.appId}/environmentVariable`, {
|
await standardRequest.get(
|
||||||
headers: {
|
`${INTEGRATION_QOVERY_API_URL}/${integration.scope}/${integration.appId}/environmentVariable`,
|
||||||
Authorization: `Token ${accessToken}`,
|
{
|
||||||
"Accept-Encoding": "application/json"
|
headers: {
|
||||||
|
Authorization: `Token ${accessToken}`,
|
||||||
|
"Accept-Encoding": "application/json"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
)
|
||||||
).data.results.reduce(
|
).data.results.reduce(
|
||||||
(obj: any, secret: any) => ({
|
(obj: any, secret: any) => ({
|
||||||
...obj,
|
...obj,
|
||||||
[secret.key]: {"id": secret.id, "value": secret.value}
|
[secret.key]: { id: secret.id, value: secret.value }
|
||||||
}),
|
}),
|
||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
@@ -3076,4 +3108,65 @@ const syncSecretsNorthflank = async ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const syncSecretsHasuraCloud = async ({
|
||||||
|
integration,
|
||||||
|
secrets,
|
||||||
|
accessToken
|
||||||
|
}: {
|
||||||
|
integration: IIntegration;
|
||||||
|
secrets: Record<string, { value: string; comment?: string }>;
|
||||||
|
accessToken: string;
|
||||||
|
}) => {
|
||||||
|
const res = await standardRequest.post(
|
||||||
|
INTEGRATION_HASURA_CLOUD_API_URL,
|
||||||
|
{
|
||||||
|
query:
|
||||||
|
"query MyQuery($tenantId: uuid!) { getTenantEnv(tenantId: $tenantId) { hash envVars } }",
|
||||||
|
variables: {
|
||||||
|
tenantId: integration.appId
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `pat ${accessToken}`,
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: {
|
||||||
|
getTenantEnv: { hash: currentHash }
|
||||||
|
}
|
||||||
|
} = ZGetTenantEnv.parse(res.data);
|
||||||
|
|
||||||
|
const envs = Object.keys(secrets).reduce<{ key: string; value: any }[]>((prev, key) => {
|
||||||
|
if (secrets?.[key]?.value) {
|
||||||
|
prev.push({ key, value: secrets[key].value });
|
||||||
|
}
|
||||||
|
return prev;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const variables = {
|
||||||
|
currentHash,
|
||||||
|
envs,
|
||||||
|
tenantId: integration.appId
|
||||||
|
};
|
||||||
|
|
||||||
|
await standardRequest.post(
|
||||||
|
INTEGRATION_HASURA_CLOUD_API_URL,
|
||||||
|
{
|
||||||
|
query:
|
||||||
|
"mutation MyQuery($currentHash: String!, $envs: [UpdateEnvObject!]!, $tenantId: uuid!) { updateTenantEnv(currentHash: $currentHash, envs: $envs, tenantId: $tenantId) { hash envVars} }",
|
||||||
|
variables
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `pat ${accessToken}`,
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export { syncSecrets };
|
export { syncSecrets };
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import * as z from "zod";
|
||||||
|
|
||||||
|
export const ZGetTenantEnv = z.object({
|
||||||
|
data: z.object({
|
||||||
|
getTenantEnv: z.object({
|
||||||
|
hash: z.string(),
|
||||||
|
envVars: z.record(z.any())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user