mirror of
https://github.com/Infisical/infisical.git
synced 2025-03-24 00:15:26 +00:00
Compare commits
72 Commits
v0.3.2
...
revert-374
Author | SHA1 | Date | |
---|---|---|---|
ec22291aca | |||
16c49a9626 | |||
06ea809d60 | |||
12364005c1 | |||
98573e9e05 | |||
c1a4ca6203 | |||
21c2fd8542 | |||
b27bc8fc1b | |||
091115e6ba | |||
d9c055872d | |||
f73d18ddc7 | |||
eb47126f68 | |||
4750767268 | |||
b0ed772885 | |||
7fdab81b5f | |||
c17bf13f8c | |||
0e17c9a6db | |||
1c4dd78dea | |||
23418b3a09 | |||
0f143adbde | |||
1f3f4b7900 | |||
2c5f26380e | |||
8f974fb087 | |||
a0722b4ca5 | |||
41e039578a | |||
c89e8e8a96 | |||
cac83ab927 | |||
0f0b894363 | |||
43f9af1bc6 | |||
f5ed14c84c | |||
2dd57d7c73 | |||
0b1891b64a | |||
5614b0f58a | |||
3bb178976d | |||
1777f98aef | |||
45e3706335 | |||
337ed1fc46 | |||
d1ea76e5a0 | |||
4a72d725b1 | |||
1693db3199 | |||
1ff42991b3 | |||
978423ba5b | |||
4d0dc0d7b7 | |||
3817e666a9 | |||
b61350f6a4 | |||
0fb1a1dc6f | |||
9eefc87b7a | |||
53d35757ee | |||
e80e8e00b1 | |||
0b08e574c7 | |||
499323d0e3 | |||
89ad2f163a | |||
7f04617b7d | |||
44904628bc | |||
fafde7b1ad | |||
7e65314670 | |||
40c80f417c | |||
7bb2c1c278 | |||
a5278affe6 | |||
2f953192d6 | |||
8bf8968588 | |||
7e9ce0360a | |||
1d35c41dcb | |||
824315f773 | |||
8a74799d64 | |||
f0f6e8a988 | |||
c233fd8ed1 | |||
d7acd7aef6 | |||
860b8efd7d | |||
6ca3fc5ad2 | |||
189af07ff5 | |||
caf7426f86 |
@ -1,18 +1,27 @@
|
||||
FROM node:16-bullseye-slim
|
||||
# Build stage
|
||||
FROM node:16-alpine AS build
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package.json package-lock.json ./
|
||||
|
||||
# RUN npm ci --only-production --ignore-scripts
|
||||
# "prepare": "cd .. && npm install"
|
||||
|
||||
COPY package*.json ./
|
||||
RUN npm ci --only-production
|
||||
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
# Production stage
|
||||
FROM node:16-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package*.json ./
|
||||
RUN npm ci --only-production
|
||||
|
||||
COPY --from=build /app .
|
||||
|
||||
HEALTHCHECK --interval=10s --timeout=3s --start-period=10s \
|
||||
CMD node healthcheck.js
|
||||
|
||||
EXPOSE 4000
|
||||
|
||||
CMD ["npm", "run", "start"]
|
||||
CMD ["npm", "run", "start"]
|
9282
backend/package-lock.json
generated
9282
backend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -48,7 +48,7 @@
|
||||
"version": "1.0.0",
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
"start": "npm run build && node build/index.js",
|
||||
"start": "node build/index.js",
|
||||
"dev": "nodemon",
|
||||
"swagger-autogen": "node ./swagger/index.ts",
|
||||
"build": "rimraf ./build && tsc && cp -R ./src/templates ./build",
|
||||
|
@ -6,7 +6,7 @@ const axiosInstance = axios.create();
|
||||
// add retry functionality to the axios instance
|
||||
axiosRetry(axiosInstance, {
|
||||
retries: 3,
|
||||
retryDelay: (retryCount) => retryCount * 1000, // delay between retries (in milliseconds)
|
||||
retryDelay: axiosRetry.exponentialDelay, // exponential back-off delay between retries
|
||||
retryCondition: (error) => {
|
||||
// only retry if the error is a network error or a 5xx server error
|
||||
return axiosRetry.isNetworkError(error) || axiosRetry.isRetryableError(error);
|
||||
|
@ -8,7 +8,7 @@ import {
|
||||
import { issueAuthTokens } from '../../helpers/auth';
|
||||
import { INVITED, ACCEPTED } from '../../variables';
|
||||
import { NODE_ENV } from '../../config';
|
||||
import axios from 'axios';
|
||||
import request from '../../config/request';
|
||||
|
||||
/**
|
||||
* Complete setting up user by adding their personal and auth information as part of the
|
||||
@ -109,7 +109,7 @@ export const completeAccountSignup = async (req: Request, res: Response) => {
|
||||
|
||||
// sending a welcome email to new users
|
||||
if (process.env.LOOPS_API_KEY) {
|
||||
await axios.post("https://app.loops.so/api/v1/events/send", {
|
||||
await request.post("https://app.loops.so/api/v1/events/send", {
|
||||
"email": email,
|
||||
"eventName": "Sign Up",
|
||||
"firstName": firstName,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import axios from "axios";
|
||||
import * as Sentry from "@sentry/node";
|
||||
import { Octokit } from "@octokit/rest";
|
||||
import { IIntegrationAuth } from "../models";
|
||||
import request from '../config/request';
|
||||
import {
|
||||
INTEGRATION_AZURE_KEY_VAULT,
|
||||
INTEGRATION_AWS_PARAMETER_STORE,
|
||||
@ -13,12 +13,14 @@ import {
|
||||
INTEGRATION_RENDER,
|
||||
INTEGRATION_FLYIO,
|
||||
INTEGRATION_CIRCLECI,
|
||||
INTEGRATION_TRAVISCI,
|
||||
INTEGRATION_HEROKU_API_URL,
|
||||
INTEGRATION_VERCEL_API_URL,
|
||||
INTEGRATION_NETLIFY_API_URL,
|
||||
INTEGRATION_RENDER_API_URL,
|
||||
INTEGRATION_FLYIO_API_URL,
|
||||
INTEGRATION_CIRCLECI_API_URL,
|
||||
INTEGRATION_TRAVISCI_API_URL,
|
||||
} from "../variables";
|
||||
|
||||
/**
|
||||
@ -42,7 +44,7 @@ const getApps = async ({
|
||||
owner?: string;
|
||||
}
|
||||
|
||||
let apps: App[];
|
||||
let apps: App[] = [];
|
||||
try {
|
||||
switch (integrationAuth.integration) {
|
||||
case INTEGRATION_AZURE_KEY_VAULT:
|
||||
@ -90,6 +92,11 @@ const getApps = async ({
|
||||
accessToken,
|
||||
});
|
||||
break;
|
||||
case INTEGRATION_TRAVISCI:
|
||||
apps = await getAppsTravisCI({
|
||||
accessToken,
|
||||
})
|
||||
break;
|
||||
}
|
||||
} catch (err) {
|
||||
Sentry.setUser(null);
|
||||
@ -111,7 +118,7 @@ const getAppsHeroku = async ({ accessToken }: { accessToken: string }) => {
|
||||
let apps;
|
||||
try {
|
||||
const res = (
|
||||
await axios.get(`${INTEGRATION_HEROKU_API_URL}/apps`, {
|
||||
await request.get(`${INTEGRATION_HEROKU_API_URL}/apps`, {
|
||||
headers: {
|
||||
Accept: "application/vnd.heroku+json; version=3",
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
@ -148,7 +155,7 @@ const getAppsVercel = async ({
|
||||
let apps;
|
||||
try {
|
||||
const res = (
|
||||
await axios.get(`${INTEGRATION_VERCEL_API_URL}/v9/projects`, {
|
||||
await request.get(`${INTEGRATION_VERCEL_API_URL}/v9/projects`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
'Accept-Encoding': 'application/json'
|
||||
@ -186,7 +193,7 @@ const getAppsNetlify = async ({ accessToken }: { accessToken: string }) => {
|
||||
let apps;
|
||||
try {
|
||||
const res = (
|
||||
await axios.get(`${INTEGRATION_NETLIFY_API_URL}/api/v1/sites`, {
|
||||
await request.get(`${INTEGRATION_NETLIFY_API_URL}/api/v1/sites`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
'Accept-Encoding': 'application/json'
|
||||
@ -257,7 +264,7 @@ const getAppsRender = async ({ accessToken }: { accessToken: string }) => {
|
||||
let apps: any;
|
||||
try {
|
||||
const res = (
|
||||
await axios.get(`${INTEGRATION_RENDER_API_URL}/v1/services`, {
|
||||
await request.get(`${INTEGRATION_RENDER_API_URL}/v1/services`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
Accept: 'application/json',
|
||||
@ -303,23 +310,18 @@ const getAppsFlyio = async ({ accessToken }: { accessToken: string }) => {
|
||||
}
|
||||
`;
|
||||
|
||||
const res = (
|
||||
await axios({
|
||||
url: INTEGRATION_FLYIO_API_URL,
|
||||
method: "post",
|
||||
headers: {
|
||||
Authorization: "Bearer " + accessToken,
|
||||
const res = (await request.post(INTEGRATION_FLYIO_API_URL, {
|
||||
query,
|
||||
variables: {
|
||||
role: null,
|
||||
},
|
||||
}, {
|
||||
headers: {
|
||||
Authorization: "Bearer " + accessToken,
|
||||
'Accept': 'application/json',
|
||||
'Accept-Encoding': 'application/json',
|
||||
},
|
||||
data: {
|
||||
query,
|
||||
variables: {
|
||||
role: null,
|
||||
},
|
||||
},
|
||||
})
|
||||
).data.data.apps.nodes;
|
||||
},
|
||||
})).data.data.apps.nodes;
|
||||
|
||||
apps = res.map((a: any) => ({
|
||||
name: a.name,
|
||||
@ -344,7 +346,7 @@ const getAppsCircleCI = async ({ accessToken }: { accessToken: string }) => {
|
||||
let apps: any;
|
||||
try {
|
||||
const res = (
|
||||
await axios.get(
|
||||
await request.get(
|
||||
`${INTEGRATION_CIRCLECI_API_URL}/v1.1/projects`,
|
||||
{
|
||||
headers: {
|
||||
@ -369,4 +371,34 @@ const getAppsCircleCI = async ({ accessToken }: { accessToken: string }) => {
|
||||
return apps;
|
||||
};
|
||||
|
||||
const getAppsTravisCI = async ({ accessToken }: { accessToken: string }) => {
|
||||
let apps: any;
|
||||
try {
|
||||
const res = (
|
||||
await request.get(
|
||||
`${INTEGRATION_TRAVISCI_API_URL}/repos`,
|
||||
{
|
||||
headers: {
|
||||
"Authorization": `token ${accessToken}`,
|
||||
"Accept-Encoding": "application/json",
|
||||
},
|
||||
}
|
||||
)
|
||||
).data;
|
||||
|
||||
apps = res?.map((a: any) => {
|
||||
return {
|
||||
name: a?.slug?.split("/")[1],
|
||||
appId: a?.id,
|
||||
}
|
||||
});
|
||||
}catch (err) {
|
||||
Sentry.setUser(null);
|
||||
Sentry.captureException(err);
|
||||
throw new Error("Failed to get TravisCI projects");
|
||||
}
|
||||
|
||||
return apps;
|
||||
}
|
||||
|
||||
export { getApps };
|
||||
|
@ -1,4 +1,4 @@
|
||||
import axios from 'axios';
|
||||
import request from '../config/request';
|
||||
import * as Sentry from '@sentry/node';
|
||||
import {
|
||||
INTEGRATION_AZURE_KEY_VAULT,
|
||||
@ -136,7 +136,7 @@ const exchangeCodeAzure = async ({
|
||||
const accessExpiresAt = new Date();
|
||||
let res: ExchangeCodeAzureResponse;
|
||||
try {
|
||||
res = (await axios.post(
|
||||
res = (await request.post(
|
||||
INTEGRATION_AZURE_TOKEN_URL,
|
||||
new URLSearchParams({
|
||||
grant_type: 'authorization_code',
|
||||
@ -182,7 +182,7 @@ const exchangeCodeHeroku = async ({
|
||||
let res: ExchangeCodeHerokuResponse;
|
||||
const accessExpiresAt = new Date();
|
||||
try {
|
||||
res = (await axios.post(
|
||||
res = (await request.post(
|
||||
INTEGRATION_HEROKU_TOKEN_URL,
|
||||
new URLSearchParams({
|
||||
grant_type: 'authorization_code',
|
||||
@ -221,7 +221,7 @@ const exchangeCodeVercel = async ({ code }: { code: string }) => {
|
||||
let res: ExchangeCodeVercelResponse;
|
||||
try {
|
||||
res = (
|
||||
await axios.post(
|
||||
await request.post(
|
||||
INTEGRATION_VERCEL_TOKEN_URL,
|
||||
new URLSearchParams({
|
||||
code: code,
|
||||
@ -260,7 +260,7 @@ const exchangeCodeNetlify = async ({ code }: { code: string }) => {
|
||||
let accountId;
|
||||
try {
|
||||
res = (
|
||||
await axios.post(
|
||||
await request.post(
|
||||
INTEGRATION_NETLIFY_TOKEN_URL,
|
||||
new URLSearchParams({
|
||||
grant_type: 'authorization_code',
|
||||
@ -272,14 +272,14 @@ const exchangeCodeNetlify = async ({ code }: { code: string }) => {
|
||||
)
|
||||
).data;
|
||||
|
||||
const res2 = await axios.get('https://api.netlify.com/api/v1/sites', {
|
||||
const res2 = await request.get('https://api.netlify.com/api/v1/sites', {
|
||||
headers: {
|
||||
Authorization: `Bearer ${res.access_token}`
|
||||
}
|
||||
});
|
||||
|
||||
const res3 = (
|
||||
await axios.get('https://api.netlify.com/api/v1/accounts', {
|
||||
await request.get('https://api.netlify.com/api/v1/accounts', {
|
||||
headers: {
|
||||
Authorization: `Bearer ${res.access_token}`
|
||||
}
|
||||
@ -314,7 +314,7 @@ const exchangeCodeGithub = async ({ code }: { code: string }) => {
|
||||
let res: ExchangeCodeGithubResponse;
|
||||
try {
|
||||
res = (
|
||||
await axios.get(INTEGRATION_GITHUB_TOKEN_URL, {
|
||||
await request.get(INTEGRATION_GITHUB_TOKEN_URL, {
|
||||
params: {
|
||||
client_id: CLIENT_ID_GITHUB,
|
||||
client_secret: CLIENT_SECRET_GITHUB,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import axios from 'axios';
|
||||
import request from '../config/request';
|
||||
import * as Sentry from '@sentry/node';
|
||||
import { INTEGRATION_AZURE_KEY_VAULT, INTEGRATION_HEROKU } from '../variables';
|
||||
import {
|
||||
@ -71,7 +71,7 @@ const exchangeRefreshAzure = async ({
|
||||
refreshToken: string;
|
||||
}) => {
|
||||
try {
|
||||
const res: RefreshTokenAzureResponse = (await axios.post(
|
||||
const res: RefreshTokenAzureResponse = (await request.post(
|
||||
INTEGRATION_AZURE_TOKEN_URL,
|
||||
new URLSearchParams({
|
||||
client_id: CLIENT_ID_AZURE,
|
||||
@ -105,7 +105,7 @@ const exchangeRefreshHeroku = async ({
|
||||
|
||||
let accessToken;
|
||||
try {
|
||||
const res = await axios.post(
|
||||
const res = await request.post(
|
||||
INTEGRATION_HEROKU_TOKEN_URL,
|
||||
new URLSearchParams({
|
||||
grant_type: 'refresh_token',
|
||||
|
@ -1,4 +1,3 @@
|
||||
import axios from "axios";
|
||||
import * as Sentry from "@sentry/node";
|
||||
import _ from 'lodash';
|
||||
import AWS from 'aws-sdk';
|
||||
@ -23,14 +22,16 @@ import {
|
||||
INTEGRATION_RENDER,
|
||||
INTEGRATION_FLYIO,
|
||||
INTEGRATION_CIRCLECI,
|
||||
INTEGRATION_TRAVISCI,
|
||||
INTEGRATION_HEROKU_API_URL,
|
||||
INTEGRATION_VERCEL_API_URL,
|
||||
INTEGRATION_NETLIFY_API_URL,
|
||||
INTEGRATION_RENDER_API_URL,
|
||||
INTEGRATION_FLYIO_API_URL,
|
||||
INTEGRATION_CIRCLECI_API_URL,
|
||||
INTEGRATION_TRAVISCI_API_URL,
|
||||
} from "../variables";
|
||||
import axiosWithRetry from '../config/request';
|
||||
import request from '../config/request';
|
||||
|
||||
/**
|
||||
* Sync/push [secrets] to [app] in integration named [integration]
|
||||
@ -129,6 +130,14 @@ const syncSecrets = async ({
|
||||
secrets,
|
||||
accessToken,
|
||||
});
|
||||
break;
|
||||
case INTEGRATION_TRAVISCI:
|
||||
await syncSecretsTravisCI({
|
||||
integration,
|
||||
secrets,
|
||||
accessToken,
|
||||
});
|
||||
break;
|
||||
}
|
||||
} catch (err) {
|
||||
Sentry.setUser(null);
|
||||
@ -179,7 +188,7 @@ const syncSecretsAzureKeyVault = async ({
|
||||
let result: GetAzureKeyVaultSecret[] = [];
|
||||
|
||||
while (url) {
|
||||
const res = await axios.get(url, {
|
||||
const res = await request.get(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
'Accept-Encoding': 'application/json'
|
||||
@ -201,7 +210,7 @@ const syncSecretsAzureKeyVault = async ({
|
||||
lastSlashIndex = getAzureKeyVaultSecret.id.lastIndexOf('/');
|
||||
}
|
||||
|
||||
const azureKeyVaultSecret = await axios.get(`${getAzureKeyVaultSecret.id}?api-version=7.3`, {
|
||||
const azureKeyVaultSecret = await request.get(`${getAzureKeyVaultSecret.id}?api-version=7.3`, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${accessToken}`,
|
||||
'Accept-Encoding': 'application/json'
|
||||
@ -254,7 +263,7 @@ const syncSecretsAzureKeyVault = async ({
|
||||
// Sync/push set secrets
|
||||
if (setSecrets.length > 0) {
|
||||
setSecrets.forEach(async ({ key, value }) => {
|
||||
await axios.put(
|
||||
await request.put(
|
||||
`${integration.app}/secrets/${key}?api-version=7.3`,
|
||||
{
|
||||
value
|
||||
@ -271,7 +280,7 @@ const syncSecretsAzureKeyVault = async ({
|
||||
|
||||
if (deleteSecrets.length > 0) {
|
||||
deleteSecrets.forEach(async (secret) => {
|
||||
await axios.delete(`${integration.app}/secrets/${secret.key}?api-version=7.3`, {
|
||||
await request.delete(`${integration.app}/secrets/${secret.key}?api-version=7.3`, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${accessToken}`,
|
||||
'Accept-Encoding': 'application/json'
|
||||
@ -486,7 +495,7 @@ const syncSecretsHeroku = async ({
|
||||
}) => {
|
||||
try {
|
||||
const herokuSecrets = (
|
||||
await axios.get(
|
||||
await request.get(
|
||||
`${INTEGRATION_HEROKU_API_URL}/apps/${integration.app}/config-vars`,
|
||||
{
|
||||
headers: {
|
||||
@ -504,7 +513,7 @@ const syncSecretsHeroku = async ({
|
||||
}
|
||||
});
|
||||
|
||||
await axios.patch(
|
||||
await request.patch(
|
||||
`${INTEGRATION_HEROKU_API_URL}/apps/${integration.app}/config-vars`,
|
||||
secrets,
|
||||
{
|
||||
@ -562,7 +571,7 @@ const syncSecretsVercel = async ({
|
||||
// const res = (
|
||||
// await Promise.all(
|
||||
// (
|
||||
// await axios.get(
|
||||
// await request.get(
|
||||
// `${INTEGRATION_VERCEL_API_URL}/v9/projects/${integration.app}/env`,
|
||||
// {
|
||||
// params,
|
||||
@ -578,7 +587,7 @@ const syncSecretsVercel = async ({
|
||||
// .map(async (secret: VercelSecret) => {
|
||||
// if (secret.type === 'encrypted') {
|
||||
// // case: secret is encrypted -> need to decrypt
|
||||
// const decryptedSecret = (await axios.get(
|
||||
// const decryptedSecret = (await request.get(
|
||||
// `${INTEGRATION_VERCEL_API_URL}/v9/projects/${integration.app}/env/${secret.id}`,
|
||||
// {
|
||||
// params,
|
||||
@ -598,7 +607,7 @@ const syncSecretsVercel = async ({
|
||||
// [secret.key]: secret
|
||||
// }), {});
|
||||
|
||||
const vercelSecrets: VercelSecret[] = (await axiosWithRetry.get(
|
||||
const vercelSecrets: VercelSecret[] = (await request.get(
|
||||
`${INTEGRATION_VERCEL_API_URL}/v9/projects/${integration.app}/env`,
|
||||
{
|
||||
params,
|
||||
@ -617,7 +626,7 @@ const syncSecretsVercel = async ({
|
||||
for await (const vercelSecret of vercelSecrets) {
|
||||
if (vercelSecret.type === 'encrypted') {
|
||||
// case: secret is encrypted -> need to decrypt
|
||||
const decryptedSecret = (await axiosWithRetry.get(
|
||||
const decryptedSecret = (await request.get(
|
||||
`${INTEGRATION_VERCEL_API_URL}/v9/projects/${integration.app}/env/${vercelSecret.id}`,
|
||||
{
|
||||
params,
|
||||
@ -680,7 +689,7 @@ const syncSecretsVercel = async ({
|
||||
|
||||
// Sync/push new secrets
|
||||
if (newSecrets.length > 0) {
|
||||
await axiosWithRetry.post(
|
||||
await request.post(
|
||||
`${INTEGRATION_VERCEL_API_URL}/v10/projects/${integration.app}/env`,
|
||||
newSecrets,
|
||||
{
|
||||
@ -696,7 +705,7 @@ const syncSecretsVercel = async ({
|
||||
for await (const secret of updateSecrets) {
|
||||
if (secret.type !== 'sensitive') {
|
||||
const { id, ...updatedSecret } = secret;
|
||||
await axiosWithRetry.patch(
|
||||
await request.patch(
|
||||
`${INTEGRATION_VERCEL_API_URL}/v9/projects/${integration.app}/env/${secret.id}`,
|
||||
updatedSecret,
|
||||
{
|
||||
@ -711,7 +720,7 @@ const syncSecretsVercel = async ({
|
||||
}
|
||||
|
||||
for await (const secret of deleteSecrets) {
|
||||
await axiosWithRetry.delete(
|
||||
await request.delete(
|
||||
`${INTEGRATION_VERCEL_API_URL}/v9/projects/${integration.app}/env/${secret.id}`,
|
||||
{
|
||||
params,
|
||||
@ -770,7 +779,7 @@ const syncSecretsNetlify = async ({
|
||||
});
|
||||
|
||||
const res = (
|
||||
await axios.get(
|
||||
await request.get(
|
||||
`${INTEGRATION_NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env`,
|
||||
{
|
||||
params: getParams,
|
||||
@ -884,7 +893,7 @@ const syncSecretsNetlify = async ({
|
||||
});
|
||||
|
||||
if (newSecrets.length > 0) {
|
||||
await axios.post(
|
||||
await request.post(
|
||||
`${INTEGRATION_NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env`,
|
||||
newSecrets,
|
||||
{
|
||||
@ -899,7 +908,7 @@ const syncSecretsNetlify = async ({
|
||||
|
||||
if (updateSecrets.length > 0) {
|
||||
updateSecrets.forEach(async (secret: NetlifySecret) => {
|
||||
await axios.patch(
|
||||
await request.patch(
|
||||
`${INTEGRATION_NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${secret.key}`,
|
||||
{
|
||||
context: secret.values[0].context,
|
||||
@ -918,7 +927,7 @@ const syncSecretsNetlify = async ({
|
||||
|
||||
if (deleteSecrets.length > 0) {
|
||||
deleteSecrets.forEach(async (key: string) => {
|
||||
await axios.delete(
|
||||
await request.delete(
|
||||
`${INTEGRATION_NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${key}`,
|
||||
{
|
||||
params: syncParams,
|
||||
@ -933,7 +942,7 @@ const syncSecretsNetlify = async ({
|
||||
|
||||
if (deleteSecretValues.length > 0) {
|
||||
deleteSecretValues.forEach(async (secret: NetlifySecret) => {
|
||||
await axios.delete(
|
||||
await request.delete(
|
||||
`${INTEGRATION_NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${secret.key}/value/${secret.values[0].id}`,
|
||||
{
|
||||
params: syncParams,
|
||||
@ -1084,7 +1093,7 @@ const syncSecretsRender = async ({
|
||||
accessToken: string;
|
||||
}) => {
|
||||
try {
|
||||
await axios.put(
|
||||
await request.put(
|
||||
`${INTEGRATION_RENDER_API_URL}/v1/services/${integration.appId}/env-vars`,
|
||||
Object.keys(secrets).map((key) => ({
|
||||
key,
|
||||
@ -1142,24 +1151,21 @@ const syncSecretsFlyio = async ({
|
||||
}
|
||||
`;
|
||||
|
||||
await axios({
|
||||
url: INTEGRATION_FLYIO_API_URL,
|
||||
method: "post",
|
||||
await request.post(INTEGRATION_FLYIO_API_URL, {
|
||||
query: SetSecrets,
|
||||
variables: {
|
||||
input: {
|
||||
appId: integration.app,
|
||||
secrets: Object.entries(secrets).map(([key, value]) => ({
|
||||
key,
|
||||
value,
|
||||
})),
|
||||
},
|
||||
},
|
||||
}, {
|
||||
headers: {
|
||||
Authorization: "Bearer " + accessToken,
|
||||
'Accept-Encoding': 'application/json'
|
||||
},
|
||||
data: {
|
||||
query: SetSecrets,
|
||||
variables: {
|
||||
input: {
|
||||
appId: integration.app,
|
||||
secrets: Object.entries(secrets).map(([key, value]) => ({
|
||||
key,
|
||||
value,
|
||||
})),
|
||||
},
|
||||
},
|
||||
'Accept-Encoding': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
@ -1180,23 +1186,18 @@ const syncSecretsFlyio = async ({
|
||||
}
|
||||
}`;
|
||||
|
||||
const getSecretsRes = (
|
||||
await axios({
|
||||
method: "post",
|
||||
url: INTEGRATION_FLYIO_API_URL,
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + accessToken,
|
||||
'Content-Type': 'application/json',
|
||||
'Accept-Encoding': 'application/json'
|
||||
},
|
||||
data: {
|
||||
query: GetSecrets,
|
||||
variables: {
|
||||
appName: integration.app,
|
||||
},
|
||||
},
|
||||
})
|
||||
).data.data.app.secrets;
|
||||
const getSecretsRes = (await request.post(INTEGRATION_FLYIO_API_URL, {
|
||||
query: GetSecrets,
|
||||
variables: {
|
||||
appName: integration.app,
|
||||
},
|
||||
}, {
|
||||
headers: {
|
||||
Authorization: "Bearer " + accessToken,
|
||||
'Content-Type': 'application/json',
|
||||
'Accept-Encoding': 'application/json',
|
||||
},
|
||||
})).data.data.app.secrets;
|
||||
|
||||
const deleteSecretsKeys = getSecretsRes
|
||||
.filter((secret: FlyioSecret) => !(secret.name in secrets))
|
||||
@ -1221,24 +1222,22 @@ const syncSecretsFlyio = async ({
|
||||
}
|
||||
}`;
|
||||
|
||||
await axios({
|
||||
method: "post",
|
||||
url: INTEGRATION_FLYIO_API_URL,
|
||||
await request.post(INTEGRATION_FLYIO_API_URL, {
|
||||
query: DeleteSecrets,
|
||||
variables: {
|
||||
input: {
|
||||
appId: integration.app,
|
||||
keys: deleteSecretsKeys,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
headers: {
|
||||
Authorization: "Bearer " + accessToken,
|
||||
"Content-Type": "application/json",
|
||||
'Accept-Encoding': 'application/json'
|
||||
},
|
||||
data: {
|
||||
query: DeleteSecrets,
|
||||
variables: {
|
||||
input: {
|
||||
appId: integration.app,
|
||||
keys: deleteSecretsKeys,
|
||||
},
|
||||
},
|
||||
'Accept-Encoding': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
Sentry.setUser(null);
|
||||
Sentry.captureException(err);
|
||||
@ -1264,7 +1263,7 @@ const syncSecretsCircleCI = async ({
|
||||
}) => {
|
||||
try {
|
||||
const circleciOrganizationDetail = (
|
||||
await axios.get(`${INTEGRATION_CIRCLECI_API_URL}/v2/me/collaborations`, {
|
||||
await request.get(`${INTEGRATION_CIRCLECI_API_URL}/v2/me/collaborations`, {
|
||||
headers: {
|
||||
"Circle-Token": accessToken,
|
||||
"Accept-Encoding": "application/json",
|
||||
@ -1277,7 +1276,7 @@ const syncSecretsCircleCI = async ({
|
||||
// sync secrets to CircleCI
|
||||
Object.keys(secrets).forEach(
|
||||
async (key) =>
|
||||
await axios.post(
|
||||
await request.post(
|
||||
`${INTEGRATION_CIRCLECI_API_URL}/v2/project/${slug}/${integration.app}/envvar`,
|
||||
{
|
||||
name: key,
|
||||
@ -1294,7 +1293,7 @@ const syncSecretsCircleCI = async ({
|
||||
|
||||
// get secrets from CircleCI
|
||||
const getSecretsRes = (
|
||||
await axios.get(
|
||||
await request.get(
|
||||
`${INTEGRATION_CIRCLECI_API_URL}/v2/project/${slug}/${integration.app}/envvar`,
|
||||
{
|
||||
headers: {
|
||||
@ -1308,7 +1307,7 @@ const syncSecretsCircleCI = async ({
|
||||
// delete secrets from CircleCI
|
||||
getSecretsRes.forEach(async (sec: any) => {
|
||||
if (!(sec.name in secrets)) {
|
||||
await axios.delete(
|
||||
await request.delete(
|
||||
`${INTEGRATION_CIRCLECI_API_URL}/v2/project/${slug}/${integration.app}/envvar/${sec.name}`,
|
||||
{
|
||||
headers: {
|
||||
@ -1326,4 +1325,105 @@ const syncSecretsCircleCI = async ({
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sync/push [secrets] to TravisCI project
|
||||
* @param {Object} obj
|
||||
* @param {IIntegration} 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 TravisCI integration
|
||||
*/
|
||||
const syncSecretsTravisCI = async ({
|
||||
integration,
|
||||
secrets,
|
||||
accessToken,
|
||||
}: {
|
||||
integration: IIntegration;
|
||||
secrets: any;
|
||||
accessToken: string;
|
||||
}) => {
|
||||
try {
|
||||
// get secrets from travis-ci
|
||||
const getSecretsRes = (
|
||||
await request.get(
|
||||
`${INTEGRATION_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.name]: secret
|
||||
}), {});
|
||||
|
||||
// add secrets
|
||||
for await (const key of Object.keys(secrets)) {
|
||||
if (!(key in getSecretsRes)) {
|
||||
// case: secret does not exist in travis ci
|
||||
// -> add secret
|
||||
await request.post(
|
||||
`${INTEGRATION_TRAVISCI_API_URL}/settings/env_vars?repository_id=${integration.appId}`,
|
||||
{
|
||||
env_var: {
|
||||
name: key,
|
||||
value: secrets[key]
|
||||
}
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"Authorization": `token ${accessToken}`,
|
||||
"Content-Type": "application/json",
|
||||
"Accept-Encoding": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
} else {
|
||||
// case: secret exists in travis ci
|
||||
// -> update/set secret
|
||||
await request.patch(
|
||||
`${INTEGRATION_TRAVISCI_API_URL}/settings/env_vars/${getSecretsRes[key].id}?repository_id=${getSecretsRes[key].repository_id}`,
|
||||
{
|
||||
env_var: {
|
||||
name: key,
|
||||
value: secrets[key],
|
||||
}
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"Authorization": `token ${accessToken}`,
|
||||
"Content-Type": "application/json",
|
||||
"Accept-Encoding": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for await (const key of Object.keys(getSecretsRes)) {
|
||||
if (!(key in secrets)){
|
||||
// delete secret
|
||||
await request.delete(
|
||||
`${INTEGRATION_TRAVISCI_API_URL}/settings/env_vars/${getSecretsRes[key].id}?repository_id=${getSecretsRes[key].repository_id}`,
|
||||
{
|
||||
headers: {
|
||||
"Authorization": `token ${accessToken}`,
|
||||
"Content-Type": "application/json",
|
||||
"Accept-Encoding": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
Sentry.setUser(null);
|
||||
Sentry.captureException(err);
|
||||
throw new Error("Failed to sync secrets to TravisCI");
|
||||
}
|
||||
}
|
||||
|
||||
export { syncSecrets };
|
||||
|
@ -10,6 +10,7 @@ import {
|
||||
INTEGRATION_RENDER,
|
||||
INTEGRATION_FLYIO,
|
||||
INTEGRATION_CIRCLECI,
|
||||
INTEGRATION_TRAVISCI,
|
||||
} from "../variables";
|
||||
|
||||
export interface IIntegration {
|
||||
@ -33,7 +34,8 @@ export interface IIntegration {
|
||||
| 'github'
|
||||
| 'render'
|
||||
| 'flyio'
|
||||
| 'circleci';
|
||||
| 'circleci'
|
||||
| 'travisci';
|
||||
integrationAuth: Types.ObjectId;
|
||||
}
|
||||
|
||||
@ -97,6 +99,7 @@ const integrationSchema = new Schema<IIntegration>(
|
||||
INTEGRATION_RENDER,
|
||||
INTEGRATION_FLYIO,
|
||||
INTEGRATION_CIRCLECI,
|
||||
INTEGRATION_TRAVISCI,
|
||||
],
|
||||
required: true,
|
||||
},
|
||||
|
@ -10,12 +10,13 @@ import {
|
||||
INTEGRATION_RENDER,
|
||||
INTEGRATION_FLYIO,
|
||||
INTEGRATION_CIRCLECI,
|
||||
INTEGRATION_TRAVISCI,
|
||||
} from "../variables";
|
||||
|
||||
export interface IIntegrationAuth {
|
||||
_id: Types.ObjectId;
|
||||
workspace: Types.ObjectId;
|
||||
integration: 'heroku' | 'vercel' | 'netlify' | 'github' | 'render' | 'flyio' | 'azure-key-vault' | 'circleci' | 'aws-parameter-store' | 'aws-secret-manager';
|
||||
integration: 'heroku' | 'vercel' | 'netlify' | 'github' | 'render' | 'flyio' | 'azure-key-vault' | 'circleci' | 'travisci' | 'aws-parameter-store' | 'aws-secret-manager';
|
||||
teamId: string;
|
||||
accountId: string;
|
||||
refreshCiphertext?: string;
|
||||
@ -50,6 +51,7 @@ const integrationAuthSchema = new Schema<IIntegrationAuth>(
|
||||
INTEGRATION_RENDER,
|
||||
INTEGRATION_FLYIO,
|
||||
INTEGRATION_CIRCLECI,
|
||||
INTEGRATION_TRAVISCI,
|
||||
],
|
||||
required: true,
|
||||
},
|
||||
|
@ -16,9 +16,9 @@ const tokenDataSchema = new Schema<ITokenData>({
|
||||
type: {
|
||||
type: String,
|
||||
enum: [
|
||||
'emailConfirmation',
|
||||
'emailMfa',
|
||||
'organizationInvitation',
|
||||
'emailConfirmation',
|
||||
'emailMfa',
|
||||
'organizationInvitation',
|
||||
'passwordReset'
|
||||
],
|
||||
required: true
|
||||
@ -50,12 +50,6 @@ const tokenDataSchema = new Schema<ITokenData>({
|
||||
timestamps: true
|
||||
});
|
||||
|
||||
tokenDataSchema.index({
|
||||
expiresAt: 1
|
||||
}, {
|
||||
expireAfterSeconds: 0
|
||||
});
|
||||
|
||||
const TokenData = model<ITokenData>('TokenData', tokenDataSchema);
|
||||
|
||||
export default TokenData;
|
||||
|
@ -16,6 +16,7 @@ import {
|
||||
INTEGRATION_RENDER,
|
||||
INTEGRATION_FLYIO,
|
||||
INTEGRATION_CIRCLECI,
|
||||
INTEGRATION_TRAVISCI,
|
||||
INTEGRATION_SET,
|
||||
INTEGRATION_OAUTH2,
|
||||
INTEGRATION_AZURE_TOKEN_URL,
|
||||
@ -29,6 +30,7 @@ import {
|
||||
INTEGRATION_RENDER_API_URL,
|
||||
INTEGRATION_FLYIO_API_URL,
|
||||
INTEGRATION_CIRCLECI_API_URL,
|
||||
INTEGRATION_TRAVISCI_API_URL,
|
||||
INTEGRATION_OPTIONS,
|
||||
} from "./integration";
|
||||
import { OWNER, ADMIN, MEMBER, INVITED, ACCEPTED } from "./organization";
|
||||
@ -81,6 +83,7 @@ export {
|
||||
INTEGRATION_RENDER,
|
||||
INTEGRATION_FLYIO,
|
||||
INTEGRATION_CIRCLECI,
|
||||
INTEGRATION_TRAVISCI,
|
||||
INTEGRATION_SET,
|
||||
INTEGRATION_OAUTH2,
|
||||
INTEGRATION_AZURE_TOKEN_URL,
|
||||
@ -94,6 +97,7 @@ export {
|
||||
INTEGRATION_RENDER_API_URL,
|
||||
INTEGRATION_FLYIO_API_URL,
|
||||
INTEGRATION_CIRCLECI_API_URL,
|
||||
INTEGRATION_TRAVISCI_API_URL,
|
||||
EVENT_PUSH_SECRETS,
|
||||
EVENT_PULL_SECRETS,
|
||||
ACTION_LOGIN,
|
||||
|
@ -20,6 +20,7 @@ const INTEGRATION_GITHUB = "github";
|
||||
const INTEGRATION_RENDER = "render";
|
||||
const INTEGRATION_FLYIO = "flyio";
|
||||
const INTEGRATION_CIRCLECI = "circleci";
|
||||
const INTEGRATION_TRAVISCI = "travisci";
|
||||
const INTEGRATION_SET = new Set([
|
||||
INTEGRATION_AZURE_KEY_VAULT,
|
||||
INTEGRATION_HEROKU,
|
||||
@ -29,6 +30,7 @@ const INTEGRATION_SET = new Set([
|
||||
INTEGRATION_RENDER,
|
||||
INTEGRATION_FLYIO,
|
||||
INTEGRATION_CIRCLECI,
|
||||
INTEGRATION_TRAVISCI,
|
||||
]);
|
||||
|
||||
// integration types
|
||||
@ -50,6 +52,7 @@ const INTEGRATION_NETLIFY_API_URL = "https://api.netlify.com";
|
||||
const INTEGRATION_RENDER_API_URL = "https://api.render.com";
|
||||
const INTEGRATION_FLYIO_API_URL = "https://api.fly.io/graphql";
|
||||
const INTEGRATION_CIRCLECI_API_URL = "https://circleci.com/api";
|
||||
const INTEGRATION_TRAVISCI_API_URL = "https://api.travis-ci.com";
|
||||
|
||||
const INTEGRATION_OPTIONS = [
|
||||
{
|
||||
@ -134,6 +137,15 @@ const INTEGRATION_OPTIONS = [
|
||||
clientId: '',
|
||||
docsLink: ''
|
||||
},
|
||||
{
|
||||
name: 'Travis CI',
|
||||
slug: 'travisci',
|
||||
image: 'Travis CI.png',
|
||||
isAvailable: true,
|
||||
type: 'pat',
|
||||
clientId: '',
|
||||
docsLink: ''
|
||||
},
|
||||
{
|
||||
name: 'Azure Key Vault',
|
||||
slug: 'azure-key-vault',
|
||||
@ -152,15 +164,6 @@ const INTEGRATION_OPTIONS = [
|
||||
type: '',
|
||||
clientId: '',
|
||||
docsLink: ''
|
||||
},
|
||||
{
|
||||
name: 'Travis CI',
|
||||
slug: 'travisci',
|
||||
image: 'Travis CI.png',
|
||||
isAvailable: false,
|
||||
type: '',
|
||||
clientId: '',
|
||||
docsLink: ''
|
||||
}
|
||||
]
|
||||
|
||||
@ -175,6 +178,7 @@ export {
|
||||
INTEGRATION_RENDER,
|
||||
INTEGRATION_FLYIO,
|
||||
INTEGRATION_CIRCLECI,
|
||||
INTEGRATION_TRAVISCI,
|
||||
INTEGRATION_SET,
|
||||
INTEGRATION_OAUTH2,
|
||||
INTEGRATION_AZURE_TOKEN_URL,
|
||||
@ -188,5 +192,6 @@ export {
|
||||
INTEGRATION_RENDER_API_URL,
|
||||
INTEGRATION_FLYIO_API_URL,
|
||||
INTEGRATION_CIRCLECI_API_URL,
|
||||
INTEGRATION_TRAVISCI_API_URL,
|
||||
INTEGRATION_OPTIONS,
|
||||
};
|
||||
|
@ -7,7 +7,7 @@ require (
|
||||
github.com/muesli/mango-cobra v1.2.0
|
||||
github.com/muesli/roff v0.1.0
|
||||
github.com/spf13/cobra v1.6.1
|
||||
golang.org/x/crypto v0.6.0
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
|
||||
golang.org/x/term v0.5.0
|
||||
)
|
||||
|
||||
@ -31,7 +31,7 @@ require (
|
||||
github.com/oklog/ulid v1.3.1 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
go.mongodb.org/mongo-driver v1.10.0 // indirect
|
||||
golang.org/x/net v0.6.0 // indirect
|
||||
golang.org/x/net v0.7.0 // indirect
|
||||
golang.org/x/sys v0.5.0 // indirect
|
||||
)
|
||||
|
||||
|
16
cli/go.sum
16
cli/go.sum
@ -103,17 +103,13 @@ github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgk
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
|
||||
go.mongodb.org/mongo-driver v1.10.0 h1:UtV6N5k14upNp4LTduX0QCufG124fSu25Wz9tu94GLg=
|
||||
go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
|
||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@ -125,13 +121,9 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI=
|
||||
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
|
||||
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
|
49
cli/packages/cmd/cmd_test.go
Normal file
49
cli/packages/cmd/cmd_test.go
Normal file
@ -0,0 +1,49 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/Infisical/infisical-merge/packages/models"
|
||||
)
|
||||
|
||||
func TestFilterReservedEnvVars(t *testing.T) {
|
||||
|
||||
// some test env vars.
|
||||
// HOME and PATH are reserved key words and should be filtered out
|
||||
// XDG_SESSION_ID and LC_CTYPE are reserved key word prefixes and should be filtered out
|
||||
// The filter function only checks the keys of the env map, so we dont need to set any values
|
||||
env := map[string]models.SingleEnvironmentVariable{
|
||||
"test": {},
|
||||
"test2": {},
|
||||
"HOME": {},
|
||||
"PATH": {},
|
||||
"XDG_SESSION_ID": {},
|
||||
"LC_CTYPE": {},
|
||||
}
|
||||
|
||||
// check to see if there are any reserved key words in secrets to inject
|
||||
filterReservedEnvVars(env)
|
||||
|
||||
if len(env) != 2 {
|
||||
t.Errorf("Expected 2 secrets to be returned, got %d", len(env))
|
||||
}
|
||||
if _, ok := env["test"]; !ok {
|
||||
t.Errorf("Expected test to be returned")
|
||||
}
|
||||
if _, ok := env["test2"]; !ok {
|
||||
t.Errorf("Expected test2 to be returned")
|
||||
}
|
||||
if _, ok := env["HOME"]; ok {
|
||||
t.Errorf("Expected HOME to be filtered out")
|
||||
}
|
||||
if _, ok := env["PATH"]; ok {
|
||||
t.Errorf("Expected PATH to be filtered out")
|
||||
}
|
||||
if _, ok := env["XDG_SESSION_ID"]; ok {
|
||||
t.Errorf("Expected XDG_SESSION_ID to be filtered out")
|
||||
}
|
||||
if _, ok := env["LC_CTYPE"]; ok {
|
||||
t.Errorf("Expected LC_CTYPE to be filtered out")
|
||||
}
|
||||
|
||||
}
|
@ -38,7 +38,7 @@ var exportCmd = &cobra.Command{
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
environmentName, _ := cmd.Flags().GetString("env")
|
||||
if !cmd.Flags().Changed("env") {
|
||||
environmentFromWorkspace := util.GetEnvelopmentBasedOnGitBranch()
|
||||
environmentFromWorkspace := util.GetEnvFromWorkspaceFile()
|
||||
if environmentFromWorkspace != "" {
|
||||
environmentName = environmentFromWorkspace
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ func writeWorkspaceFile(selectedWorkspace models.Workspace) error {
|
||||
WorkspaceId: selectedWorkspace.ID,
|
||||
}
|
||||
|
||||
marshalledWorkspaceFile, err := json.Marshal(workspaceFileToSave)
|
||||
marshalledWorkspaceFile, err := json.MarshalIndent(workspaceFileToSave, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -234,8 +234,16 @@ var loginCmd = &cobra.Command{
|
||||
// clear backed up secrets from prev account
|
||||
util.DeleteBackupSecrets()
|
||||
|
||||
color.Green("Nice! You are logged in as: %v", email)
|
||||
whilte := color.New(color.FgGreen)
|
||||
boldWhite := whilte.Add(color.Bold)
|
||||
boldWhite.Printf(">>>> Welcome to Infisical!")
|
||||
boldWhite.Printf(" You are now logged in as %v <<<< \n", email)
|
||||
|
||||
plainBold := color.New(color.Bold)
|
||||
|
||||
plainBold.Println("\nQuick links")
|
||||
fmt.Println("- Learn to inject secrets into your application at https://infisical.com/docs/cli/usage")
|
||||
fmt.Println("- Stuck? Join our slack for quick support https://infisical.com/slack")
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ var runCmd = &cobra.Command{
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
environmentName, _ := cmd.Flags().GetString("env")
|
||||
if !cmd.Flags().Changed("env") {
|
||||
environmentFromWorkspace := util.GetEnvelopmentBasedOnGitBranch()
|
||||
environmentFromWorkspace := util.GetEnvFromWorkspaceFile()
|
||||
if environmentFromWorkspace != "" {
|
||||
environmentName = environmentFromWorkspace
|
||||
}
|
||||
@ -110,13 +110,7 @@ var runCmd = &cobra.Command{
|
||||
}
|
||||
|
||||
// check to see if there are any reserved key words in secrets to inject
|
||||
reservedEnvironmentVariables := []string{"HOME", "PATH", "PS1", "PS2"}
|
||||
for _, reservedEnvName := range reservedEnvironmentVariables {
|
||||
if _, ok := secretsByKey[reservedEnvName]; ok {
|
||||
delete(secretsByKey, reservedEnvName)
|
||||
util.PrintWarning(fmt.Sprintf("Infisical secret named [%v] has been removed because it is a reserved secret name", reservedEnvName))
|
||||
}
|
||||
}
|
||||
filterReservedEnvVars(secretsByKey)
|
||||
|
||||
// now add infisical secrets
|
||||
for k, v := range secretsByKey {
|
||||
@ -149,6 +143,37 @@ var runCmd = &cobra.Command{
|
||||
},
|
||||
}
|
||||
|
||||
var (
|
||||
reservedEnvVars = []string{
|
||||
"HOME", "PATH", "PS1", "PS2",
|
||||
"PWD", "EDITOR", "XAUTHORITY", "USER",
|
||||
"TERM", "TERMINFO", "SHELL", "MAIL",
|
||||
}
|
||||
|
||||
reservedEnvVarPrefixes = []string{
|
||||
"XDG_",
|
||||
"LC_",
|
||||
}
|
||||
)
|
||||
|
||||
func filterReservedEnvVars(env map[string]models.SingleEnvironmentVariable) {
|
||||
for _, reservedEnvName := range reservedEnvVars {
|
||||
if _, ok := env[reservedEnvName]; ok {
|
||||
delete(env, reservedEnvName)
|
||||
util.PrintWarning(fmt.Sprintf("Infisical secret named [%v] has been removed because it is a reserved secret name", reservedEnvName))
|
||||
}
|
||||
}
|
||||
|
||||
for _, reservedEnvPrefix := range reservedEnvVarPrefixes {
|
||||
for envName := range env {
|
||||
if strings.HasPrefix(envName, reservedEnvPrefix) {
|
||||
delete(env, envName)
|
||||
util.PrintWarning(fmt.Sprintf("Infisical secret named [%v] has been removed because it contains a reserved prefix", envName))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(runCmd)
|
||||
runCmd.Flags().String("token", "", "Fetch secrets using the Infisical Token")
|
||||
|
@ -32,7 +32,7 @@ var secretsCmd = &cobra.Command{
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
environmentName, _ := cmd.Flags().GetString("env")
|
||||
if !cmd.Flags().Changed("env") {
|
||||
environmentFromWorkspace := util.GetEnvelopmentBasedOnGitBranch()
|
||||
environmentFromWorkspace := util.GetEnvFromWorkspaceFile()
|
||||
if environmentFromWorkspace != "" {
|
||||
environmentName = environmentFromWorkspace
|
||||
}
|
||||
@ -98,7 +98,7 @@ var secretsSetCmd = &cobra.Command{
|
||||
|
||||
environmentName, _ := cmd.Flags().GetString("env")
|
||||
if !cmd.Flags().Changed("env") {
|
||||
environmentFromWorkspace := util.GetEnvelopmentBasedOnGitBranch()
|
||||
environmentFromWorkspace := util.GetEnvFromWorkspaceFile()
|
||||
if environmentFromWorkspace != "" {
|
||||
environmentName = environmentFromWorkspace
|
||||
}
|
||||
@ -277,7 +277,7 @@ var secretsDeleteCmd = &cobra.Command{
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
environmentName, _ := cmd.Flags().GetString("env")
|
||||
if !cmd.Flags().Changed("env") {
|
||||
environmentFromWorkspace := util.GetEnvelopmentBasedOnGitBranch()
|
||||
environmentFromWorkspace := util.GetEnvFromWorkspaceFile()
|
||||
if environmentFromWorkspace != "" {
|
||||
environmentName = environmentFromWorkspace
|
||||
}
|
||||
@ -338,7 +338,7 @@ var secretsDeleteCmd = &cobra.Command{
|
||||
func getSecretsByNames(cmd *cobra.Command, args []string) {
|
||||
environmentName, _ := cmd.Flags().GetString("env")
|
||||
if !cmd.Flags().Changed("env") {
|
||||
environmentFromWorkspace := util.GetEnvelopmentBasedOnGitBranch()
|
||||
environmentFromWorkspace := util.GetEnvFromWorkspaceFile()
|
||||
if environmentFromWorkspace != "" {
|
||||
environmentName = environmentFromWorkspace
|
||||
}
|
||||
@ -361,10 +361,7 @@ func getSecretsByNames(cmd *cobra.Command, args []string) {
|
||||
|
||||
requestedSecrets := []models.SingleEnvironmentVariable{}
|
||||
|
||||
secretsMap := make(map[string]models.SingleEnvironmentVariable)
|
||||
for _, secret := range secrets {
|
||||
secretsMap[secret.Key] = secret
|
||||
}
|
||||
secretsMap := getSecretsByKeys(secrets)
|
||||
|
||||
for _, secretKeyFromArg := range args {
|
||||
if value, ok := secretsMap[strings.ToUpper(secretKeyFromArg)]; ok {
|
||||
@ -384,7 +381,7 @@ func getSecretsByNames(cmd *cobra.Command, args []string) {
|
||||
func generateExampleEnv(cmd *cobra.Command, args []string) {
|
||||
environmentName, _ := cmd.Flags().GetString("env")
|
||||
if !cmd.Flags().Changed("env") {
|
||||
environmentFromWorkspace := util.GetEnvelopmentBasedOnGitBranch()
|
||||
environmentFromWorkspace := util.GetEnvFromWorkspaceFile()
|
||||
if environmentFromWorkspace != "" {
|
||||
environmentName = environmentFromWorkspace
|
||||
}
|
||||
@ -587,7 +584,7 @@ func addHash(input string) string {
|
||||
}
|
||||
|
||||
func getSecretsByKeys(secrets []models.SingleEnvironmentVariable) map[string]models.SingleEnvironmentVariable {
|
||||
secretMapByName := make(map[string]models.SingleEnvironmentVariable)
|
||||
secretMapByName := make(map[string]models.SingleEnvironmentVariable, len(secrets))
|
||||
|
||||
for _, secret := range secrets {
|
||||
secretMapByName[secret.Key] = secret
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/Infisical/infisical-merge/packages/models"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@ -73,7 +74,12 @@ func WorkspaceConfigFileExistsInCurrentPath() bool {
|
||||
}
|
||||
|
||||
func GetWorkSpaceFromFile() (models.WorkspaceConfigFile, error) {
|
||||
configFileAsBytes, err := os.ReadFile(INFISICAL_WORKSPACE_CONFIG_FILE_NAME)
|
||||
cfgFile, err := FindWorkspaceConfigFile()
|
||||
if err != nil {
|
||||
return models.WorkspaceConfigFile{}, err
|
||||
}
|
||||
|
||||
configFileAsBytes, err := os.ReadFile(cfgFile)
|
||||
if err != nil {
|
||||
return models.WorkspaceConfigFile{}, err
|
||||
}
|
||||
@ -87,6 +93,37 @@ func GetWorkSpaceFromFile() (models.WorkspaceConfigFile, error) {
|
||||
return workspaceConfigFile, nil
|
||||
}
|
||||
|
||||
// FindWorkspaceConfigFile searches for a .infisical.json file in the current directory and all parent directories.
|
||||
func FindWorkspaceConfigFile() (string, error) {
|
||||
dir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for {
|
||||
path := filepath.Join(dir, INFISICAL_WORKSPACE_CONFIG_FILE_NAME)
|
||||
_, err := os.Stat(path)
|
||||
if err == nil {
|
||||
// file found
|
||||
log.Debugf("FindWorkspaceConfigFile: workspace file found at [path=%s]", path)
|
||||
|
||||
return path, nil
|
||||
}
|
||||
|
||||
// check if we have reached the root directory
|
||||
if dir == filepath.Dir(dir) {
|
||||
break
|
||||
}
|
||||
|
||||
// move up one directory
|
||||
dir = filepath.Dir(dir)
|
||||
}
|
||||
|
||||
// file not found
|
||||
return "", fmt.Errorf("file not found: %s", INFISICAL_WORKSPACE_CONFIG_FILE_NAME)
|
||||
|
||||
}
|
||||
|
||||
func GetFullConfigFilePath() (fullPathToFile string, fullPathToDirectory string, err error) {
|
||||
homeDir, err := GetHomeDir()
|
||||
if err != nil {
|
||||
|
@ -89,8 +89,8 @@ func RequireServiceToken() {
|
||||
}
|
||||
|
||||
func RequireLocalWorkspaceFile() {
|
||||
workspaceFileExists := WorkspaceConfigFileExistsInCurrentPath()
|
||||
if !workspaceFileExists {
|
||||
workspaceFilePath, _ := FindWorkspaceConfigFile()
|
||||
if workspaceFilePath == "" {
|
||||
PrintErrorMessageAndExit("It looks you have not yet connected this project to Infisical", "To do so, run [infisical init] then run your command again")
|
||||
}
|
||||
|
||||
@ -115,8 +115,20 @@ func GetHashFromStringList(list []string) string {
|
||||
return fmt.Sprintf("%x", sum)
|
||||
}
|
||||
|
||||
// execCmd is a struct that holds the command and arguments to be executed.
|
||||
// By using this struct, we can easily mock the command and arguments.
|
||||
type execCmd struct {
|
||||
cmd string
|
||||
args []string
|
||||
}
|
||||
|
||||
var getCurrentBranchCmd = execCmd{
|
||||
cmd: "git",
|
||||
args: []string{"symbolic-ref", "--short", "HEAD"},
|
||||
}
|
||||
|
||||
func getCurrentBranch() (string, error) {
|
||||
cmd := exec.Command("git", "symbolic-ref", "--short", "HEAD")
|
||||
cmd := exec.Command(getCurrentBranchCmd.cmd, getCurrentBranchCmd.args...)
|
||||
var out bytes.Buffer
|
||||
cmd.Stdout = &out
|
||||
err := cmd.Run()
|
||||
|
@ -482,21 +482,29 @@ func DeleteBackupSecrets() error {
|
||||
return os.RemoveAll(fullPathToSecretsBackupFolder)
|
||||
}
|
||||
|
||||
func GetEnvelopmentBasedOnGitBranch() string {
|
||||
func GetEnvFromWorkspaceFile() string {
|
||||
workspaceFile, err := GetWorkSpaceFromFile()
|
||||
if err != nil {
|
||||
log.Debugf("getEnvFromWorkspaceFile: [err=%s]", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
if env := GetEnvelopmentBasedOnGitBranch(workspaceFile); env != "" {
|
||||
return env
|
||||
}
|
||||
|
||||
return workspaceFile.DefaultEnvironment
|
||||
}
|
||||
|
||||
func GetEnvelopmentBasedOnGitBranch(workspaceFile models.WorkspaceConfigFile) string {
|
||||
branch, err := getCurrentBranch()
|
||||
if err != nil {
|
||||
log.Debugf("getEnvelopmentBasedOnGitBranch: [err=%s]", err)
|
||||
}
|
||||
|
||||
workspaceFile, err := GetWorkSpaceFromFile()
|
||||
if err != nil {
|
||||
log.Debugf("getEnvelopmentBasedOnGitBranch: [err=%s]", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
envBasedOnGitBranch, ok := workspaceFile.GitBranchToEnvironmentMapping[branch]
|
||||
|
||||
log.Debugf("GetEnvelopmentBasedOnGitBranch: [envBasedOnGitBranch=%s] [ok=%s]", envBasedOnGitBranch, ok)
|
||||
log.Debugf("GetEnvelopmentBasedOnGitBranch: [envBasedOnGitBranch=%s] [ok=%t]", envBasedOnGitBranch, ok)
|
||||
|
||||
if err == nil && ok {
|
||||
return envBasedOnGitBranch
|
||||
|
@ -1,6 +1,9 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/Infisical/infisical-merge/packages/models"
|
||||
@ -158,3 +161,98 @@ func Test_SubstituteSecrets_When_No_SubstituteNeeded(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Read_Env_From_File(t *testing.T) {
|
||||
type testCase struct {
|
||||
TestFile string
|
||||
ExpectedEnv string
|
||||
}
|
||||
|
||||
var cases = []testCase{
|
||||
{
|
||||
TestFile: "testdata/infisical-default-env.json",
|
||||
ExpectedEnv: "myDefaultEnv",
|
||||
},
|
||||
{
|
||||
TestFile: "testdata/infisical-branch-env.json",
|
||||
ExpectedEnv: "myMainEnv",
|
||||
},
|
||||
{
|
||||
TestFile: "testdata/infisical-no-matching-branch-env.json",
|
||||
ExpectedEnv: "myDefaultEnv",
|
||||
},
|
||||
}
|
||||
|
||||
// create a tmp directory for testing
|
||||
testDir, err := os.MkdirTemp(os.TempDir(), "infisical-test")
|
||||
if err != nil {
|
||||
t.Errorf("Test_Read_DefaultEnv_From_File: Failed to create temp directory: %s", err)
|
||||
}
|
||||
|
||||
// safe the current working directory
|
||||
originalDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Errorf("Test_Read_DefaultEnv_From_File: Failed to get current working directory: %s", err)
|
||||
}
|
||||
|
||||
// backup the original git command
|
||||
originalGitCmd := getCurrentBranchCmd
|
||||
|
||||
// make sure to clean up after the test
|
||||
t.Cleanup(func() {
|
||||
os.Chdir(originalDir)
|
||||
os.RemoveAll(testDir)
|
||||
getCurrentBranchCmd = originalGitCmd
|
||||
})
|
||||
|
||||
// mock the git command to return "main" as the current branch
|
||||
getCurrentBranchCmd = execCmd{cmd: "echo", args: []string{"main"}}
|
||||
|
||||
for _, c := range cases {
|
||||
// make sure we start in the original directory
|
||||
err = os.Chdir(originalDir)
|
||||
if err != nil {
|
||||
t.Errorf("Test_Read_DefaultEnv_From_File: Failed to change working directory: %s", err)
|
||||
}
|
||||
|
||||
// remove old test file if it exists
|
||||
err = os.Remove(path.Join(testDir, INFISICAL_WORKSPACE_CONFIG_FILE_NAME))
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
t.Errorf("Test_Read_DefaultEnv_From_File: Failed to remove old test file: %s", err)
|
||||
}
|
||||
|
||||
// deploy the test file
|
||||
copyTestFile(t, c.TestFile, path.Join(testDir, INFISICAL_WORKSPACE_CONFIG_FILE_NAME))
|
||||
|
||||
// change the working directory to the tmp directory
|
||||
err = os.Chdir(testDir)
|
||||
if err != nil {
|
||||
t.Errorf("Test_Read_DefaultEnv_From_File: Failed to change working directory: %s", err)
|
||||
}
|
||||
|
||||
// get env from file
|
||||
env := GetEnvFromWorkspaceFile()
|
||||
if env != c.ExpectedEnv {
|
||||
t.Errorf("Test_Read_DefaultEnv_From_File: Expected env to be %s but got %s", c.ExpectedEnv, env)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func copyTestFile(t *testing.T, src, dst string) {
|
||||
srcFile, err := os.Open(src)
|
||||
if err != nil {
|
||||
t.Errorf("Test_Read_Env_From_File_By_Branch: Failed to open source file: %s", err)
|
||||
}
|
||||
defer srcFile.Close()
|
||||
|
||||
dstFile, err := os.Create(dst)
|
||||
if err != nil {
|
||||
t.Errorf("Test_Read_Env_From_File_By_Branch: Failed to create destination file: %s", err)
|
||||
}
|
||||
defer dstFile.Close()
|
||||
|
||||
_, err = io.Copy(dstFile, srcFile)
|
||||
if err != nil {
|
||||
t.Errorf("Test_Read_Env_From_File_By_Branch: Failed to copy file: %s", err)
|
||||
}
|
||||
}
|
||||
|
7
cli/packages/util/testdata/infisical-branch-env.json
vendored
Normal file
7
cli/packages/util/testdata/infisical-branch-env.json
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"workspaceId": "12345678",
|
||||
"defaultEnvironment": "myDefaultEnv",
|
||||
"gitBranchToEnvironmentMapping": {
|
||||
"main": "myMainEnv"
|
||||
}
|
||||
}
|
5
cli/packages/util/testdata/infisical-default-env.json
vendored
Normal file
5
cli/packages/util/testdata/infisical-default-env.json
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"workspaceId": "12345678",
|
||||
"defaultEnvironment": "myDefaultEnv",
|
||||
"gitBranchToEnvironmentMapping": null
|
||||
}
|
7
cli/packages/util/testdata/infisical-no-matching-branch-env.json
vendored
Normal file
7
cli/packages/util/testdata/infisical-no-matching-branch-env.json
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"workspaceId": "12345678",
|
||||
"defaultEnvironment": "myDefaultEnv",
|
||||
"gitBranchToEnvironmentMapping": {
|
||||
"notmain": "myMainEnv"
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
version: '3'
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
nginx:
|
||||
@ -22,7 +22,6 @@ services:
|
||||
depends_on:
|
||||
- mongo
|
||||
image: infisical/backend
|
||||
command: npm run start
|
||||
env_file: .env
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
|
@ -20,7 +20,7 @@ The Infisical CLI provides a way to inject environment variables from the platfo
|
||||
### Updates
|
||||
|
||||
```bash
|
||||
brew upgrade infisical
|
||||
brew update && brew upgrade infisical
|
||||
```
|
||||
|
||||
</Tab>
|
||||
@ -45,19 +45,19 @@ The Infisical CLI provides a way to inject environment variables from the platfo
|
||||
<Tab title="Alpine">
|
||||
Install prerequisite
|
||||
```bash
|
||||
sudo apk add --no-cache bash sudo
|
||||
apk add --no-cache bash sudo
|
||||
```
|
||||
|
||||
Add Infisical repository
|
||||
```bash
|
||||
curl -1sLf \
|
||||
'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.alpine.sh' \
|
||||
| sudo -E bash
|
||||
| bash
|
||||
```
|
||||
|
||||
Then install CLI
|
||||
```bash
|
||||
sudo apk update && sudo apk add infisical
|
||||
apk update && sudo apk add infisical
|
||||
```
|
||||
|
||||
</Tab>
|
||||
|
@ -7,6 +7,24 @@ To link your local project on your machine with an Infisical project, we suggest
|
||||
|
||||
The `.infisical.json` file specifies various parameters, such as the Infisical project to retrieve secrets from, along with other configuration options. Furthermore, you can define additional properties in the file to further tailor your local development experience.
|
||||
|
||||
## Set default environment
|
||||
If you need to change environments while using the CLI, you can do so by including the `--env` flag in your command.
|
||||
However, this can be inconvenient if you typically work in just one environment.
|
||||
To simplify the process, you can establish a default environment, which will be used for every command unless you specify otherwise.
|
||||
|
||||
```json .infisical.json
|
||||
{
|
||||
"workspaceId": "63ee5410a45f7a1ed39ba118",
|
||||
"defaultEnvironment": "test",
|
||||
"gitBranchToEnvironmentMapping": null
|
||||
}
|
||||
```
|
||||
|
||||
### How it works
|
||||
If both `defaultEnvironment` and `gitBranchToEnvironmentMapping` are configured, `gitBranchToEnvironmentMapping` will take precedence over `defaultEnvironment`.
|
||||
However, if `gitBranchToEnvironmentMapping` is not set and `defaultEnvironment` is, then the `defaultEnvironment` will be used to execute your Infisical CLI commands.
|
||||
If you wish to override the `defaultEnvironment`, you can do so by using the `--env` flag explicitly.
|
||||
|
||||
## Set Infisical environment based on GitHub branch
|
||||
When fetching your secrets from Infisical, you can switch between environments by using the `--env` flag. However, in certain cases, you may prefer the environment to be automatically mapped based on the current GitHub branch you are working on.
|
||||
To achieve this, simply add the `gitBranchToEnvironmentMapping` property to your configuration file, as shown below.
|
||||
@ -23,4 +41,4 @@ To achieve this, simply add the `gitBranchToEnvironmentMapping` property to your
|
||||
|
||||
### How it works
|
||||
After configuring this property, every time you use the CLI with the specified configuration file, it will automatically verify if there is a corresponding environment mapping for the current Github branch you are on.
|
||||
If it exists, the CLI will use that environment to retrieve secrets. You can override this behavior by explicitly using the `--env` flag while interacting with the CLI.
|
||||
If it exists, the CLI will use that environment to retrieve secrets. You can override this behavior by explicitly using the `--env` flag while interacting with the CLI.
|
||||
|
@ -1,12 +1,12 @@
|
||||
---
|
||||
title: "Activity Logs"
|
||||
title: "Audit Logs"
|
||||
description: "See which events are triggered within your Infisical project."
|
||||
---
|
||||
|
||||
Activity logs record all actions going through Infisical including who performed which CRUD operations on environment variables and from what IP address. They help answer questions like:
|
||||
Audit logs record all actions going through Infisical including who performed which CRUD operations on environment variables and from what IP address. They help answer questions like:
|
||||
|
||||
- Who added or updated environment variables recently?
|
||||
- Did Bob read environment variables last week (if at all)?
|
||||
- What IP address was used for that action?
|
||||
|
||||

|
||||

|
||||
|
@ -12,7 +12,7 @@ This is a non-exhaustive list of features that Infisical offers:
|
||||
- Sync secrets to platforms via integrations to platforms like GitHub, Vercel, and Netlify.
|
||||
- Rollback secrets to any point in time.
|
||||
- Rollback each secrets to any version.
|
||||
- Track actions through activity logs.
|
||||
- Track actions through audit logs.
|
||||
|
||||
## CLI
|
||||
|
||||
|
BIN
docs/images/integrations-travisci-auth.png
Normal file
BIN
docs/images/integrations-travisci-auth.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 166 KiB |
BIN
docs/images/integrations-travisci-create.png
Normal file
BIN
docs/images/integrations-travisci-create.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 184 KiB |
BIN
docs/images/integrations-travisci-token.png
Normal file
BIN
docs/images/integrations-travisci-token.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 292 KiB |
BIN
docs/images/integrations-travisci.png
Normal file
BIN
docs/images/integrations-travisci.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 370 KiB |
Binary file not shown.
Before Width: | Height: | Size: 385 KiB After Width: | Height: | Size: 424 KiB |
@ -1,5 +1,5 @@
|
||||
---
|
||||
title: "Circle CI"
|
||||
title: "CircleCI"
|
||||
description: "How to automatically sync secrets from Infisical into your CircleCI project."
|
||||
---
|
||||
|
||||
@ -32,5 +32,5 @@ Press on the CircleCI tile and input your CircleCI API token to grant Infisical
|
||||
|
||||
Select which Infisical environment secrets you want to sync to which CircleCI project and press create integration to start syncing secrets to CircleCI.
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
36
docs/integrations/cicd/travisci.mdx
Normal file
36
docs/integrations/cicd/travisci.mdx
Normal file
@ -0,0 +1,36 @@
|
||||
---
|
||||
title: "Travis CI"
|
||||
description: "How to automatically sync secrets from Infisical to your Travis CI repository."
|
||||
---
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- Set up and add envars to [Infisical Cloud](https://app.infisical.com)
|
||||
|
||||
## Navigate to your project's integrations tab
|
||||
|
||||

|
||||
|
||||
## Authorize Infisical for Travis CI
|
||||
|
||||
Obtain your API token in User Settings > API authentication > Token
|
||||
|
||||

|
||||
|
||||
Press on the Travis CI tile and input your Travis CI API token to grant Infisical access to your Travis CI account.
|
||||
|
||||

|
||||
|
||||
<Info>
|
||||
If this is your project's first cloud integration, then you'll have to grant
|
||||
Infisical access to your project's environment variables. Although this step
|
||||
breaks E2EE, it's necessary for Infisical to sync the environment variables to
|
||||
the cloud platform.
|
||||
</Info>
|
||||
|
||||
## Start integration
|
||||
|
||||
Select which Infisical environment secrets you want to sync to which Travis CI repository and press create integration to start syncing secrets to Travis CI.
|
||||
|
||||

|
||||

|
@ -23,6 +23,7 @@ Missing an integration? Throw in a [request](https://github.com/Infisical/infisi
|
||||
| [GitHub Actions](/integrations/cicd/githubactions) | CI/CD | Available |
|
||||
| [GitLab Pipeline](/integrations/cicd/gitlab) | CI/CD | Available |
|
||||
| [CircleCI](/integrations/cicd/circleci) | CI/CD | Available |
|
||||
| [Travis CI](/integrations/cicd/travisci) | CI/CD | Available |
|
||||
| [React](/integrations/frameworks/react) | Framework | Available |
|
||||
| [Vue](/integrations/frameworks/vue) | Framework | Available |
|
||||
| [Express](/integrations/frameworks/express) | Framework | Available |
|
||||
@ -41,6 +42,5 @@ Missing an integration? Throw in a [request](https://github.com/Infisical/infisi
|
||||
| GCP | Cloud | Coming soon |
|
||||
| Azure | Cloud | Coming soon |
|
||||
| DigitalOcean | Cloud | Coming soon |
|
||||
| TravisCI | CI/CD | Coming soon |
|
||||
| GitHub Actions | CI/CD | Coming soon |
|
||||
| Jenkins | CI/CD | Coming soon |
|
||||
|
@ -233,7 +233,8 @@
|
||||
"pages": [
|
||||
"integrations/cicd/githubactions",
|
||||
"integrations/cicd/gitlab",
|
||||
"integrations/cicd/circleci"
|
||||
"integrations/cicd/circleci",
|
||||
"integrations/cicd/travisci"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -8,7 +8,7 @@ module.exports = {
|
||||
debug: false,
|
||||
i18n: {
|
||||
defaultLocale: "en",
|
||||
locales: ["en", "ko", "fr", "pt-BR"],
|
||||
locales: ["en", "ko", "fr", "pt-BR", "pt-PT"],
|
||||
},
|
||||
fallbackLng: {
|
||||
default: ["en"],
|
||||
|
105
frontend/package-lock.json
generated
105
frontend/package-lock.json
generated
@ -13,7 +13,7 @@
|
||||
"@fortawesome/free-regular-svg-icons": "^6.1.1",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.1.2",
|
||||
"@fortawesome/react-fontawesome": "^0.1.19",
|
||||
"@headlessui/react": "^1.6.6",
|
||||
"@headlessui/react": "^1.7.7",
|
||||
"@hookform/resolvers": "^2.9.10",
|
||||
"@octokit/rest": "^19.0.7",
|
||||
"@radix-ui/react-accordion": "^1.1.0",
|
||||
@ -30,14 +30,14 @@
|
||||
"@radix-ui/react-tabs": "^1.0.2",
|
||||
"@radix-ui/react-toast": "^1.1.2",
|
||||
"@reduxjs/toolkit": "^1.8.3",
|
||||
"@stripe/react-stripe-js": "^1.10.0",
|
||||
"@stripe/react-stripe-js": "^1.16.3",
|
||||
"@stripe/stripe-js": "^1.46.0",
|
||||
"@tanstack/react-query": "^4.23.0",
|
||||
"@types/argon2-browser": "^1.18.1",
|
||||
"add": "^2.0.6",
|
||||
"argon2-browser": "^1.18.0",
|
||||
"axios": "^0.27.2",
|
||||
"axios-auth-refresh": "^3.3.3",
|
||||
"axios-auth-refresh": "^3.3.6",
|
||||
"base64-loader": "^1.0.0",
|
||||
"classnames": "^2.3.1",
|
||||
"cookies": "^0.8.0",
|
||||
@ -45,13 +45,13 @@
|
||||
"fs": "^0.0.1-security",
|
||||
"gray-matter": "^4.0.3",
|
||||
"http-proxy": "^1.18.1",
|
||||
"i18next": "^22.4.6",
|
||||
"i18next": "^22.4.9",
|
||||
"jspdf": "^2.5.1",
|
||||
"jsrp": "^0.2.4",
|
||||
"markdown-it": "^13.0.1",
|
||||
"next": "^12.3.4",
|
||||
"next-i18next": "^13.0.2",
|
||||
"posthog-js": "^1.34.0",
|
||||
"posthog-js": "^1.39.4",
|
||||
"query-string": "^7.1.3",
|
||||
"react": "^17.0.2",
|
||||
"react-beautiful-dnd": "^13.1.1",
|
||||
@ -2544,9 +2544,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@headlessui/react": {
|
||||
"version": "1.6.6",
|
||||
"resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.6.6.tgz",
|
||||
"integrity": "sha512-MFJtmj9Xh/hhBMhLccGbBoSk+sk61BlP6sJe4uQcVMtXZhCgGqd2GyIQzzmsdPdTEWGSF434CBi8mnhR6um46Q==",
|
||||
"version": "1.7.7",
|
||||
"resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.7.tgz",
|
||||
"integrity": "sha512-BqDOd/tB9u2tA0T3Z0fn18ktw+KbVwMnkxxsGPIH2hzssrQhKB5n/6StZOyvLYP/FsYtvuXfi9I0YowKPv2c1w==",
|
||||
"dependencies": {
|
||||
"client-only": "^0.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
@ -3935,9 +3938,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@sentry/types": {
|
||||
"version": "7.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.15.0.tgz",
|
||||
"integrity": "sha512-MN9haDRh9ZOsTotoDTHu2BT3sT8Vs1F0alhizUpDyjN2YgBCqR6JV+AbAE1XNHwS2+5zbppch1PwJUVeE58URQ==",
|
||||
"version": "7.22.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.22.0.tgz",
|
||||
"integrity": "sha512-LhCL+wb1Jch+OesB2CIt6xpfO1Ab6CRvoNYRRzVumWPLns1T3ZJkarYfhbLaOEIb38EIbPgREdxn2AJT560U4Q==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@ -6281,14 +6284,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@stripe/react-stripe-js": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@stripe/react-stripe-js/-/react-stripe-js-1.10.0.tgz",
|
||||
"integrity": "sha512-vuIjJUZJ3nyiaGa5z5iyMCzZfGGsgzOOjWjqknbbhkNsewyyginfeky9EZLSz9+iSAsgC9K6MeNOTLKVGcMycQ==",
|
||||
"version": "1.16.3",
|
||||
"resolved": "https://registry.npmjs.org/@stripe/react-stripe-js/-/react-stripe-js-1.16.3.tgz",
|
||||
"integrity": "sha512-gS6UDGEuM92K50pFB3o//EqqPxmaqpC8IrsBda4P4LxeULoO0pBFSHXJ5Ab6uA7G2lyO2bluvSLereh0OH9GrQ==",
|
||||
"dependencies": {
|
||||
"prop-types": "^15.7.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@stripe/stripe-js": "^1.34.0",
|
||||
"@stripe/stripe-js": "^1.44.1",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
||||
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
@ -8157,9 +8160,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/axios-auth-refresh": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/axios-auth-refresh/-/axios-auth-refresh-3.3.3.tgz",
|
||||
"integrity": "sha512-2IbDhJ/h6ddNBBnnzn1VFK/qx17pE9aVqiafB8rx5LVHsJ1HtFpUGkbXY7PzTG+8P9HJWcyA3fNZl9BikSuilg==",
|
||||
"version": "3.3.6",
|
||||
"resolved": "https://registry.npmjs.org/axios-auth-refresh/-/axios-auth-refresh-3.3.6.tgz",
|
||||
"integrity": "sha512-2CeBUce/SxIfFxow5/n8vApJ97yYF6qoV4gh1UrswT7aEOnlOdBLxxyhOI4IaxGs6BY0l8YujU2jlc4aCmK17Q==",
|
||||
"peerDependencies": {
|
||||
"axios": ">= 0.18 < 0.19.0 || >= 0.19.1"
|
||||
}
|
||||
@ -9205,6 +9208,11 @@
|
||||
"@colors/colors": "1.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/client-only": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
|
||||
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="
|
||||
},
|
||||
"node_modules/cliui": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
||||
@ -13224,9 +13232,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/i18next": {
|
||||
"version": "22.4.6",
|
||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-22.4.6.tgz",
|
||||
"integrity": "sha512-9Tm1ezxWyzV+306CIDMBbYBitC1jedQyYuuLtIv7oxjp2ohh8eyxP9xytIf+2bbQfhH784IQKPSYp+Zq9+YSbw==",
|
||||
"version": "22.4.9",
|
||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-22.4.9.tgz",
|
||||
"integrity": "sha512-8gWMmUz460KJDQp/ob3MNUX84cVuDRY9PLFPnV8d+Qezz/6dkjxwOaH70xjrCNDO+JrUL25iXfAIN9wUkInNZw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@ -17079,11 +17087,11 @@
|
||||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
|
||||
},
|
||||
"node_modules/posthog-js": {
|
||||
"version": "1.34.0",
|
||||
"resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.34.0.tgz",
|
||||
"integrity": "sha512-HkRwwzdz31N5ykQIO3SIkSS8nwhdqqnuDZ/qltitX4FhxrV9/tSRavEXz0YLvioOXeNVmQWtsN3krKajErwkwg==",
|
||||
"version": "1.39.4",
|
||||
"resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.39.4.tgz",
|
||||
"integrity": "sha512-Elpf1gwyuObueXi89iH+9pP+WhpkiivP8Qwej4RzOLwSTa7Floaa4rgAw7rnCnX1PtRoJ3F0kqb6q9T+aZjRiA==",
|
||||
"dependencies": {
|
||||
"@sentry/types": "^7.2.0",
|
||||
"@sentry/types": "7.22.0",
|
||||
"fflate": "^0.4.1",
|
||||
"rrweb-snapshot": "^1.1.14"
|
||||
}
|
||||
@ -23946,10 +23954,12 @@
|
||||
}
|
||||
},
|
||||
"@headlessui/react": {
|
||||
"version": "1.6.6",
|
||||
"resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.6.6.tgz",
|
||||
"integrity": "sha512-MFJtmj9Xh/hhBMhLccGbBoSk+sk61BlP6sJe4uQcVMtXZhCgGqd2GyIQzzmsdPdTEWGSF434CBi8mnhR6um46Q==",
|
||||
"requires": {}
|
||||
"version": "1.7.7",
|
||||
"resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.7.tgz",
|
||||
"integrity": "sha512-BqDOd/tB9u2tA0T3Z0fn18ktw+KbVwMnkxxsGPIH2hzssrQhKB5n/6StZOyvLYP/FsYtvuXfi9I0YowKPv2c1w==",
|
||||
"requires": {
|
||||
"client-only": "^0.0.1"
|
||||
}
|
||||
},
|
||||
"@hookform/resolvers": {
|
||||
"version": "2.9.10",
|
||||
@ -24987,9 +24997,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@sentry/types": {
|
||||
"version": "7.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.15.0.tgz",
|
||||
"integrity": "sha512-MN9haDRh9ZOsTotoDTHu2BT3sT8Vs1F0alhizUpDyjN2YgBCqR6JV+AbAE1XNHwS2+5zbppch1PwJUVeE58URQ=="
|
||||
"version": "7.22.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.22.0.tgz",
|
||||
"integrity": "sha512-LhCL+wb1Jch+OesB2CIt6xpfO1Ab6CRvoNYRRzVumWPLns1T3ZJkarYfhbLaOEIb38EIbPgREdxn2AJT560U4Q=="
|
||||
},
|
||||
"@sinclair/typebox": {
|
||||
"version": "0.24.51",
|
||||
@ -26659,9 +26669,9 @@
|
||||
}
|
||||
},
|
||||
"@stripe/react-stripe-js": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@stripe/react-stripe-js/-/react-stripe-js-1.10.0.tgz",
|
||||
"integrity": "sha512-vuIjJUZJ3nyiaGa5z5iyMCzZfGGsgzOOjWjqknbbhkNsewyyginfeky9EZLSz9+iSAsgC9K6MeNOTLKVGcMycQ==",
|
||||
"version": "1.16.3",
|
||||
"resolved": "https://registry.npmjs.org/@stripe/react-stripe-js/-/react-stripe-js-1.16.3.tgz",
|
||||
"integrity": "sha512-gS6UDGEuM92K50pFB3o//EqqPxmaqpC8IrsBda4P4LxeULoO0pBFSHXJ5Ab6uA7G2lyO2bluvSLereh0OH9GrQ==",
|
||||
"requires": {
|
||||
"prop-types": "^15.7.2"
|
||||
}
|
||||
@ -28115,9 +28125,9 @@
|
||||
}
|
||||
},
|
||||
"axios-auth-refresh": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/axios-auth-refresh/-/axios-auth-refresh-3.3.3.tgz",
|
||||
"integrity": "sha512-2IbDhJ/h6ddNBBnnzn1VFK/qx17pE9aVqiafB8rx5LVHsJ1HtFpUGkbXY7PzTG+8P9HJWcyA3fNZl9BikSuilg==",
|
||||
"version": "3.3.6",
|
||||
"resolved": "https://registry.npmjs.org/axios-auth-refresh/-/axios-auth-refresh-3.3.6.tgz",
|
||||
"integrity": "sha512-2CeBUce/SxIfFxow5/n8vApJ97yYF6qoV4gh1UrswT7aEOnlOdBLxxyhOI4IaxGs6BY0l8YujU2jlc4aCmK17Q==",
|
||||
"requires": {}
|
||||
},
|
||||
"axobject-query": {
|
||||
@ -28888,6 +28898,11 @@
|
||||
"string-width": "^4.2.0"
|
||||
}
|
||||
},
|
||||
"client-only": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
|
||||
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="
|
||||
},
|
||||
"cliui": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
||||
@ -31990,9 +32005,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"i18next": {
|
||||
"version": "22.4.6",
|
||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-22.4.6.tgz",
|
||||
"integrity": "sha512-9Tm1ezxWyzV+306CIDMBbYBitC1jedQyYuuLtIv7oxjp2ohh8eyxP9xytIf+2bbQfhH784IQKPSYp+Zq9+YSbw==",
|
||||
"version": "22.4.9",
|
||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-22.4.9.tgz",
|
||||
"integrity": "sha512-8gWMmUz460KJDQp/ob3MNUX84cVuDRY9PLFPnV8d+Qezz/6dkjxwOaH70xjrCNDO+JrUL25iXfAIN9wUkInNZw==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.20.6"
|
||||
}
|
||||
@ -34690,11 +34705,11 @@
|
||||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
|
||||
},
|
||||
"posthog-js": {
|
||||
"version": "1.34.0",
|
||||
"resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.34.0.tgz",
|
||||
"integrity": "sha512-HkRwwzdz31N5ykQIO3SIkSS8nwhdqqnuDZ/qltitX4FhxrV9/tSRavEXz0YLvioOXeNVmQWtsN3krKajErwkwg==",
|
||||
"version": "1.39.4",
|
||||
"resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.39.4.tgz",
|
||||
"integrity": "sha512-Elpf1gwyuObueXi89iH+9pP+WhpkiivP8Qwej4RzOLwSTa7Floaa4rgAw7rnCnX1PtRoJ3F0kqb6q9T+aZjRiA==",
|
||||
"requires": {
|
||||
"@sentry/types": "^7.2.0",
|
||||
"@sentry/types": "7.22.0",
|
||||
"fflate": "^0.4.1",
|
||||
"rrweb-snapshot": "^1.1.14"
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
"@fortawesome/free-regular-svg-icons": "^6.1.1",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.1.2",
|
||||
"@fortawesome/react-fontawesome": "^0.1.19",
|
||||
"@headlessui/react": "^1.6.6",
|
||||
"@headlessui/react": "^1.7.7",
|
||||
"@hookform/resolvers": "^2.9.10",
|
||||
"@octokit/rest": "^19.0.7",
|
||||
"@radix-ui/react-accordion": "^1.1.0",
|
||||
@ -37,14 +37,14 @@
|
||||
"@radix-ui/react-tabs": "^1.0.2",
|
||||
"@radix-ui/react-toast": "^1.1.2",
|
||||
"@reduxjs/toolkit": "^1.8.3",
|
||||
"@stripe/react-stripe-js": "^1.10.0",
|
||||
"@stripe/react-stripe-js": "^1.16.3",
|
||||
"@stripe/stripe-js": "^1.46.0",
|
||||
"@types/argon2-browser": "^1.18.1",
|
||||
"@tanstack/react-query": "^4.23.0",
|
||||
"add": "^2.0.6",
|
||||
"argon2-browser": "^1.18.0",
|
||||
"axios": "^0.27.2",
|
||||
"axios-auth-refresh": "^3.3.3",
|
||||
"axios-auth-refresh": "^3.3.6",
|
||||
"base64-loader": "^1.0.0",
|
||||
"classnames": "^2.3.1",
|
||||
"cookies": "^0.8.0",
|
||||
@ -52,13 +52,13 @@
|
||||
"fs": "^0.0.1-security",
|
||||
"gray-matter": "^4.0.3",
|
||||
"http-proxy": "^1.18.1",
|
||||
"i18next": "^22.4.6",
|
||||
"i18next": "^22.4.9",
|
||||
"jspdf": "^2.5.1",
|
||||
"jsrp": "^0.2.4",
|
||||
"markdown-it": "^13.0.1",
|
||||
"next": "^12.3.4",
|
||||
"next-i18next": "^13.0.2",
|
||||
"posthog-js": "^1.34.0",
|
||||
"posthog-js": "^1.39.4",
|
||||
"query-string": "^7.1.3",
|
||||
"react": "^17.0.2",
|
||||
"react-beautiful-dnd": "^13.1.1",
|
||||
|
@ -12,7 +12,8 @@ const integrationSlugNameMapping: Mapping = {
|
||||
'github': 'GitHub',
|
||||
'render': 'Render',
|
||||
'flyio': 'Fly.io',
|
||||
"circleci": 'CircleCI'
|
||||
'circleci': 'CircleCI',
|
||||
'travisci': 'TravisCI'
|
||||
}
|
||||
|
||||
const envMapping: Mapping = {
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"title": "Activity Logs",
|
||||
"title": "Audit Logs",
|
||||
"subtitle": "Event history for this Infisical project.",
|
||||
"event": {
|
||||
"readSecrets": "Secrets Viewed",
|
||||
|
@ -13,8 +13,8 @@
|
||||
"project-id": "Project ID",
|
||||
"save-changes": "Save Changes",
|
||||
"saved": "Saved",
|
||||
"drop-zone": "Drag and drop a .env or .yml file here.",
|
||||
"drop-zone-keys": "Drag and drop a .env or .yml file here to add more secrets.",
|
||||
"drop-zone": "Drag and drop a .env, .json, or .yml file here.",
|
||||
"drop-zone-keys": "Drag and drop a .env, .json, or .yml file here to add more secrets.",
|
||||
"role": "Role",
|
||||
"role_admin": "admin",
|
||||
"display-name": "Display Name",
|
||||
|
11
frontend/public/locales/pt-PT/activity.json
Normal file
11
frontend/public/locales/pt-PT/activity.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"title": "Registo de Atividade",
|
||||
"subtitle": "Histórico de eventos para este projeto Infisical.",
|
||||
"event": {
|
||||
"readSecrets": "Segredos Vistos",
|
||||
"updateSecrets": "Segredos Atualizados",
|
||||
"addSecrets": "Segredos Adicionados",
|
||||
"deleteSecrets": "Segredos Apagados"
|
||||
},
|
||||
"ip-address": "Endereço IP"
|
||||
}
|
28
frontend/public/locales/pt-PT/billing.json
Normal file
28
frontend/public/locales/pt-PT/billing.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"title": "Utilização & Faturação",
|
||||
"description": "Vê e faz a gestão da subscrição da tua organização aqui",
|
||||
"subscription": "Subscrição",
|
||||
"starter": {
|
||||
"name": "Base",
|
||||
"price-explanation": "Até 5 membros de equipa",
|
||||
"text": "Faz a gestão a qualquer projeto com 5 membros gratuitamente!",
|
||||
"subtext": "$5 por membro adicional / mês."
|
||||
},
|
||||
"professional": {
|
||||
"name": "Profissional",
|
||||
"price-explanation": "/membro/mês",
|
||||
"subtext": "Inclui projetos e membros ilimitados.",
|
||||
"text": "Acompanha a gestão de chaves à medida que cresces."
|
||||
},
|
||||
"enterprise": {
|
||||
"name": "Empresarial",
|
||||
"text": "Acompanha a gestão de chaves à medida que cresces."
|
||||
},
|
||||
"current-usage": "Utilização atual",
|
||||
"free": "Grátis",
|
||||
"downgrade": "Reduzir",
|
||||
"upgrade": "Melhorar",
|
||||
"learn-more": "Saber mais",
|
||||
"custom-pricing": "Preço personalizado",
|
||||
"schedule-demo": "Marca uma demonstração"
|
||||
}
|
34
frontend/public/locales/pt-PT/common.json
Normal file
34
frontend/public/locales/pt-PT/common.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"head-title": "{{title}} | Infisical",
|
||||
"error_project-already-exists": "Já existe um projeto com este nome.",
|
||||
"no-mobile": "Para usar o Infisical, inicia a sessão através dum dispositivo com resolução maior.",
|
||||
"email": "E-mail",
|
||||
"password": "Palavra-passe",
|
||||
"first-name": "Nome",
|
||||
"last-name": "Apelido",
|
||||
"logout": "Terminar sessão",
|
||||
"validate-required": "Por favor, insire o teu {{name}}",
|
||||
"maintenance-alert": "Estamos com pequenas dificuldades técnicas. Estamos a solucioná-las agora. Por favor, volte dentro de alguns minutos.",
|
||||
"click-to-copy": "Clica para copiar",
|
||||
"project-id": "ID do Projeto",
|
||||
"save-changes": "Guardar alterações",
|
||||
"saved": "Guardado",
|
||||
"drop-zone": "Arrasta e solta um ficheiro .env ou .yml aqui.",
|
||||
"drop-zone-keys": "Arrasta e solta um ficheiro .env ou .yml aqui para adicionar mais segredos.",
|
||||
"role": "Função",
|
||||
"role_admin": "Administrador",
|
||||
"display-name": "Nome de exibição",
|
||||
"environment": "Ambiente",
|
||||
"expired-in": "Expira em",
|
||||
"language": "Idioma",
|
||||
"search": "Pequisar...",
|
||||
"note": "Note",
|
||||
"view-more": "Ver mais",
|
||||
"end-of-history": "Fim do histórico",
|
||||
"select-event": "Escolhe um evento",
|
||||
"event": "Evento",
|
||||
"user": "Utilizador",
|
||||
"source": "Fonte",
|
||||
"time": "Data/Hora",
|
||||
"timestamp": "Timestamp"
|
||||
}
|
36
frontend/public/locales/pt-PT/dashboard.json
Normal file
36
frontend/public/locales/pt-PT/dashboard.json
Normal file
@ -0,0 +1,36 @@
|
||||
{
|
||||
"title": "Segredos",
|
||||
"og-title": "Faz a gestão os teus ficheiros .env em segundos",
|
||||
"og-description": "Infisical é uma plataforma simples e criptografada de ponta a ponta que permite que as equipas sincronizem e façam a gestão dos seus ficheiros .env.",
|
||||
"search-keys": "Pesquisar chaves...",
|
||||
"add-key": "Adicionar chave",
|
||||
"personal": "Pessoal",
|
||||
"personal-description": "As chaves pessoais são visíveis apenas para si",
|
||||
"shared": "Partilhado",
|
||||
"shared-description": "As chaves partilhadas são visíveis para toda tua equipa",
|
||||
"make-shared": "Partilhar",
|
||||
"make-personal": "Tornar pessoal",
|
||||
"add-secret": "Adicionar um novo segredo",
|
||||
"check-docs": {
|
||||
"button": "Verificar documentação",
|
||||
"title": "Bom trabalho!",
|
||||
"line1": "Parabéns por adicionar mais segredos.",
|
||||
"line2": "Veja como conectá-los à tua codebase."
|
||||
},
|
||||
"sidebar": {
|
||||
"secret": "Segredo",
|
||||
"key": "Chave",
|
||||
"value": "Valor",
|
||||
"override": "Substitui o valor por um valor pessoal",
|
||||
"version-history": "Histórico da versões",
|
||||
"comments": "Comentários e Notas",
|
||||
"personal-explanation": "Este segredo é pessoal. Não é partilhado com nenhum dos seus colegas de equipa.",
|
||||
"generate-random-hex": "Criar código HEX aleatório",
|
||||
"digits": "digitos",
|
||||
"delete-key-dialog": {
|
||||
"title": "Apagar chave",
|
||||
"confirm-delete-message": "Tens a certeza que queres apagar esta chave? Esta ação não pode ser desfeita."
|
||||
}
|
||||
}
|
||||
|
||||
}
|
16
frontend/public/locales/pt-PT/integrations.json
Normal file
16
frontend/public/locales/pt-PT/integrations.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"title": "Integrações do Projeto",
|
||||
"description": "Faz a gestão das tuas integrações do Infisical com serviços de terceiros.",
|
||||
"no-integrations1": "Ainda não tens nenhuma integração definida. Quando o fizer, aparecerá aqui.",
|
||||
"no-integrations2": "Para começar, clica em qualquer uma das opções abaixo. São necessários 5 cliques para configurar.",
|
||||
"available": "Integrações de Plataforma & Cloud",
|
||||
"available-text1": "Clica na integração que pretende ligar. Isto irá permitir que as tuas variáveis de ambiente fluam automaticamente para os serviços de terceiros selecionados.",
|
||||
"available-text2": "Nota: durante uma integração com o Heroku, por razões de segurança, não é possível manter a criptografia de ponta a ponta. Teoricamente, isto permite que o Infisical decifre as suas variáveis de ambiente. Na prática, podemos assegurar-lhe que isto nunca será feito, e permite-nos proteger os teus segredos de atores mal-intencionados online. O serviço Infisical mantém-se sempre criptografado de ponta a ponta. Para qualquer dúvida, contacte support@infisical.com.",
|
||||
"cloud-integrations": "Integrações de Cloud",
|
||||
"framework-integrations": "Integrações de Framework",
|
||||
"click-to-start": "Clica numa integração para começar a sincronizar segredos.",
|
||||
"click-to-setup": "Clique num framework para obter as instruções de configuração.",
|
||||
"grant-access-to-secrets": "Conceda acesso ao Infisical aos teus segredos",
|
||||
"why-infisical-needs-access": "A maioria das integrações de cloud requerem que o Infisical possa decifrar os teus segredos para que possam ser encaminhados.",
|
||||
"grant-access-button": "Conceder acesso"
|
||||
}
|
10
frontend/public/locales/pt-PT/login.json
Normal file
10
frontend/public/locales/pt-PT/login.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"title": "Iniciar sessão",
|
||||
"og-title": "Iniciar sessão na Infisical",
|
||||
"og-description": "Infisical é uma plataforma simples e criptografada que permite às equipas sincronizar e fazer a gestão dos seus ficheiros .env.",
|
||||
"login": "Iniciar sessão",
|
||||
"need-account": "Precisa de uma conta Infisical?",
|
||||
"create-account": "Regista-te",
|
||||
"forgot-password": "Esqueceste da tua palavra-passe?",
|
||||
"error-login": "Credenciais erradas."
|
||||
}
|
28
frontend/public/locales/pt-PT/mfa.json
Normal file
28
frontend/public/locales/pt-PT/mfa.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"title": "Registar",
|
||||
"og-title": "Substitui os ficheiros .env com 1 linha de código. Regista-te na Infisical em 3 minutos.",
|
||||
"og-description": "Infisical é uma plataforma simples e encriptada de ponta a ponta que permite às equipas sincronizar e gerir chaves API e variáveis de ambiente. Funciona com Node.js, Next.js, Gatsby, Nest.js...",
|
||||
"signup": "Registar",
|
||||
"already-have-account": "Já tens uma conta? Inicia a sessão",
|
||||
"forgot-password": "Esqueceste da palavra-passe?",
|
||||
"verify": "Verificar",
|
||||
"step1-start": "Vamos começar",
|
||||
"step1-privacy": "Ao criares uma conta, concorda com os nossos Termos e leu a Política de Privacidade.",
|
||||
"step1-submit": "Começar",
|
||||
"step2-message": "Enviámos um código de verificação para",
|
||||
"step2-code-error": "Epá! O seu código está errado. Tentativas restantes:",
|
||||
"step2-resend-alert": "Não vês o código?",
|
||||
"step2-resend-submit": "Reenviar",
|
||||
"step2-resend-progress": "A reenviar...",
|
||||
"step2-spam-alert": "Não te esqueças de verificar a tua caixa de spam.",
|
||||
"step3-message": "Tá quase!",
|
||||
"step4-message": "Guarda o teu Kit de Emergência",
|
||||
"step4-description1": "Se perderes o acesso a tua conta, o teu Kit de Emergência é a única forma de iniciares a sessão.",
|
||||
"step4-description2": "Recomendamos que o descarregues e guardes num local seguro.",
|
||||
"step4-description3": "Contém a sua Chave Secreta que não podemos aceder nem recuperar para si se a perder.",
|
||||
"step4-download": "Descarregar PDF",
|
||||
"step5-send-invites": "Enviar Convites",
|
||||
"step5-invite-team": "Convida a tua equipa",
|
||||
"step5-subtitle": "A Infisical é pensada para ser usada com a tua equipa. Convida-os para testar.",
|
||||
"step5-skip": "Saltar"
|
||||
}
|
22
frontend/public/locales/pt-PT/nav.json
Normal file
22
frontend/public/locales/pt-PT/nav.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"support": {
|
||||
"slack": "Partipa do Slack",
|
||||
"docs": "Leia a documentação",
|
||||
"issue": "Abra um issue no Github",
|
||||
"email": "Envia-nos um email"
|
||||
},
|
||||
"user": {
|
||||
"signed-in-as": "SESSÃO INICIADA COMO",
|
||||
"current-organization": "ORGANIZAÇÃO ATUAL",
|
||||
"usage-billing": "Utilização e Faturação",
|
||||
"invite": "Convida Membros",
|
||||
"other-organizations": "OUTRA ORGANIZAÇÃO"
|
||||
},
|
||||
"menu": {
|
||||
"project": "PROJETO",
|
||||
"secrets": "Segredos",
|
||||
"members": "Membros",
|
||||
"integrations": "Integrações",
|
||||
"project-settings": "Definições do Projeto"
|
||||
}
|
||||
}
|
11
frontend/public/locales/pt-PT/section-incident.json
Normal file
11
frontend/public/locales/pt-PT/section-incident.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"incident-contacts": "Contactos de Emergência",
|
||||
"incident-contacts-description": "Estes contactos serão notificados no caso improvável de um incidente grave.",
|
||||
"no-incident-contacts": "Nenhum contacto de emergência encontrado.",
|
||||
"add-contact": "Adicionar Contacto",
|
||||
"add-dialog": {
|
||||
"title": "Adicionar um Contacto de Emergência",
|
||||
"description": "Este contacto será notificado no caso improvável de um incidente grave.",
|
||||
"add-incident": "Adicionar Contacto de Emergência"
|
||||
}
|
||||
}
|
14
frontend/public/locales/pt-PT/section-members.json
Normal file
14
frontend/public/locales/pt-PT/section-members.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"add-member": "Adicionar Membro",
|
||||
"org-members": "Membros da Organização",
|
||||
"org-members-description": "Faz a gestão dos membros da tua organização. Estes utilizadores poderão depois ser organizados em projetos.",
|
||||
"search-members": "Procurar membros...",
|
||||
"add-dialog": {
|
||||
"add-member-to-project": "Adicionar um membro ao teu projeto",
|
||||
"already-all-invited": "Todos os utilizadores da tua organização já foram convidados.",
|
||||
"add-user-org-first": "Adicione mais utilizadores à organização primeiro.",
|
||||
"user-will-email": "O utilizador receberá um e-mail com as instruções.",
|
||||
"looking-add": "<0>Se estás à procura de adicionar utilizadores à tua organização,</0><1>clica aqui</1>",
|
||||
"add-user-to-org": "Adicionar Utilizadores à Organização"
|
||||
}
|
||||
}
|
11
frontend/public/locales/pt-PT/section-password.json
Normal file
11
frontend/public/locales/pt-PT/section-password.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"password": "Palavra-passe",
|
||||
"change": "Alterar palavra-passe",
|
||||
"current": "Palavra-passe atual",
|
||||
"current-wrong": "A palavra-passe atual pode estar errada",
|
||||
"new": "Nova palavra-passe",
|
||||
"validate-base": "A palavra-passe deve ter ao menos:",
|
||||
"validate-length": "14 caracteres",
|
||||
"validate-case": "1 letra minúscula",
|
||||
"validate-number": "1 número"
|
||||
}
|
13
frontend/public/locales/pt-PT/section-token.json
Normal file
13
frontend/public/locales/pt-PT/section-token.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"service-tokens": "Tokens de Serviço",
|
||||
"service-tokens-description": "Cada token de serviço é específico para si, um determinado projeto e um determinado ambiente dentro deste projeto.",
|
||||
"add-new": "Adicionar Novo Token",
|
||||
"add-dialog" : {
|
||||
"title": "Adicionar um token de serviço para {{target}}",
|
||||
"description": "Quando um token é criado, só poderá vê-lo uma vez antes dele desaparecer. Certifique-se de o guardar num local seguro.",
|
||||
"name": "Nome do Token de Serviço",
|
||||
"add": "Adicionar Token de Serviço",
|
||||
"copy-service-token": "Copia o seu token de serviço",
|
||||
"copy-service-token-description": "Uma vez que fechar esta janela, nunca mais irás ver o teu token de serviço"
|
||||
}
|
||||
}
|
4
frontend/public/locales/pt-PT/settings-members.json
Normal file
4
frontend/public/locales/pt-PT/settings-members.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"title": "Membros do Projeto",
|
||||
"description": "Esta página mostra os membros do projeto selecionado e permite-lhe modificar as suas permissões."
|
||||
}
|
4
frontend/public/locales/pt-PT/settings-org.json
Normal file
4
frontend/public/locales/pt-PT/settings-org.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"title": "Definições da Organização",
|
||||
"description": "Faz a gestão dos membros da sua organização. Estes utilizadores depois poderão ser organizados em projetos."
|
||||
}
|
16
frontend/public/locales/pt-PT/settings-personal.json
Normal file
16
frontend/public/locales/pt-PT/settings-personal.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"title": "Definições Pessoais",
|
||||
"description": "Vê e faz a gestão das tuas informações pessoais aqui.",
|
||||
"emergency": {
|
||||
"name": "Kit de Emergência",
|
||||
"text1": "O seu Kit de Emergência contém as informações que necessita para aceder à sua conta Infisical.",
|
||||
"text2": "Apenas o último Kit de Emergência emitido é válido. Para obter um novo Kit de Emergência, verifique a sua palavra-passe.",
|
||||
"download": "Descarregar Kit de Emergência"
|
||||
},
|
||||
"change-language": "Alterar Idioma",
|
||||
"api-keys": {
|
||||
"title": "Chaves API",
|
||||
"description": "Faz a gestão das suas chaves API pessoais para aceder à API Infisical.",
|
||||
"add-new": "Adicionar nova"
|
||||
}
|
||||
}
|
15
frontend/public/locales/pt-PT/settings-project.json
Normal file
15
frontend/public/locales/pt-PT/settings-project.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"title": "Definições do Projeto",
|
||||
"description": "Estas definições só se aplicam ao Projeto selecionado.",
|
||||
"danger-zone": "Zona de Perigo",
|
||||
"delete-project": "Apagar Projeto",
|
||||
"project-to-delete": "Projeto a Apagar",
|
||||
"danger-zone-note": "Assim que apares este projeto, não poderás desfazer a ação. Isto irá apagar imediatamente todas as chaves. Se ainda quiseres fazer isso, insere o nome do projeto abaixo.",
|
||||
"delete-project-note": "Nota: Só podes eliminar algum projeto caso tenhas mais do que um",
|
||||
"project-id-description": "Para integrar o Infisical no seu código e obter a injeção automática de variáveis de ambiente, deve usar o seguinte ID de Projeto.",
|
||||
"project-id-description2": "Para obter mais orientações, incluindo trechos de código para várias linguagens e frameworks, consulte ",
|
||||
"auto-generated": "Este é o identificador único - criado automaticamente - do teu projeto. Não pode ser alterado.",
|
||||
"docs": "Documentação do Infisical",
|
||||
"auto-capitalization": "Converter em maísculas automaticamente",
|
||||
"auto-capitalization-description": "Por defeito, o Infisical irá converter o texto das tuas chaves em maísculas automaticamente. Se quiser desativar este recurso, pode fazê-lo aqui."
|
||||
}
|
28
frontend/public/locales/pt-PT/signup.json
Normal file
28
frontend/public/locales/pt-PT/signup.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"title": "Registar",
|
||||
"og-title": "Substitua os ficheiros .env com 1 linha de código. Regista-te na Infisical em 3 minutos.",
|
||||
"og-description": "Infisical é uma plataforma simples e end-to-end encriptada que permite às equipas sincronizar e gerir chaves API e variáveis de ambiente. Funciona com Node.js, Next.js, Gatsby, Nest.js...",
|
||||
"signup": "Registar",
|
||||
"already-have-account": "Já tens uma conta? Inicia a sessão",
|
||||
"forgot-password": "Esqueceste da palavra-passe?",
|
||||
"verify": "Verificar",
|
||||
"step1-start": "Vamos começar",
|
||||
"step1-privacy": "Ao criares uma conta, concorda com os nossos Termos e leu a Política de Privacidade.",
|
||||
"step1-submit": "Começar",
|
||||
"step2-message": "Enviámos um código de verificação para",
|
||||
"step2-code-error": "Epá! O seu código está errado. Por favor, tenta novamente.",
|
||||
"step2-resend-alert": "Não vês o código?",
|
||||
"step2-resend-submit": "Reenviar",
|
||||
"step2-resend-progress": "A reenviar...",
|
||||
"step2-spam-alert": "Não te esqueças de verificar a sua caixa de spam.",
|
||||
"step3-message": "Tá quase!",
|
||||
"step4-message": "Guarda o teu Kit de Emergência",
|
||||
"step4-description1": "Se perderes o acesso a tua conta, o teu Kit de Emergência é a única forma de iniciares a sessão.",
|
||||
"step4-description2": "Recomendamos que o descarregues e guardes num local seguro.",
|
||||
"step4-description3": "Contém a sua Chave Secreta que não podemos aceder nem recuperar para si se a perder.",
|
||||
"step4-download": "Descarregar PDF",
|
||||
"step5-send-invites": "Enviar Convites",
|
||||
"step5-invite-team": "Convida a tua equipa",
|
||||
"step5-subtitle": "A Infisical é pensada para ser usada com a tua equipa. Convida-os para testar",
|
||||
"step5-skip": "Saltar"
|
||||
}
|
@ -162,7 +162,7 @@ const Layout = ({ children }: LayoutProps) => {
|
||||
},
|
||||
{
|
||||
href: `/activity/${workspaceMapping[workspaceSelected as any]}`,
|
||||
title: 'Activity Logs',
|
||||
title: 'Audit Logs',
|
||||
emoji: <FontAwesomeIcon icon={faFileLines} />
|
||||
},
|
||||
{
|
||||
|
@ -71,6 +71,19 @@ const DropZone = ({
|
||||
}));
|
||||
break;
|
||||
}
|
||||
case 'json': {
|
||||
const keyPairs = JSON.parse(String(file));
|
||||
secrets = Object.keys(keyPairs).map((key, index) => ({
|
||||
id: guidGenerator(),
|
||||
pos: numCurrentRows + index,
|
||||
key,
|
||||
value: keyPairs[key as keyof typeof keyPairs],
|
||||
comment: '',
|
||||
type: 'shared',
|
||||
tags: []
|
||||
}));
|
||||
break;
|
||||
}
|
||||
case 'yml': {
|
||||
const parsedFile = parseDocument(file.toString());
|
||||
const keyPairs = parsedFile.contents!.toJSON();
|
||||
|
@ -11,7 +11,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export const EmptyState = ({ title, className, children, icon = faCubesStacked }: Props) => (
|
||||
<div className={twMerge('flex w-full flex-col items-center px-2 pt-6 text-bunker-300', className)}>
|
||||
<div className={twMerge('flex w-full bg-bunker-700 flex-col items-center px-2 pt-6 text-bunker-300', className)}>
|
||||
<FontAwesomeIcon icon={icon} size="2x" className='mr-4' />
|
||||
<div className='flex flex-row items-center py-4'>
|
||||
<div className="text-bunker-300 text-sm">{title}</div>
|
||||
|
@ -14,7 +14,7 @@ const tagVariants = cva('inline-flex whitespace-nowrap text-sm rounded-sm mr-1.5
|
||||
red: 'bg-red/80 text-bunker-100'
|
||||
},
|
||||
size: {
|
||||
sm: 'px-1 py-0.5'
|
||||
sm: 'px-1.5 py-0.5'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -308,7 +308,7 @@ export const AppLayout = ({ children }: LayoutProps) => {
|
||||
isSelected={router.asPath === `/activity/${currentWorkspace?._id}`}
|
||||
icon={<FontAwesomeIcon icon={faFileLines} size="lg" />}
|
||||
>
|
||||
Activity Logs
|
||||
Audit Logs
|
||||
</MenuItem>
|
||||
</a>
|
||||
</Link>
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import Head from 'next/head';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
@ -125,7 +126,12 @@ export default function Activity() {
|
||||
|
||||
return (
|
||||
<div className="mx-6 lg:mx-0 w-full h-screen">
|
||||
<NavHeader pageName="Project Activity" isProjectRelated />
|
||||
<Head>
|
||||
<title>Audit Logs</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
<meta property="og:image" content="/images/message.png" />
|
||||
</Head>
|
||||
<NavHeader pageName="Audit Logs" isProjectRelated />
|
||||
{currentSidebarAction && (
|
||||
<ActivitySideBar toggleSidebar={toggleSidebar} currentAction={currentSidebarAction} />
|
||||
)}
|
||||
|
@ -201,6 +201,9 @@ export default function Integrations() {
|
||||
case 'circleci':
|
||||
link = `${window.location.origin}/integrations/circleci/authorize`
|
||||
break;
|
||||
case 'travisci':
|
||||
link = `${window.location.origin}/integrations/travisci/authorize`
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -247,6 +250,9 @@ export default function Integrations() {
|
||||
case 'circleci':
|
||||
link = `${window.location.origin}/integrations/circleci/create?integrationAuthId=${integrationAuth._id}`;
|
||||
break;
|
||||
case 'travisci':
|
||||
link = `${window.location.origin}/integrations/travisci/create?integrationAuthId=${integrationAuth._id}`;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
77
frontend/src/pages/integrations/travisci/authorize.tsx
Normal file
77
frontend/src/pages/integrations/travisci/authorize.tsx
Normal file
@ -0,0 +1,77 @@
|
||||
import { useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../components/utilities/withTranslateProps';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardTitle,
|
||||
FormControl,
|
||||
Input,
|
||||
} from '../../../components/v2';
|
||||
import saveIntegrationAccessToken from "../../api/integrations/saveIntegrationAccessToken";
|
||||
|
||||
export default function TravisCICreateIntegrationPage() {
|
||||
const router = useRouter();
|
||||
const [apiKey, setApiKey] = useState('');
|
||||
const [apiKeyErrorText, setApiKeyErrorText] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
setApiKeyErrorText('');
|
||||
if (apiKey.length === 0) {
|
||||
setApiKeyErrorText('API Key cannot be blank');
|
||||
return;
|
||||
}
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
const integrationAuth = await saveIntegrationAccessToken({
|
||||
workspaceId: localStorage.getItem('projectData.id'),
|
||||
integration: 'travisci',
|
||||
accessToken: apiKey,
|
||||
accessId: null,
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(
|
||||
`/integrations/travisci/create?integrationAuthId=${integrationAuth._id}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-full w-full flex justify-center items-center">
|
||||
<Card className="max-w-md p-8 rounded-md">
|
||||
<CardTitle className='text-center'>Travis CI Integration</CardTitle>
|
||||
<FormControl
|
||||
label="Travis CI API Token"
|
||||
errorText={apiKeyErrorText}
|
||||
isError={apiKeyErrorText !== '' ?? false}
|
||||
>
|
||||
<Input
|
||||
placeholder=''
|
||||
value={apiKey}
|
||||
onChange={(e) => setApiKey(e.target.value)}
|
||||
/>
|
||||
</FormControl>
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className='mt-4'
|
||||
isLoading={isLoading}
|
||||
>
|
||||
Connect to Travis CI
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
TravisCICreateIntegrationPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
124
frontend/src/pages/integrations/travisci/create.tsx
Normal file
124
frontend/src/pages/integrations/travisci/create.tsx
Normal file
@ -0,0 +1,124 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import queryString from 'query-string';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../components/utilities/withTranslateProps';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardTitle,
|
||||
FormControl,
|
||||
Select,
|
||||
SelectItem
|
||||
} from '../../../components/v2';
|
||||
import { useGetIntegrationAuthApps,useGetIntegrationAuthById } from '../../../hooks/api/integrationAuth';
|
||||
import { useGetWorkspaceById } from '../../../hooks/api/workspace';
|
||||
import createIntegration from "../../api/integrations/createIntegration";
|
||||
|
||||
export default function TravisCICreateIntegrationPage() {
|
||||
const router = useRouter();
|
||||
|
||||
const { integrationAuthId } = queryString.parse(router.asPath.split('?')[1]);
|
||||
|
||||
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
|
||||
const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? '');
|
||||
const { data: integrationAuthApps } = useGetIntegrationAuthApps(integrationAuthId as string ?? '');
|
||||
|
||||
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
|
||||
const [targetApp, setTargetApp] = useState('');
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace) {
|
||||
setSelectedSourceEnvironment(workspace.environments[0].slug);
|
||||
}
|
||||
}, [workspace]);
|
||||
|
||||
useEffect(() => {
|
||||
// TODO: handle case where apps can be empty
|
||||
if (integrationAuthApps) {
|
||||
setTargetApp(integrationAuthApps[0]?.name);
|
||||
}
|
||||
}, [integrationAuthApps]);
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
if (!integrationAuth?._id) return;
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
await createIntegration({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
isActive: true,
|
||||
app: targetApp,
|
||||
appId: (integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.name === targetApp))?.appId ?? null,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: null,
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(
|
||||
`/integrations/${localStorage.getItem('projectData.id')}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
return (integrationAuth && workspace && selectedSourceEnvironment && integrationAuthApps && targetApp) ? (
|
||||
<div className="h-full w-full flex justify-center items-center">
|
||||
<Card className="max-w-md p-8 rounded-md">
|
||||
<CardTitle className='text-center'>Travis CI Integration</CardTitle>
|
||||
<FormControl
|
||||
label="Project Environment"
|
||||
className='mt-4'
|
||||
>
|
||||
<Select
|
||||
value={selectedSourceEnvironment}
|
||||
onValueChange={(val) => setSelectedSourceEnvironment(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
>
|
||||
{workspace?.environments.map((sourceEnvironment) => (
|
||||
<SelectItem value={sourceEnvironment.slug} key={`azure-key-vault-environment-${sourceEnvironment.slug}`}>
|
||||
{sourceEnvironment.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl
|
||||
label="Travis CI Project"
|
||||
className='mt-4'
|
||||
>
|
||||
<Select
|
||||
value={targetApp}
|
||||
onValueChange={(val) => setTargetApp(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
>
|
||||
{integrationAuthApps.map((integrationAuthApp) => (
|
||||
<SelectItem value={integrationAuthApp.name} key={`render-environment-${integrationAuthApp.name}`}>
|
||||
{integrationAuthApp.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className='mt-4'
|
||||
isLoading={isLoading}
|
||||
>
|
||||
Create Integration
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
) : <div />
|
||||
}
|
||||
|
||||
TravisCICreateIntegrationPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
@ -90,7 +90,7 @@ export default function Login() {
|
||||
<ListBox
|
||||
isSelected={lang}
|
||||
onChange={setLanguage}
|
||||
data={['en', 'ko', 'fr', 'pt-BR']}
|
||||
data={['en', 'ko', 'fr', 'pt-BR', 'pt-PT']}
|
||||
isFull
|
||||
text={`${t('common:language')}: `}
|
||||
/>
|
||||
|
@ -77,13 +77,13 @@ export default function SettingsBilling() {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="bg-bunker-800 max-h-screen flex flex-col justify-between text-white">
|
||||
<div className="bg-bunker-800 pb-4 flex flex-col justify-between text-white">
|
||||
<Head>
|
||||
<title>{t('common:head-title', { title: t('billing:title') })}</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
</Head>
|
||||
<div className="flex flex-row">
|
||||
<div className="w-full max-h-screen pb-2 overflow-y-auto">
|
||||
<div className="w-full pb-2">
|
||||
<NavHeader pageName={t('billing:title')} />
|
||||
<div className="flex flex-row justify-between items-center ml-6 my-8 text-xl max-w-5xl">
|
||||
<div className="flex flex-col justify-start items-start text-3xl">
|
||||
@ -93,7 +93,6 @@ export default function SettingsBilling() {
|
||||
</div>
|
||||
<div className="flex flex-col ml-6 text-mineshaft-50 w-max">
|
||||
<p className="text-xl font-semibold">{t('billing:subscription')}</p>
|
||||
<div className="mt-4 text-bunker-200 h-14 flex justify-center items-center rounded-md bg-bunker-600 mr-4"> If you are looking to get an annual plan, please reach out to <a className="ml-1.5 underline text-primary underline-offset-2" href="mailto:team@infisical.com">team@infisical.com</a></div>
|
||||
<div className="grid grid-cols-2 grid-rows-2 gap-y-6 gap-x-3 mt-4 overflow-x-auto">
|
||||
{plans.map((plan) => (
|
||||
<Plan key={plan.name} plan={plan} />
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { useMemo, useState } from 'react';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
import { useRouter } from 'next/router';
|
||||
import { faMagnifyingGlass, faPlus, faTrash, faUsers } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
@ -61,6 +62,7 @@ export const OrgMembersTable = ({
|
||||
userId,
|
||||
isLoading
|
||||
}: Props) => {
|
||||
const router = useRouter();
|
||||
const [searchMemberFilter, setSearchMemberFilter] = useState('');
|
||||
const { handlePopUpToggle, popUp, handlePopUpOpen, handlePopUpClose } = usePopUp([
|
||||
'addMember',
|
||||
@ -159,7 +161,7 @@ export const OrgMembersTable = ({
|
||||
<Select
|
||||
defaultValue={role}
|
||||
isDisabled={userId === user?._id}
|
||||
className="w-full bg-mineshaft-600"
|
||||
className="w-40 bg-mineshaft-600"
|
||||
onValueChange={(selectedRole) =>
|
||||
onRoleChange(orgMembershipId, selectedRole)
|
||||
}
|
||||
@ -172,8 +174,8 @@ export const OrgMembersTable = ({
|
||||
</Select>
|
||||
)}
|
||||
{(status === 'invited' || status === 'verified') && (
|
||||
<Button colorSchema="secondary" onClick={() => onInviteMember(email)}>
|
||||
Resent Invite
|
||||
<Button className='w-40' colorSchema="secondary" onClick={() => onInviteMember(email)}>
|
||||
Resend Invite
|
||||
</Button>
|
||||
)}
|
||||
{status === 'completed' && (
|
||||
@ -193,7 +195,17 @@ export const OrgMembersTable = ({
|
||||
</Tag>
|
||||
))
|
||||
) : (
|
||||
<Tag colorSchema="red">This user isn't part of any projects yet</Tag>
|
||||
<div className='flex flex-row'>
|
||||
<Tag colorSchema="red">This user isn't part of any projects yet</Tag>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => router.push(`/users/${router.query.id}`)}
|
||||
className='text-sm bg-mineshaft w-max px-1.5 py-0.5 hover:bg-primary duration-200 hover:text-black cursor-pointer rounded-sm'
|
||||
>
|
||||
<FontAwesomeIcon icon={faPlus} className="mr-1" />
|
||||
Add to projects
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</Td>
|
||||
<Td>
|
||||
|
@ -2,26 +2,29 @@
|
||||
|
||||
Welcome to Infisical Helm Charts repository! Find instructions below to setup and install our charts.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
# Add the Infisical repository
|
||||
helm repo add infisical 'https://dl.cloudsmith.io/public/infisical/helm-charts/helm/charts/' && helm repo update
|
||||
|
||||
# Install Infisical
|
||||
# Install Infisical (default values)
|
||||
helm upgrade --install --atomic \
|
||||
-n infisical-dev --create-namespace \
|
||||
-n infisical --create-namespace \
|
||||
infisical infisical/infisical
|
||||
|
||||
# Install Infisical Secrets Operator
|
||||
# Install Infisical Secrets Operator (default values)
|
||||
helm upgrade --install --atomic \
|
||||
-n infisical-dev --create-namespace \
|
||||
-n infisical --create-namespace \
|
||||
infisical-secrets-operator infisical/secrets-operator
|
||||
```
|
||||
|
||||
## Charts
|
||||
|
||||
Here's the link to our charts corresponding documentation :
|
||||
- **`[infisical](./infisical/README.md)`**
|
||||
- **`secrets-operator`**
|
||||
|
||||
- [**`infisical`**](./infisical/README.md)
|
||||
- [**`secrets-operator`**](./secrets-operator/README.md)
|
||||
|
||||
## Documentation
|
||||
|
||||
@ -30,7 +33,7 @@ We're trying to follow a documentation convention across our charts, allowing us
|
||||
Steps to update the documentation :
|
||||
1. `cd helm-charts/<chart>`
|
||||
1. `git clone https://github.com/bitnami-labs/readme-generator-for-helm`
|
||||
2. `npm install ./readme-generator-for-helm`
|
||||
3. `npm exec readme-generator -- --readme README.md --values values.yaml`
|
||||
1. `npm install ./readme-generator-for-helm`
|
||||
1. `npm exec readme-generator -- --readme README.md --values values.yaml`
|
||||
- It'll insert the table below the `## Parameters` title
|
||||
- It'll output errors if some of the path aren't documented
|
@ -1,6 +1,40 @@
|
||||
# Infisical - Helm Chart
|
||||
# Infisical Helm Chart
|
||||
|
||||
This is the Infisical application Helm chart.
|
||||
This is the Infisical application Helm chart. This chart includes the following :
|
||||
|
||||
| Service | Description |
|
||||
| ---------- | ----------------------------------- |
|
||||
| `frontend` | Infisical's Web UI |
|
||||
| `backend` | Infisical's API |
|
||||
| `mongodb` | Infisical's local database |
|
||||
| `mailhog` | Infisical's development SMTP server |
|
||||
|
||||
## Installation
|
||||
|
||||
To install the chart, run the following :
|
||||
|
||||
```sh
|
||||
# Add the Infisical repository
|
||||
helm repo add infisical 'https://dl.cloudsmith.io/public/infisical/helm-charts/helm/charts/' && helm repo update
|
||||
|
||||
# Install Infisical (with default values)
|
||||
helm upgrade --install --atomic \
|
||||
-n infisical-dev --create-namespace \
|
||||
infisical infisical/infisical
|
||||
|
||||
# Install Infisical (with custom inline values, replace with your own values)
|
||||
helm upgrade --install --atomic \
|
||||
-n infisical-dev --create-namespace \
|
||||
--set mongodb.enabled=false \
|
||||
--set mongodbConnection.externalMongoDBConnectionString="mongodb://<user>:<pass>@<host>:<port>/<database-name>" \
|
||||
infisical infisical/infisical
|
||||
|
||||
# Install Infisical (with custom values file, replace with your own values file)
|
||||
helm upgrade --install --atomic \
|
||||
-n infisical-dev --create-namespace \
|
||||
-f custom-values.yaml \
|
||||
infisical infisical/infisical
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
@ -118,6 +152,7 @@ This is the Infisical application Helm chart.
|
||||
| `mailhog.ingress.labels` | Ingress labels | `{}` |
|
||||
| `mailhog.ingress.hosts[0].host` | Mailhog host | `mailhog.infisical.local` |
|
||||
|
||||
Learn more in our [docs](https://infisical.com/docs/self-hosting/deployments/kubernetes)
|
||||
|
||||
## Persistence
|
||||
|
||||
@ -125,13 +160,36 @@ The database persistence is enabled by default, your volumes will remain on your
|
||||
|
||||
## Local development
|
||||
|
||||
Use below values if you want to setup a local development environment, and adapt those variables as you need. Below example will deploy the following :
|
||||
- https://infisical.local
|
||||
Find the resources and configuration about how to setup your local develoment environment on a k8s environment.
|
||||
|
||||
### Requirements
|
||||
|
||||
To create a local k8s environment, you'll need :
|
||||
|
||||
- [`helm`](https://helm.sh/docs/intro/install/) <kbd>required</kbd>
|
||||
- to generate the manifests and deploy the chart
|
||||
- local/remote k8s cluster <kbd>required</kbd>
|
||||
- e.g. [`kind`](https://kubernetes.io/docs/tasks/tools/), [`minikube`](https://kubernetes.io/docs/tasks/tools/) or an online provider
|
||||
- [`kubectl`](https://kubernetes.io/docs/tasks/tools/) <kbd>optional</kbd>
|
||||
- to interact with the cluster
|
||||
|
||||
### Examples
|
||||
|
||||
ℹ️ Find complete setup scripts in [**./examples**](./examples)
|
||||
|
||||
Below example will deploy the following :
|
||||
|
||||
- [**infisical.local**](https://infisical.local)
|
||||
- Your local Infisical instance
|
||||
- You may have to add `infisical.local` to your `/etc/hosts` or similar depending your OS
|
||||
- https://mailhog.infisical.local
|
||||
- The corresponding IP will depend on the tool or the way you're exposing the services ([learn more](https://minikube.sigs.k8s.io/docs/handbook/host-access/))
|
||||
|
||||
- [**mailhog.infisical.local**](https://mailhog.infisical.local)
|
||||
- Local SMTP server used to receive the signup verification code
|
||||
- You may have to add `mailhog.infisical.local` to your `/etc/hosts` or similar depending your OS
|
||||
- The corresponding IP will depend on the tool or the way you're exposing the services ([learn more](https://minikube.sigs.k8s.io/docs/handbook/host-access/))
|
||||
|
||||
Use below values to setup a local development environment, adapt those variables as you need
|
||||
|
||||
```yaml
|
||||
# values.dev.yaml
|
||||
@ -146,7 +204,7 @@ mongodb:
|
||||
mailhog:
|
||||
enabled: true
|
||||
|
||||
# Configure backend development variables
|
||||
# Configure backend development variables (required)
|
||||
backendEnvironmentVariables:
|
||||
ENCRYPTION_KEY: 6c1fe4e407b8911c104518103505b218
|
||||
JWT_AUTH_SECRET: 4be6ba5602e0fa0ac6ac05c3cd4d247f
|
||||
@ -162,7 +220,7 @@ backendEnvironmentVariables:
|
||||
SMTP_SECURE: false
|
||||
SMTP_USERNAME: dev@infisical.local
|
||||
|
||||
# Configure frontend development variables
|
||||
# Configure frontend development variables (required)
|
||||
frontendEnvironmentVariables:
|
||||
SITE_URL: https://infisical.local
|
||||
```
|
||||
|
83
helm-charts/infisical/examples/kind.sh
Executable file
83
helm-charts/infisical/examples/kind.sh
Executable file
@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
## Infisical local k8s development environment setup script
|
||||
## using 'kind' and 'ingress-nginx'
|
||||
## https://kind.sigs.k8s.io/docs/user/ingress/
|
||||
##
|
||||
|
||||
##
|
||||
## DEVELOPMENT USE ONLY
|
||||
## DO NOT USE IN PRODUCTION
|
||||
##
|
||||
|
||||
# define variables
|
||||
cluster_name=infisical
|
||||
host=infisical.local
|
||||
|
||||
# create the local cluster (expose 80/443 on localhost)
|
||||
cat <<EOF | kind create cluster -n $cluster_name --wait --config=-
|
||||
kind: Cluster
|
||||
apiVersion: kind.x-k8s.io/v1alpha4
|
||||
nodes:
|
||||
- role: control-plane
|
||||
kubeadmConfigPatches:
|
||||
- |
|
||||
kind: InitConfiguration
|
||||
nodeRegistration:
|
||||
kubeletExtraArgs:
|
||||
node-labels: "ingress-ready=true"
|
||||
extraPortMappings:
|
||||
- containerPort: 80
|
||||
hostPort: 80
|
||||
protocol: TCP
|
||||
- containerPort: 443
|
||||
hostPort: 443
|
||||
protocol: TCP
|
||||
EOF
|
||||
|
||||
# install ingress-nginx
|
||||
# kind version : https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
|
||||
helm upgrade -i --atomic \
|
||||
--repo https://kubernetes.github.io/ingress-nginx \
|
||||
ingress-nginx ingress-nginx \
|
||||
-n ingress-nginx --create-namespace \
|
||||
--set controller.service.type="NodePort" \
|
||||
--set controller.hostPort.enabled=true \
|
||||
--set controller.service.externalTrafficPolicy=Local
|
||||
|
||||
kubectl wait -n ingress-nginx \
|
||||
--for=condition=ready pod \
|
||||
--selector=app.kubernetes.io/component=controller \
|
||||
--timeout=120s
|
||||
|
||||
# install infisical (local development)
|
||||
helm dep update
|
||||
cat <<EOF | helm upgrade --install --atomic \
|
||||
-n infisical-dev --create-namespace \
|
||||
-f - \
|
||||
infisical-dev .
|
||||
frontend:
|
||||
enabled: true
|
||||
backend:
|
||||
enabled: true
|
||||
mongodb:
|
||||
enabled: true
|
||||
mailhog:
|
||||
enabled: true
|
||||
backendEnvironmentVariables:
|
||||
ENCRYPTION_KEY: $(openssl rand -hex 16)
|
||||
JWT_AUTH_SECRET: $(openssl rand -hex 16)
|
||||
JWT_REFRESH_SECRET: $(openssl rand -hex 16)
|
||||
JWT_SERVICE_SECRET: $(openssl rand -hex 16)
|
||||
JWT_SIGNUP_SECRET: $(openssl rand -hex 16)
|
||||
SITE_URL: https://$host
|
||||
SMTP_FROM_ADDRESS: dev@$host
|
||||
SMTP_FROM_NAME: Local Infisical
|
||||
SMTP_HOST: mailhog
|
||||
SMTP_PASSWORD: ""
|
||||
SMTP_PORT: 1025
|
||||
SMTP_SECURE: false
|
||||
SMTP_USERNAME: dev@$host
|
||||
frontendEnvironmentVariables:
|
||||
SITE_URL: https://$host
|
||||
EOF
|
99
helm-charts/secrets-operator/README.md
Normal file
99
helm-charts/secrets-operator/README.md
Normal file
@ -0,0 +1,99 @@
|
||||
# Infisical Helm Chart
|
||||
|
||||
This is the Infisical Secrets Operator Helm chart. Find the integration documentation [here](https://infisical.com/docs/integrations/platforms/kubernetes)
|
||||
|
||||
## Installation
|
||||
|
||||
To install the chart, run the following :
|
||||
|
||||
```sh
|
||||
# Add the Infisical repository
|
||||
helm repo add infisical 'https://dl.cloudsmith.io/public/infisical/helm-charts/helm/charts/' && helm repo update
|
||||
|
||||
# Install Infisical Secrets Operator (with default values)
|
||||
helm upgrade --install --atomic \
|
||||
-n infisical-dev --create-namespace \
|
||||
infisical-secrets-operator infisical/secrets-operator
|
||||
|
||||
# Install Infisical Secrets Operator (with custom inline values, replace with your own values)
|
||||
helm upgrade --install --atomic \
|
||||
-n infisical-dev --create-namespace \
|
||||
--set controllerManager.replicas=3 \
|
||||
infisical-secrets-operator infisical/secrets-operator
|
||||
|
||||
# Install Infisical Secrets Operator (with custom values file, replace with your own values file)
|
||||
helm upgrade --install --atomic \
|
||||
-n infisical-dev --create-namespace \
|
||||
-f custom-values.yaml \
|
||||
infisical-secrets-operator infisical/secrets-operator
|
||||
```
|
||||
|
||||
## Synchronization
|
||||
|
||||
To sync your secrets from Infisical (or from your own instance), create the below resources :
|
||||
|
||||
```sh
|
||||
# Create the tokenSecretReference (replace with your own token)
|
||||
kubectl create secret generic infisical-example-service-token \
|
||||
--from-literal=infisicalToken="<infisical-token-here>"
|
||||
|
||||
# Create the InfisicalSecret
|
||||
cat <<EOF | kubectl apply -f -
|
||||
apiVersion: secrets.infisical.com/v1alpha1
|
||||
kind: InfisicalSecret
|
||||
metadata:
|
||||
# Name of of this InfisicalSecret resource
|
||||
name: infisicalsecret-example
|
||||
spec:
|
||||
# The host that should be used to pull secrets from. The default value is https://app.infisical.com/api.
|
||||
hostAPI: https://app.infisical.com/api
|
||||
|
||||
# The Kubernetes secret the stores the Infisical token
|
||||
tokenSecretReference:
|
||||
# Kubernetes secret name
|
||||
secretName: infisical-example-service-token
|
||||
# The secret namespace
|
||||
secretNamespace: default
|
||||
|
||||
# The Kubernetes secret that Infisical Operator will create and populate with secrets from the above project
|
||||
managedSecretReference:
|
||||
# The name of managed Kubernetes secret that should be created
|
||||
secretName: infisical-managed-secret
|
||||
# The namespace the managed secret should be installed in
|
||||
secretNamespace: default
|
||||
EOF
|
||||
```
|
||||
|
||||
### Managed secrets
|
||||
|
||||
#### Methods
|
||||
|
||||
To use the above created manage secrets, you can use the below methods :
|
||||
- `env`
|
||||
- `envFrom`
|
||||
- `volumes`
|
||||
|
||||
Check the [docs](https://infisical.com/docs/integrations/platforms/kubernetes#using-managed-secret-in-your-deployment) to learn more about their implementation within your k8s resources
|
||||
|
||||
#### Auto-reload
|
||||
|
||||
And if you want to [auto-reload](https://infisical.com/docs/integrations/platforms/kubernetes#auto-redeployment) your deployments, add this annotation where the managed secret is consumed :
|
||||
|
||||
```yaml
|
||||
annotations:
|
||||
secrets.infisical.com/auto-reload: "true"
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
*Coming soon*
|
||||
|
||||
## Local development
|
||||
|
||||
*Coming soon*
|
||||
|
||||
## Upgrading
|
||||
|
||||
### 0.1.2
|
||||
|
||||
Latest stable version, no breaking changes
|
368
i18n/README.de.md
Normal file
368
i18n/README.de.md
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user