Compare commits

..

72 Commits

Author SHA1 Message Date
ec22291aca Revert "fix: always execute cmd in subshell" 2023-02-27 14:24:47 -05:00
16c49a9626 update slack link in welcome message 2023-02-26 23:21:36 -05:00
06ea809d60 change color of bold welcome text 2023-02-26 23:19:28 -05:00
12364005c1 improve login welcome message 2023-02-26 22:49:31 -05:00
98573e9e05 Dependabot alerts #13 2023-02-26 21:55:34 -05:00
c1a4ca6203 Dependabot alerts #19 2023-02-26 21:43:01 -05:00
21c2fd8542 address Dependabot alerts #17 2023-02-26 21:40:55 -05:00
b27bc8fc1b address dependabot alerts #18 2023-02-26 21:38:44 -05:00
091115e6ba Merge branch 'main' of https://github.com/Infisical/infisical 2023-02-26 17:51:45 -08:00
d9c055872d Fixed minor bugs everywhere 2023-02-26 17:51:26 -08:00
f73d18ddc7 merge PR 287 2023-02-26 20:03:40 -05:00
eb47126f68 merge PR 288 2023-02-26 20:00:37 -05:00
4750767268 merge PR 289 2023-02-26 19:53:03 -05:00
b0ed772885 merge PR 290 2023-02-26 19:50:22 -05:00
7fdab81b5f merge pr 291 2023-02-26 19:46:40 -05:00
c17bf13f8c remove sudo for alpine 2023-02-26 19:32:33 -05:00
0e17c9a6db Merge pull request #383 from 5h4k4r/use-multi-stage-build
Builds Docker image of backend component with multi-stage Dockerfile
2023-02-26 10:50:56 -05:00
1c4dd78dea use node alpine base image 2023-02-26 10:49:01 -05:00
23418b3a09 Builds Docker image of backend component with multi-stage Dockerfile
Updates package.json `npm start` command
Delete unnecessary `npm run start` commands

Signed-off-by: Shakar <5h4k4r.b4kr@gmail.com>
2023-02-26 14:50:49 +03:00
0f143adbde Merge pull request #377 from caioluis/main
feat(webui localization): add support for pt-PT
2023-02-25 12:01:51 -08:00
1f3f4b7900 Merge pull request #353 from Grraahaam/chore/helm-docs
chore(docs): helm charts + local cluster setup script
2023-02-25 13:25:47 -05:00
2c5f26380e Merge pull request #373 from jon4hz/default-env
fix: properly support default environment
2023-02-25 13:08:00 -05:00
8f974fb087 Add docs for default environment 2023-02-25 13:07:07 -05:00
a0722b4ca5 Merge pull request #372 from jon4hz/format-cfg
fix: pretty print workspace file
2023-02-25 12:42:46 -05:00
41e039578a Merge pull request #374 from jon4hz/shell
fix: always execute cmd in subshell
2023-02-25 12:39:08 -05:00
c89e8e8a96 Merge pull request #375 from jon4hz/workspace
feat: search for workspace config in parent dir
2023-02-25 11:27:34 -05:00
cac83ab927 add debug log to workspace path location 2023-02-25 11:25:49 -05:00
0f0b894363 Revert "feat(webui-localization): fix and update pt-br copies"
I was dizzy and forgot to make a branch

This reverts commit 43f9af1bc6d27b0e6fc477535f5a17d963df6b51.

Signed-off-by: Caio Gomes <ocaioluis@gmail.com>
2023-02-25 08:05:43 +00:00
43f9af1bc6 feat(webui-localization): fix and update pt-br copies 2023-02-25 08:04:02 +00:00
f5ed14c84c fix(localization): add pt-PT to the options and fix a copy 2023-02-25 07:22:34 +00:00
2dd57d7c73 feat(localization): add locales for pt-PT 2023-02-25 06:53:02 +00:00
0b1891b64a Merge pull request #371 from jon4hz/env-filter
Improve env filter
2023-02-24 23:12:20 -05:00
5614b0f58a nit: method name change 2023-02-24 22:21:20 -05:00
3bb178976d Remove auto delete index 2023-02-24 21:57:13 -05:00
1777f98aef feat: search for workspace config in parent dir 2023-02-25 01:25:39 +01:00
45e3706335 fix: always execute cmd in subshell 2023-02-25 00:19:58 +01:00
337ed1fc46 fix: properly support default environment 2023-02-24 23:20:30 +01:00
d1ea76e5a0 fix: pretty print workspace file 2023-02-24 22:28:28 +01:00
4a72d725b1 fix: use function to get secrets by key 2023-02-24 22:03:50 +01:00
1693db3199 fix: preallocate map size 2023-02-24 22:03:13 +01:00
1ff42991b3 fix: improve filtering of reserved env vars 2023-02-24 21:57:48 +01:00
978423ba5b Merge pull request #364 from alexdanilowicz/patch-3
chore(docs): Update README MIT License badge link
2023-02-24 11:41:28 -08:00
4d0dc0d7b7 Update README.md 2023-02-24 11:40:03 -08:00
3817e666a9 Merge pull request #365 from Infisical/travisci
Add Travis CI Docs
2023-02-24 16:44:15 +07:00
b61350f6a4 Add Travis CI docs, minor edits 2023-02-24 16:37:26 +07:00
0fb1a1dc6f Merge remote-tracking branch 'origin' into travisci 2023-02-24 16:08:53 +07:00
9eefc87b7a Merge pull request #350 from Aashish-Upadhyay-101/Aashish-Upadhyay-101/TravisCI-integration
Feat: travis ci integration
2023-02-24 16:08:19 +07:00
53d35757ee Make minor changes to TravisCI sync, faster, reliable 2023-02-24 15:59:12 +07:00
e80e8e00b1 Replace axios with request 2023-02-24 15:31:46 +07:00
0b08e574c7 Merge remote-tracking branch 'refs/remotes/origin/main' into Aashish-Upadhyay-101/TravisCI-integration 2023-02-24 13:36:35 +05:45
499323d0e3 Sync travis-ci 2023-02-24 13:36:17 +05:45
89ad2f163a chore(docs): README
Another small README typo that I noticed. Links to a different repo.
2023-02-23 23:27:28 -08:00
7f04617b7d update brew command to update cli 2023-02-23 19:37:19 -05:00
44904628bc Merge pull request #360 from bngmnn/main
add german as readme language
2023-02-23 15:10:44 -08:00
fafde7b1ad update other languages' readme files with 'de' flag 2023-02-23 23:56:48 +01:00
7e65314670 add german readme 2023-02-23 23:56:17 +01:00
40c80f417c chore(script): added warning 2023-02-22 10:30:33 +01:00
7bb2c1c278 fix(script): auto generate secrets at runtime 2023-02-22 10:25:08 +01:00
a5278affe6 chore(docs): improved charts related documentation 2023-02-22 10:18:22 +01:00
2f953192d6 feat(script): kind local development setup 2023-02-22 10:18:22 +01:00
8bf8968588 Other frontend configurations for travis-ci 2023-02-22 13:36:22 +05:45
7e9ce0360a Create.tsx for travis-ci 2023-02-22 13:26:10 +05:45
1d35c41dcb Authorize.tsx for travis-ci 2023-02-22 13:20:34 +05:45
824315f773 model steup for travis-ci 2023-02-22 13:14:06 +05:45
8a74799d64 variable setup for travis-ci 2023-02-22 12:52:42 +05:45
f0f6e8a988 Merge remote-tracking branch 'refs/remotes/origin/main' 2023-02-22 12:29:49 +05:45
c233fd8ed1 Merge remote-tracking branch 'refs/remotes/origin/main' 2023-02-13 15:39:38 +05:45
d7acd7aef6 fix: upgrade i18next from 22.4.6 to 22.4.9
Snyk has created this PR to upgrade i18next from 22.4.6 to 22.4.9.

See this package in npm:
https://www.npmjs.com/package/i18next

See this project in Snyk:
https://app.snyk.io/org/maidul98/project/53d4ecb6-6cc1-4918-aa73-bf9cae4ffd13?utm_source=github&utm_medium=referral&page=upgrade-pr
2023-02-02 22:37:54 +00:00
860b8efd7d fix: upgrade axios-auth-refresh from 3.3.3 to 3.3.6
Snyk has created this PR to upgrade axios-auth-refresh from 3.3.3 to 3.3.6.

See this package in npm:
https://www.npmjs.com/package/axios-auth-refresh

See this project in Snyk:
https://app.snyk.io/org/maidul98/project/53d4ecb6-6cc1-4918-aa73-bf9cae4ffd13?utm_source=github&utm_medium=referral&page=upgrade-pr
2023-02-02 22:37:50 +00:00
6ca3fc5ad2 fix: upgrade @headlessui/react from 1.6.6 to 1.7.7
Snyk has created this PR to upgrade @headlessui/react from 1.6.6 to 1.7.7.

See this package in npm:
https://www.npmjs.com/package/@headlessui/react

See this project in Snyk:
https://app.snyk.io/org/maidul98/project/53d4ecb6-6cc1-4918-aa73-bf9cae4ffd13?utm_source=github&utm_medium=referral&page=upgrade-pr
2023-02-02 22:37:45 +00:00
189af07ff5 fix: upgrade @stripe/react-stripe-js from 1.10.0 to 1.16.3
Snyk has created this PR to upgrade @stripe/react-stripe-js from 1.10.0 to 1.16.3.

See this package in npm:
https://www.npmjs.com/package/@stripe/react-stripe-js

See this project in Snyk:
https://app.snyk.io/org/maidul98/project/53d4ecb6-6cc1-4918-aa73-bf9cae4ffd13?utm_source=github&utm_medium=referral&page=upgrade-pr
2023-02-02 22:37:38 +00:00
caf7426f86 fix: upgrade posthog-js from 1.34.0 to 1.39.4
Snyk has created this PR to upgrade posthog-js from 1.34.0 to 1.39.4.

See this package in npm:
https://www.npmjs.com/package/posthog-js

See this project in Snyk:
https://app.snyk.io/org/maidul98/project/53d4ecb6-6cc1-4918-aa73-bf9cae4ffd13?utm_source=github&utm_medium=referral&page=upgrade-pr
2023-02-02 22:37:32 +00:00
87 changed files with 5057 additions and 6629 deletions

File diff suppressed because one or more lines are too long

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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",

View File

@ -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);

View File

@ -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,

View File

@ -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 };

View File

@ -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,

View File

@ -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',

View File

@ -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 };

View File

@ -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,
},

View File

@ -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,
},

View File

@ -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;

View File

@ -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,

View File

@ -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,
};

View File

@ -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
)

View File

@ -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=

View 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")
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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")
},
}

View File

@ -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")

View File

@ -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

View File

@ -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 {

View File

@ -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()

View File

@ -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

View File

@ -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)
}
}

View File

@ -0,0 +1,7 @@
{
"workspaceId": "12345678",
"defaultEnvironment": "myDefaultEnv",
"gitBranchToEnvironmentMapping": {
"main": "myMainEnv"
}
}

View File

@ -0,0 +1,5 @@
{
"workspaceId": "12345678",
"defaultEnvironment": "myDefaultEnv",
"gitBranchToEnvironmentMapping": null
}

View File

@ -0,0 +1,7 @@
{
"workspaceId": "12345678",
"defaultEnvironment": "myDefaultEnv",
"gitBranchToEnvironmentMapping": {
"notmain": "myMainEnv"
}
}

View File

@ -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

View File

@ -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>

View File

@ -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.

View File

@ -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?
![Activity logs](../../images/activity-logs.png)
![Audit logs](../../images/activity-logs.png)

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 KiB

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

View File

@ -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.
![integrations fly](../../images/integrations-circleci-create.png)
![integrations fly](../../images/integrations-circleci.png)
![create integration circleci](../../images/integrations-circleci-create.png)
![integrations circleci](../../images/integrations-circleci.png)

View 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
![integrations](../../images/integrations.png)
## Authorize Infisical for Travis CI
Obtain your API token in User Settings > API authentication > Token
![integrations travis ci token](../../images/integrations-travisci-token.png)
Press on the Travis CI tile and input your Travis CI API token to grant Infisical access to your Travis CI account.
![integrations travis ci authorization](../../images/integrations-travisci-auth.png)
<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.
![create integration travis ci](../../images/integrations-travisci-create.png)
![integrations travis ci](../../images/integrations-travisci.png)

View File

@ -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 |

View File

@ -233,7 +233,8 @@
"pages": [
"integrations/cicd/githubactions",
"integrations/cicd/gitlab",
"integrations/cicd/circleci"
"integrations/cicd/circleci",
"integrations/cicd/travisci"
]
},
{

View File

@ -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"],

View File

@ -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"
}

View File

@ -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",

View File

@ -12,7 +12,8 @@ const integrationSlugNameMapping: Mapping = {
'github': 'GitHub',
'render': 'Render',
'flyio': 'Fly.io',
"circleci": 'CircleCI'
'circleci': 'CircleCI',
'travisci': 'TravisCI'
}
const envMapping: Mapping = {

View File

@ -1,5 +1,5 @@
{
"title": "Activity Logs",
"title": "Audit Logs",
"subtitle": "Event history for this Infisical project.",
"event": {
"readSecrets": "Secrets Viewed",

View File

@ -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",

View 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"
}

View 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"
}

View 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"
}

View 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."
}
}
}

View 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"
}

View 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."
}

View 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"
}

View 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"
}
}

View 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"
}
}

View 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"
}
}

View 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"
}

View 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"
}
}

View 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."
}

View 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."
}

View 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"
}
}

View 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."
}

View 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"
}

View File

@ -162,7 +162,7 @@ const Layout = ({ children }: LayoutProps) => {
},
{
href: `/activity/${workspaceMapping[workspaceSelected as any]}`,
title: 'Activity Logs',
title: 'Audit Logs',
emoji: <FontAwesomeIcon icon={faFileLines} />
},
{

View File

@ -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();

View File

@ -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>

View File

@ -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'
}
}
});

View File

@ -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>

View File

@ -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} />
)}

View File

@ -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;
}

View 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']);

View 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']);

View File

@ -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')}: `}
/>

View File

@ -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} />

View File

@ -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&apos;t part of any projects yet</Tag>
<div className='flex flex-row'>
<Tag colorSchema="red">This user isn&apos;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>

View File

@ -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

View File

@ -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
```

View 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

View 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

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