1
0
mirror of https://github.com/Infisical/infisical.git synced 2025-03-24 00:15:26 +00:00

Compare commits

..

53 Commits

Author SHA1 Message Date
9ed2bb38c3 Merge branch 'main' into snyk-fix-4a9e6187125617ed814113514828d4f5 2024-02-16 11:59:31 -05:00
f458cf0d40 Merge pull request from jinsley8/fix-webhook-settings-ui
fix(frontend): Remove max-width to match other views
2024-02-16 11:40:25 -05:00
ce3dc86f78 add troubleshoot for ansible 2024-02-16 10:37:34 -05:00
d1927cb9cf Merge pull request from ORCID/docs/ansible-workaround
docs: cover ansible forking error
2024-02-16 10:36:37 -05:00
e80426f72e update signup complete route 2024-02-16 09:15:52 -05:00
f5cd68168b Merge pull request from Infisical/docker-compose-selfhost-docs
Docker compose docs with postgres
2024-02-15 12:58:06 -05:00
1a0a9a7402 docker compose docs with postgres 2024-02-15 12:54:22 -05:00
afdc5e8531 Merge pull request from abdulhakkeempa/bug-fix-model-close-on-cancel
(Fix): Create API Modal closes on Cancel button
2024-02-15 22:39:21 +05:30
57daeb71e6 Merge remote-tracking branch 'origin/main' into bug-fix-model-close-on-cancel 2024-02-15 10:47:50 +05:30
98b5f713a5 Fix: Cancel button working on Create API in Personal Settings 2024-02-15 10:09:45 +05:30
1855fc769d Update check-api-for-breaking-changes.yml 2024-02-14 15:42:45 -05:00
217fef65e8 update breaking change workflow to dev.yml 2024-02-14 15:37:21 -05:00
8a0fd62785 update docker compose name 2024-02-14 15:19:47 -05:00
c69601c14e Merge pull request from Infisical/identity-access-token-ttl
Patch identity access token + client secret TTL
2024-02-14 12:19:45 -08:00
faf6323a58 Patch identity ttl conversion 2024-02-14 12:09:56 -08:00
b82d1b6a5d update docker compose on readme 2024-02-13 19:50:58 -05:00
3dcda44c50 Merge pull request from akhilmhdh/feat/init-container
feat: changed docker compose to use init container pattern for running migration
2024-02-13 19:46:39 -05:00
f320b08ca8 rename docker compose and bring back make up-dev 2024-02-13 19:44:42 -05:00
df6e5674cf patch breaking change ci 2024-02-13 19:10:28 -05:00
6bac143a8e test without pg connection 2024-02-13 19:06:47 -05:00
38b93e499f logs on health check 2024-02-13 18:58:13 -05:00
a521538010 show all logs 2024-02-13 18:47:12 -05:00
8cc2553452 test workflow no db connection 2024-02-13 18:43:43 -05:00
b1cb9de001 correct -d mode 2024-02-13 18:39:28 -05:00
036256b350 add back -d mode 2024-02-13 18:37:04 -05:00
d3a06b82e6 update health check 2024-02-13 18:34:15 -05:00
87436cfb57 Update check-api-for-breaking-changes.yml 2024-02-13 18:04:49 -05:00
5c58a4d1a3 added signup event and restyled admin flow 2024-02-13 13:15:54 -08:00
03a91b2c59 Merge pull request from akhilmhdh/chore/doc-openapi
chore: changed mintlify to directly get from prod openapi
2024-02-13 00:42:47 -05:00
751361bd54 add new propety to api 2024-02-13 00:38:59 -05:00
b4b88daf36 Revert "test breaking change"
This reverts commit 6546740bd9e08d88f464546005aa63a6aec53545.
2024-02-13 00:37:49 -05:00
6546740bd9 test breaking change 2024-02-13 00:34:31 -05:00
b32558c66f add . 2024-02-13 00:29:49 -05:00
effd30857e fix typo 2024-02-12 22:45:35 -05:00
60998c8944 Merge pull request from akhilmhdh/chore/feature-x-guide
feat: added guides for new backend development
2024-02-12 22:35:16 -05:00
3c4d9fd4a9 delete docs in backend 2024-02-12 22:34:36 -05:00
ad70c783e8 add backend guide to contributor 2024-02-12 22:33:55 -05:00
7347362738 rephrase new feature development guide 2024-02-12 21:49:15 -05:00
4b7f2e808b Update overview.mdx 2024-02-12 15:06:56 -08:00
57f9d13189 Merge pull request from Infisical/infisical-jenkins
Rewrite Infisical Jenkins docs
2024-02-12 18:02:11 -05:00
79694750af Remove signup disable check for SAML 2024-02-12 11:43:55 -08:00
03db367a4e Merge pull request from Infisical/azure-saml
Add disableRequestedAuthnContext for azure saml
2024-02-12 10:40:19 -08:00
b0fb848a92 Add disableRequestedAuthnContext for azure saml 2024-02-12 10:35:38 -08:00
4fdfcd50dc feat: changed check-api-breaking with oasdiff 2024-02-12 22:32:02 +05:30
db205b855a feat: removed mongo comments from compose file 2024-02-12 14:52:19 +05:30
e707f0d235 feat: added description and security over api written in docs 2024-02-12 14:19:49 +05:30
48a97fb39d chore: changed mintlify to directly get from prod openapi 2024-02-09 22:53:27 +05:30
d8ea26feb7 feat: changed docker compose to use init container pattern for migration 2024-02-09 13:12:25 +05:30
dc146d0883 feat: fixed spelling errors 2024-02-05 22:28:40 +05:30
24dd79b566 feat: added guides for new backend development 2024-02-05 16:31:03 +05:30
00650df501 fix: backend/package.json & backend/package-lock.json to reduce vulnerabilities
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-NODEMAILER-6219989
2024-02-01 20:01:54 +00:00
9fe2021d9f docs: cover ansible forking error 2024-01-10 22:33:38 +00:00
fe2f2f972e fix(frontend): Remove max-width to match other views
This commit removes the max-width constraint on the WebhooksTab.tsx component, aligning it with the full-width layout consistency seen in other views. The previous max-width of 1024px resulted in unused space on larger screens.
2023-10-25 13:54:09 -04:00
75 changed files with 789 additions and 5595 deletions
.env.example.env.migration.example
.github/workflows
.gitignoreMakefileREADME.md
backend
docker-compose.dev.ymldocker-compose.pg.ymldocker-compose.prod.yml
docs
frontend/src
components/signup
views
Settings
PersonalSettingsPage/APIKeySection
ProjectSettingsPage/components/WebhooksTab
admin/SignUpPage
SignUpPage.tsx
components/DownloadBackupKeys

@ -3,16 +3,18 @@
# THIS IS A SAMPLE ENCRYPTION KEY AND SHOULD NEVER BE USED FOR PRODUCTION
ENCRYPTION_KEY=6c1fe4e407b8911c104518103505b218
# Required
DB_CONNECTION_URI=postgres://infisical:infisical@db:5432/infisical
# JWT
# Required secrets to sign JWT tokens
# THIS IS A SAMPLE AUTH_SECRET KEY AND SHOULD NEVER BE USED FOR PRODUCTION
AUTH_SECRET=5lrMXKKWCVocS/uerPsl7V+TX/aaUaI7iDkgl3tSmLE=
# MongoDB
# Backend will connect to the MongoDB instance at connection string MONGO_URL which can either be a ref
# to the MongoDB container instance or Mongo Cloud
# Required
MONGO_URL=mongodb://root:example@mongo:27017/?authSource=admin
# Postgres creds
POSTGRES_PASSWORD=infisical
POSTGRES_USER=infisical
POSTGRES_DB=infisical
# Redis
REDIS_URL=redis://redis:6379

1
.env.migration.example Normal file

@ -0,0 +1 @@
DB_CONNECTION_URI=

@ -14,36 +14,62 @@ jobs:
steps:
- name: Checkout source
uses: actions/checkout@v3
- name: Setup Node 20
uses: actions/setup-node@v3
with:
node-version: "20"
# uncomment this when testing locally using nektos/act
# - uses: KengoTODA/actions-setup-docker-compose@v1
# if: ${{ env.ACT }}
# name: Install `docker-compose` for local simulations
# - name: Setup Node 20
# uses: actions/setup-node@v3
# with:
# version: "2.14.2"
# node-version: "20"
# uncomment this when testing locally using nektos/act
- uses: KengoTODA/actions-setup-docker-compose@v1
if: ${{ env.ACT }}
name: Install `docker-compose` for local simulations
with:
version: "2.14.2"
- name: 📦Build the latest image
run: docker build --tag infisical-api .
working-directory: backend
- name: Start postgres and redis
run: touch .env && docker-compose -f docker-compose.pg.yml up -d db redis
run: touch .env && docker-compose -f docker-compose.dev.yml up -d db redis
- name: Start the server
run: docker run --name infisical-api -d -p 4000:4000 -e DB_CONNECTION_URI=$DB_CONNECTION_URI -e REDIS_URL=$REDIS_URL -e JWT_AUTH_SECRET=$JWT_AUTH_SECRET --entrypoint '/bin/sh' infisical-api -c "npm run migration:latest && ls && node dist/main.mjs"
run: |
echo "SECRET_SCANNING_GIT_APP_ID=793712" >> .env
echo "SECRET_SCANNING_PRIVATE_KEY=some-random" >> .env
echo "SECRET_SCANNING_WEBHOOK_SECRET=some-random" >> .env
docker run --name infisical-api -d -p 4000:4000 -e DB_CONNECTION_URI=$DB_CONNECTION_URI -e REDIS_URL=$REDIS_URL -e JWT_AUTH_SECRET=$JWT_AUTH_SECRET --env-file .env --entrypoint '/bin/sh' infisical-api -c "npm run migration:latest && ls && node dist/main.mjs"
env:
REDIS_URL: redis://172.17.0.1:6379
DB_CONNECTION_URI: postgres://infisical:infisical@172.17.0.1:5432/infisical?sslmode=disable
JWT_AUTH_SECRET: something-random
- name: Install openapi api diff
run: npm install -g openapi-diff
- name: Wait for containers to be stable
run: timeout 60s sh -c 'until docker ps | grep infisical-api | grep -q healthy; do echo "Waiting for container to be healthy..."; sleep 2; done'
- name: Get changes made in API
id: openapi-diff
run: openapi-diff https://app.infisical.com/api/docs/json http://localhost:4000/api/docs/json
- uses: actions/setup-go@v5
with:
go-version: '1.21.5'
- name: Wait for container to be stable and check logs
run: |
SECONDS=0
HEALTHY=0
while [ $SECONDS -lt 60 ]; do
if docker ps | grep infisical-api | grep -q healthy; then
echo "Container is healthy."
HEALTHY=1
break
fi
echo "Waiting for container to be healthy... ($SECONDS seconds elapsed)"
docker logs infisical-api
sleep 2
SECONDS=$((SECONDS+2))
done
if [ $HEALTHY -ne 1 ]; then
echo "Container did not become healthy in time"
exit 1
fi
- name: Install openapi-diff
run: go install github.com/tufin/oasdiff@latest
- name: Running OpenAPI Spec diff action
run: oasdiff breaking https://app.infisical.com/api/docs/json http://localhost:4000/api/docs/json --fail-on ERR
- name: cleanup
run: |
docker-compose -f "docker-compose.pg.yml" down
run: |
docker-compose -f "docker-compose.dev.yml" down
docker stop infisical-api
docker remove infisical-api

2
.gitignore vendored

@ -6,7 +6,7 @@ node_modules
.env.gamma
.env.prod
.env.infisical
.env.migration
*~
*.swp
*.swo

@ -5,16 +5,10 @@ push:
docker-compose -f docker-compose.yml push
up-dev:
docker-compose -f docker-compose.dev.yml up --build
up-pg-dev:
docker compose -f docker-compose.pg.yml up --build
i-dev:
infisical run -- docker-compose -f docker-compose.dev.yml up --build
docker compose -f docker-compose.dev.yml up --build
up-prod:
docker-compose -f docker-compose.yml up --build
docker-compose -f docker-compose.prod.yml up --build
down:
docker-compose down

@ -84,13 +84,13 @@ To set up and run Infisical locally, make sure you have Git and Docker installed
Linux/macOS:
```console
git clone https://github.com/Infisical/infisical && cd "$(basename $_ .git)" && cp .env.example .env && docker-compose -f docker-compose.yml up
git clone https://github.com/Infisical/infisical && cd "$(basename $_ .git)" && cp .env.example .env && docker-compose -f docker-compose.prod.yml up
```
Windows Command Prompt:
```console
git clone https://github.com/Infisical/infisical && cd infisical && copy .env.example .env && docker-compose -f docker-compose.yml up
git clone https://github.com/Infisical/infisical && cd infisical && copy .env.example .env && docker-compose -f docker-compose.prod.yml up
```
Create an account at `http://localhost:80`

@ -48,7 +48,8 @@
"mysql2": "^3.6.5",
"nanoid": "^5.0.4",
"node-cache": "^5.1.2",
"nodemailer": "^6.9.7",
"nodemailer": "^6.9.9",
"ora": "^7.0.1",
"passport-github": "^1.1.0",
"passport-gitlab2": "^5.0.0",
"passport-google-oauth20": "^2.0.0",

@ -109,7 +109,8 @@
"mysql2": "^3.6.5",
"nanoid": "^5.0.4",
"node-cache": "^5.1.2",
"nodemailer": "^6.9.7",
"nodemailer": "^6.9.9",
"ora": "^7.0.1",
"passport-github": "^1.1.0",
"passport-gitlab2": "^5.0.0",
"passport-google-oauth20": "^2.0.0",

@ -3,13 +3,9 @@ import dotenv from "dotenv";
import path from "path";
import knex from "knex";
import { writeFileSync } from "fs";
import promptSync from "prompt-sync";
const prompt = promptSync({ sigint: true });
dotenv.config({
path: path.join(__dirname, "../.env"),
debug: true
path: path.join(__dirname, "../../.env.migration")
});
const db = knex({
@ -94,17 +90,7 @@ const main = async () => {
.orderBy("table_name")
).filter((el) => !el.tableName.includes("_migrations"));
console.log("Select a table to generate schema");
console.table(tables);
console.log("all: all tables");
const selectedTables = prompt("Type table numbers comma seperated: ");
const tableNumbers =
selectedTables !== "all" ? selectedTables.split(",").map((el) => Number(el)) : [];
for (let i = 0; i < tables.length; i += 1) {
// skip if not desired table
if (selectedTables !== "all" && !tableNumbers.includes(i)) continue;
const { tableName } = tables[i];
const columns = await db(tableName).columnInfo();
const columnNames = Object.keys(columns);
@ -124,16 +110,16 @@ const main = async () => {
if (colInfo.nullable) {
ztype = ztype.concat(".nullable().optional()");
}
schema = schema.concat(`${!schema ? "\n" : ""} ${columnName}: ${ztype},\n`);
schema = schema.concat(
`${!schema ? "\n" : ""} ${columnName}: ${ztype}${colNum === columnNames.length - 1 ? "" : ","}\n`
);
}
const dashcase = tableName.split("_").join("-");
const pascalCase = tableName
.split("_")
.reduce(
(prev, curr) => prev + `${curr.at(0)?.toUpperCase()}${curr.slice(1).toLowerCase()}`,
""
);
.reduce((prev, curr) => prev + `${curr.at(0)?.toUpperCase()}${curr.slice(1).toLowerCase()}`, "");
writeFileSync(
path.join(__dirname, "../src/db/schemas", `${dashcase}.ts`),
`// Code generated by automation script, DO NOT EDIT.
@ -152,15 +138,6 @@ export type T${pascalCase}Insert = Omit<T${pascalCase}, TImmutableDBKeys>;
export type T${pascalCase}Update = Partial<Omit<T${pascalCase}, TImmutableDBKeys>>;
`
);
// const file = readFileSync(path.join(__dirname, "../src/db/schemas/index.ts"), "utf8");
// if (!file.includes(`export * from "./${dashcase};"`)) {
// appendFileSync(
// path.join(__dirname, "../src/db/schemas/index.ts"),
// `\nexport * from "./${dashcase}";`,
// "utf8"
// );
// }
}
process.exit(0);

@ -5,9 +5,9 @@ import dotenv from "dotenv";
import type { Knex } from "knex";
import path from "path";
// Update with your config settings.
// Update with your config settings. .
dotenv.config({
path: path.join(__dirname, "../../.env"),
path: path.join(__dirname, "../../../.env.migration"),
debug: true
});
export default {

@ -11,6 +11,13 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
method: "GET",
url: "/:workspaceId/secret-snapshots",
schema: {
description: "Return project secret snapshots ids",
security: [
{
apiKeyAuth: [],
bearerAuth: []
}
],
params: z.object({
workspaceId: z.string().trim()
}),
@ -74,6 +81,13 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
method: "GET",
url: "/:workspaceId/audit-logs",
schema: {
description: "Return audit logs",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({
workspaceId: z.string().trim()
}),

@ -19,7 +19,6 @@ import { BadRequestError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
import { getServerCfg } from "@app/services/super-admin/super-admin-service";
type TSAMLConfig = {
callbackUrl: string;
@ -28,6 +27,7 @@ type TSAMLConfig = {
cert: string;
audience: string;
wantAuthnResponseSigned?: boolean;
disableRequestedAuthnContext?: boolean;
};
export const registerSamlRouter = async (server: FastifyZodProvider) => {
@ -77,6 +77,7 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
samlConfig.wantAuthnResponseSigned = false;
}
if (ssoConfig.authProvider === SamlProviders.AZURE_SAML) {
samlConfig.disableRequestedAuthnContext = true;
if (req.body?.RelayState && JSON.parse(req.body.RelayState).spInitiated) {
samlConfig.audience = `spn:${ssoConfig.issuer}`;
}
@ -92,7 +93,6 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
// eslint-disable-next-line
async (req, profile, cb) => {
try {
const serverCfg = await getServerCfg();
if (!profile) throw new BadRequestError({ message: "Missing profile" });
const { firstName } = profile;
const email = profile?.email ?? (profile?.emailAddress as string); // emailRippling is added because in Rippling the field `email` reserved
@ -105,7 +105,6 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
email,
firstName: profile.firstName as string,
lastName: profile.lastName as string,
isSignupAllowed: Boolean(serverCfg.allowSignUp),
relayState: (req.body as { RelayState?: string }).RelayState,
authProvider: (req as unknown as FastifyRequest).ssoConfig?.authProvider as string,
orgId: (req as unknown as FastifyRequest).ssoConfig?.orgId as string

@ -57,6 +57,13 @@ export const registerSnapshotRouter = async (server: FastifyZodProvider) => {
method: "POST",
url: "/:secretSnapshotId/rollback",
schema: {
description: "Roll back project secrets to those captured in a secret snapshot version.",
security: [
{
apiKeyAuth: [],
bearerAuth: []
}
],
params: z.object({
secretSnapshotId: z.string().trim()
}),

@ -300,19 +300,9 @@ export const samlConfigServiceFactory = ({
};
};
const samlLogin = async ({
firstName,
email,
lastName,
authProvider,
orgId,
relayState,
isSignupAllowed
}: TSamlLoginDTO) => {
const samlLogin = async ({ firstName, email, lastName, authProvider, orgId, relayState }: TSamlLoginDTO) => {
const appCfg = getConfig();
let user = await userDAL.findUserByEmail(email);
const isSamlSignUpDisabled = !isSignupAllowed && !user;
if (isSamlSignUpDisabled) throw new BadRequestError({ message: "User signup disabled", name: "Saml SSO login" });
const organization = await orgDAL.findOrgById(orgId);
if (!organization) throw new BadRequestError({ message: "Org not found" });

@ -41,7 +41,6 @@ export type TSamlLoginDTO = {
lastName?: string;
authProvider: string;
orgId: string;
isSignupAllowed: boolean;
// saml thingy
relayState?: string;
};

@ -25,13 +25,13 @@ export const fastifySwagger = fp(async (fastify) => {
],
components: {
securitySchemes: {
bearer: {
bearerAuth: {
type: "http",
scheme: "bearer",
bearerFormat: "JWT",
description: "A service token in Infisical"
description: "An access token in Infisical"
},
apiKey: {
apiKeyAuth: {
type: "apiKey",
in: "header",
name: "X-API-Key",

@ -72,7 +72,8 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
200: z.object({
message: z.string(),
user: UsersSchema,
token: z.string()
token: z.string(),
new: z.string()
})
}
},
@ -107,7 +108,8 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
return {
message: "Successfully set up admin account",
user: user.user,
token: token.access
token: token.access,
new: "123"
};
}
});

@ -5,6 +5,7 @@ export const registerIdentityAccessTokenRouter = async (server: FastifyZodProvid
url: "/token/renew",
method: "POST",
schema: {
description: "Renew access token",
body: z.object({
accessToken: z.string().trim()
}),

@ -11,6 +11,12 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
url: "/",
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
description: "Create identity",
security: [
{
bearerAuth: []
}
],
body: z.object({
name: z.string().trim(),
organizationId: z.string().trim(),
@ -52,6 +58,12 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
url: "/:identityId",
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
description: "Update identity",
security: [
{
bearerAuth: []
}
],
params: z.object({
identityId: z.string()
}),
@ -95,6 +107,12 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
url: "/:identityId",
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
description: "Delete identity",
security: [
{
bearerAuth: []
}
],
params: z.object({
identityId: z.string()
}),

@ -24,6 +24,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
url: "/universal-auth/login",
method: "POST",
schema: {
description: "Login with Universal Auth",
body: z.object({
clientId: z.string().trim(),
clientSecret: z.string().trim()
@ -67,6 +68,12 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
method: "POST",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Attach Universal Auth configuration onto identity",
security: [
{
bearerAuth: []
}
],
params: z.object({
identityId: z.string().trim()
}),
@ -141,6 +148,12 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
method: "PATCH",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Update Universal Auth configuration on identity",
security: [
{
bearerAuth: []
}
],
params: z.object({
identityId: z.string()
}),
@ -209,6 +222,12 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
method: "GET",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Retrieve Universal Auth configuration on identity",
security: [
{
bearerAuth: []
}
],
params: z.object({
identityId: z.string()
}),
@ -246,6 +265,12 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
method: "POST",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Create Universal Auth Client Secret for identity",
security: [
{
bearerAuth: []
}
],
params: z.object({
identityId: z.string()
}),
@ -291,6 +316,12 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
method: "GET",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "List Universal Auth Client Secrets for identity",
security: [
{
bearerAuth: []
}
],
params: z.object({
identityId: z.string()
}),
@ -327,6 +358,12 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
method: "POST",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Revoke Universal Auth Client Secrets for identity",
security: [
{
bearerAuth: []
}
],
params: z.object({
identityId: z.string(),
clientSecretId: z.string()

@ -10,6 +10,13 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
url: "/:workspaceId/environments",
method: "POST",
schema: {
description: "Create environment",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({
workspaceId: z.string().trim()
}),
@ -58,6 +65,13 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
url: "/:workspaceId/environments/:id",
method: "PATCH",
schema: {
description: "Update environment",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({
workspaceId: z.string().trim(),
id: z.string().trim()
@ -114,6 +128,13 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
url: "/:workspaceId/environments/:id",
method: "DELETE",
schema: {
description: "Delete environment",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({
workspaceId: z.string().trim(),
id: z.string().trim()

@ -10,6 +10,13 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
url: "/:workspaceId/memberships",
method: "GET",
schema: {
description: "Return project user memberships",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({
workspaceId: z.string().trim()
}),
@ -96,6 +103,13 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
url: "/:workspaceId/memberships/:membershipId",
method: "PATCH",
schema: {
description: "Update project user membership",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({
workspaceId: z.string().trim(),
membershipId: z.string().trim()
@ -141,6 +155,13 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
url: "/:workspaceId/memberships/:membershipId",
method: "DELETE",
schema: {
description: "Delete project user membership",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({
workspaceId: z.string().trim(),
membershipId: z.string().trim()

@ -11,6 +11,13 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
url: "/",
method: "POST",
schema: {
description: "Create folders",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
body: z.object({
workspaceId: z.string().trim(),
environment: z.string().trim(),
@ -57,6 +64,13 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
url: "/:folderId",
method: "PATCH",
schema: {
description: "Update folder",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({
// old way this was name
folderId: z.string()
@ -109,6 +123,13 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
url: "/:folderId",
method: "DELETE",
schema: {
description: "Delete a folder",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({
folderId: z.string()
}),
@ -158,6 +179,13 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
url: "/",
method: "GET",
schema: {
description: "Get folders",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
querystring: z.object({
workspaceId: z.string().trim(),
environment: z.string().trim(),

@ -11,6 +11,13 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
url: "/",
method: "POST",
schema: {
description: "Create secret imports",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
body: z.object({
workspaceId: z.string().trim(),
environment: z.string().trim(),
@ -65,6 +72,13 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
url: "/:secretImportId",
method: "PATCH",
schema: {
description: "Update secret imports",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({
secretImportId: z.string().trim()
}),
@ -128,6 +142,13 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
url: "/:secretImportId",
method: "DELETE",
schema: {
description: "Delete secret imports",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({
secretImportId: z.string().trim()
}),
@ -181,6 +202,13 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
url: "/",
method: "GET",
schema: {
description: "Get secret imports",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
querystring: z.object({
workspaceId: z.string().trim(),
environment: z.string().trim(),

@ -10,6 +10,13 @@ export const registerIdentityOrgRouter = async (server: FastifyZodProvider) => {
url: "/:orgId/identity-memberships",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Return organization identity memberships",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({
orgId: z.string().trim()
}),

@ -46,6 +46,12 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
url: "/:projectId/identity-memberships/:identityId",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Update project identity memberships",
security: [
{
bearerAuth: []
}
],
params: z.object({
projectId: z.string().trim(),
identityId: z.string().trim()
@ -77,6 +83,12 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
url: "/:projectId/identity-memberships/:identityId",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Delete project identity memberships",
security: [
{
bearerAuth: []
}
],
params: z.object({
projectId: z.string().trim(),
identityId: z.string().trim()
@ -104,6 +116,12 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
url: "/:projectId/identity-memberships",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Return project identity memberships",
security: [
{
bearerAuth: []
}
],
params: z.object({
projectId: z.string().trim()
}),

@ -9,6 +9,13 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
method: "GET",
url: "/:organizationId/memberships",
schema: {
description: "Return organization user memberships",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({
organizationId: z.string().trim()
}),
@ -46,6 +53,13 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
method: "GET",
url: "/:organizationId/workspaces",
schema: {
description: "Return projects in organization that user is part of",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({
organizationId: z.string().trim()
}),
@ -84,6 +98,13 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
method: "PATCH",
url: "/:organizationId/memberships/:membershipId",
schema: {
description: "Update organization user memberships",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({ organizationId: z.string().trim(), membershipId: z.string().trim() }),
body: z.object({
role: z.string().trim()
@ -113,6 +134,13 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
method: "DELETE",
url: "/:organizationId/memberships/:membershipId",
schema: {
description: "Delete organization user memberships",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({ organizationId: z.string().trim(), membershipId: z.string().trim() }),
response: {
200: z.object({

@ -10,6 +10,12 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
url: "/:workspaceId/encrypted-key",
method: "GET",
schema: {
description: "Return encrypted project key",
security: [
{
apiKeyAuth: []
}
],
params: z.object({
workspaceId: z.string().trim()
}),

@ -21,6 +21,12 @@ export const registerServiceTokenRouter = async (server: FastifyZodProvider) =>
method: "GET",
onRequest: verifyAuth([AuthMode.SERVICE_TOKEN]),
schema: {
description: "Return Infisical Token data",
security: [
{
bearerAuth: []
}
],
response: {
200: ServiceTokensSchema.merge(
z.object({

@ -71,6 +71,12 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
method: "GET",
url: "/me/organizations",
schema: {
description: "Return organizations that current user is part of",
security: [
{
apiKeyAuth: []
}
],
response: {
200: z.object({
organizations: OrganizationsSchema.array()
@ -179,6 +185,12 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
method: "GET",
url: "/me",
schema: {
description: "Retrieve the current user on the request",
security: [
{
apiKeyAuth: []
}
],
response: {
200: z.object({
user: UsersSchema.merge(UserEncryptionKeysSchema.omit({ verifier: true }))

@ -38,6 +38,13 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
url: "/raw",
method: "GET",
schema: {
description: "List secrets",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
querystring: z.object({
workspaceId: z.string().trim().optional(),
environment: z.string().trim().optional(),
@ -121,6 +128,13 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
url: "/raw/:secretName",
method: "GET",
schema: {
description: "Get a secret by name",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({
secretName: z.string().trim()
}),
@ -204,6 +218,13 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
url: "/raw/:secretName",
method: "POST",
schema: {
description: "Create secret",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({
secretName: z.string().trim()
}),
@ -274,6 +295,13 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
url: "/raw/:secretName",
method: "PATCH",
schema: {
description: "Update secret",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({
secretName: z.string().trim()
}),
@ -341,6 +369,13 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
url: "/raw/:secretName",
method: "DELETE",
schema: {
description: "Delete secret",
security: [
{
bearerAuth: [],
apiKeyAuth: []
}
],
params: z.object({
secretName: z.string().trim()
}),

@ -156,7 +156,19 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => {
const { user, accessToken, refreshToken } = await server.services.signup.completeAccountInvite({
...req.body,
ip: req.realIp,
userAgent
userAgent,
authorization: req.headers.authorization as string
});
void server.services.telemetry.sendLoopsEvent(user.email, user.firstName || "", user.lastName || "");
void server.services.telemetry.sendPostHogEvents({
event: PostHogEventTypes.UserSignedUp,
distinctId: user.email,
properties: {
email: user.email,
attributionSource: "Team Invite"
}
});
void res.setCookie("jid", refreshToken, {

@ -212,13 +212,16 @@ export const authSignupServiceFactory = ({
protectedKeyTag,
encryptedPrivateKey,
encryptedPrivateKeyIV,
encryptedPrivateKeyTag
encryptedPrivateKeyTag,
authorization
}: TCompleteAccountInviteDTO) => {
const user = await userDAL.findUserByEmail(email);
if (!user || (user && user.isAccepted)) {
throw new Error("Failed to complete account for complete user");
}
validateSignUpAuthorization(authorization, user.id);
const [orgMembership] = await orgDAL.findMembership({
inviteEmail: email,
status: OrgMembershipStatus.Invited

@ -34,4 +34,5 @@ export type TCompleteAccountInviteDTO = {
verifier: string;
ip: string;
userAgent: string;
authorization: string;
};

@ -35,12 +35,12 @@ export const identityAccessTokenServiceFactory = ({
}
// ttl check
if (accessTokenTTL > 0) {
if (Number(accessTokenTTL) > 0) {
const currentDate = new Date();
if (accessTokenLastRenewedAt) {
// access token has been renewed
const accessTokenRenewed = new Date(accessTokenLastRenewedAt);
const ttlInMilliseconds = accessTokenTTL * 1000;
const ttlInMilliseconds = Number(accessTokenTTL) * 1000;
const expirationDate = new Date(accessTokenRenewed.getTime() + ttlInMilliseconds);
if (currentDate > expirationDate)
@ -50,7 +50,7 @@ export const identityAccessTokenServiceFactory = ({
} else {
// access token has never been renewed
const accessTokenCreated = new Date(accessTokenCreatedAt);
const ttlInMilliseconds = accessTokenTTL * 1000;
const ttlInMilliseconds = Number(accessTokenTTL) * 1000;
const expirationDate = new Date(accessTokenCreated.getTime() + ttlInMilliseconds);
if (currentDate > expirationDate)
@ -61,9 +61,9 @@ export const identityAccessTokenServiceFactory = ({
}
// max ttl checks
if (accessTokenMaxTTL > 0) {
if (Number(accessTokenMaxTTL) > 0) {
const accessTokenCreated = new Date(accessTokenCreatedAt);
const ttlInMilliseconds = accessTokenMaxTTL * 1000;
const ttlInMilliseconds = Number(accessTokenMaxTTL) * 1000;
const currentDate = new Date();
const expirationDate = new Date(accessTokenCreated.getTime() + ttlInMilliseconds);
@ -72,7 +72,7 @@ export const identityAccessTokenServiceFactory = ({
message: "Failed to renew MI access token due to Max TTL expiration"
});
const extendToDate = new Date(currentDate.getTime() + accessTokenTTL);
const extendToDate = new Date(currentDate.getTime() + Number(accessTokenTTL));
if (extendToDate > expirationDate)
throw new UnauthorizedError({
message: "Failed to renew MI access token past its Max TTL expiration"

@ -69,9 +69,9 @@ export const identityUaServiceFactory = ({
if (!validClientSecretInfo) throw new UnauthorizedError();
const { clientSecretTTL, clientSecretNumUses, clientSecretNumUsesLimit } = validClientSecretInfo;
if (clientSecretTTL > 0) {
if (Number(clientSecretTTL) > 0) {
const clientSecretCreated = new Date(validClientSecretInfo.createdAt);
const ttlInMilliseconds = clientSecretTTL * 1000;
const ttlInMilliseconds = Number(clientSecretTTL) * 1000;
const currentDate = new Date();
const expirationTime = new Date(clientSecretCreated.getTime() + ttlInMilliseconds);
@ -124,7 +124,10 @@ export const identityUaServiceFactory = ({
} as TIdentityAccessTokenJwtPayload,
appCfg.AUTH_SECRET,
{
expiresIn: identityAccessToken.accessTokenMaxTTL === 0 ? undefined : identityAccessToken.accessTokenMaxTTL
expiresIn:
Number(identityAccessToken.accessTokenMaxTTL) === 0
? undefined
: Number(identityAccessToken.accessTokenMaxTTL)
}
);

@ -1,4 +1,4 @@
version: '3'
version: "3.9"
services:
nginx:
@ -10,36 +10,84 @@ services:
volumes:
- ./nginx/default.dev.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- frontend
- backend
networks:
- infisical-dev
- frontend
backend:
container_name: infisical-dev-backend
restart: unless-stopped
db:
image: postgres:14-alpine
ports:
- "5432:5432"
volumes:
- postgres-data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: infisical
POSTGRES_USER: infisical
POSTGRES_DB: infisical
redis:
image: redis
container_name: infisical-dev-redis
environment:
- ALLOW_EMPTY_PASSWORD=yes
ports:
- 6379:6379
volumes:
- redis_data:/data
redis-commander:
container_name: infisical-dev-redis-commander
image: rediscommander/redis-commander
restart: always
depends_on:
- mongo
- smtp-server
- redis
environment:
- REDIS_HOSTS=local:redis:6379
ports:
- "8085:8081"
db-test:
profiles: ["test"]
image: postgres:14-alpine
ports:
- "5430:5432"
environment:
POSTGRES_PASSWORD: infisical
POSTGRES_USER: infisical
POSTGRES_DB: infisical-test
db-migration:
container_name: infisical-db-migration
depends_on:
- db
build:
context: ./backend
dockerfile: Dockerfile
volumes:
- ./backend/src:/app/src
- ./backend/nodemon.json:/app/nodemon.json
- /app/node_modules
- ./backend/api-documentation.json:/app/api-documentation.json
- ./backend/swagger.ts:/app/swagger.ts
command: npm run dev
dockerfile: Dockerfile.dev
env_file: .env
environment:
- DB_CONNECTION_URI=postgres://infisical:infisical@db/infisical?sslmode=disable
command: npm run migration:latest
backend:
container_name: infisical-dev-api
build:
context: ./backend
dockerfile: Dockerfile.dev
depends_on:
db:
condition: service_started
redis:
condition: service_started
db-migration:
condition: service_completed_successfully
env_file:
- .env
ports:
- 4000:4000
environment:
- NODE_ENV=development
- MONGO_URL=mongodb://root:example@mongo:27017/?authSource=admin
networks:
- infisical-dev
extra_hosts:
- "host.docker.internal:host-gateway"
- DB_CONNECTION_URI=postgres://infisical:infisical@db/infisical?sslmode=disable
volumes:
- ./backend/src:/app/src
frontend:
container_name: infisical-dev-frontend
@ -55,81 +103,31 @@ services:
env_file: .env
environment:
- NEXT_PUBLIC_ENV=development
- INFISICAL_TELEMETRY_ENABLED=${TELEMETRY_ENABLED}
networks:
- infisical-dev
- INFISICAL_TELEMETRY_ENABLED=false
mongo:
image: mongo
container_name: infisical-dev-mongo
pgadmin:
image: dpage/pgadmin4
restart: always
env_file: .env
environment:
- MONGO_INITDB_ROOT_USERNAME=root
- MONGO_INITDB_ROOT_PASSWORD=example
volumes:
- mongo-data:/data/db
networks:
- infisical-dev
mongo-express:
container_name: infisical-dev-mongo-express
image: mongo-express
restart: always
depends_on:
- mongo
env_file: .env
environment:
- ME_CONFIG_MONGODB_ADMINUSERNAME=root
- ME_CONFIG_MONGODB_ADMINPASSWORD=example
- ME_CONFIG_MONGODB_URL=mongodb://root:example@mongo:27017/
PGADMIN_DEFAULT_EMAIL: admin@example.com
PGADMIN_DEFAULT_PASSWORD: pass
ports:
- 8081:8081
networks:
- infisical-dev
- 5050:80
depends_on:
- db
smtp-server:
container_name: infisical-dev-smtp-server
image: lytrax/mailhog:latest # https://github.com/mailhog/MailHog/issues/353#issuecomment-821137362
restart: always
logging:
driver: 'none' # disable saving logs
driver: "none" # disable saving logs
ports:
- 1025:1025 # SMTP server
- 8025:8025 # Web UI
networks:
- infisical-dev
redis:
image: redis
container_name: infisical-dev-redis
environment:
- ALLOW_EMPTY_PASSWORD=yes
ports:
- 6379:6379
volumes:
- redis_data:/data
networks:
- infisical-dev
redis-commander:
container_name: infisical-dev-redis-commander
image: rediscommander/redis-commander
restart: always
depends_on:
- redis
environment:
- REDIS_HOSTS=local:redis:6379
ports:
- "8085:8081"
networks:
- infisical-dev
volumes:
mongo-data:
postgres-data:
driver: local
redis_data:
driver: local
networks:
infisical-dev:

@ -1,146 +0,0 @@
version: "3.9"
services:
nginx:
container_name: infisical-dev-nginx
image: nginx
restart: always
ports:
- 8080:80
volumes:
- ./nginx/default.dev.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- backend
- frontend
db:
image: postgres:14-alpine
ports:
- "5432:5432"
volumes:
- postgres-data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: infisical
POSTGRES_USER: infisical
POSTGRES_DB: infisical
redis:
image: redis
container_name: infisical-dev-redis
environment:
- ALLOW_EMPTY_PASSWORD=yes
ports:
- 6379:6379
volumes:
- redis_data:/data
redis-commander:
container_name: infisical-dev-redis-commander
image: rediscommander/redis-commander
restart: always
depends_on:
- redis
environment:
- REDIS_HOSTS=local:redis:6379
ports:
- "8085:8081"
db-test:
profiles: ["test"]
image: postgres:14-alpine
ports:
- "5430:5432"
environment:
POSTGRES_PASSWORD: infisical
POSTGRES_USER: infisical
POSTGRES_DB: infisical-test
backend:
container_name: infisical-dev-api
build:
context: ./backend
dockerfile: Dockerfile.dev
depends_on:
- db
- redis
env_file:
- .env
ports:
- 4000:4000
environment:
- NODE_ENV=development
- DB_CONNECTION_URI=postgres://infisical:infisical@db/infisical?sslmode=disable
volumes:
- ./backend/src:/app/src
frontend:
container_name: infisical-dev-frontend
restart: unless-stopped
depends_on:
- backend
build:
context: ./frontend
dockerfile: Dockerfile.dev
volumes:
- ./frontend/src:/app/src/ # mounted whole src to avoid missing reload on new files
- ./frontend/public:/app/public
env_file: .env
environment:
- NEXT_PUBLIC_ENV=development
- INFISICAL_TELEMETRY_ENABLED=false
pgadmin:
image: dpage/pgadmin4
restart: always
environment:
PGADMIN_DEFAULT_EMAIL: admin@example.com
PGADMIN_DEFAULT_PASSWORD: pass
ports:
- 5050:80
depends_on:
- db
smtp-server:
container_name: infisical-dev-smtp-server
image: lytrax/mailhog:latest # https://github.com/mailhog/MailHog/issues/353#issuecomment-821137362
restart: always
logging:
driver: "none" # disable saving logs
ports:
- 1025:1025 # SMTP server
- 8025:8025 # Web UI
# mongo:
# image: mongo
# container_name: infisical-dev-mongo
# restart: always
# env_file: .env
# environment:
# - MONGO_INITDB_ROOT_USERNAME=root
# - MONGO_INITDB_ROOT_PASSWORD=example
# volumes:
# - mongo-data:/data/db
# ports:
# - 27017:27017
#
# mongo-express:
# container_name: infisical-dev-mongo-express
# image: mongo-express
# restart: always
# depends_on:
# - mongo
# env_file: .env
# environment:
# - ME_CONFIG_MONGODB_ADMINUSERNAME=root
# - ME_CONFIG_MONGODB_ADMINPASSWORD=example
# - ME_CONFIG_MONGODB_URL=mongodb://root:example@mongo:27017/
# ports:
# - 8081:8081
volumes:
postgres-data:
driver: local
redis_data:
driver: local
mongo-data:
driver: local

@ -1,12 +1,27 @@
version: "3"
services:
db-migration:
container_name: infisical-db-migration
depends_on:
- db
image: infisical/infisical:latest-postgres
env_file: .env
command: npm run migration:latest
networks:
- infisical
backend:
container_name: infisical-backend
restart: unless-stopped
depends_on:
- mongo
image: infisical/infisical:latest
db:
condition: service_started
redis:
condition: service_started
db-migration:
condition: service_completed_successfully
image: infisical/infisical:latest-postgres
env_file: .env
ports:
- 80:8080
@ -28,21 +43,18 @@ services:
volumes:
- redis_data:/data
mongo:
container_name: infisical-mongo
image: mongo
db:
container_name: infisical-db
image: postgres:14-alpine
restart: always
env_file: .env
environment:
- MONGO_INITDB_ROOT_USERNAME=${MONGO_USERNAME}
- MONGO_INITDB_ROOT_PASSWORD=${MONGO_PASSWORD}
volumes:
- mongo-data:/data/db
- pg_data:/data/db
networks:
- infisical
volumes:
mongo-data:
pg_data:
driver: local
redis_data:
driver: local

@ -1,4 +1,4 @@
---
title: "Create"
openapi: "POST /api/v2/workspace/{workspaceId}/environments"
openapi: "POST /api/v1/workspace/{workspaceId}/environments"
---

@ -1,4 +1,4 @@
---
title: "Delete"
openapi: "DELETE /api/v2/workspace/{workspaceId}/environments"
---
openapi: "DELETE /api/v1/workspace/{workspaceId}/environments/{id}"
---

@ -1,4 +1,4 @@
---
title: "Update"
openapi: "PUT /api/v2/workspace/{workspaceId}/environments"
---
openapi: "PATCH /api/v1/workspace/{workspaceId}/environments/{id}"
---

@ -1,4 +1,4 @@
---
title: "Create"
openapi: "POST /api/v1/folders/"
---
openapi: "POST /api/v1/folders"
---

@ -1,4 +1,4 @@
---
title: "Delete"
openapi: "DELETE /api/v1/folders/{folderName}"
---
openapi: "DELETE /api/v1/folders/{folderId}"
---

@ -1,4 +1,4 @@
---
title: "List"
openapi: "GET /api/v1/folders/"
---
openapi: "GET /api/v1/folders"
---

@ -1,4 +1,4 @@
---
title: "Update"
openapi: "PATCH /api/v1/folders/{folderName}"
---
openapi: "PATCH /api/v1/folders/{folderId}"
---

@ -1,4 +1,4 @@
---
title: "Create"
openapi: "POST /api/v1/identities/"
---
openapi: "POST /api/v1/identities"
---

@ -1,4 +1,4 @@
---
title: "Delete"
openapi: "DELETE /api/v1/identities/{identityId}"
---
---

@ -1,4 +1,4 @@
---
title: "Update"
openapi: "PATCH /api/v1/identities/{identityId}"
---
---

@ -1,4 +1,4 @@
---
title: "List Identity Memberships"
openapi: "GET /api/v2/organizations/{organizationId}/identity-memberships"
---
openapi: "GET /api/v2/organizations/{orgId}/identity-memberships"
---

@ -1,4 +1,4 @@
---
title: "Create"
openapi: "POST /api/v1/secret-imports/"
---
openapi: "POST /api/v1/secret-imports"
---

@ -1,4 +1,4 @@
---
title: "Delete"
openapi: "DELETE /api/v1/secret-imports/{id}"
---
openapi: "DELETE /api/v1/secret-imports/{secretImportId}"
---

@ -1,4 +1,4 @@
---
title: "List"
openapi: "GET /api/v1/secret-imports/"
---
openapi: "GET /api/v1/secret-imports"
---

@ -1,4 +1,4 @@
---
title: "Update"
openapi: "PUT /api/v1/secret-imports/{id}"
---
openapi: "PATCH /api/v1/secret-imports/{secretImportId}"
---

@ -1,6 +1,6 @@
---
title: "Get"
openapi: "GET /api/v2/service-token/"
openapi: "GET /api/v2/service-token"
---
<Warning>

@ -1,4 +1,4 @@
---
title: "Delete Identity Membership"
openapi: "DELETE /api/v2/workspace/{workspaceId}/identity-memberships/{identityId}"
---
openapi: "DELETE /api/v2/workspace/{projectId}/identity-memberships/{identityId}"
---

@ -1,4 +1,4 @@
---
title: "Delete User Membership"
openapi: "DELETE /api/v2/workspace/{workspaceId}/memberships/{membershipId}"
openapi: "DELETE /api/v1/workspace/{workspaceId}/memberships/{membershipId}"
---

@ -1,4 +1,4 @@
---
title: "List Identity Memberships"
openapi: "GET /api/v2/workspace/{workspaceId}/identity-memberships"
---
openapi: "GET /api/v2/workspace/{projectId}/identity-memberships"
---

@ -1,4 +1,4 @@
---
title: "Get User Memberships"
openapi: "GET /api/v2/workspace/{workspaceId}/memberships"
openapi: "GET /api/v1/workspace/{workspaceId}/memberships"
---

@ -1,4 +1,4 @@
---
title: "Roll Back to Snapshot"
openapi: "POST /api/v1/workspace/{workspaceId}/secret-snapshots/rollback"
openapi: "POST /api/v1/secret-snapshot/{secretSnapshotId}/rollback"
---

@ -1,4 +1,4 @@
---
title: "Update Identity Membership"
openapi: "PATCH /api/v2/workspace/{workspaceId}/identity-memberships/{identityId}"
---
openapi: "PATCH /api/v2/workspace/{projectId}/identity-memberships/{identityId}"
---

@ -1,4 +1,4 @@
---
title: "Update User Membership"
openapi: "PATCH /api/v2/workspace/{workspaceId}/memberships/{membershipId}"
openapi: "PATCH /api/v1/workspace/{workspaceId}/memberships/{membershipId}"
---

@ -0,0 +1,82 @@
---
title: 'Backend folder structure'
---
```
├── scripts
├── e2e-test
└── src/
├── @types/
│ ├── knex.d.ts
│ └── fastify.d.ts
├── db/
│ ├── migrations
│ ├── schemas
│ └── seed
├── lib/
│ ├── fn
│ ├── date
│ └── config
├── queue
├── server/
│ ├── routes/
│ │ ├── v1
│ │ └── v2
│ ├── plugins
│ └── config
├── services/
│ ├── auth
│ ├── org
│ └── project/
│ ├── project-service.ts
│ ├── project-types.ts
│ └── project-dal.ts
└── ee/
├── routes
└── services
```
### `backend/scripts`
Contains reusable scripts for backend automation, like running migrations and generating SQL schemas.
### `backend/e2e-test`
Integration tests for the APIs.
### `backend/src`
The source code of the backend.
- `@types`: Type definitions for libraries like Fastify and Knex.
- `db`: Knex.js configuration for the database, including migration, seed files, and SQL type schemas.
- `lib`: Stateless, reusable functions used across the codebase.
- `queue`: Infisical's queue system based on BullMQ.
### `src/server`
- Scope anything related to Fastify/service here.
- Includes routes, Fastify plugins, and server configurations.
- The routes folder contains various versions of routes separated into v1, v2, etc.
### `src/services`
- Handles the core business logic for all operations.
- Follows the co-location principle: related components should be kept together.
- Each service component typically contains:
1. **dal**: Database Access Layer functions for database operations
2. **service**: The service layer containing business logic.
3. **type**: Type definitions used within the service component.
4. **fns**: An optional component for sharing reusable functions related to the service.
5. **queue**: An optional component for queue-specific logic, like `secret-queue.ts`.
### `src/ee`
Follows the same pattern as above, with the exception of a license change from MIT to Infisical Proprietary License.
### Guidelines and Best Practices
- All services are interconnected at `/src/server/routes/index.ts`, following the principle of simple dependency injection.
- Files should be named in dash-case.
- Avoid using classes in the codebase; opt for simple functions instead.
- All committed code must be properly linted using `npm run lint:fix` and type-checked with `npm run type:check`.
- Minimize shared logic between services as much as possible.
- Controllers within a router component should ideally call only one service layer, with exceptions for services like `audit-log` that require access to request object data.

@ -0,0 +1,56 @@
---
title: "Backend development guide"
---
Suppose you're interested in implementing a new feature in Infisical's backend, let's call it "feature-x." Here are the general steps you should follow.
## Database schema migration
In order to run [schema migrations](https://en.wikipedia.org/wiki/Schema_migration#:~:text=A%20schema%20migration%20is%20performed,some%20newer%20or%20older%20version) you need to expose your database connection string. Create a `.env.migration` file to set the database connection URI for migration scripts, or alternatively, export the `DB_CONNECTION_URI` environment variable.
## Creating new database model
If your feature involves a change in the database, you need to first address this by generating the necessary database schemas.
1. If you're adding a new table, update the `TableName` enum in `/src/db/schemas/models.ts` to include the new table name.
2. Create a new migration file by running `npm run migration:new` and give it a relevant name, such as `feature-x`.
3. Navigate to `/src/db/migrations/<timestamp>_<feature-x>.ts`.
4. Modify both the `up` and `down` functions to create or alter Postgres fields on migration up and to revert these changes on migration down, ensuring idempotency as outlined [here](https://github.com/graphile/migrate/blob/main/docs/idempotent-examples.md).
### Generating TS Schemas
While typically you would need to manually write TS types for Knex type-sense, we have automated this process:
1. Start the server.
2. Run `npm run migration:latest` to apply all database changes.
3. Execute `npm run generate:schema` to automatically generate types and schemas using [zod](https://github.com/colinhacks/zod) in the `/src/db/schemas` folder.
4. Update the barrel export in `schema/index` and include the new tables in `/src/@types/knex.d.ts` to enable type-sensing in Knex.js.
## Business Logic
Once the database changes are in place, it's time to create the APIs for `feature-x`:
1. Execute `npm run generate:component`.
2. Choose option 1 for the service component.
3. Name the service in dash-case, like `feature-x`. This will create a `feature-x` folder in `/src/services` containing three files.
1. `feature-x-dal`: The Database Access Layer functions.
2. `feature-x-service`: The service layer where all the business logic is handled.
3. `feature-x-type`: The types used by `feature-x`.
For reusable shared functions, set up a file named `feature-x-fns`.
Use the custom Infisical function `ormify` in `src/lib/knex` for simple database operations within the DAL.
## Connecting the Service Layer to the Server Layer
Server-related logic is handled in `/src/server`. To connect the service layer to the server layer, we use Fastify plugins for dependency injection:
1. Add the service type in the `fastify.d.ts` file under the `service` namespace of a FastifyServerInstance type.
2. In `/src/server/routes/index.ts`, instantiate the required dependencies for `feature-x`, such as the DAL and service layers, and then pass them to `fastify.register("service,{...dependencies})`.
3. This makes the service layer accessible within all routes under the Fastify service instance, accessed via `server.services.<registered service name>.<function>`.
## Writing API Routes
1. To create a route component, run `npm generate:component`.
2. Select option 3, type the router name in dash-case, and provide the version number. This will generate a router file in `src/server/routes/v<version-number>/<router component name>`
1. Implement your logic to connect with the service layer as needed.
2. Import the router component in the version folder's index.ts. For instance, if it's in v1, import it in `v1/index.ts`.
3. Finally, register it under the appropriate prefix for access.

@ -4,7 +4,7 @@ description: "Programmatically interact with Infisical"
---
<Note>
Currently, identities can only be used to make authenticated requests to the Infisical API and SDKs. They do not work with clients such as CLI, K8s Operator, Terraform Provider, etc.
Currently, identities can only be used to make authenticated requests to the Infisical API, SDKs, and Agent. They do not work with clients such as CLI, K8s Operator, Terraform Provider, etc.
We will be releasing compatibility with it across clients in the coming quarter.
</Note>
@ -50,4 +50,4 @@ Check out the following authentication method-specific guides for step-by-step i
- The identity you are trying to read, update, or delete is more privileged than yourself.
- The role you are trying to create an identity for or update an identity to is more privileged than yours.
</Accordion>
</AccordionGroup>
</AccordionGroup>

@ -5,6 +5,19 @@ description: "How to use Infisical for secret management in Ansible"
The documentation for using Infisical to manage secrets in Ansible is currently available [here](https://galaxy.ansible.com/ui/repo/published/infisical/vault/).
<Info>
Have any questions? Join Infisical's [community Slack](https://infisical.com/slack) for quick support.
</Info>
## Troubleshoot
<Accordion title="I'm getting a error related to objc[72832]: +[__NSCFConstantString initialize]">
If you get this Python error when you running the lookup plugin:-
```
objc[72832]: +[__NSCFConstantString initialize] may have been in progress in another thread when fork() was called. We cannot safely call it or ignore it in the fork() child process. Crashing instead. Set a breakpoint on objc_initializeAfterForkError to debug.
Fatal Python error: Aborted
```
You will need to add this to your shell environment or ansible wrapper script:-
```
export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES
```
</Accordion>

@ -1,5 +1,6 @@
{
"name": "Infisical",
"openapi": "https://app.infisical.com/api/docs/json",
"logo": {
"dark": "/logo/dark.svg",
"light": "/logo/light.svg",
@ -463,7 +464,9 @@
{
"group": "Contributing to platform",
"pages": [
"contributing/platform/developing"
"contributing/platform/developing",
"contributing/platform/backend/how-to-create-a-feature",
"contributing/platform/backend/folder-structure"
]
},
{

@ -18,8 +18,8 @@ Other environment variables are listed below to increase the functionality of yo
Must be a random 32 byte base64 string. Can be generated with `openssl rand -base64 32`
</ParamField>
<ParamField query="MONGO_URL" type="string" default="none" required>
Mongo connection string. *TLS based connection string is not yet supported
<ParamField query="DB_CONNECTION_URI" type="string" default="none" required>
Postgres database connection string.
</ParamField>
<ParamField query="REDIS_URL" type="string" default="none" required>

@ -2,53 +2,79 @@
title: "Docker Compose"
description: "Run Infisical with Docker Compose template"
---
Install Infisical using Docker compose. This self hosting method contains all of the required components needed
to run a functional instance of Infisical.
<Steps>
<Step title="Install Docker on your VM">
```bash
# Example in ubuntu
apt-get update
apt-get upgrade
apt install docker-compose
```
</Step>
<Step title="Download required files">
2.1. Run the command below to download the `.env` file template.
```bash
wget -O .env https://raw.githubusercontent.com/Infisical/infisical/main/.env.example
```
2.2. Run the command below to download the docker compose template.
```bash
wget -O docker-compose.yml https://raw.githubusercontent.com/Infisical/infisical/main/docker-compose.yml
```
2.3. Run the command below to download the `nginx` config file.
```bash
mkdir nginx && wget -O ./nginx/default.conf https://raw.githubusercontent.com/Infisical/infisical/main/nginx/default.dev.conf
```
</Step>
<Step title="Update the .env file">
Running Infisical requires a few environment variables to be set.
At minimum, Infisical requires that you set the variables `ENCRYPTION_KEY`, `AUTH_SECRET`, `MONGO_URL`, and `REDIS_URL` which you can read more about [here](/self-hosting/configuration/envars).
## Prerequisites
- [Docker](https://docs.docker.com/engine/install/)
- [Docker compose](https://docs.docker.com/compose/install/)
Tweak the `.env` accordingly.
<Warning>
This Docker Compose configuration is not designed for high-availability production scenarios.
It includes just the essential components needed to set up an Infisical proof of concept (POC).
Additional configuration is required to enhance data redundancy and ensure higher availability for production environments.
</Warning>
```bash
nano .env
```
</Step>
<Step title="Start Infisical">
Finally, run the command below to get Infisical up and running (in detached mode).
## Verify prerequisites
To verify that Docker compose and Docker are installed on the machine where you plan to install Infisical, run the following commands.
Check for docker installation
```bash
docker-compose -f docker-compose.yml up -d
docker
```
Your Infisical installation is complete and should be running on port `80` or `http://localhost:80`.
</Step>
</Steps>
Check for docker compose installation
```bash
docker-compose
```
## Download docker compose file
You can obtain the Infisical docker compose file by using a command-line downloader such as `wget` or `curl`.
If your system doesn't have either of these, you can use a equivalent command that works with your machine.
<Tabs>
<Tab title="curl">
```bash
curl -o docker-compose.prod.yml https://raw.githubusercontent.com/Infisical/infisical/main/docker-compose.prod.yml
```
</Tab>
<Tab title="wget">
```bash
wget -O docker-compose.prod.yml https://raw.githubusercontent.com/Infisical/infisical/main/docker-compose.prod.yml
```
</Tab>
</Tabs>
## Configure instance credentials
Infisical requires a set of credentials used for connecting to dependent services such as Postgres, Redis, etc.
The default credentials can be downloaded using the one of the commands listed below.
<Tabs>
<Tab title="curl">
```bash
curl -o .env https://raw.githubusercontent.com/Infisical/infisical/main/.env.example
```
</Tab>
<Tab title="wget">
```bash
wget -O .env https://raw.githubusercontent.com/Infisical/infisical/main/.env.example
```
</Tab>
</Tabs>
Once downloaded, the credentials file will be saved to your working directly as `.env` file.
View all available configurations [here](/self-hosting/configuration/envars).
<Warning>
The default .env file contains credentials that are intended solely for testing purposes.
For production use, please generate a new `ENCRYPTION_KEY` and `AUTH_SECRET`. Instructions to do so, can be found [here](/self-hosting/configuration/envars)
</Warning>
## Start Infisical
Run the command below to start Infisical and all related services.
```bash
docker-compose -f docker-compose.prod.yml up
```
Your Infisical instance should now be running on port `80`. To access your instance, visit `http://localhost:80`.

File diff suppressed because it is too large Load Diff

@ -58,8 +58,8 @@ export default function DonwloadBackupPDFStep({
return (
<div className="flex flex-col items-center w-full h-full md:px-6 mx-auto mb-36 md:mb-16">
<p className="text-xl text-center font-medium flex justify-center text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200">
<FontAwesomeIcon icon={faWarning} className="ml-2 mr-3 pt-1 text-2xl text-bunker-200" />
<p className="text-xl text-center font-medium flex flex-col justify-center items-center text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200">
<FontAwesomeIcon icon={faWarning} className="ml-2 mr-3 pt-1 mb-6 text-6xl text-bunker-200" />
{t("signup.step4-message")}
</p>
<div className="flex flex-col pb-2 bg-mineshaft-800 border border-mineshaft-600 items-center justify-center text-center lg:w-1/6 w-full md:min-w-[24rem] mt-8 max-w-md text-bunker-300 text-md rounded-md">

@ -170,7 +170,11 @@ export const AddAPIKeyModal = ({
>
Add
</Button>
<Button colorSchema="secondary" variant="plain">
<Button
colorSchema="secondary"
variant="plain"
onClick={() => handlePopUpToggle("addAPIKey", false)}
>
Cancel
</Button>
</div>

@ -139,7 +139,7 @@ export const WebhooksTab = withProjectPermission(
};
return (
<div className="mb-6 max-w-screen-lg rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="flex justify-between">
<p className="text-xl font-semibold text-mineshaft-100">{t("settings.webhooks.title")}</p>
<ProjectPermissionCan

@ -128,10 +128,10 @@ export const SignUpPage = () => {
animate={{ opacity: 1, translateX: 0 }}
exit={{ opacity: 0, translateX: 30 }}
>
<div className="flex flex-col items-center space-y-4 text-center">
<div className="flex flex-col items-center space-y-2 text-center">
<img src="/images/gradientLogo.svg" height={90} width={120} alt="Infisical logo" />
<div className="text-4xl">Welcome to Infisical</div>
<div>Create your first Admin Account</div>
<div className="text-4xl pt-4">Welcome to Infisical</div>
<div className="text-bunker-300 pb-4">Create your first Super Admin Account</div>
</div>
<form onSubmit={handleSubmit(handleFormSubmit)}>
<div className="mt-8">
@ -145,7 +145,7 @@ export const SignUpPage = () => {
errorText={error?.message}
isError={Boolean(error)}
>
<Input isFullWidth size="lg" {...field} />
<Input isFullWidth size="md" {...field} />
</FormControl>
)}
/>
@ -158,7 +158,7 @@ export const SignUpPage = () => {
errorText={error?.message}
isError={Boolean(error)}
>
<Input isFullWidth size="lg" {...field} />
<Input isFullWidth size="md" {...field} />
</FormControl>
)}
/>
@ -168,7 +168,7 @@ export const SignUpPage = () => {
name="email"
render={({ field, fieldState: { error } }) => (
<FormControl label="Email" errorText={error?.message} isError={Boolean(error)}>
<Input isFullWidth size="lg" {...field} />
<Input isFullWidth size="md" {...field} />
</FormControl>
)}
/>
@ -181,7 +181,7 @@ export const SignUpPage = () => {
errorText={error?.message}
isError={Boolean(error)}
>
<Input isFullWidth size="lg" type="password" {...field} />
<Input isFullWidth size="md" type="password" {...field} />
</FormControl>
)}
/>
@ -194,13 +194,13 @@ export const SignUpPage = () => {
errorText={error?.message}
isError={Boolean(error)}
>
<Input isFullWidth size="lg" type="password" {...field} />
<Input isFullWidth size="md" type="password" {...field} />
</FormControl>
)}
/>
</div>
<Button type="submit" isFullWidth className="mt-4" isLoading={isSubmitting}>
Let&apos;s Go
<Button type="submit" colorSchema="primary" variant="outline_bg" isFullWidth className="mt-4" isLoading={isSubmitting}>
Continue
</Button>
</form>
</motion.div>

@ -15,8 +15,8 @@ export const DownloadBackupKeys = ({ onGenerate }: Props): JSX.Element => {
return (
<div className="flex flex-col items-center w-full h-full md:px-6 mx-auto mb-36 md:mb-16">
<p className="text-xl text-center font-medium flex justify-center text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200">
<FontAwesomeIcon icon={faWarning} className="ml-2 mr-3 pt-1 text-2xl text-bunker-200" />
<p className="text-xl text-center font-medium flex flex-col justify-center items-center text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200">
<FontAwesomeIcon icon={faWarning} className="ml-2 mr-3 pt-1 mb-6 text-6xl text-bunker-200" />
{t("signup.step4-message")}
</p>
<div className="flex flex-col pb-2 bg-mineshaft-800 border border-mineshaft-600 items-center justify-center text-center lg:w-1/6 w-full md:min-w-[24rem] mt-8 max-w-md text-bunker-300 text-md rounded-md">