Compare commits

...

53 Commits

Author SHA1 Message Date
7487b373fe adding cypress test 2023-10-24 10:38:08 -04:00
9a500504a4 adding cypress tests 2023-10-21 09:49:31 -07:00
1510c39631 Update Chart.yaml 2023-10-19 19:19:46 +01:00
d0579b383f update readiness probe 2023-10-19 19:19:32 +01:00
b4f4c1064d Update values.yaml 2023-10-19 19:10:22 +01:00
d72d3940e6 update img name in prod img gha 2023-10-19 17:45:29 +01:00
7217bcb3d8 Merge pull request #1100 from Infisical/migrate-to-standalone-infisical
Migrate to standalone infisical
2023-10-19 16:07:55 +01:00
2faa9222d8 update gamma gh action 2023-10-19 16:05:41 +01:00
589f0bc134 update staging test for img 2023-10-19 13:23:07 +01:00
bd6dc3d4c0 update gamma helm values 2023-10-19 13:10:36 +01:00
9338babda6 update infisical helm chart read me 2023-10-19 13:03:18 +01:00
6f9e8644d7 update infisical helm chart to use standalone img 2023-10-19 12:58:16 +01:00
2fdb10277e update docs to use standalone infisical 2023-10-19 12:53:20 +01:00
15d2c536ed update prod docker compose 2023-10-19 12:23:20 +01:00
a304228961 Merge pull request #1095 from akhilmhdh/feat/folder-service-api-key
feat: added api key support for folder and secret import
2023-10-18 12:36:11 +01:00
c865b78b41 feat: added api key support for folder and secret import 2023-10-18 16:38:19 +05:30
be80ac999e Merge pull request #1094 from Infisical/fix-azure-saml-flow
Patch Azure SAML Flow
2023-10-18 11:56:45 +01:00
076fe58325 Fix azure-saml flow 2023-10-18 11:49:57 +01:00
66bfab1994 update platform version env 2023-10-18 10:41:15 +01:00
b92c50addd properly add pre baked values 2023-10-18 10:40:34 +01:00
8fbca05052 remove extract_version 2023-10-17 23:13:04 +01:00
d99830067e bake posthog key in single docker img 2023-10-17 23:08:43 +01:00
cdc8ef95ab add platform version to UI 2023-10-17 23:08:43 +01:00
072e97b956 Fix azure samlConfig 2023-10-17 16:51:46 +01:00
4f26a7cad3 Revert audience change for azure saml 2023-10-17 15:50:31 +01:00
7bb6ff3d0c Merge branch 'main' of https://github.com/Infisical/infisical 2023-10-17 15:32:42 +01:00
ecccec8e35 Attempt fix azure samlConfig 2023-10-17 15:32:34 +01:00
7fd15a06e5 conditionally build standalone infisical 2023-10-17 14:32:56 +01:00
5d4a37004e Merge pull request #1089 from G3root/serve-frontend-from-backend
feat: serve frontend from backend
2023-10-17 14:15:41 +01:00
aa61fd091d remove redundant file from docker ignore 2023-10-17 14:11:16 +01:00
04ac54bcfa run cmd as non root user and update port to non privileged 2023-10-17 14:08:22 +01:00
38dbf1e738 Add missing / to samlConfig callbackURL 2023-10-17 14:03:37 +01:00
ddf9d7848c Update protocol in samlConfig 2023-10-17 12:57:05 +01:00
0b40de49ec remove redis error logs 2023-10-17 12:24:54 +01:00
b1d16cab39 remove promise.all from closeDatabaseHelper 2023-10-17 12:24:18 +01:00
fb7c7045e9 set telemetry post frontend build in standalone docker img 2023-10-17 12:22:08 +01:00
d570828e47 Update path and callbackURL for samlConfig 2023-10-17 12:13:54 +01:00
2a92b6c787 Merge pull request #1093 from akhilmhdh/feat/secret-update-id
feat: changed secret update to use id
2023-10-17 11:14:30 +01:00
ee54fdabe1 feat: changed secret update to use id 2023-10-17 15:38:30 +05:30
136308f299 revert: temp workaround: remove use of get static prop 2023-10-16 20:37:35 +05:30
ba41244877 chore: remove next.js 2023-10-16 20:35:47 +05:30
c4dcf334f0 fix: remove copy config 2023-10-16 20:35:29 +05:30
66bac3ef48 fix: static props not rendered 2023-10-16 20:35:16 +05:30
e5347719c3 temp workaround: remove use of get static prop 2023-10-16 15:03:55 +01:00
abe1f54aab remove nginx and pm2 2023-10-15 23:58:04 +01:00
13c1e2b349 fix: docker file 2023-10-15 12:09:45 +05:30
f5a9afec61 fix: pm2 config 2023-10-15 11:52:55 +05:30
d0a85c98b2 chore: add docker ignore and git ignore 2023-10-15 11:47:35 +05:30
e0669cae7c chore: update path 2023-10-15 11:47:06 +05:30
2c011b7d53 feat: add custom server 2023-10-14 13:20:27 +05:30
1b24a9b6e9 chore: add next to gitignore 2023-10-14 13:20:14 +05:30
00c173aead chore: add next for backend 2023-10-14 13:19:54 +05:30
2e15ad0625 fix: type 2023-10-14 12:54:26 +05:30
78 changed files with 2657 additions and 672 deletions

View File

@ -1,2 +1,10 @@
backend/node_modules
frontend/node_modules
frontend/node_modules
backend/frontend-build
**/node_modules
**/.next
.dockerignore
.git
README.md
.dockerignore
**/Dockerfile

View File

@ -6,7 +6,7 @@ services:
restart: unless-stopped
depends_on:
- mongo
image: infisical/backend:test
image: infisical/infisical:test
command: npm run start
environment:
- NODE_ENV=production

36
.github/values.yaml vendored
View File

@ -1,29 +1,3 @@
# secretScanningGitApp:
# enabled: false
# deploymentAnnotations:
# secrets.infisical.com/auto-reload: "true"
# image:
# repository: infisical/staging_deployment_secret-scanning-git-app
frontend:
enabled: true
name: frontend
podAnnotations: {}
deploymentAnnotations:
secrets.infisical.com/auto-reload: "true"
replicaCount: 2
image:
repository: infisical/staging_deployment_frontend
tag: "latest"
pullPolicy: Always
kubeSecretRef: managed-secret-frontend
service:
annotations: {}
type: ClusterIP
nodePort: ""
frontendEnvironmentVariables: null
backend:
enabled: true
name: backend
@ -32,7 +6,7 @@ backend:
secrets.infisical.com/auto-reload: "true"
replicaCount: 2
image:
repository: infisical/staging_deployment_backend
repository: infisical/staging_infisical
tag: "latest"
pullPolicy: Always
kubeSecretRef: managed-backend-secret
@ -63,14 +37,8 @@ ingress:
enabled: true
# annotations:
# kubernetes.io/ingress.class: "nginx"
# cert-manager.io/issuer: letsencrypt-nginx
# cert-manager.io/issuer: letsencrypt-nginx
hostName: gamma.infisical.com ## <- Replace with your own domain
frontend:
path: /
pathType: Prefix
backend:
path: /api
pathType: Prefix
tls:
[]
# - secretName: letsencrypt-nginx

View File

@ -39,7 +39,7 @@ jobs:
token: ${{ secrets.DEPOT_PROJECT_TOKEN }}
load: true
context: backend
tags: infisical/backend:test
tags: infisical/infisical:test
- name: ⏻ Spawn backend container and dependencies
run: |
docker compose -f .github/resources/docker-compose.be-test.yml up --wait --quiet-pull

View File

@ -2,7 +2,7 @@ name: Build, Publish and Deploy to Gamma
on: [workflow_dispatch]
jobs:
backend-image:
infisical-image:
name: Build backend image
runs-on: ubuntu-latest
steps:
@ -32,8 +32,9 @@ jobs:
project: 64mmf0n610
token: ${{ secrets.DEPOT_PROJECT_TOKEN }}
load: true
context: backend
tags: infisical/backend:test
context: .
file: Dockerfile.standalone-infisical
tags: infisical/infisical:test
- name: ⏻ Spawn backend container and dependencies
run: |
docker compose -f .github/resources/docker-compose.be-test.yml up --wait --quiet-pull
@ -49,68 +50,20 @@ jobs:
project: 64mmf0n610
token: ${{ secrets.DEPOT_PROJECT_TOKEN }}
push: true
context: backend
context: .
file: Dockerfile.standalone-infisical
tags: |
infisical/staging_deployment_backend:${{ steps.commit.outputs.short }}
infisical/staging_deployment_backend:latest
infisical/staging_infisical:${{ steps.commit.outputs.short }}
infisical/staging_infisical:latest
platforms: linux/amd64,linux/arm64
build-args: |
POSTHOG_API_KEY=${{ secrets.PUBLIC_POSTHOG_API_KEY }}
INFISICAL_PLATFORM_VERSION=${{ steps.extract_version.outputs.version }}
frontend-image:
name: Build frontend image
runs-on: ubuntu-latest
steps:
- name: ☁️ Checkout source
uses: actions/checkout@v3
- name: Save commit hashes for tag
id: commit
uses: pr-mpt/actions-commit-hash@v2
- name: 🔧 Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: 🐋 Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up Depot CLI
uses: depot/setup-action@v1
- name: 📦 Build frontend and export to Docker
uses: depot/build-push-action@v1
with:
load: true
token: ${{ secrets.DEPOT_PROJECT_TOKEN }}
project: 64mmf0n610
context: frontend
tags: infisical/staging_deployment_frontend:test
build-args: |
POSTHOG_API_KEY=${{ secrets.PUBLIC_POSTHOG_API_KEY }}
NEXT_INFISICAL_PLATFORM_VERSION=${{ steps.extract_version.outputs.version }}
- name: ⏻ Spawn frontend container
run: |
docker run -d --rm --name infisical-frontend-test infisical/staging_deployment_frontend:test
- name: 🧪 Test frontend image
run: |
./.github/resources/healthcheck.sh infisical-frontend-test
- name: ⏻ Shut down frontend container
run: |
docker stop infisical-frontend-test
- name: 🏗️ Build frontend and push
uses: depot/build-push-action@v1
with:
project: 64mmf0n610
push: true
token: ${{ secrets.DEPOT_PROJECT_TOKEN }}
context: frontend
tags: |
infisical/staging_deployment_frontend:${{ steps.commit.outputs.short }}
infisical/staging_deployment_frontend:latest
platforms: linux/amd64,linux/arm64
build-args: |
POSTHOG_API_KEY=${{ secrets.PUBLIC_POSTHOG_API_KEY }}
NEXT_INFISICAL_PLATFORM_VERSION=${{ steps.extract_version.outputs.version }}
gamma-deployment:
name: Deploy to gamma
runs-on: ubuntu-latest
needs: [frontend-image, backend-image]
needs: [infisical-image]
steps:
- name: ☁️ Checkout source
uses: actions/checkout@v3

View File

@ -73,3 +73,6 @@ jobs:
infisical/infisical:${{ steps.extract_version.outputs.version }}
platforms: linux/amd64,linux/arm64
file: Dockerfile.standalone-infisical
build-args: |
POSTHOG_API_KEY=${{ secrets.PUBLIC_POSTHOG_API_KEY }}
INFISICAL_PLATFORM_VERSION=${{ steps.extract_version.outputs.version }}

6
.gitignore vendored
View File

@ -33,7 +33,7 @@ reports
junit.xml
# next.js
/.next/
.next/
/out/
# production
@ -59,4 +59,6 @@ yarn-error.log*
.infisical.json
# Editor specific
.vscode/*
.vscode/*
frontend-build

View File

@ -1,7 +1,13 @@
ARG POSTHOG_HOST=https://app.posthog.com
ARG POSTHOG_API_KEY=posthog-api-key
ARG INTERCOM_ID=intercom-id
FROM node:16-alpine AS frontend-dependencies
FROM node:16-alpine AS base
FROM base AS frontend-dependencies
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
@ -11,7 +17,7 @@ COPY frontend/package.json frontend/package-lock.json frontend/next.config.js ./
RUN npm ci --only-production --ignore-scripts
# Rebuild the source code only when needed
FROM node:16-alpine AS frontend-builder
FROM base AS frontend-builder
WORKDIR /app
# Copy dependencies
@ -27,41 +33,38 @@ ARG POSTHOG_API_KEY
ENV NEXT_PUBLIC_POSTHOG_API_KEY $POSTHOG_API_KEY
ARG INTERCOM_ID
ENV NEXT_PUBLIC_INTERCOM_ID $INTERCOM_ID
ARG INFISICAL_PLATFORM_VERSION
ENV NEXT_PUBLIC_INFISICAL_PLATFORM_VERSION $INFISICAL_PLATFORM_VERSION
# Build
RUN npm run build
# Production image
FROM node:16-alpine AS frontend-runner
FROM base AS frontend-runner
WORKDIR /app
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
RUN adduser --system --uid 1001 non-root-user
RUN mkdir -p /app/.next/cache/images && chown nextjs:nodejs /app/.next/cache/images
RUN mkdir -p /app/.next/cache/images && chown non-root-user:nodejs /app/.next/cache/images
VOLUME /app/.next/cache/images
ARG POSTHOG_API_KEY
ENV NEXT_PUBLIC_POSTHOG_API_KEY=$POSTHOG_API_KEY \
BAKED_NEXT_PUBLIC_POSTHOG_API_KEY=$POSTHOG_API_KEY
ARG INTERCOM_ID
ENV NEXT_PUBLIC_INTERCOM_ID=$INTERCOM_ID \
BAKED_NEXT_PUBLIC_INTERCOM_ID=$INTERCOM_ID
COPY --chown=nextjs:nodejs --chmod=555 frontend/scripts ./scripts
COPY --chown=non-root-user:nodejs --chmod=555 frontend/scripts ./scripts
COPY --from=frontend-builder /app/public ./public
RUN chown nextjs:nodejs ./public/data
COPY --from=frontend-builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=frontend-builder --chown=nextjs:nodejs /app/.next/static ./.next/static
RUN chown non-root-user:nodejs ./public/data
COPY --from=frontend-builder --chown=non-root-user:nodejs /app/.next/standalone ./
COPY --from=frontend-builder --chown=non-root-user:nodejs /app/.next/static ./.next/static
USER nextjs
USER non-root-user
ENV NEXT_TELEMETRY_DISABLED 1
##
## BACKEND
##
FROM node:16-alpine AS backend-build
FROM base AS backend-build
RUN addgroup --system --gid 1001 nodejs \
&& adduser --system --uid 1001 non-root-user
WORKDIR /app
@ -69,10 +72,11 @@ COPY backend/package*.json ./
RUN npm ci --only-production
COPY /backend .
COPY --chown=non-root-user:nodejs standalone-entrypoint.sh standalone-entrypoint.sh
RUN npm run build
# Production stage
FROM node:16-alpine AS backend-runner
FROM base AS backend-runner
WORKDIR /app
@ -81,27 +85,44 @@ RUN npm ci --only-production
COPY --from=backend-build /app .
RUN mkdir frontend-build
# Production stage
FROM node:16-alpine AS production
FROM base AS production
RUN addgroup --system --gid 1001 nodejs \
&& adduser --system --uid 1001 non-root-user
## set pre baked keys
ARG POSTHOG_API_KEY
ENV NEXT_PUBLIC_POSTHOG_API_KEY=$POSTHOG_API_KEY \
BAKED_NEXT_PUBLIC_POSTHOG_API_KEY=$POSTHOG_API_KEY
ARG INTERCOM_ID=intercom-id
ENV NEXT_PUBLIC_INTERCOM_ID=$INTERCOM_ID \
BAKED_NEXT_PUBLIC_INTERCOM_ID=$INTERCOM_ID
WORKDIR /
# Install PM2
RUN npm install -g pm2
# Copy ecosystem.config.js
COPY ecosystem.config.js .
RUN apk add --no-cache nginx
COPY nginx/default-stand-alone-docker.conf /etc/nginx/nginx.conf
COPY --from=backend-runner /app /backend
COPY --from=frontend-runner /app/ /app/
COPY --from=frontend-runner /app ./backend/frontend-build
EXPOSE 80
ENV PORT 8080
ENV HTTPS_ENABLED false
ENV NODE_ENV production
ENV STANDALONE_BUILD true
WORKDIR /backend
ENV TELEMETRY_ENABLED true
HEALTHCHECK --interval=10s --timeout=3s --start-period=10s \
CMD node healthcheck.js
EXPOSE 8080
USER non-root-user
CMD ["./standalone-entrypoint.sh"]
CMD ["pm2-runtime", "start", "ecosystem.config.js"]

View File

@ -476,7 +476,7 @@ export const getSecrets = async (req: Request, res: Response) => {
if (folderId && folderId !== "root") {
const folder = await Folder.findOne({ workspace: workspaceId, environment });
if (!folder) throw BadRequestError({ message: "Folder not found" });
if (!folder) return res.send({ secrets: [] });
secretPath = getFolderWithPathFromId(folder.nodes, folderId).folderPath;
}
@ -673,6 +673,7 @@ export const updateSecretByName = async (req: Request, res: Response) => {
secretValueCiphertext,
secretValueTag,
secretValueIV,
secretId,
type,
environment,
secretPath,
@ -741,6 +742,7 @@ export const updateSecretByName = async (req: Request, res: Response) => {
workspaceId: new Types.ObjectId(workspaceId),
environment,
type,
secretId,
authData: req.authData,
newSecretName,
secretValueCiphertext,

View File

@ -13,7 +13,10 @@ router.get(
const options = {
failureRedirect: "/",
additionalParams: {
RelayState: req.query.callback_port ?? ""
RelayState: JSON.stringify({
spInitiated: true,
callbackPort: req.query.callback_port ?? ""
})
},
};
passport.authenticate("saml", options)(req, res, next);

View File

@ -14,7 +14,7 @@ export const initDatabaseHelper = async ({
}) => {
try {
await mongoose.connect(mongoURL);
// allow empty strings to pass the required validator
mongoose.Schema.Types.String.checkRequired(v => typeof v === "string");
@ -31,14 +31,10 @@ export const initDatabaseHelper = async ({
* Close database conection
*/
export const closeDatabaseHelper = async () => {
return Promise.all([
new Promise((resolve) => {
if (mongoose.connection && mongoose.connection.readyState == 1) {
mongoose.connection.close()
.then(() => resolve("Database connection closed"));
} else {
resolve("Database connection already closed");
}
}),
]);
}
if (mongoose.connection && mongoose.connection.readyState === 1) {
await mongoose.connection.close();
return "Database connection closed";
} else {
return "Database connection already closed";
}
};

View File

@ -790,6 +790,7 @@ export const getSecretHelper = async ({
export const updateSecretHelper = async ({
secretName,
workspaceId,
secretId,
environment,
type,
authData,
@ -812,11 +813,20 @@ export const updateSecretHelper = async ({
workspaceId: new Types.ObjectId(workspaceId)
});
const oldSecretBlindIndex = await generateSecretBlindIndexWithSaltHelper({
let oldSecretBlindIndex = await generateSecretBlindIndexWithSaltHelper({
secretName,
salt
});
if (secretId) {
const secret = await Secret.findOne({
workspace: workspaceId,
environment,
_id: secretId
}).select("secretBlindIndex");
if (secret && secret.secretBlindIndex) oldSecretBlindIndex = secret.secretBlindIndex;
}
let secret: ISecret | null = null;
const folderId = await getFolderIdFromServiceToken(workspaceId, environment, secretPath);
@ -891,6 +901,9 @@ export const updateSecretHelper = async ({
skipMultilineEncoding,
secretBlindIndex: newSecretNameBlindIndex,
$inc: { version: 1 }
},
{
new: true
}
);
}

View File

@ -87,6 +87,9 @@ import { setup } from "./utils/setup";
import { syncSecretsToThirdPartyServices } from "./queues/integrations/syncSecretsToThirdPartyServices";
import { githubPushEventSecretScan } from "./queues/secret-scanning/githubScanPushEvent";
const SmeeClient = require("smee-client"); // eslint-disable-line
import path from "path";
let handler: null | any = null;
const main = async () => {
await setup();
@ -147,6 +150,27 @@ const main = async () => {
next();
});
if ((await getNodeEnv()) === "production" && process.env.STANDALONE_BUILD === "true") {
const nextJsBuildPath = path.join(__dirname, "../frontend-build");
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-var-requires
const conf = require("../frontend-build/.next/required-server-files.json").config;
const NextServer =
// eslint-disable-next-line @typescript-eslint/no-var-requires
require("../frontend-build/node_modules/next/dist/server/next-server").default;
const nextApp = new NextServer({
dev: false,
dir: nextJsBuildPath,
port: await getPort(),
conf,
hostname: "local",
customServer: false
});
handler = nextApp.getRequestHandler();
}
// (EE) routes
app.use("/api/v1/secret", eeSecretRouter);
app.use("/api/v1/secret-snapshot", eeSecretSnapshotRouter);
@ -209,6 +233,12 @@ const main = async () => {
// server status
app.use("/api", healthCheck);
if (handler) {
app.all("*", (req, res) => {
return handler(req, res);
});
}
//* Handle unrouted requests and respond with proper error message as well as status code
app.use((req, res, next) => {
if (res.headersSent) return next();

View File

@ -44,6 +44,7 @@ export interface GetSecretParams {
export interface UpdateSecretParams {
secretName: string;
newSecretName?: string;
secretId?: string;
secretKeyCiphertext?: string;
secretKeyIV?: string;
secretKeyTag?: string;

View File

@ -40,9 +40,9 @@ syncSecretsToThirdPartyServices.process(async (job: Job) => {
const prefix = (integration.metadata?.secretPrefix || "");
const suffix = (integration.metadata?.secretSuffix || "");
const newKey = prefix + key + suffix;
suffixedSecrets[newKey] = secrets[key];
}
}
}
const integrationAuth = await IntegrationAuth.findById(integration.integrationAuth);
@ -67,7 +67,7 @@ syncSecretsToThirdPartyServices.process(async (job: Job) => {
})
syncSecretsToThirdPartyServices.on("error", (error) => {
console.log("QUEUE ERROR:", error) // eslint-disable-line
// console.log("QUEUE ERROR:", error) // eslint-disable-line
})
export const syncSecretsToActiveIntegrationsQueue = (jobDetails: TSyncSecretsToThirdPartyServices) => {

View File

@ -7,7 +7,7 @@ import { AuthMode } from "../../variables";
router.post(
"/",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN]
acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN, AuthMode.API_KEY]
}),
secretImpsController.createSecretImp
);
@ -15,7 +15,7 @@ router.post(
router.put(
"/:id",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN]
acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN, AuthMode.API_KEY]
}),
secretImpsController.updateSecretImport
);
@ -23,7 +23,7 @@ router.put(
router.delete(
"/:id",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN]
acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN, AuthMode.API_KEY]
}),
secretImpsController.deleteSecretImport
);
@ -31,7 +31,7 @@ router.delete(
router.get(
"/",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN]
acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN, AuthMode.API_KEY]
}),
secretImpsController.getSecretImports
);
@ -39,7 +39,7 @@ router.get(
router.get(
"/secrets",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN]
acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN, AuthMode.API_KEY]
}),
secretImpsController.getAllSecretsFromImport
);

View File

@ -12,7 +12,7 @@ import { AuthMode } from "../../variables";
router.post(
"/",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN]
acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN, AuthMode.API_KEY]
}),
createFolder
);
@ -20,7 +20,7 @@ router.post(
router.patch(
"/:folderName",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN]
acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN, AuthMode.API_KEY]
}),
updateFolderById
);
@ -28,7 +28,7 @@ router.patch(
router.delete(
"/:folderName",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN]
acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN, AuthMode.API_KEY]
}),
deleteFolder
);
@ -36,7 +36,7 @@ router.delete(
router.get(
"/",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN]
acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN, AuthMode.API_KEY]
}),
getFolders
);

View File

@ -291,8 +291,7 @@ const initializePassport = async () => {
});
interface ISAMLConfig {
path: string;
callbackURL: string;
callbackUrl: string;
entryPoint: string;
issuer: string;
cert: string;
@ -301,8 +300,7 @@ const initializePassport = async () => {
}
const samlConfig: ISAMLConfig = ({
path: `${await getSiteURL()}/api/v1/sso/saml2/${ssoIdentifier}`,
callbackURL: `${await getSiteURL()}/api/v1/sso/saml2${ssoIdentifier}`,
callbackUrl: `${await getSiteURL()}/api/v1/sso/saml2/${ssoIdentifier}`,
entryPoint: ssoConfig.entryPoint,
issuer: ssoConfig.issuer,
cert: ssoConfig.cert,
@ -313,6 +311,12 @@ const initializePassport = async () => {
samlConfig.wantAuthnResponseSigned = false;
}
if (ssoConfig.authProvider.toString() === AuthMethod.AZURE_SAML.toString()) {
if (req.body.RelayState && JSON.parse(req.body.RelayState).spInitiated) {
samlConfig.audience = `spn:${ssoConfig.issuer}`;
}
}
req.ssoConfig = ssoConfig;
done(null, samlConfig);
@ -405,7 +409,7 @@ const initializePassport = async () => {
authMethod: req.ssoConfig.authProvider,
isUserCompleted,
...(req.body.RelayState ? {
callbackPort: req.body.RelayState as string
callbackPort: JSON.parse(req.body.RelayState).callbackPort as string
} : {})
},
expiresIn: await getJwtProviderAuthLifetime(),

View File

@ -55,9 +55,6 @@ export const setup = async () => {
// initializing global feature set
await EELicenseService.initGlobalFeatureSet();
// initializing the database connection
await DatabaseService.initDatabase(await getMongoURL());
await initializePassport();
// re-encrypt any data previously encrypted under server hex 128-bit ENCRYPTION_KEY

View File

@ -353,6 +353,7 @@ export const UpdateSecretByNameV3 = z.object({
body: z.object({
workspaceId: z.string().trim(),
environment: z.string().trim(),
secretId: z.string().trim().optional(),
type: z.enum([SECRET_SHARED, SECRET_PERSONAL]),
secretPath: z.string().trim().default("/"),
secretValueCiphertext: z.string().trim(),

7
cypress.config.js Normal file
View File

@ -0,0 +1,7 @@
module.exports = {
e2e: {
baseUrl: 'http://localhost:8080',
viewportWidth: 1480,
viewportHeight: 920,
},
};

View File

@ -0,0 +1,47 @@
/// <reference types="cypress" />
describe('organization Overview', () => {
beforeEach(() => {
cy.login(`test@localhost.local`, `testInfisical1`)
})
const projectName = "projectY"
it('can`t create projects with empty names', () => {
cy.get('.button').click()
cy.get('input[placeholder="Type your project name"]').type('abc').clear()
cy.intercept('*').as('anyRequest');
cy.get('@anyRequest').should('not.exist');
})
it('can delete a newly-created project', () => {
// Create a project
cy.get('.button').click()
cy.get('input[placeholder="Type your project name"]').type(`${projectName}`)
cy.contains('button', 'Create Project').click()
cy.url().should('include', '/project')
// Delete a project
cy.get(`[href^="/project/"][href$="/settings"] > a > .group`).click()
cy.contains('button', `Delete ${projectName}`).click()
cy.contains('button', 'Delete Project').should('have.attr', 'disabled')
cy.get('input[placeholder="Type to delete..."]').type('confirm')
cy.contains('button', 'Delete Project').should('not.have.attr', 'disabled')
cy.url().then((currentUrl) => {
let projectId = currentUrl.split("/")[4]
cy.intercept('DELETE', `/api/v1/workspace/${projectId}`).as('deleteProject');
cy.contains('button', 'Delete Project').click();
cy.get('@deleteProject').should('have.property', 'response').and('have.property', 'statusCode', 200);
})
})
it('can display no projects', () => {
cy.intercept('/api/v1/workspace', {
body: {
"workspaces": []
},
})
cy.get('.border-mineshaft-700 > :nth-child(2)').should('have.text', 'You are not part of any projects in this organization yet. When you are, they will appear here.')
})
})

View File

@ -0,0 +1,24 @@
/// <reference types="cypress" />
describe('Organization Settings', () => {
let orgId;
beforeEach(() => {
cy.login(`test@localhost.local`, `testInfisical1`)
cy.url().then((currentUrl) => {
orgId = currentUrl.split("/")[4]
cy.visit(`org/${orgId}/settings`)
})
})
it('can rename org', () => {
cy.get('input[placeholder="Acme Corp"]').clear().type('ABC')
cy.intercept('PATCH', `/api/v1/organization/${orgId}/name`).as('renameOrg');
cy.get('form.p-4 > .button').click()
cy.get('@renameOrg').should('have.property', 'response').and('have.property', 'statusCode', 200);
cy.get('.pl-3').should("have.text", "ABC ")
})
})

View File

@ -0,0 +1,84 @@
/// <reference types="cypress" />
describe('Project Overview', () => {
const projectName = "projectY"
let projectId;
let isFirstTest = true;
before(() => {
cy.login(`test@localhost.local`, `testInfisical1`)
// Create a project
cy.get('.button').click()
cy.get('input[placeholder="Type your project name"]').type(`${projectName}`)
cy.contains('button', 'Create Project').click()
cy.url().should('include', '/project').then((currentUrl) => {
projectId = currentUrl.split("/")[4]
})
})
beforeEach(() => {
if (isFirstTest) {
isFirstTest = false;
return; // Skip the rest of the beforeEach for the first test
}
cy.login(`test@localhost.local`, `testInfisical1`)
cy.visit(`/project/${projectId}/secrets/overview`)
})
it('can create secrets', () => {
cy.contains('button', 'Go to Development').click()
cy.contains('button', 'Add a new secret').click()
cy.get('input[placeholder="Type your secret name"]').type('SECRET_A')
cy.contains('button', 'Create Secret').click()
cy.get('.w-80 > .inline-flex > .input').should('have.value', 'SECRET_A')
cy.get(':nth-child(6) > .button > .w-min').should('have.text', '1 Commit')
})
it('can update secrets', () => {
cy.get(':nth-child(2) > .flex > .button').click()
cy.get('.overflow-auto > .relative > .absolute').type('VALUE_A')
cy.get('.button.text-primary > .svg-inline--fa').click()
cy.get(':nth-child(6) > .button > .w-min').should('have.text', '2 Commits')
})
it('can`t create duplicate-name secrets', () => {
cy.get(':nth-child(2) > .flex > .button').click()
cy.contains('button', 'Add Secret').click()
cy.get('input[placeholder="Type your secret name"]').type('SECRET_A')
cy.intercept('POST', `/api/v3/secrets/SECRET_A`).as('createSecret');
cy.contains('button', 'Create Secret').click()
cy.get('@createSecret').should('have.property', 'response').and('have.property', 'statusCode', 400);
})
it('can add another secret', () => {
cy.get(':nth-child(2) > .flex > .button').click()
cy.contains('button', 'Add Secret').click()
cy.get('input[placeholder="Type your secret name"]').type('SECRET_B')
cy.contains('button', 'Create Secret').click()
cy.get(':nth-child(6) > .button > .w-min').should('have.text', '3 Commits')
})
it('can delete a secret', () => {
cy.get(':nth-child(2) > .flex > .button').click()
// cy.get(':nth-child(3) > .shadow-none').trigger('mouseover')
cy.get(':nth-child(3) > .shadow-none > .group > .h-10 > .border-red').click()
cy.contains('button', 'Delete Secret').should('have.attr', 'disabled')
cy.get('input[placeholder="Type to delete..."]').type('SECRET_B')
cy.intercept('DELETE', `/api/v3/secrets/SECRET_B`).as('deleteSecret');
cy.contains('button', 'Delete Secret').should('not.have.attr', 'disabled')
cy.contains('button', 'Delete Secret').click();
cy.get('@deleteSecret').should('have.property', 'response').and('have.property', 'statusCode', 200);
})
it('can add a comment', () => {
return;
cy.get(':nth-child(2) > .flex > .button').click()
// for some reason this hover does not want to work
cy.get('.overflow-auto').trigger('mouseover').then(() => {
cy.get('.shadow-none > .group > .pl-4 > .h-8 > button[aria-label="add-comment"]').should('be.visible').click()
});
})
})

View File

@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}

View File

@ -0,0 +1,51 @@
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add('login', (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
Cypress.Commands.add('login', (username, password) => {
cy.visit('/login')
cy.get('input[placeholder="Enter your email..."]').type(username)
cy.get('input[placeholder="Enter your password..."]').type(password)
cy.contains('Continue with Email').click()
cy.url().should('include', '/overview')
// Need to make this work for CSRF tokens; Cypress has an example in the docs
// cy.session(
// username,
// () => {
// cy.visit('/login')
// cy.get('input[placeholder="Enter your email..."]').type(username)
// cy.get('input[placeholder="Enter your password..."]').type(password)
// cy.contains('Continue with Email').click()
// cy.url().should('include', '/overview')
// },
// {
// validate: () => {
// cy.getCookie('jid').should('exist')
// },
// }
// )
})

20
cypress/support/e2e.js Normal file
View File

@ -0,0 +1,20 @@
// ***********************************************************
// This example support/e2e.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands'
// Alternatively you can use CommonJS syntax:
// require('./commands')

View File

@ -1,46 +1,20 @@
version: "3"
services:
nginx:
container_name: infisical-nginx
image: nginx
restart: always
ports:
- 80:80
- 443:443
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- frontend
- backend
networks:
- infisical
backend:
container_name: infisical-backend
restart: unless-stopped
depends_on:
- mongo
image: infisical/backend
image: infisical/infisical:latest
env_file: .env
ports:
- 80:8080
environment:
- NODE_ENV=production
networks:
- infisical
frontend:
container_name: infisical-frontend
restart: unless-stopped
depends_on:
- backend
image: infisical/frontend
env_file: .env
environment:
# - NEXT_PUBLIC_POSTHOG_API_KEY=${POSTHOG_PROJECT_API_KEY}
- INFISICAL_TELEMETRY_ENABLED=${TELEMETRY_ENABLED}
networks:
- infisical
redis:
image: redis
container_name: infisical-dev-redis

View File

@ -63,12 +63,17 @@ description: "Configure Azure SAML for Infisical SSO"
7. Get IdP values:
Back in the **Set up Single Sign-On with SAML** screen, copy the **Login URL**, **Azure AD Identifier** and **SAML Certificate** to use when finishing configuring Azure SAML in Infisical.
In the **Set up Single Sign-On with SAML** screen, copy the **Login URL** and **SAML Certificate** to use when finishing configuring Azure SAML in Infisical.
Back in Infisical, set **Login URL** and **Azure AD Identifier** from above. Once you've done that, press **Update** to complete the required configuration.
![Azure SAML identity provider values 1](../../../images/sso/azure/idp-values.png)
![Azure SAML identity provider values](../../../images/sso/azure/idp-values.png)
![Azure SAML paste identity provider values](../../../images/sso/azure/idp-values-2.png)
In the **Properties** screen, copy the **Application ID** to use when finishing configuring Azure SAML in Infisical.
![Azure SAML identity provider values 2](../../../images/sso/azure/idp-values-2.png)
Back in Infisical, set **Login URL**, **Azure Application ID**, and **SAML Certificate** from above. Once you've done that, press **Update** to complete the required configuration.
![Azure SAML paste identity provider values](../../../images/sso/azure/idp-values-3.png)
<Note>
When pasting the certificate into Infisical, you'll want to retain `-----BEGIN

Binary file not shown.

Before

Width:  |  Height:  |  Size: 521 KiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

View File

@ -3,7 +3,7 @@ title: "All environment variables"
description: "Configure your environment variables when self-hosting Infisical."
---
## Backend environment variables
## Environment variables
Depending on your chosen self hosted deployment method, you may need to configured at least the required environment variable listed below.
Other environment variables are listed below to increase the functionality of your self hosted instance based on your use case.
@ -232,12 +232,3 @@ Infisical uses Sentry to report error logs
<ParamField query="TELEMETRY_ENABLED" type="string" default="true" optional></ParamField>
</Tab>
</Tabs>
## Frontend environment variables
<ParamField
query="TELEMETRY_ENABLED"
type="string"
default="true"
optional
></ParamField>

View File

@ -31,7 +31,7 @@ primary_region = "iad"
MONGO_URL = <>
[http_service]
internal_port = 80
internal_port = 8080
```

View File

@ -23,40 +23,27 @@ helm repo update
## Add Helm values
Create a values.yaml file to configure various installation settings, such as the docker image tags and environment variables for both the frontend and backend. To explore all configurable properties for your values file, [visit this page](https://github.com/Infisical/infisical/tree/main/helm-charts/infisical).
Create a values.yaml file to configure various installation settings, such as the docker image tags and environment variables. To explore all configurable properties for your values file, [visit this page](https://github.com/Infisical/infisical/tree/main/helm-charts/infisical).
#### Set image tags
By default, the application will use the latest tag to retrieve the required Docker images, which may be appropriate for most cases.
However, it's important to specify a particular version of Infisical during installation to prevent any significant updates from disrupting your deployment.
View [properties for frontend and backend](https://github.com/Infisical/infisical/tree/main/helm-charts/infisical#parameters).
By default, the application will use the `latest` docker image tag. This is okay for test environments; however, for production deployments it is important to pin your deployment to a particular docker image tag to prevent receiving unintended changes.
<Tip>
To find the latest version number of Infisical, follow the links below
- [frontend Docker image](https://hub.docker.com/r/infisical/frontend/tags)
- [backend Docker image](https://hub.docker.com/r/infisical/backend/tags)
To find the latest version number of Infisical, click [here](https://hub.docker.com/r/infisical/infisical/tags)
</Tip>
```yaml simple-values-example.yaml
frontend:
name: frontend
replicaCount: 2
image:
repository: infisical/frontend
tag: "v0.34.2" # <--- frontend version
pullPolicy: Always
backend:
replicaCount: 2
image:
repository: infisical/backend
tag: "v0.34.2" # <--- backend version
repository: infisical/infisical
tag: "v0.39.5"
pullPolicy: Always
```
#### Configure environment variables
You can configure environment variables for the frontend and backend in your Helm values file under the property `frontendEnvironmentVariables` and `backendEnvironmentVariables` respectively. View configurable [environment variables](../configuration/envars).
You can configure environment variables for your instance of Infisical though the Helm values file under the property `backendEnvironmentVariables`. View configurable [environment variables](../configuration/envars).
Infisical requires the following backend environment variables to be defined: _`ENCRYPTION_KEY`_, _`JWT_SIGNUP_SECRET`_, _`JWT_REFRESH_SECRET`_, _`JWT_AUTH_SECRET`_, _`JWT_MFA_SECRET`_ and _`JWT_SERVICE_SECRET`_.
@ -87,38 +74,30 @@ Infisical uses Nginx to route external traffic. You can install Nginx along with
...
ingress:
nginx:
enabled: false #<-- if you would like to install nginx along with Infisical
enabled: true #<-- if you would like to install nginx along with Infisical
```
#### Database
Infisical uses a document database as its persistence layer. With this Helm chart, you spin up a MongoDB instance power by Bitnami along side other Infisical services in your cluster.
Infisical uses a MongoDB as its persistence layer. With this Helm chart, a MongoDB instance is automatically spun up for use with Infisical.
When persistence is enabled, the data will be stored as Kubernetes Persistence Volume. View all [properties for mongodb](https://github.com/Infisical/infisical/tree/main/helm-charts/infisical).
```yaml simple-values-example.yaml
mongodb:
enabled: false
enabled: true
persistence:
enabled: false
```
To increase data redundancy, we recommend that you use a managed document database service such as AWS Document DB, MongoDB or similar services instead.
To achieve high availability and data redundancy, we recommend that you use a managed document database service such as AWS Document DB, MongoDB or similar services instead of the in cluster database.
Managed database connection string can be set in the `backendEnvironmentVariables`.
#### Example helm values
```yaml simple-values-example.yaml
frontend:
name: frontend
replicaCount: 2
image:
repository: infisical/frontend
tag: "v0.34.2" # <--- frontend version
pullPolicy: Always
backend:
replicaCount: 2
image:
repository: infisical/backend
tag: "v0.34.2" # <--- backend version
repository: infisical/infisical
tag: "v0.39.5"
pullPolicy: Always
backendEnvironmentVariables:
@ -126,7 +105,7 @@ backendEnvironmentVariables:
ingress:
nginx:
enabled: true #<-- if you would like to install nginx along with Infisical
enabled: true
```
@ -136,22 +115,6 @@ ingress:
nginx:
enabled: true
frontend:
enabled: true
name: frontend
podAnnotations: {}
deploymentAnnotations: {}
replicaCount: 4
image:
repository: infisical/frontend
tag: "v0.34.2" # <--- frontend version
pullPolicy: IfNotPresent
kubeSecretRef: null
service:
annotations: {}
type: ClusterIP
nodePort: ""
backend:
enabled: true
name: backend
@ -159,8 +122,8 @@ ingress:
deploymentAnnotations: {}
replicaCount: 4
image:
repository: infisical/backend
tag: "v0.34.2" # <--- backend version
repository: infisical/infisical
tag: "v0.39.5"
pullPolicy: IfNotPresent
kubeSecretRef: null
service:
@ -176,26 +139,9 @@ ingress:
## Mongo DB persistence
mongodb:
enabled: false
persistence:
enabled: false
ingress:
enabled: true
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod" # <-- if you are setting up HTTPS
hostName: app.infisical.com ## <- Replace with your own domain
frontend:
path: /
pathType: Prefix
backend:
path: /api
pathType: Prefix
tls: # <-- if you are setting up HTTPS
- secretName: echo-tls
hosts:
- app.infisical.com
persistence:
enabled: true
```
</Accordion>

View File

@ -58,7 +58,7 @@ Add the required environment variables listed below to your docker run command.
Once you have added the required environment variables to your docker run command, execute it in your terminal.
```bash
docker run -p 80:80 \
docker run -p 80:8080 \
-e ENCRYPTION_KEY=f40c9178624764ad85a6830b37ce239a \
-e JWT_SIGNUP_SECRET=38ea90fb7998b92176080f457d890392 \
-e JWT_REFRESH_SECRET=7764c7bbf3928ad501591a3e005eb364 \

View File

@ -1,32 +0,0 @@
module.exports = {
apps: [
{
name: 'frontend',
script: "./scripts/start.sh",
instances: 1,
cwd: "./app",
interpreter: 'sh',
exec_mode: "fork",
autorestart: true,
watch: false,
max_memory_restart: '500M',
},
{
name: 'backend',
script: 'npm',
args: 'run start',
cwd: "./backend",
instances: 1,
exec_mode: "fork",
autorestart: true,
watch: false,
max_memory_restart: '500M',
},
{
name: "nginx",
script: "nginx",
args: "-g 'daemon off;'",
exec_interpreter: "none",
},
],
};

View File

@ -96,7 +96,7 @@ module.exports = {
}
]
},
ignorePatterns: ["next.config.js"],
ignorePatterns: ["next.config.js", "cypress/**/*.js", "cypress.config.js"],
settings: {
"import/resolver": {
typescript: {

View File

@ -0,0 +1,7 @@
module.exports = {
e2e: {
baseUrl: 'http://localhost:8080',
viewportWidth: 1480,
viewportHeight: 920,
},
};

View File

@ -0,0 +1,47 @@
/// <reference types="cypress" />
describe('organization Overview', () => {
beforeEach(() => {
cy.login(`test@localhost.local`, `testInfisical1`)
})
const projectName = "projectY"
it('can`t create projects with empty names', () => {
cy.get('.button').click()
cy.get('input[placeholder="Type your project name"]').type('abc').clear()
cy.intercept('*').as('anyRequest');
cy.get('@anyRequest').should('not.exist');
})
it('can delete a newly-created project', () => {
// Create a project
cy.get('.button').click()
cy.get('input[placeholder="Type your project name"]').type(`${projectName}`)
cy.contains('button', 'Create Project').click()
cy.url().should('include', '/project')
// Delete a project
cy.get(`[href^="/project/"][href$="/settings"] > a > .group`).click()
cy.contains('button', `Delete ${projectName}`).click()
cy.contains('button', 'Delete Project').should('have.attr', 'disabled')
cy.get('input[placeholder="Type to delete..."]').type('confirm')
cy.contains('button', 'Delete Project').should('not.have.attr', 'disabled')
cy.url().then((currentUrl) => {
let projectId = currentUrl.split("/")[4]
cy.intercept('DELETE', `/api/v1/workspace/${projectId}`).as('deleteProject');
cy.contains('button', 'Delete Project').click();
cy.get('@deleteProject').should('have.property', 'response').and('have.property', 'statusCode', 200);
})
})
it('can display no projects', () => {
cy.intercept('/api/v1/workspace', {
body: {
"workspaces": []
},
})
cy.get('.border-mineshaft-700 > :nth-child(2)').should('have.text', 'You are not part of any projects in this organization yet. When you are, they will appear here.')
})
})

View File

@ -0,0 +1,24 @@
/// <reference types="cypress" />
describe('Organization Settings', () => {
let orgId;
beforeEach(() => {
cy.login(`test@localhost.local`, `testInfisical1`)
cy.url().then((currentUrl) => {
orgId = currentUrl.split("/")[4]
cy.visit(`org/${orgId}/settings`)
})
})
it('can rename org', () => {
cy.get('input[placeholder="Acme Corp"]').clear().type('ABC')
cy.intercept('PATCH', `/api/v1/organization/${orgId}/name`).as('renameOrg');
cy.get('form.p-4 > .button').click()
cy.get('@renameOrg').should('have.property', 'response').and('have.property', 'statusCode', 200);
cy.get('.pl-3').should("have.text", "ABC ")
})
})

View File

@ -0,0 +1,84 @@
/// <reference types="cypress" />
describe('Project Overview', () => {
const projectName = "projectY"
let projectId;
let isFirstTest = true;
before(() => {
cy.login(`test@localhost.local`, `testInfisical1`)
// Create a project
cy.get('.button').click()
cy.get('input[placeholder="Type your project name"]').type(`${projectName}`)
cy.contains('button', 'Create Project').click()
cy.url().should('include', '/project').then((currentUrl) => {
projectId = currentUrl.split("/")[4]
})
})
beforeEach(() => {
if (isFirstTest) {
isFirstTest = false;
return; // Skip the rest of the beforeEach for the first test
}
cy.login(`test@localhost.local`, `testInfisical1`)
cy.visit(`/project/${projectId}/secrets/overview`)
})
it('can create secrets', () => {
cy.contains('button', 'Go to Development').click()
cy.contains('button', 'Add a new secret').click()
cy.get('input[placeholder="Type your secret name"]').type('SECRET_A')
cy.contains('button', 'Create Secret').click()
cy.get('.w-80 > .inline-flex > .input').should('have.value', 'SECRET_A')
cy.get(':nth-child(6) > .button > .w-min').should('have.text', '1 Commit')
})
it('can update secrets', () => {
cy.get(':nth-child(2) > .flex > .button').click()
cy.get('.overflow-auto > .relative > .absolute').type('VALUE_A')
cy.get('.button.text-primary > .svg-inline--fa').click()
cy.get(':nth-child(6) > .button > .w-min').should('have.text', '2 Commits')
})
it('can`t create duplicate-name secrets', () => {
cy.get(':nth-child(2) > .flex > .button').click()
cy.contains('button', 'Add Secret').click()
cy.get('input[placeholder="Type your secret name"]').type('SECRET_A')
cy.intercept('POST', `/api/v3/secrets/SECRET_A`).as('createSecret');
cy.contains('button', 'Create Secret').click()
cy.get('@createSecret').should('have.property', 'response').and('have.property', 'statusCode', 400);
})
it('can add another secret', () => {
cy.get(':nth-child(2) > .flex > .button').click()
cy.contains('button', 'Add Secret').click()
cy.get('input[placeholder="Type your secret name"]').type('SECRET_B')
cy.contains('button', 'Create Secret').click()
cy.get(':nth-child(6) > .button > .w-min').should('have.text', '3 Commits')
})
it('can delete a secret', () => {
cy.get(':nth-child(2) > .flex > .button').click()
// cy.get(':nth-child(3) > .shadow-none').trigger('mouseover')
cy.get(':nth-child(3) > .shadow-none > .group > .h-10 > .border-red').click()
cy.contains('button', 'Delete Secret').should('have.attr', 'disabled')
cy.get('input[placeholder="Type to delete..."]').type('SECRET_B')
cy.intercept('DELETE', `/api/v3/secrets/SECRET_B`).as('deleteSecret');
cy.contains('button', 'Delete Secret').should('not.have.attr', 'disabled')
cy.contains('button', 'Delete Secret').click();
cy.get('@deleteSecret').should('have.property', 'response').and('have.property', 'statusCode', 200);
})
it('can add a comment', () => {
return;
cy.get(':nth-child(2) > .flex > .button').click()
// for some reason this hover does not want to work
cy.get('.overflow-auto').trigger('mouseover').then(() => {
cy.get('.shadow-none > .group > .pl-4 > .h-8 > button[aria-label="add-comment"]').should('be.visible').click()
});
})
})

View File

@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}

View File

@ -0,0 +1,19 @@
Cypress.Commands.add('login', (username, password) => {
cy.visit('/login')
cy.get('input[placeholder="Enter your email..."]').type(username)
cy.get('input[placeholder="Enter your password..."]').type(password)
cy.contains('Continue with Email').click()
cy.url().should('include', '/overview')
})
// Cypress.Commands.add('login', (username, password) => {
// cy.session([username, password], () => {
// cy.visit('/login')
// cy.get('input[placeholder="Enter your email..."]').type(username)
// cy.get('input[placeholder="Enter your password..."]').type(password)
// cy.contains('Continue with Email').click()
// cy.url().should('include', '/overview')
// cy.wait(2000);
// })
// })

View File

@ -0,0 +1,20 @@
// ***********************************************************
// This example support/e2e.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands'
// Alternatively you can use CommonJS syntax:
// require('./commands')

View File

@ -1,8 +1,4 @@
// @ts-check
/**
* @type {import('next').NextConfig}
**/
const path = require("path");
const ContentSecurityPolicy = `
@ -53,7 +49,9 @@ const securityHeaders = [
value: ContentSecurityPolicy.replace(/\s{2,}/g, " ").trim()
}
];
/**
* @type {import('next').NextConfig}
**/
module.exports = {
output: "standalone",
i18n: {

File diff suppressed because it is too large Load Diff

View File

@ -124,6 +124,7 @@
"@typescript-eslint/eslint-plugin": "^5.48.1",
"@typescript-eslint/parser": "^5.45.0",
"autoprefixer": "^10.4.7",
"cypress": "^13.3.2",
"eslint": "^8.32.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-typescript": "^17.0.0",

View File

@ -0,0 +1,13 @@
#!/bin/sh
scripts/replace-standalone-build-variable.sh "$BAKED_NEXT_PUBLIC_POSTHOG_API_KEY" "$NEXT_PUBLIC_POSTHOG_API_KEY"
scripts/replace-standalone-build-variable.sh "$BAKED_NEXT_PUBLIC_INTERCOM_ID" "$NEXT_PUBLIC_INTERCOM_ID"
if [ "$TELEMETRY_ENABLED" != "false" ]; then
echo "Telemetry is enabled"
scripts/set-standalone-build-telemetry.sh true
else
echo "Client opted out of telemetry"
scripts/set-standalone-build-telemetry.sh false
fi

View File

@ -0,0 +1,16 @@
#!/bin/sh
ORIGINAL=$1
REPLACEMENT=$2
if [ "${ORIGINAL}" = "${REPLACEMENT}" ]; then
echo "Environment variable replacement is the same, skipping.."
exit 0
fi
echo "Replacing pre-baked value.."
find public .next -type f -name "*.js" |
while read file; do
sed -i "s|$ORIGINAL|$REPLACEMENT|g" "$file"
done

0
frontend/scripts/replace-variable.sh Normal file → Executable file
View File

View File

@ -0,0 +1,8 @@
#!/bin/sh
VALUE=$1
find public .next -type f -name "*.js" |
while read file; do
sed -i "s|TELEMETRY_CAPTURING_ENABLED|$VALUE|g" "$file"
done

0
frontend/scripts/set-telemetry.sh Normal file → Executable file
View File

View File

@ -10,7 +10,7 @@ export const initPostHog = () => {
try {
if (typeof window !== "undefined") {
// @ts-ignore
if (ENV === "production" && TELEMETRY_CAPTURING_ENABLED) {
if (ENV === "production" && TELEMETRY_CAPTURING_ENABLED === "true") {
posthog.init(POSTHOG_API_KEY, {
api_host: POSTHOG_HOST
});

View File

@ -13,7 +13,7 @@ class Capturer {
}
capture(item: string) {
if (ENV === 'production' && TELEMETRY_CAPTURING_ENABLED) {
if (ENV === 'production' && TELEMETRY_CAPTURING_ENABLED === "true") {
try {
this.api.capture(item);
} catch (error) {
@ -23,7 +23,7 @@ class Capturer {
}
identify(id: string, email?: string) {
if (ENV === 'production' && TELEMETRY_CAPTURING_ENABLED) {
if (ENV === 'production' && TELEMETRY_CAPTURING_ENABLED === "true") {
try {
this.api.identify(id, {
email: email

View File

@ -15,6 +15,7 @@ type Props = {
title: string;
subTitle?: string;
onDeleteApproved: () => Promise<void>;
buttonText?: string;
};
export const DeleteActionModal = ({
@ -24,7 +25,8 @@ export const DeleteActionModal = ({
deleteKey,
onDeleteApproved,
title,
subTitle = "This action is irreversible!"
subTitle = "This action is irreversible!",
buttonText = "Delete"
}: Props): JSX.Element => {
const [inputData, setInputData] = useState("");
const [isLoading, setIsLoading] = useToggle();
@ -56,7 +58,7 @@ export const DeleteActionModal = ({
title={title}
subTitle={subTitle}
footerContent={
<div className="flex items-center">
<div className="flex items-center mx-2">
<Button
className="mr-4"
colorSchema="danger"
@ -64,7 +66,7 @@ export const DeleteActionModal = ({
onClick={onDelete}
isLoading={isLoading}
>
Delete
{buttonText}
</Button>
<ModalClose asChild>
<Button variant="plain" colorSchema="secondary" onClick={onClose}>
@ -87,9 +89,9 @@ export const DeleteActionModal = ({
Type <span className="font-bold">{deleteKey}</span> to delete the resource
</div>
}
className="mb-4"
className="mb-0"
>
<Input value={inputData} onChange={(e) => setInputData(e.target.value)} />
<Input value={inputData} onChange={(e) => setInputData(e.target.value)} placeholder="Type to delete..." />
</FormControl>
</form>
</ModalContent>

View File

@ -131,6 +131,7 @@ export const useUpdateSecretV3 = ({
mutationFn: async ({
secretPath = "/",
type,
secretId,
environment,
workspaceId,
secretName,
@ -157,6 +158,7 @@ export const useUpdateSecretV3 = ({
environment,
type,
secretPath,
secretId,
...encryptSecret(randomBytes, newSecretName ?? secretName, secretValue, secretComment),
tags,
skipMultilineEncoding,

View File

@ -109,6 +109,7 @@ export type TUpdateSecretsV3DTO = {
skipMultilineEncoding?: boolean;
newSecretName?: string;
secretName: string;
secretId?: string;
secretValue: string;
secretComment?: string;
tags?: string[];

View File

@ -692,7 +692,7 @@ export const AppLayout = ({ children }: LayoutProps) => {
{infisicalPlatformVersion && (
<div className="mb-2 w-full pl-5 duration-200 hover:text-mineshaft-200">
<FontAwesomeIcon icon={faInfo} className="mr-4 px-[0.1rem]" />
Platform Version: {infisicalPlatformVersion}
Version: {infisicalPlatformVersion}
</div>
)}
</div>

View File

@ -239,7 +239,7 @@ export const SecretMainPage = () => {
onClickRollbackMode={() => handlePopUpToggle("snapshots", true)}
/>
<div className="mt-3 overflow-y-auto overflow-x-hidden thin-scrollbar bg-mineshaft-800 text-left text-bunker-300 rounded-md text-sm">
<div className="flex flex-col ">
<div className="flex flex-col" id="dashboard">
{isNotEmtpy && (
<div className="flex font-medium border-b border-mineshaft-600">
<div style={{ width: "2.8rem" }} className="px-4 py-3 flex-shrink-0" />

View File

@ -289,7 +289,7 @@ export const ActionBar = ({
className="h-10"
isDisabled={!isAllowed}
>
{snapshotCount} Commits
{`${snapshotCount} ${snapshotCount === 1 ? "Commit" : "Commits"}`}
</Button>
)}
</ProjectPermissionCan>

View File

@ -105,7 +105,7 @@ export const CreateSecretForm = ({
>
<SecretInput
{...field}
containerClassName="text-bunker-300 hover:border-primary-400/50 border border-mineshaft-600 bg-mineshaft-900 px-2 py-1.5"
containerClassName="text-bunker-300 hover:border-primary-400/50 border border-mineshaft-600 bg-mineshaft-900 px-2 py-1.5"
/>
</FormControl>
)}

View File

@ -153,6 +153,7 @@ export const SecretListView = ({
workspaceId,
secretPath,
secretName: key,
secretId,
secretValue: value || "",
type,
latestFileKey: decryptFileKey,
@ -201,11 +202,14 @@ export const SecretListView = ({
try {
// personal secret change
if (overrideAction === "deleted") {
await handleSecretOperation("delete", "personal", oldKey);
await handleSecretOperation("delete", "personal", oldKey, {
secretId: orgSecret.idOverride
});
} else if (overrideAction && idOverride) {
await handleSecretOperation("update", "personal", oldKey, {
value: valueOverride,
newKey: hasKeyChanged ? key : undefined,
secretId: orgSecret.idOverride,
skipMultilineEncoding: modSecret.skipMultilineEncoding
});
} else if (overrideAction) {
@ -218,6 +222,7 @@ export const SecretListView = ({
value,
tags: tagIds,
comment,
secretId: orgSecret._id,
newKey: hasKeyChanged ? key : undefined,
skipMultilineEncoding: modSecret.skipMultilineEncoding
});
@ -308,7 +313,6 @@ export const SecretListView = ({
>
{namespace}
</div>
{filteredSecrets.map((secret) => (
<SecretItem
environment={environment}
@ -335,6 +339,7 @@ export const SecretListView = ({
title="Do you want to delete this secret?"
onChange={(isOpen) => handlePopUpToggle("deleteSecret", isOpen)}
onDeleteApproved={handleSecretDelete}
buttonText="Delete Secret"
/>
<SecretDetailSidebar
environment={environment}

View File

@ -146,12 +146,13 @@ export const SecretOverviewPage = () => {
}
};
const handleSecretUpdate = async (env: string, key: string, value: string) => {
const handleSecretUpdate = async (env: string, key: string, value: string, secretId?: string) => {
try {
await updateSecretV3({
environment: env,
workspaceId,
secretPath,
secretId,
secretName: key,
secretValue: value,
type: "shared",
@ -242,7 +243,6 @@ export const SecretOverviewPage = () => {
);
const canViewOverviewPage = Boolean(userAvailableEnvs.length);
const filteredSecretNames = secKeys
?.filter((name) => name.toUpperCase().includes(searchFilter.toUpperCase()))
.sort((a, b) => (sortDir === "asc" ? a.localeCompare(b) : b.localeCompare(a)));

View File

@ -18,7 +18,7 @@ type Props = {
environment: string;
secretPath: string;
onSecretCreate: (env: string, key: string, value: string) => Promise<void>;
onSecretUpdate: (env: string, key: string, value: string) => Promise<void>;
onSecretUpdate: (env: string, key: string, value: string, secretId?: string) => Promise<void>;
onSecretDelete: (env: string, key: string, secretId?: string) => Promise<void>;
};
@ -42,7 +42,7 @@ export const SecretEditRow = ({
formState: { isDirty, isSubmitting }
} = useForm({
values: {
value: defaultValue
value: defaultValue || null
}
});
const [isDeleting, setIsDeleting] = useToggle();
@ -70,7 +70,7 @@ export const SecretEditRow = ({
if (isCreatable) {
await onSecretCreate(environment, secretName, value);
} else {
await onSecretUpdate(environment, secretName, value);
await onSecretUpdate(environment, secretName, value, secretId);
}
}
reset({ value });
@ -80,7 +80,7 @@ export const SecretEditRow = ({
setIsDeleting.on();
try {
await onSecretDelete(environment, secretName, secretId);
reset({ value: undefined });
reset({ value: null });
} finally {
setIsDeleting.off();
}

View File

@ -23,7 +23,7 @@ type Props = {
expandableColWidth: number;
getSecretByKey: (slug: string, key: string) => DecryptedSecret | undefined;
onSecretCreate: (env: string, key: string, value: string) => Promise<void>;
onSecretUpdate: (env: string, key: string, value: string) => Promise<void>;
onSecretUpdate: (env: string, key: string, value: string, secretId?: string) => Promise<void>;
onSecretDelete: (env: string, key: string, secretId?: string) => Promise<void>;
};

View File

@ -143,8 +143,8 @@ export const SSOModal = ({
entityId: "Identifier (Entity ID)",
entryPoint: "Login URL",
entryPointPlaceholder: "https://login.microsoftonline.com/xxx/saml2",
issuer: "Azure AD Identifier",
issuerPlaceholder: "https://sts.windows.net/xxx/"
issuer: "Azure Application ID",
issuerPlaceholder: "abc-def-ghi-jkl-mno"
});
case AuthProvider.JUMPCLOUD_SAML:
return ({

View File

@ -10,7 +10,7 @@ export const OrgGeneralTab = () => {
const { user } = useUser();
const { data: members } = useGetOrgUsers(currentOrg?._id ?? "");
const membershipOrg = members?.find((member) => member.user._id === user._id);
const membershipOrg = members?.find((member) => member.user._id === user?._id);
return (
<div>

View File

@ -77,9 +77,10 @@ export const DeleteProjectSection = () => {
<DeleteActionModal
isOpen={popUp.deleteWorkspace.isOpen}
title="Are you sure want to delete this project?"
subTitle={`Permanently remove ${currentWorkspace?.name} and all of its data. This action is not reversible, so please be careful.`}
subTitle={`Permanently delete ${currentWorkspace?.name} and all of its data. This action is not reversible, so please be careful.`}
onChange={(isOpen) => handlePopUpToggle("deleteWorkspace", isOpen)}
deleteKey="confirm"
buttonText="Delete Project"
onDeleteApproved={handleDeleteWorkspaceSubmit}
/>
</div>

View File

@ -7,7 +7,7 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.3.5
version: 0.4.1
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to

View File

@ -4,7 +4,6 @@ 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 database |
| `redis` | Infisical's cache service |
@ -59,28 +58,6 @@ kubectl get secrets -n <namespace> <secret-name> \
| `nameOverride` | Override release name | `""` |
| `fullnameOverride` | Override release fullname | `""` |
### Infisical frontend parameters
| Name | Description | Value |
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
| `frontend.enabled` | Enable frontend | `true` |
| `frontend.name` | Frontend name | `frontend` |
| `frontend.fullnameOverride` | Frontend fullnameOverride | `""` |
| `frontend.podAnnotations` | Frontend pod annotations | `{}` |
| `frontend.deploymentAnnotations` | Frontend deployment annotations | `{}` |
| `frontend.replicaCount` | Frontend replica count | `2` |
| `frontend.image.repository` | Frontend image repository | `infisical/frontend` |
| `frontend.image.tag` | Frontend image tag | `latest` |
| `frontend.image.pullPolicy` | Frontend image pullPolicy | `IfNotPresent` |
| `frontend.resources.limits.memory` | container memory limit [check the offical kubernetes documentations](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) | `100Mi` |
| `frontend.resources.requests.cpu` | container CPU request [check the offical kubernetes documentations](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) | `100m` |
| `frontend.affinity` | Frontend pod affinity | `{}` |
| `frontend.kubeSecretRef` | Backend secret resource reference name (containing required [frontend configuration variables](https://infisical.com/docs/self-hosting/configuration/envars)) | `""` |
| `frontend.service.annotations` | Backend service annotations | `{}` |
| `frontend.service.type` | Backend service type | `ClusterIP` |
| `frontend.service.nodePort` | Backend service nodePort (used if above type is `NodePort`) | `""` |
| `frontendEnvironmentVariables.SITE_URL` | Absolute URL including the protocol (e.g. https://app.infisical.com) | `infisical.local` |
### Infisical backend parameters
| Name | Description | Value |
@ -91,11 +68,9 @@ kubectl get secrets -n <namespace> <secret-name> \
| `backend.podAnnotations` | Backend pod annotations | `{}` |
| `backend.deploymentAnnotations` | Backend deployment annotations | `{}` |
| `backend.replicaCount` | Backend replica count | `2` |
| `backend.image.repository` | Backend image repository | `infisical/backend` |
| `backend.image.repository` | Backend image repository | `infisical/infisical` |
| `backend.image.tag` | Backend image tag | `latest` |
| `backend.image.pullPolicy` | Backend image pullPolicy | `IfNotPresent` |
| `backend.resources.limits.memory` | container memory limit [check the offical kubernetes documentations](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) | `200Mi` |
| `backend.resources.requests.cpu` | container CPU request [check the offical kubernetes documentations](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) | `150m` |
| `backend.affinity` | Backend pod affinity | `{}` |
| `backend.kubeSecretRef` | Backend secret resource reference name (containing required [backend configuration variables](https://infisical.com/docs/self-hosting/configuration/envars)) | `""` |
| `backend.service.annotations` | Backend service annotations | `{}` |
@ -197,6 +172,7 @@ kubectl get secrets -n <namespace> <secret-name> \
## Persistence
The database persistence is enabled by default, your volumes will remain on your cluster even after uninstalling the chart. To disable persistence, set this value `mongodb.persistence.enabled: false`

View File

@ -2,34 +2,6 @@
-- Infisical Helm Chart --
__ __
( _) ( _)
/ / \\ / /\_\_
/ / \\ / / | \ \
/ / \\ / / |\ \ \
/ / , \ , / / /| \ \
/ / |\_ /| / / / \ \_\
/ / |\/ _ '_|\ / / / \ \\
| / |/ 0 \0\\ / | | \ \\
| |\| \_\_ / / | \ \\
| | |/ \.\ o\o) / \ | \\
\ | /\\`v-v / | | \\
| \/ /_| \\_| / | | \ \\
| | /__/_ / _____ | | \ \\
\| [__] \_/ |_________ \ | \ ()
/ [___] ( \ \ |\ | | //
| [___] |\| \| / |/
/| [____] \ |/\ / / ||
( \ [____ / ) _\ \ \ \| | ||
\ \ [_____| / / __/ \ / / //
| \ [_____/ / / \ | \/ //
| / '----| /=\____ _/ | / //
__ / / | / ___/ _/\ \ | ||
(/-(/-\) / \ (/\/\)/ | / | /
(/\/\) / / //
_________/ / /
\____________/ (
██╗███╗ ██╗███████╗██╗███████╗██╗ ██████╗ █████╗ ██╗
██║████╗ ██║██╔════╝██║██╔════╝██║██╔════╝██╔══██╗██║
██║██╔██╗ ██║█████╗ ██║███████╗██║██║ ███████║██║
@ -46,7 +18,6 @@
│ Visit < https://infisical.com/docs/self-hosting/overview > for further documentation about self-hosting!
│ Current installation (infisical) :
│ • infisical-frontend : {{ .Values.frontend.enabled }}
│ • infisical-backend : {{ .Values.backend.enabled }}
│ • mongodb : {{ .Values.mongodb.enabled }}
│ • mailhog : {{ .Values.mailhog.enabled }}

View File

@ -41,16 +41,6 @@ component: {{ .Values.backend.name | quote }}
{{ include "infisical.common.matchLabels" . }}
{{- end -}}
{{- define "infisical.frontend.labels" -}}
{{ include "infisical.frontend.matchLabels" . }}
{{ include "infisical.common.metaLabels" . }}
{{- end -}}
{{- define "infisical.frontend.matchLabels" -}}
component: {{ .Values.frontend.name | quote }}
{{ include "infisical.common.matchLabels" . }}
{{- end -}}
{{- define "infisical.mongodb.labels" -}}
{{ include "infisical.mongodb.matchLabels" . }}
{{ include "infisical.common.metaLabels" . }}
@ -78,22 +68,6 @@ We truncate at 63 chars because some Kubernetes name fields are limited to this
{{- end -}}
{{- end -}}
{{/*
Create a fully qualified frontend name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
*/}}
{{- define "infisical.frontend.fullname" -}}
{{- if .Values.frontend.fullnameOverride -}}
{{- .Values.frontend.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- printf "%s-%s" .Release.Name .Values.frontend.name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s-%s" .Release.Name $name .Values.frontend.name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Create a fully qualified mongodb name.

View File

@ -36,17 +36,17 @@ spec:
readinessProbe:
httpGet:
path: /api/status
port: 4000
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
ports:
- containerPort: 4000
- containerPort: 8080
envFrom:
- secretRef:
name: {{ $backend.kubeSecretRef | default (include "infisical.backend.fullname" .) }}
{{- if $backend.resources }}
resources: {{- toYaml $backend.resources | nindent 12 }}
{{- end }}
# {{- if $backend.resources }}
# resources: {{- toYaml $backend.resources | nindent 12 }}
# {{- end }}
---
apiVersion: v1
@ -65,8 +65,8 @@ spec:
{{- include "infisical.backend.matchLabels" . | nindent 8 }}
ports:
- protocol: TCP
port: 4000
targetPort: 4000 # container port
port: 8080
targetPort: 8080 # container port
{{- if eq $backend.service.type "NodePort" }}
nodePort: {{ $backend.service.nodePort }}
{{- end }}

View File

@ -1,94 +0,0 @@
{{- $frontend := .Values.frontend }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "infisical.frontend.fullname" . }}
annotations:
updatedAt: {{ now | date "2006-01-01 MST 15:04:05" | quote }}
{{- with .Values.frontend.deploymentAnnotations }}
{{- toYaml . | nindent 4 }}
{{- end }}
labels:
{{- include "infisical.frontend.labels" . | nindent 4 }}
spec:
replicas: {{ $frontend.replicaCount }}
selector:
matchLabels:
{{- include "infisical.frontend.matchLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "infisical.frontend.matchLabels" . | nindent 8 }}
annotations:
updatedAt: {{ now | date "2006-01-01 MST 15:04:05" | quote }}
{{- with $frontend.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
{{- with $frontend.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: {{ template "infisical.name" . }}-{{ $frontend.name }}
image: "{{ $frontend.image.repository }}:{{ $frontend.image.tag | default "latest" }}"
imagePullPolicy: {{ $frontend.image.pullPolicy }}
readinessProbe:
httpGet:
path: /
port: 3000
initialDelaySeconds: 10
periodSeconds: 10
envFrom:
- secretRef:
name: {{ $frontend.kubeSecretRef | default (include "infisical.frontend.fullname" .) }}
ports:
- containerPort: 3000
{{- if $frontend.resources }}
resources: {{- toYaml $frontend.resources | nindent 12 }}
{{- end }}
---
apiVersion: v1
kind: Service
metadata:
name: {{ include "infisical.frontend.fullname" . }}
labels:
{{- include "infisical.frontend.labels" . | nindent 4 }}
{{- with $frontend.service.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
type: {{ $frontend.service.type }}
selector:
{{- include "infisical.frontend.matchLabels" . | nindent 8 }}
ports:
- protocol: TCP
port: 3000 # service
targetPort: 3000 # container port
{{- if eq $frontend.service.type "NodePort" }}
nodePort: {{ $frontend.service.nodePort }}
{{- end }}
---
{{ if not $frontend.kubeSecretRef }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "infisical.frontend.fullname" . }}
annotations:
"helm.sh/resource-policy": "keep"
type: Opaque
stringData:
{{- $requiredVars := dict }}
{{- $secretObj := (lookup "v1" "Secret" .Release.Namespace (include "infisical.frontend.fullname" .)) | default dict }}
{{- $secretData := (get $secretObj "data") | default dict }}
{{ range $key, $value := .Values.frontendEnvironmentVariables }}
{{- $default := get $requiredVars $key -}}
{{- $current := get $secretData $key | b64dec -}}
{{- $v := $value | default ($current | default $default) -}}
{{ $key }}: {{ $v | quote }}
{{ end -}}
{{- end }}

View File

@ -30,27 +30,20 @@ spec:
rules:
- http:
paths:
- path: {{ $ingress.frontend.path }}
pathType: {{ $ingress.frontend.pathType }}
backend:
service:
name: {{ include "infisical.frontend.fullname" . }}
port:
number: 3000
- path: {{ $ingress.backend.path }}
pathType: {{ $ingress.backend.pathType }}
- path: /
pathType: Prefix
backend:
service:
name: {{ include "infisical.backend.fullname" . }}
port:
number: 4000
number: 8080
- path: /ss-webhook
pathType: Exact
backend:
service:
name: {{ include "infisical.backend.fullname" . }}
port:
number: 4000
number: 8080
{{- if $ingress.hostName }}
host: {{ $ingress.hostName }}
{{- end }}

View File

@ -8,76 +8,6 @@ nameOverride: ""
##
fullnameOverride: ""
## @section Infisical frontend parameters
## Documentation : https://infisical.com/docs/self-hosting/deployments/kubernetes
##
frontend:
## @param frontend.enabled Enable frontend
##
enabled: true
## @param frontend.name Frontend name
##
name: frontend
## @param frontend.fullnameOverride Frontend fullnameOverride
##
fullnameOverride: ""
## @param frontend.podAnnotations Frontend pod annotations
##
podAnnotations: {}
## @param frontend.deploymentAnnotations Frontend deployment annotations
##
deploymentAnnotations: {}
## @param frontend.replicaCount Frontend replica count
##
replicaCount: 2
## Frontend image parameters
##
image:
## @param frontend.image.repository Frontend image repository
##
repository: infisical/frontend
## @param frontend.image.tag Frontend image tag
##
tag: "latest"
## @param frontend.image.pullPolicy Frontend image pullPolicy
##
pullPolicy: IfNotPresent
## @param frontend.resources.limits.memory container memory limit [check the offical kubernetes documentations](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/)
## @param frontend.resources.requests.cpu container CPU request [check the offical kubernetes documentations](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/)
##
resources:
limits:
memory: 100Mi
requests:
cpu: 100m
## @param frontend.affinity Frontend pod affinity
##
affinity: {}
## @param frontend.kubeSecretRef Backend secret resource reference name (containing required [frontend configuration variables](https://infisical.com/docs/self-hosting/configuration/envars))
##
kubeSecretRef: ""
## Frontend service
##
service:
## @param frontend.service.annotations Backend service annotations
##
annotations: {}
## @param frontend.service.type Backend service type
##
type: ClusterIP
## @param frontend.service.nodePort Backend service nodePort (used if above type is `NodePort`)
##
nodePort: ""
## Frontend variables configuration
## Documentation : https://infisical.com/docs/self-hosting/configuration/envars
##
frontendEnvironmentVariables:
## @param frontendEnvironmentVariables.SITE_URL Absolute URL including the protocol (e.g. https://app.infisical.com)
##
SITE_URL: infisical.local
## @section Infisical backend parameters
## Documentation : https://infisical.com/docs/self-hosting/deployments/kubernetes
##
@ -106,21 +36,13 @@ backend:
image:
## @param backend.image.repository Backend image repository
##
repository: infisical/backend
repository: infisical/infisical
## @param backend.image.tag Backend image tag
##
tag: "latest"
## @param backend.image.pullPolicy Backend image pullPolicy
##
pullPolicy: IfNotPresent
## @param backend.resources.limits.memory container memory limit [check the offical kubernetes documentations](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/)
## @param backend.resources.requests.cpu container CPU request [check the offical kubernetes documentations](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/)
##
resources:
limits:
memory: 200Mi
requests:
cpu: 150m
## @param backend.affinity Backend pod affinity
##
affinity: {}
@ -349,16 +271,6 @@ ingress:
## Replace with your own domain
##
hostName: ""
## @skip ingress.frontend
##
frontend:
path: /
pathType: Prefix
## @skip ingress.backend
##
backend:
path: /api
pathType: Prefix
## @param ingress.tls Ingress TLS hosts (matching above hostName)
## Replace with your own domain
##

View File

@ -1,36 +0,0 @@
events {}
http {
server {
listen 80;
location /api {
proxy_set_header X-Real-RIP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://localhost:4000; # for backend
proxy_redirect off;
# proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
proxy_cookie_path / "/; HttpOnly; SameSite=strict";
}
location / {
include /etc/nginx/mime.types;
proxy_set_header X-Real-RIP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://localhost:3000; # for frontend
proxy_redirect off;
}
}
}

8
standalone-entrypoint.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/sh
cd frontend-build
scripts/initialize-standalone-build.sh
cd ../
exec node build/index.js