diff --git a/.env.example b/.env.example index 6b8639a748..4029cb141c 100644 --- a/.env.example +++ b/.env.example @@ -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 diff --git a/.env.migration.example b/.env.migration.example new file mode 100644 index 0000000000..4d1c8f9ef5 --- /dev/null +++ b/.env.migration.example @@ -0,0 +1 @@ +DB_CONNECTION_URI= diff --git a/.github/workflows/check-api-for-breaking-changes.yml b/.github/workflows/check-api-for-breaking-changes.yml index f6acd084cd..683f9fe9bb 100644 --- a/.github/workflows/check-api-for-breaking-changes.yml +++ b/.github/workflows/check-api-for-breaking-changes.yml @@ -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.prod.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: | + run: | docker-compose -f "docker-compose.pg.yml" down docker stop infisical-api docker remove infisical-api diff --git a/.gitignore b/.gitignore index f3c03e8140..07322c82f4 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ node_modules .env.gamma .env.prod .env.infisical - +.env.migration *~ *.swp *.swo diff --git a/Makefile b/Makefile index 544a0256d6..2b7f43c852 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/README.md b/README.md index 5e0cb854ff..3c2fd5387c 100644 --- a/README.md +++ b/README.md @@ -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` diff --git a/backend/scripts/generate-schema-types.ts b/backend/scripts/generate-schema-types.ts index 5d51a5164c..68330613ca 100644 --- a/backend/scripts/generate-schema-types.ts +++ b/backend/scripts/generate-schema-types.ts @@ -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; export type T${pascalCase}Update = Partial>; ` ); - - // 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); diff --git a/backend/src/db/knexfile.ts b/backend/src/db/knexfile.ts index ec7458da62..73eb507f40 100644 --- a/backend/src/db/knexfile.ts +++ b/backend/src/db/knexfile.ts @@ -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 { diff --git a/backend/src/ee/routes/v1/project-router.ts b/backend/src/ee/routes/v1/project-router.ts index 2a17f747d2..cfcecb8f0c 100644 --- a/backend/src/ee/routes/v1/project-router.ts +++ b/backend/src/ee/routes/v1/project-router.ts @@ -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() }), diff --git a/backend/src/ee/routes/v1/saml-router.ts b/backend/src/ee/routes/v1/saml-router.ts index f81c21ffd4..00dd09c330 100644 --- a/backend/src/ee/routes/v1/saml-router.ts +++ b/backend/src/ee/routes/v1/saml-router.ts @@ -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 diff --git a/backend/src/ee/routes/v1/snapshot-router.ts b/backend/src/ee/routes/v1/snapshot-router.ts index 0b9eadb0c4..0b858255f7 100644 --- a/backend/src/ee/routes/v1/snapshot-router.ts +++ b/backend/src/ee/routes/v1/snapshot-router.ts @@ -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() }), diff --git a/backend/src/ee/services/saml-config/saml-config-service.ts b/backend/src/ee/services/saml-config/saml-config-service.ts index 132f93f52c..767729179a 100644 --- a/backend/src/ee/services/saml-config/saml-config-service.ts +++ b/backend/src/ee/services/saml-config/saml-config-service.ts @@ -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" }); diff --git a/backend/src/ee/services/saml-config/saml-config-types.ts b/backend/src/ee/services/saml-config/saml-config-types.ts index 587ea52dcb..a2c2c63c05 100644 --- a/backend/src/ee/services/saml-config/saml-config-types.ts +++ b/backend/src/ee/services/saml-config/saml-config-types.ts @@ -41,7 +41,6 @@ export type TSamlLoginDTO = { lastName?: string; authProvider: string; orgId: string; - isSignupAllowed: boolean; // saml thingy relayState?: string; }; diff --git a/backend/src/server/plugins/swagger.ts b/backend/src/server/plugins/swagger.ts index 482e8260b3..1eb1a0f4ec 100644 --- a/backend/src/server/plugins/swagger.ts +++ b/backend/src/server/plugins/swagger.ts @@ -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", diff --git a/backend/src/server/routes/v1/admin-router.ts b/backend/src/server/routes/v1/admin-router.ts index e23f68c3ae..da13d5e00c 100644 --- a/backend/src/server/routes/v1/admin-router.ts +++ b/backend/src/server/routes/v1/admin-router.ts @@ -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" }; } }); diff --git a/backend/src/server/routes/v1/identity-access-token-router.ts b/backend/src/server/routes/v1/identity-access-token-router.ts index 4ddf7b74a9..78112f8962 100644 --- a/backend/src/server/routes/v1/identity-access-token-router.ts +++ b/backend/src/server/routes/v1/identity-access-token-router.ts @@ -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() }), diff --git a/backend/src/server/routes/v1/identity-router.ts b/backend/src/server/routes/v1/identity-router.ts index 055735f323..4ca4ef3249 100644 --- a/backend/src/server/routes/v1/identity-router.ts +++ b/backend/src/server/routes/v1/identity-router.ts @@ -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() }), diff --git a/backend/src/server/routes/v1/identity-ua.ts b/backend/src/server/routes/v1/identity-ua.ts index 8c56ab4311..11b8e0e8de 100644 --- a/backend/src/server/routes/v1/identity-ua.ts +++ b/backend/src/server/routes/v1/identity-ua.ts @@ -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() diff --git a/backend/src/server/routes/v1/project-env-router.ts b/backend/src/server/routes/v1/project-env-router.ts index ccf77e7657..b93ffe9283 100644 --- a/backend/src/server/routes/v1/project-env-router.ts +++ b/backend/src/server/routes/v1/project-env-router.ts @@ -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() diff --git a/backend/src/server/routes/v1/project-membership-router.ts b/backend/src/server/routes/v1/project-membership-router.ts index 1d340c84cc..09de72233c 100644 --- a/backend/src/server/routes/v1/project-membership-router.ts +++ b/backend/src/server/routes/v1/project-membership-router.ts @@ -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() diff --git a/backend/src/server/routes/v1/secret-folder-router.ts b/backend/src/server/routes/v1/secret-folder-router.ts index cad682ddce..8a80fb7281 100644 --- a/backend/src/server/routes/v1/secret-folder-router.ts +++ b/backend/src/server/routes/v1/secret-folder-router.ts @@ -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(), diff --git a/backend/src/server/routes/v1/secret-import-router.ts b/backend/src/server/routes/v1/secret-import-router.ts index 9f8c8174fb..2ec2d5ce2e 100644 --- a/backend/src/server/routes/v1/secret-import-router.ts +++ b/backend/src/server/routes/v1/secret-import-router.ts @@ -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(), diff --git a/backend/src/server/routes/v2/identity-org-router.ts b/backend/src/server/routes/v2/identity-org-router.ts index ba2bde7cc9..1832e89621 100644 --- a/backend/src/server/routes/v2/identity-org-router.ts +++ b/backend/src/server/routes/v2/identity-org-router.ts @@ -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() }), diff --git a/backend/src/server/routes/v2/identity-project-router.ts b/backend/src/server/routes/v2/identity-project-router.ts index 7698474be9..fdd810b4b6 100644 --- a/backend/src/server/routes/v2/identity-project-router.ts +++ b/backend/src/server/routes/v2/identity-project-router.ts @@ -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() }), diff --git a/backend/src/server/routes/v2/organization-router.ts b/backend/src/server/routes/v2/organization-router.ts index 8f71ad0384..01ef7973ac 100644 --- a/backend/src/server/routes/v2/organization-router.ts +++ b/backend/src/server/routes/v2/organization-router.ts @@ -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({ diff --git a/backend/src/server/routes/v2/project-router.ts b/backend/src/server/routes/v2/project-router.ts index 13f7a6a216..d38efdbb96 100644 --- a/backend/src/server/routes/v2/project-router.ts +++ b/backend/src/server/routes/v2/project-router.ts @@ -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() }), diff --git a/backend/src/server/routes/v2/service-token-router.ts b/backend/src/server/routes/v2/service-token-router.ts index 3f28095842..2b6445deac 100644 --- a/backend/src/server/routes/v2/service-token-router.ts +++ b/backend/src/server/routes/v2/service-token-router.ts @@ -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({ diff --git a/backend/src/server/routes/v2/user-router.ts b/backend/src/server/routes/v2/user-router.ts index 8061aa0e55..8fc114e766 100644 --- a/backend/src/server/routes/v2/user-router.ts +++ b/backend/src/server/routes/v2/user-router.ts @@ -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 })) diff --git a/backend/src/server/routes/v3/secret-router.ts b/backend/src/server/routes/v3/secret-router.ts index 9c6e8917b5..5f47ae3c5f 100644 --- a/backend/src/server/routes/v3/secret-router.ts +++ b/backend/src/server/routes/v3/secret-router.ts @@ -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() }), diff --git a/backend/src/server/routes/v3/signup-router.ts b/backend/src/server/routes/v3/signup-router.ts index 2a2f50f43c..15264b9268 100644 --- a/backend/src/server/routes/v3/signup-router.ts +++ b/backend/src/server/routes/v3/signup-router.ts @@ -159,6 +159,17 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => { userAgent }); + 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, { httpOnly: true, path: "/", diff --git a/backend/src/services/identity-access-token/identity-access-token-service.ts b/backend/src/services/identity-access-token/identity-access-token-service.ts index cdc8effe2d..32774ccbb0 100644 --- a/backend/src/services/identity-access-token/identity-access-token-service.ts +++ b/backend/src/services/identity-access-token/identity-access-token-service.ts @@ -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" diff --git a/backend/src/services/identity-ua/identity-ua-service.ts b/backend/src/services/identity-ua/identity-ua-service.ts index 60e748ff76..3b73da6d46 100644 --- a/backend/src/services/identity-ua/identity-ua-service.ts +++ b/backend/src/services/identity-ua/identity-ua-service.ts @@ -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) } ); diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 774cd5b022..f95810777e 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -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 - - 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 - networks: - - infisical-dev + - INFISICAL_TELEMETRY_ENABLED=false - mongo-express: - container_name: infisical-dev-mongo-express - image: mongo-express + pgadmin: + image: dpage/pgadmin4 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: diff --git a/docker-compose.pg.yml b/docker-compose.pg.yml deleted file mode 100644 index a73f7ca5eb..0000000000 --- a/docker-compose.pg.yml +++ /dev/null @@ -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 diff --git a/docker-compose.yml b/docker-compose.prod.yml similarity index 54% rename from docker-compose.yml rename to docker-compose.prod.yml index c159a21754..5861a4a0e2 100644 --- a/docker-compose.yml +++ b/docker-compose.prod.yml @@ -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 diff --git a/docs/api-reference/endpoints/environments/create.mdx b/docs/api-reference/endpoints/environments/create.mdx index 2527c613de..826dcce3df 100644 --- a/docs/api-reference/endpoints/environments/create.mdx +++ b/docs/api-reference/endpoints/environments/create.mdx @@ -1,4 +1,4 @@ --- title: "Create" -openapi: "POST /api/v2/workspace/{workspaceId}/environments" +openapi: "POST /api/v1/workspace/{workspaceId}/environments" --- diff --git a/docs/api-reference/endpoints/environments/delete.mdx b/docs/api-reference/endpoints/environments/delete.mdx index 944e42961c..903e58d2a2 100644 --- a/docs/api-reference/endpoints/environments/delete.mdx +++ b/docs/api-reference/endpoints/environments/delete.mdx @@ -1,4 +1,4 @@ --- title: "Delete" -openapi: "DELETE /api/v2/workspace/{workspaceId}/environments" ---- \ No newline at end of file +openapi: "DELETE /api/v1/workspace/{workspaceId}/environments/{id}" +--- diff --git a/docs/api-reference/endpoints/environments/update.mdx b/docs/api-reference/endpoints/environments/update.mdx index 291344d6c0..f939686685 100644 --- a/docs/api-reference/endpoints/environments/update.mdx +++ b/docs/api-reference/endpoints/environments/update.mdx @@ -1,4 +1,4 @@ --- title: "Update" -openapi: "PUT /api/v2/workspace/{workspaceId}/environments" ---- \ No newline at end of file +openapi: "PATCH /api/v1/workspace/{workspaceId}/environments/{id}" +--- diff --git a/docs/api-reference/endpoints/folders/create.mdx b/docs/api-reference/endpoints/folders/create.mdx index 397f43cb54..e1ff3004a0 100644 --- a/docs/api-reference/endpoints/folders/create.mdx +++ b/docs/api-reference/endpoints/folders/create.mdx @@ -1,4 +1,4 @@ --- title: "Create" -openapi: "POST /api/v1/folders/" ---- \ No newline at end of file +openapi: "POST /api/v1/folders" +--- diff --git a/docs/api-reference/endpoints/folders/delete.mdx b/docs/api-reference/endpoints/folders/delete.mdx index 0aacd66e26..dc73a41da0 100644 --- a/docs/api-reference/endpoints/folders/delete.mdx +++ b/docs/api-reference/endpoints/folders/delete.mdx @@ -1,4 +1,4 @@ --- title: "Delete" -openapi: "DELETE /api/v1/folders/{folderName}" ---- \ No newline at end of file +openapi: "DELETE /api/v1/folders/{folderId}" +--- diff --git a/docs/api-reference/endpoints/folders/list.mdx b/docs/api-reference/endpoints/folders/list.mdx index c467c59750..f40f93273c 100644 --- a/docs/api-reference/endpoints/folders/list.mdx +++ b/docs/api-reference/endpoints/folders/list.mdx @@ -1,4 +1,4 @@ --- title: "List" -openapi: "GET /api/v1/folders/" ---- \ No newline at end of file +openapi: "GET /api/v1/folders" +--- diff --git a/docs/api-reference/endpoints/folders/update.mdx b/docs/api-reference/endpoints/folders/update.mdx index 3ceae7fb6d..c54778e946 100644 --- a/docs/api-reference/endpoints/folders/update.mdx +++ b/docs/api-reference/endpoints/folders/update.mdx @@ -1,4 +1,4 @@ --- title: "Update" -openapi: "PATCH /api/v1/folders/{folderName}" ---- \ No newline at end of file +openapi: "PATCH /api/v1/folders/{folderId}" +--- diff --git a/docs/api-reference/endpoints/identities/create.mdx b/docs/api-reference/endpoints/identities/create.mdx index 05a11521fa..a6595f97a6 100644 --- a/docs/api-reference/endpoints/identities/create.mdx +++ b/docs/api-reference/endpoints/identities/create.mdx @@ -1,4 +1,4 @@ --- title: "Create" -openapi: "POST /api/v1/identities/" ---- \ No newline at end of file +openapi: "POST /api/v1/identities" +--- diff --git a/docs/api-reference/endpoints/identities/delete.mdx b/docs/api-reference/endpoints/identities/delete.mdx index 07e79dfe93..5b6ed220af 100644 --- a/docs/api-reference/endpoints/identities/delete.mdx +++ b/docs/api-reference/endpoints/identities/delete.mdx @@ -1,4 +1,4 @@ --- title: "Delete" openapi: "DELETE /api/v1/identities/{identityId}" ---- \ No newline at end of file +--- diff --git a/docs/api-reference/endpoints/identities/update.mdx b/docs/api-reference/endpoints/identities/update.mdx index c0940467bf..02d2131817 100644 --- a/docs/api-reference/endpoints/identities/update.mdx +++ b/docs/api-reference/endpoints/identities/update.mdx @@ -1,4 +1,4 @@ --- title: "Update" openapi: "PATCH /api/v1/identities/{identityId}" ---- \ No newline at end of file +--- diff --git a/docs/api-reference/endpoints/organizations/list-identity-memberships.mdx b/docs/api-reference/endpoints/organizations/list-identity-memberships.mdx index 1929a4b59f..5995184a55 100644 --- a/docs/api-reference/endpoints/organizations/list-identity-memberships.mdx +++ b/docs/api-reference/endpoints/organizations/list-identity-memberships.mdx @@ -1,4 +1,4 @@ --- title: "List Identity Memberships" -openapi: "GET /api/v2/organizations/{organizationId}/identity-memberships" ---- \ No newline at end of file +openapi: "GET /api/v2/organizations/{orgId}/identity-memberships" +--- diff --git a/docs/api-reference/endpoints/secret-imports/create.mdx b/docs/api-reference/endpoints/secret-imports/create.mdx index 2c823e528d..3abfb320ff 100644 --- a/docs/api-reference/endpoints/secret-imports/create.mdx +++ b/docs/api-reference/endpoints/secret-imports/create.mdx @@ -1,4 +1,4 @@ --- title: "Create" -openapi: "POST /api/v1/secret-imports/" ---- \ No newline at end of file +openapi: "POST /api/v1/secret-imports" +--- diff --git a/docs/api-reference/endpoints/secret-imports/delete.mdx b/docs/api-reference/endpoints/secret-imports/delete.mdx index c7da4f6d0b..cfa5960b18 100644 --- a/docs/api-reference/endpoints/secret-imports/delete.mdx +++ b/docs/api-reference/endpoints/secret-imports/delete.mdx @@ -1,4 +1,4 @@ --- title: "Delete" -openapi: "DELETE /api/v1/secret-imports/{id}" ---- \ No newline at end of file +openapi: "DELETE /api/v1/secret-imports/{secretImportId}" +--- diff --git a/docs/api-reference/endpoints/secret-imports/list.mdx b/docs/api-reference/endpoints/secret-imports/list.mdx index 2de41b5d76..580d4be8d0 100644 --- a/docs/api-reference/endpoints/secret-imports/list.mdx +++ b/docs/api-reference/endpoints/secret-imports/list.mdx @@ -1,4 +1,4 @@ --- title: "List" -openapi: "GET /api/v1/secret-imports/" ---- \ No newline at end of file +openapi: "GET /api/v1/secret-imports" +--- diff --git a/docs/api-reference/endpoints/secret-imports/update.mdx b/docs/api-reference/endpoints/secret-imports/update.mdx index 76c8a8febf..f211332237 100644 --- a/docs/api-reference/endpoints/secret-imports/update.mdx +++ b/docs/api-reference/endpoints/secret-imports/update.mdx @@ -1,4 +1,4 @@ --- title: "Update" -openapi: "PUT /api/v1/secret-imports/{id}" ---- \ No newline at end of file +openapi: "PATCH /api/v1/secret-imports/{secretImportId}" +--- diff --git a/docs/api-reference/endpoints/service-tokens/get.mdx b/docs/api-reference/endpoints/service-tokens/get.mdx index 5b2604282d..593da8a92a 100644 --- a/docs/api-reference/endpoints/service-tokens/get.mdx +++ b/docs/api-reference/endpoints/service-tokens/get.mdx @@ -1,6 +1,6 @@ --- title: "Get" -openapi: "GET /api/v2/service-token/" +openapi: "GET /api/v2/service-token" --- diff --git a/docs/api-reference/endpoints/workspaces/delete-identity-membership.mdx b/docs/api-reference/endpoints/workspaces/delete-identity-membership.mdx index 4621f9b504..e2b2666263 100644 --- a/docs/api-reference/endpoints/workspaces/delete-identity-membership.mdx +++ b/docs/api-reference/endpoints/workspaces/delete-identity-membership.mdx @@ -1,4 +1,4 @@ --- title: "Delete Identity Membership" -openapi: "DELETE /api/v2/workspace/{workspaceId}/identity-memberships/{identityId}" ---- \ No newline at end of file +openapi: "DELETE /api/v2/workspace/{projectId}/identity-memberships/{identityId}" +--- diff --git a/docs/api-reference/endpoints/workspaces/delete-membership.mdx b/docs/api-reference/endpoints/workspaces/delete-membership.mdx index e93b2415bc..1995e47261 100644 --- a/docs/api-reference/endpoints/workspaces/delete-membership.mdx +++ b/docs/api-reference/endpoints/workspaces/delete-membership.mdx @@ -1,4 +1,4 @@ --- title: "Delete User Membership" -openapi: "DELETE /api/v2/workspace/{workspaceId}/memberships/{membershipId}" +openapi: "DELETE /api/v1/workspace/{workspaceId}/memberships/{membershipId}" --- diff --git a/docs/api-reference/endpoints/workspaces/list-identity-memberships.mdx b/docs/api-reference/endpoints/workspaces/list-identity-memberships.mdx index 45297efffb..e5162e693d 100644 --- a/docs/api-reference/endpoints/workspaces/list-identity-memberships.mdx +++ b/docs/api-reference/endpoints/workspaces/list-identity-memberships.mdx @@ -1,4 +1,4 @@ --- title: "List Identity Memberships" -openapi: "GET /api/v2/workspace/{workspaceId}/identity-memberships" ---- \ No newline at end of file +openapi: "GET /api/v2/workspace/{projectId}/identity-memberships" +--- diff --git a/docs/api-reference/endpoints/workspaces/memberships.mdx b/docs/api-reference/endpoints/workspaces/memberships.mdx index 386c8a089b..3c4735f943 100644 --- a/docs/api-reference/endpoints/workspaces/memberships.mdx +++ b/docs/api-reference/endpoints/workspaces/memberships.mdx @@ -1,4 +1,4 @@ --- title: "Get User Memberships" -openapi: "GET /api/v2/workspace/{workspaceId}/memberships" +openapi: "GET /api/v1/workspace/{workspaceId}/memberships" --- diff --git a/docs/api-reference/endpoints/workspaces/rollback-snapshot.mdx b/docs/api-reference/endpoints/workspaces/rollback-snapshot.mdx index 8b648a4007..527c861b28 100644 --- a/docs/api-reference/endpoints/workspaces/rollback-snapshot.mdx +++ b/docs/api-reference/endpoints/workspaces/rollback-snapshot.mdx @@ -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" --- diff --git a/docs/api-reference/endpoints/workspaces/update-identity-membership.mdx b/docs/api-reference/endpoints/workspaces/update-identity-membership.mdx index 398c7bc812..667cf7eb34 100644 --- a/docs/api-reference/endpoints/workspaces/update-identity-membership.mdx +++ b/docs/api-reference/endpoints/workspaces/update-identity-membership.mdx @@ -1,4 +1,4 @@ --- title: "Update Identity Membership" -openapi: "PATCH /api/v2/workspace/{workspaceId}/identity-memberships/{identityId}" ---- \ No newline at end of file +openapi: "PATCH /api/v2/workspace/{projectId}/identity-memberships/{identityId}" +--- diff --git a/docs/api-reference/endpoints/workspaces/update-membership.mdx b/docs/api-reference/endpoints/workspaces/update-membership.mdx index f0ef154129..9a7aa600f0 100644 --- a/docs/api-reference/endpoints/workspaces/update-membership.mdx +++ b/docs/api-reference/endpoints/workspaces/update-membership.mdx @@ -1,4 +1,4 @@ --- title: "Update User Membership" -openapi: "PATCH /api/v2/workspace/{workspaceId}/memberships/{membershipId}" +openapi: "PATCH /api/v1/workspace/{workspaceId}/memberships/{membershipId}" --- diff --git a/docs/contributing/platform/backend/folder-structure.mdx b/docs/contributing/platform/backend/folder-structure.mdx new file mode 100644 index 0000000000..abfe0f69d8 --- /dev/null +++ b/docs/contributing/platform/backend/folder-structure.mdx @@ -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. \ No newline at end of file diff --git a/docs/contributing/platform/backend/how-to-create-a-feature.mdx b/docs/contributing/platform/backend/how-to-create-a-feature.mdx new file mode 100644 index 0000000000..e77313dab1 --- /dev/null +++ b/docs/contributing/platform/backend/how-to-create-a-feature.mdx @@ -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/_.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..`. + +## 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/` + 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. \ No newline at end of file diff --git a/docs/documentation/platform/identities/overview.mdx b/docs/documentation/platform/identities/overview.mdx index d6366211f6..7a47514877 100644 --- a/docs/documentation/platform/identities/overview.mdx +++ b/docs/documentation/platform/identities/overview.mdx @@ -4,7 +4,7 @@ description: "Programmatically interact with Infisical" --- - 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. @@ -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. - \ No newline at end of file + diff --git a/docs/images/guides/agent-with-ecs/access-token-deposit.png b/docs/images/guides/agent-with-ecs/access-token-deposit.png new file mode 100644 index 0000000000..8bf3b04504 Binary files /dev/null and b/docs/images/guides/agent-with-ecs/access-token-deposit.png differ diff --git a/docs/images/guides/agent-with-ecs/ecs-diagram.png b/docs/images/guides/agent-with-ecs/ecs-diagram.png new file mode 100644 index 0000000000..ee159017cf Binary files /dev/null and b/docs/images/guides/agent-with-ecs/ecs-diagram.png differ diff --git a/docs/images/guides/agent-with-ecs/file_browser_main.png b/docs/images/guides/agent-with-ecs/file_browser_main.png new file mode 100644 index 0000000000..402583aa8c Binary files /dev/null and b/docs/images/guides/agent-with-ecs/file_browser_main.png differ diff --git a/docs/images/guides/agent-with-ecs/filebrowser_afterlogin.png b/docs/images/guides/agent-with-ecs/filebrowser_afterlogin.png new file mode 100644 index 0000000000..b3caab8d35 Binary files /dev/null and b/docs/images/guides/agent-with-ecs/filebrowser_afterlogin.png differ diff --git a/docs/images/guides/agent-with-ecs/secrets-deposit.png b/docs/images/guides/agent-with-ecs/secrets-deposit.png new file mode 100644 index 0000000000..19b3eedd7b Binary files /dev/null and b/docs/images/guides/agent-with-ecs/secrets-deposit.png differ diff --git a/docs/images/integrations/jenkins/jenkins_11.png b/docs/images/integrations/jenkins/jenkins_11.png index 577cca4c58..61f1e364f4 100644 Binary files a/docs/images/integrations/jenkins/jenkins_11.png and b/docs/images/integrations/jenkins/jenkins_11.png differ diff --git a/docs/images/integrations/jenkins/jenkins_4.png b/docs/images/integrations/jenkins/jenkins_4.png index 1103da236b..9e7360e979 100644 Binary files a/docs/images/integrations/jenkins/jenkins_4.png and b/docs/images/integrations/jenkins/jenkins_4.png differ diff --git a/docs/images/integrations/jenkins/jenkins_5.png b/docs/images/integrations/jenkins/jenkins_5.png index 824cacfffb..9491df3021 100644 Binary files a/docs/images/integrations/jenkins/jenkins_5.png and b/docs/images/integrations/jenkins/jenkins_5.png differ diff --git a/docs/images/integrations/jenkins/jenkins_9.png b/docs/images/integrations/jenkins/jenkins_9.png index 109d7305b2..81bd4f2baa 100644 Binary files a/docs/images/integrations/jenkins/jenkins_9.png and b/docs/images/integrations/jenkins/jenkins_9.png differ diff --git a/docs/images/project-token-old-add.png b/docs/images/project-token-old-add.png index 960013a3f2..c8d1b9e050 100644 Binary files a/docs/images/project-token-old-add.png and b/docs/images/project-token-old-add.png differ diff --git a/docs/integrations/cicd/jenkins.mdx b/docs/integrations/cicd/jenkins.mdx index 58c92d2180..9184aef442 100644 --- a/docs/integrations/cicd/jenkins.mdx +++ b/docs/integrations/cicd/jenkins.mdx @@ -3,22 +3,32 @@ title: "Jenkins" description: "How to effectively and securely manage secrets in Jenkins using Infisical" --- +**Objective**: Fetch secrets from Infisical to Jenkins pipelines + +In this guide, we'll outline the steps to deliver secrets from Infisical to Jenkins via the Infisical CLI. +At a high level, the Infisical CLI will be executed within your build environment and use a service token to authenticate with Infisical. +This token must be added as a Jenkins Credential and then passed to the Infisical CLI as an environment variable, enabling it to access and retrieve secrets within your workflows. + Prerequisites: - Set up and add secrets to [Infisical](https://app.infisical.com). - You have a working Jenkins installation with the [credentials plugin](https://plugins.jenkins.io/credentials/) installed. -- You have the Infisical CLI installed on your Jenkins executor nodes or container images. +- You have the [Infisical CLI](/cli/overview) installed on your Jenkins executor nodes or container images. + ## Add Infisical Service Token to Jenkins -After setting up your project in Infisical and adding the Infisical CLI to container images, you will need to add the Infisical Service Token to Jenkins. Once you have generated the token, browse to **Manage Jenkins > Manage Credentials** in your Jenkins installation. +After setting up your project in Infisical and installing the Infisical CLI to the environment where your Jenkins builds will run, you will need to add the Infisical Service Token to Jenkins. + +To generate a Infisical service token, follow the guide [here](/documentation/platform/token). +Once you have generated the token, navigate to **Manage Jenkins > Manage Credentials** in your Jenkins instance. ![Jenkins step 1](../../images/integrations/jenkins/jenkins_1.png) Click on the credential store you want to store the Infisical Service Token in. In this case, we're using the default Jenkins global store. - Each of your projects will have a different INFISICAL_SERVICE_TOKEN though. + Each of your projects will have a different `INFISICAL_TOKEN`. As a result, it may make sense to spread these out into separate credential domains depending on your use case. @@ -28,18 +38,22 @@ Now, click Add Credentials. ![Jenkins step 3](../../images/integrations/jenkins/jenkins_3.png) -Choose **Secret text** from the **Kind** dropdown menu, paste the Infisical Service Token into the **Secret** field, enter `INFISICAL_SERVICE_TOKEN` into the **Description** field, and click **OK**. +Choose **Secret text** for the **Kind** option from the dropdown list and enter the Infisical Service Token in the **Secret** field. +Although the **ID** can be any value, we'll set it to `infisical-service-token` for the sake of this guide. +The description is optional and can be any text you prefer. + ![Jenkins step 4](../../images/integrations/jenkins/jenkins_4.png) -When you're done, you should have a credential similar to the one below: +When you're done, you should see a credential similar to the one below: ![Jenkins step 5](../../images/integrations/jenkins/jenkins_5.png) ## Use Infisical in a Freestyle Project -To use Infisical in a Freestyle Project job, you'll need to expose the credential you created above in an environment variable. First, click New Item from the dashboard navigation sidebar: +To fetch secrets with Infisical in a Freestyle Project job, you'll need to expose the credential you created above as an environment variable to the Infisical CLI. +To do so, first click **New Item** from the dashboard navigation sidebar: ![Jenkins step 6](../../images/integrations/jenkins/jenkins_6.png) @@ -51,7 +65,8 @@ Scroll down to the **Build Environment** section and enable the **Use secret tex ![Jenkins step 8](../../images/integrations/jenkins/jenkins_8.png) -Enter INFISICAL_SERVICE_TOKEN in the **Variable** field, select the **Specific credentials** option from the Credentials section and choose INFISICAL_SERVICE_TOKEN from the dropdown menu. +Enter `INFISICAL_TOKEN` in the **Variable** field then click the **Specific credentials** option from the Credentials section and select the credential you created earlier. +In this case, we saved it as `Infisical service token` so we'll choose that from the dropdown menu. ![Jenkins step 9](../../images/integrations/jenkins/jenkins_9.png) @@ -59,15 +74,16 @@ Scroll down to the **Build** section and choose **Execute shell** from the **Add ![Jenkins step 10](../../images/integrations/jenkins/jenkins_10.png) -In the command field, enter the following command and click **Save**: +In the command field, you can now use the Infisical CLI to fetch secrets. +The example command below will print the secrets using the service token passed as a credential. When done, click **Save**. ``` -infisical run -- printenv +infisical secrets --env=dev --path=/ ``` ![Jenkins step 11](../../images/integrations/jenkins/jenkins_11.png) -Finally, click **Build Now** from the navigation sidebar to test your new job. +Finally, click **Build Now** from the navigation sidebar to run your new job. Running into issues? Join Infisical's [community Slack](https://infisical.com/slack) for quick support. @@ -77,7 +93,8 @@ Finally, click **Build Now** from the navigation sidebar to test your new job. ## Use Infisical in a Jenkins Pipeline -To use Infisical in a Pipeline job, you'll need to expose the credential you created above as an environment variable. First, click **New Item** from the dashboard navigation sidebar: +To fetch secrets using Infisical in a Pipeline job, you'll need to expose the Jenkins credential you created above as an environment variable. +To do so, click **New Item** from the dashboard navigation sidebar: ![Jenkins step 6](../../images/integrations/jenkins/jenkins_6.png) @@ -92,31 +109,31 @@ pipeline { agent any environment { - INFISICAL_SERVICE_TOKEN = credentials('INFISICAL_SERVICE_TOKEN') + INFISICAL_TOKEN = credentials('infisical-service-token') } stages { stage('Run Infisical') { steps { - sh("infisical secrets") + sh("infisical secrets --env=dev --path=/") // doesn't work // sh("docker run --rm test-container infisical secrets") // works - // sh("docker run -e INFISICAL_SERVICE_TOKEN=${INFISICAL_SERVICE_TOKEN} --rm test-container infisical secrets") + // sh("docker run -e INFISICAL_TOKEN=${INFISICAL_TOKEN} --rm test-container infisical secrets --env=dev --path=/") // doesn't work // sh("docker-compose up -d") // works - // sh("INFISICAL_SERVICE_TOKEN=${INFISICAL_SERVICE_TOKEN} docker-compose up -d") + // sh("INFISICAL_TOKEN=${INFISICAL_TOKEN} docker-compose up -d") } } } } ``` -This is a very basic sample that you can work from. Jenkins injects the INFISICAL_SERVICE_TOKEN environment variable defined in the pipeline into the shell the commands execute with, but there are some situations where that won't pass through properly – notably if you're executing docker containers on the executor machine. The examples above should give you some idea for how that will work. - -Finally, click **Build Now** from the navigation sidebar to test your new job. +The example provided above serves as an initial guide. It shows how Jenkins adds the `INFISICAL_TOKEN` environment variable, which is configured in the pipeline, into the shell for executing commands. +There may be instances where this doesn't work as expected in the context of running Docker commands. +However, the list of working examples should provide some insight into how this can be handled properly. diff --git a/docs/integrations/platforms/ecs-with-agent.mdx b/docs/integrations/platforms/ecs-with-agent.mdx new file mode 100644 index 0000000000..bbb88ea645 --- /dev/null +++ b/docs/integrations/platforms/ecs-with-agent.mdx @@ -0,0 +1,287 @@ +--- +title: 'Amazon ECS' +description: "How to deliver secrets to Amazon Elastic Container Service" +--- + +![ecs diagram](/images/guides/agent-with-ecs/ecs-diagram.png) + +This guide will go over the steps needed to access secrets stored in Infisical from Amazon Elastic Container Service (ECS). + +At a high level, the steps involve setting up an ECS task with a [Infisical Agent](/infisical-agent/overview) as a sidecar container. This sidecar container uses [Universal Auth](/documentation/platform/identities/universal-auth) to authenticate with Infisical to fetch secrets/access tokens. +Once the secrets/access tokens are retrieved, they are then stored in a shared [Amazon Elastic File System](https://aws.amazon.com/efs/) (EFS) volume. This volume is then made accessible to your application and all of its replicas. + +This guide primarily focuses on integrating Infisical Cloud with Amazon ECS on AWS Fargate and Amazon EFS. +However, the principles and steps can be adapted for use with any instance of Infisical (on premise or cloud) and different ECS launch configurations. + +## Prerequisites +This guide requires the following prerequisites: +- Infisical account +- Git installed +- Terraform v1.0 or later installed +- Access to AWS credentials +- Understanding of [Infisical Agent](/infisical-agent/overview) + +## What we will deploy +For this demonstration, we'll deploy the [File Browser](https://github.com/filebrowser/filebrowser) application on our ECS cluster. +Although this guide focuses on File Browser, the principles outlined here can be applied to any application of your choice. + +File Browser plays a key role in this context because it enables us to view all files attached to a specific volume. +This feature is important for our demonstration, as it allows us to verify whether the Infisical agent is depositing the expected files into the designated file volume and if those files are accessible to the application. + + +Volumes that contain sensitive secrets should not be publicly accessible. The use of File Browser here is solely for demonstration and verification purposes. + + + +## Configure Authentication with Infisical +In order for the Infisical agent to fetch credentials from Infisical, we'll first need to authenticate with Infisical. +While Infisical supports various authentication methods, this guide focuses on using Universal Auth to authenticate the agent with Infisical. + +Follow the documentation to configure and generate a client id and client secret with Universal auth [here](/documentation/platform/identities/universal-auth). +Make sure to save these credentials somewhere handy because you'll need them soon. + +## Clone guide assets repository +To help you quickly deploy the example application, please clone the guide assets from this [Github repository](https://github.com/Infisical/infisical-guides.git). +This repository contains assets for all Infisical guides. The content for this guide can be found within a sub directory called `aws-ecs-with-agent`. +The guide will assume that `aws-ecs-with-agent` is your working directory going forward. + +## Deploy example application + +Before we can deploy our full application and its related infrastructure with Terraform, we'll need to first configure our Infisical agent. + +### Agent configuration overview +The agent config file defines what authentication method will be used when connecting with Infisical along with where the fetched secrets/access tokens should be saved to. + +Since the Infisical agent will be deployed as a sidecar, the agent configuration file and any secret template files will need to be encoded in base64. +This encoding step is necessary as it allows these files to be added into our Terraform configuration file without needing to upload them first. + +#### Secret template file +The Infisical agent accepts one or more optional template files. If provided, the agent will fetch secrets using the set authentication method and format the fetched secrets according to the given template file. + +For demonstration purposes, we will create the following secret template file. +This template will transform our secrets from Infisical project with the ID `62fd92aa8b63973fee23dec7`, in the `dev` environment, and secrets located in the path `/`, into a `KEY=VALUE` format. + + + Remember to update the project id, environment slug and secret path to one that exists within your Infisical project + + +```secrets.template secrets.template +{{- with secret "62fd92aa8b63973fee23dec7" "dev" "/" }} +{{- range . }} +{{ .Key }}={{ .Value }} +{{- end }} +{{- end }} +``` + +Next, we need encode this template file in `base64` so it can be set in the agent configuration file. + +```bash +cat secrets.template | base64 +Cnt7LSB3aXRoIHNlY3JldCAiMWVkMjk2MWQtNDM5NS00MmNlLTlkNzQtYjk2ZGQwYmYzMDg0IiAiZGV2IiAiLyIgfX0Ke3stIHJhbmdlIC4gfX0Ke3sgLktleSB9fT17eyAuVmFsdWUgfX0Ke3stIGVuZCB9fQp7ey0gZW5kIH19 +``` + +#### Full agent configuration file +This agent config file will connect with Infisical Cloud using Universal Auth and deposit access tokens at path `/infisical-agent/access-token` and render secrets to file `/infisical-agent/secrets`. + +You'll notice that instead of passing the path to the secret template file as we normally would, we set the base64 encoded template from the previous step under `base64-template-content` property. + +```yaml agent-config.yaml +infisical: + address: https://app.infisical.com + exit-after-auth: true +auth: + type: universal-auth + config: + remove_client_secret_on_read: false +sinks: + - type: file + config: + path: /infisical-agent/access-token +templates: + - base64-template-content: Cnt7LSB3aXRoIHNlY3JldCAiMWVkMjk2MWQtNDM5NS00MmNlLTlkNzQtYjk2ZGQwYmYzMDg0IiAiZGV2IiAiLyIgfX0Ke3stIHJhbmdlIC4gfX0Ke3sgLktleSB9fT17eyAuVmFsdWUgfX0Ke3stIGVuZCB9fQp7ey0gZW5kIH19 + destination-path: /infisical-agent/secrets +``` + +Again, we'll need to encode the full configuration file in `base64` so it can be easily delivered via Terraform. + +```bash +cat agent-config.yaml | base64 +aW5maXNpY2FsOgogIGFkZHJlc3M6IGh0dHBzOi8vYXBwLmluZmlzaWNhbC5jb20KICBleGl0LWFmdGVyLWF1dGg6IHRydWUKYXV0aDoKICB0eXBlOiB1bml2ZXJzYWwtYXV0aAogIGNvbmZpZzoKICAgIHJlbW92ZV9jbGllbnRfc2VjcmV0X29uX3JlYWQ6IGZhbHNlCnNpbmtzOgogIC0gdHlwZTogZmlsZQogICAgY29uZmlnOgogICAgICBwYXRoOiAvaW5maXNpY2FsLWFnZW50L2FjY2Vzcy10b2tlbgp0ZW1wbGF0ZXM6CiAgLSBiYXNlNjQtdGVtcGxhdGUtY29udGVudDogQ250N0xTQjNhWFJvSUhObFkzSmxkQ0FpTVdWa01qazJNV1F0TkRNNU5TMDBNbU5sTFRsa056UXRZamsyWkdRd1ltWXpNRGcwSWlBaVpHVjJJaUFpTHlJZ2ZYMEtlM3N0SUhKaGJtZGxJQzRnZlgwS2Uzc2dMa3RsZVNCOWZUMTdleUF1Vm1Gc2RXVWdmWDBLZTNzdElHVnVaQ0I5ZlFwN2V5MGdaVzVrSUgxOQogICAgZGVzdGluYXRpb24tcGF0aDogL2luZmlzaWNhbC1hZ2VudC9zZWNyZXRzCg== +``` + +## Add auth credentials & agent config +With the base64 encoded agent config file and Universal Auth credentials in hand, it's time to assign them as values in our Terraform config file. + +To configure these values, navigate to the `ecs.tf` file in your preferred code editor and assign values to `auth_client_id`, `auth_client_secret`, and `agent_config`. + +```hcl ecs.tf +...snip... +data "template_file" "cb_app" { + template = file("./templates/ecs/cb_app.json.tpl") + + vars = { + app_image = var.app_image + sidecar_image = var.sidecar_image + app_port = var.app_port + fargate_cpu = var.fargate_cpu + fargate_memory = var.fargate_memory + aws_region = var.aws_region + auth_client_id = "" + auth_client_secret = "" + agent_config = "" + } +} +...snip... +``` + + + To keep this guide simple, `auth_client_id`, `auth_client_secret` have been added directly into the ECS container definition. + However, in production, you should securely fetch these values from AWS Secrets Manager or AWS Parameter store and feed them directly to agent sidecar. + + +After these values have been set, they will be passed to the Infisical agent during startup through environment variables, as configured in the `infisical-sidecar` container below. + +```terraform templates/ecs/cb_app.json.tpl +[ +...snip... + { + "name": "infisical-sidecar", + "image": "${sidecar_image}", + "cpu": 1024, + "memory": 1024, + "networkMode": "bridge", + "command": ["agent"], + "essential": false, + "logConfiguration": { + "logDriver": "awslogs", + "options": { + "awslogs-group": "/ecs/agent", + "awslogs-region": "${aws_region}", + "awslogs-stream-prefix": "ecs" + } + }, + "healthCheck": { + "command": ["CMD-SHELL", "agent", "--help"], + "interval": 30, + "timeout": 5, + "retries": 3, + "startPeriod": 0 + }, + "environment": [ + { + "name": "INFISICAL_UNIVERSAL_AUTH_CLIENT_ID", + "value": "${auth_client_id}" + }, + { + "name": "INFISICAL_UNIVERSAL_CLIENT_SECRET", + "value": "${auth_client_secret}" + }, + { + "name": "INFISICAL_AGENT_CONFIG_BASE64", + "value": "${agent_config}" + } + ], + "mountPoints": [ + { + "containerPath": "/infisical-agent", + "sourceVolume": "infisical-efs" + } + ] + } +] +``` + +In the above container definition, you'll notice that that the Infisical agent has a `mountPoints` defined. +This mount point is referencing to the already configured EFS volume as shown below. +`containerPath` is set to `/infisical-agent` because that is that the folder we have instructed the agent to deposit the credentials to. + +```hcl terraform/efs.tf +resource "aws_efs_file_system" "infisical_efs" { + tags = { + Name = "INFISICAL-ECS-EFS" + } +} + +resource "aws_efs_mount_target" "mount" { + count = length(aws_subnet.private.*.id) + file_system_id = aws_efs_file_system.infisical_efs.id + subnet_id = aws_subnet.private[count.index].id + security_groups = [aws_security_group.efs_sg.id] +} +``` + +## Configure AWS credentials +Because we'll be deploying the example file browser application to AWS via Terraform, you will need to obtain a set of `AWS Access Key` and `Secret Key`. +Once you have generated these credentials, export them to your terminal. + +1. Export the AWS Access Key ID: + + ```bash + export AWS_ACCESS_KEY_ID= + ``` + +2. Export the AWS Secret Access Key: + + ```bash + export AWS_SECRET_ACCESS_KEY= + ``` + +## Deploy terraform configuration +With the agent's sidecar configuration complete, we can now deploy our changes to AWS via Terraform. + +1. Change your directory to `terraform` +```sh +cd terraform +``` + +2. Initialize Terraform +``` +$ terraform init +``` + +3. Preview resources that will be created +``` +$ terraform plan +``` + +4. Trigger resource creation +```bash +$ terraform apply + +Do you want to perform these actions? + Terraform will perform the actions described above. + Only 'yes' will be accepted to approve. + + Enter a value: yes +``` + +```bash + +Apply complete! Resources: 1 added, 1 changed, 1 destroyed. + +Outputs: + +alb_hostname = "cb-load-balancer-1675475779.us-east-1.elb.amazonaws.com:8080" +``` + +Once the resources have been successfully deployed, Terrafrom will output the host address where the file browser application will be accessible. +It may take a few minutes for the application to become fully ready. + + +## Verify secrets/tokens in EFS volume +To verify that the agent is depositing access tokens and rendering secrets to the paths specified in the agent config, navigate to the web address from the previous step. +Once you visit the address, you'll be prompted to login. Enter the credentials shown below. + +![file browser main login page](/images/guides/agent-with-ecs/file_browser_main.png) + +Since our EFS volume is mounted to the path of the file browser application, we should see the access token and rendered secret file we defined via the agent config file. + +![file browswer dashbaord](/images/guides/agent-with-ecs/filebrowser_afterlogin.png) + +As expected, two files are present: `access-token` and `secrets`. +The `access-token` file should hold a valid `Bearer` token, which can be used to make HTTP requests to Infisical. +The `secrets` file should contain secrets, formatted according to the specifications in our secret template file (presented in key=value format). + +![file browser access token deposit](/images/guides/agent-with-ecs/access-token-deposit.png) + +![file browser secrets render](/images/guides/agent-with-ecs/secrets-deposit.png) \ No newline at end of file diff --git a/docs/mint.json b/docs/mint.json index 1f8dc618bf..b67493aeba 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -1,5 +1,6 @@ { "name": "Infisical", + "openapi": "https://app.infisical.com/api/docs/json", "logo": { "dark": "/logo/dark.svg", "light": "/logo/light.svg", @@ -233,7 +234,8 @@ }, "integrations/platforms/kubernetes", "integrations/frameworks/terraform", - "integrations/platforms/ansible" + "integrations/platforms/ansible", + "integrations/platforms/ecs-with-agent" ] }, { @@ -462,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" ] }, { diff --git a/docs/spec.yaml b/docs/spec.yaml deleted file mode 100644 index c3d0503953..0000000000 --- a/docs/spec.yaml +++ /dev/null @@ -1,5152 +0,0 @@ -openapi: 3.0.0 -info: - title: Infisical API - description: List of all available APIs that can be consumed - version: 1.0.0 -servers: - - url: https://app.infisical.com - description: Production server - - url: http://localhost:8080 - description: Local server -paths: - /api/v1/identities/: - post: - summary: Create identity - description: Create identity - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - identity: - $ref: '#/components/schemas/Identity' - description: Details of the created identity - security: - - bearerAuth: [] - requestBody: - content: - application/json: - schema: - type: object - properties: - name: - type: string - description: Name of entity to create - example: development - organizationId: - type: string - description: ID of organization where to create identity - example: dev-environment - role: - type: string - description: Role to assume for organization membership - example: no-access - required: - - name - - organizationId - - role - /api/v1/identities/{identityId}: - patch: - summary: Update identity - description: Update identity - parameters: - - name: identityId - in: path - required: true - schema: - type: string - description: ID of identity to update - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - identity: - $ref: '#/components/schemas/Identity' - description: Details of the updated identity - security: - - bearerAuth: [] - requestBody: - content: - application/json: - schema: - type: object - properties: - name: - type: string - description: Name of entity to update to - example: development - role: - type: string - description: Role to update to for organization membership - example: no-access - delete: - summary: Delete identity - description: Delete identity - parameters: - - name: identityId - in: path - required: true - schema: - type: string - description: ID of identity - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - identity: - $ref: '#/components/schemas/Identity' - description: Details of the deleted identity - security: - - bearerAuth: [] - /api/v1/secret/{secretId}/secret-versions: - get: - summary: Return secret versions - description: Return secret versions - parameters: - - name: secretId - in: path - required: true - schema: - type: string - description: ID of secret - - name: offset - description: Number of versions to skip - required: false - in: query - schema: - type: string - - name: limit - description: Maximum number of versions to return - required: false - in: query - schema: - type: string - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - secretVersions: - type: array - items: - $ref: '#/components/schemas/SecretVersion' - description: Secret versions - security: - - apiKeyAuth: [] - /api/v1/secret/{secretId}/secret-versions/rollback: - post: - summary: Roll back secret to a version. - description: Roll back secret to a version. - parameters: - - name: secretId - in: path - required: true - schema: - type: string - description: ID of secret - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - secret: - type: object - $ref: '#/components/schemas/Secret' - description: Secret rolled back to - security: - - apiKeyAuth: [] - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - version: - type: integer - description: Version of secret to roll back to - /api/v1/secret-snapshot/{secretSnapshotId}: - get: - description: '' - parameters: - - name: secretSnapshotId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/users/me/ip: - get: - description: '' - responses: - '200': - description: OK - /api/v1/workspace/{workspaceId}/secret-snapshots: - get: - summary: Return project secret snapshot ids - description: Return project secret snapshots ids - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - description: ID of project where to get secret snapshots for - - name: environment - description: Slug of environment where to get secret snapshots for - required: true - in: query - schema: - type: string - - name: directory - description: >- - Path where to get secret snapshots for like / or /foo/bar. Default - is / - required: false - in: query - schema: - type: string - - name: offset - description: Number of secret snapshots to skip - required: false - in: query - schema: - type: string - - name: limit - description: Maximum number of secret snapshots to return - required: false - in: query - schema: - type: string - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - secretSnapshots: - type: array - items: - $ref: '#/components/schemas/SecretSnapshot' - description: Project secret snapshots - security: - - apiKeyAuth: [] - bearerAuth: [] - /api/v1/workspace/{workspaceId}/secret-snapshots/count: - get: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/workspace/{workspaceId}/secret-snapshots/rollback: - post: - summary: >- - Roll back project secrets to those captured in a secret snapshot - version. - description: >- - Roll back project secrets to those captured in a secret snapshot - version. - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - description: ID of project where to roll back - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - secrets: - type: array - items: - $ref: '#/components/schemas/Secret' - description: Secrets rolled back to - security: - - apiKeyAuth: [] - bearerAuth: [] - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - environment: - type: string - description: Slug of environment where to roll back - directory: - type: string - description: Path where to roll back for like / or /foo/bar. Default is / - version: - type: integer - description: Version of secret snapshot to roll back to - /api/v1/workspace/{workspaceId}/audit-logs: - get: - summary: Return audit logs - description: Return audit logs - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - description: ID of the workspace where to get folders from - - name: offset - description: Number of logs to skip before starting to return logs for pagination - required: false - in: query - schema: - type: string - - name: limit - description: Maximum number of logs to return for pagination - required: false - in: query - schema: - type: string - - name: startDate - description: Filter logs from this date in ISO-8601 format - required: false - in: query - schema: - type: string - - name: endDate - description: Filter logs till this date in ISO-8601 format - required: false - in: query - schema: - type: string - - name: eventType - description: >- - Filter by type of event such as get-secrets, get-secret, - create-secret, update-secret, delete-secret, etc. - required: false - in: query - schema: - type: string - - name: userAgentType - description: Filter by type of user agent such as web, cli, k8-operator, or other - required: false - in: query - schema: - type: string - - name: actor - description: Filter by actor such as user or service - required: false - in: query - schema: - type: string - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - auditLogs: - type: array - items: - $ref: '#/components/schemas/AuditLog' - description: List of audit log - security: - - apiKeyAuth: [] - /api/v1/workspace/{workspaceId}/audit-logs/filters/actors: - get: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/workspace/{workspaceId}/trusted-ips: - get: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - post: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - '400': - description: Bad Request - /api/v1/workspace/{workspaceId}/trusted-ips/{trustedIpId}: - patch: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - - name: trustedIpId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - '400': - description: Bad Request - delete: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - - name: trustedIpId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - '400': - description: Bad Request - /api/v1/organizations/{organizationId}/plans/table: - get: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/organizations/{organizationId}/plan: - get: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/organizations/{organizationId}/session/trial: - post: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/organizations/{organizationId}/plan/billing: - get: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/organizations/{organizationId}/plan/table: - get: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/organizations/{organizationId}/billing-details: - get: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - patch: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/organizations/{organizationId}/billing-details/payment-methods: - get: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - post: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/organizations/{organizationId}/billing-details/payment-methods/{pmtMethodId}: - delete: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - - name: pmtMethodId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/organizations/{organizationId}/billing-details/tax-ids: - get: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - post: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/organizations/{organizationId}/billing-details/tax-ids/{taxId}: - delete: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - - name: taxId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/organizations/{organizationId}/invoices: - get: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/organizations/{organizationId}/licenses: - get: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/sso/redirect/saml2/{ssoIdentifier}: - get: - description: '' - parameters: - - name: ssoIdentifier - in: path - required: true - schema: - type: string - - name: callback_port - in: query - schema: - type: string - responses: - default: - description: '' - /api/v1/sso/saml2/{ssoIdentifier}: - post: - description: '' - parameters: - - name: ssoIdentifier - in: path - required: true - schema: - type: string - responses: - default: - description: '' - /api/v1/sso/config: - get: - description: '' - responses: - '200': - description: OK - post: - description: '' - responses: - '200': - description: OK - '400': - description: Bad Request - patch: - description: '' - responses: - '200': - description: OK - '400': - description: Bad Request - /api/v1/cloud-products/: - get: - description: '' - responses: - '200': - description: OK - /api/v3/api-key/: - post: - description: '' - responses: - '200': - description: OK - /api/v3/api-key/{apiKeyDataId}: - patch: - description: '' - parameters: - - name: apiKeyDataId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - delete: - description: '' - parameters: - - name: apiKeyDataId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/secret-rotation-providers/{workspaceId}: - get: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/secret-rotations/: - post: - description: '' - responses: - '200': - description: OK - get: - description: '' - responses: - '200': - description: OK - /api/v1/secret-rotations/restart: - post: - description: '' - responses: - '200': - description: OK - /api/v1/secret-rotations/{id}: - delete: - description: '' - parameters: - - name: id - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/signup/email/signup: - post: - description: '' - responses: - '200': - description: OK - '403': - description: Forbidden - /api/v1/signup/email/verify: - post: - description: '' - responses: - '200': - description: OK - '403': - description: Forbidden - /api/v1/auth/token: - post: - description: '' - responses: - '200': - description: OK - /api/v1/auth/login1: - post: - description: '' - responses: - '200': - description: OK - /api/v1/auth/login2: - post: - description: '' - parameters: - - name: user-agent - in: header - schema: - type: string - responses: - '200': - description: OK - '400': - description: Bad Request - /api/v1/auth/logout: - post: - description: '' - responses: - '200': - description: OK - /api/v1/auth/checkAuth: - post: - description: '' - responses: - '200': - description: OK - /api/v1/auth/sessions: - delete: - description: '' - responses: - '200': - description: OK - /api/v1/auth/token/renew: - post: - summary: Renew access token - description: Renew access token - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - accessToken: - type: string - description: (Same) Access token after successful renewal - expiresIn: - type: number - description: TTL of access token in seconds - tokenType: - type: string - description: Type of access token (e.g. Bearer) - description: Access token and its details - requestBody: - content: - application/json: - schema: - type: object - properties: - accessToken: - type: string - description: Access token to renew - example: ... - /api/v1/auth/universal-auth/login: - post: - summary: Login with Universal Auth - description: Login with Universal Auth - parameters: - - name: user-agent - in: header - schema: - type: string - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - accessToken: - type: string - description: Access token issued after successful login - expiresIn: - type: number - description: TTL of access token in seconds - tokenType: - type: string - description: Type of access token (e.g. Bearer) - description: Access token and its details - requestBody: - content: - application/json: - schema: - type: object - properties: - clientId: - type: string - description: Client ID for identity to login with Universal Auth - example: ... - clientSecret: - type: string - description: Client Secret for identity to login with Universal Auth - example: ... - /api/v1/auth/universal-auth/identities/{identityId}: - post: - summary: Attach Universal Auth configuration onto identity - description: Attach Universal Auth configuration onto identity - parameters: - - name: identityId - in: path - required: true - schema: - type: string - description: ID of identity to attach Universal Auth onto - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - identityUniversalAuth: - $ref: '#/components/schemas/IdentityUniversalAuth' - description: Details of attached Universal Auth - '400': - description: Bad Request - security: - - bearerAuth: [] - requestBody: - content: - application/json: - schema: - type: object - properties: - clientSecretTrustedIps: - type: array - items: - type: object - properties: - ipAddress: - type: string - description: IP address to trust - default: 0.0.0.0/0 - description: >- - List of IPs or CIDR ranges that the Client Secret can be - used from together with the Client ID to get back an access - token. By default, Client Secrets are given the 0.0.0.0/0 - entry representing all possible IPv4 addresses. - example: ... - default: - - ipAddress: 0.0.0.0/0 - accessTokenTTL: - type: number - description: >- - The incremental lifetime for an acccess token in seconds; a - value of 0 implies an infinite incremental lifetime. - example: ... - default: 100 - accessTokenMaxTTL: - type: number - description: >- - The maximum lifetime for an acccess token in seconds; a - value of 0 implies an infinite maximum lifetime. - example: ... - default: 2592000 - accessTokenNumUsesLimit: - type: number - description: >- - The maximum number of times that an access token can be - used; a value of 0 implies infinite number of uses. - example: ... - default: 0 - accessTokenTrustedIps: - type: array - items: - type: object - properties: - ipAddress: - type: string - description: IP address to trust - default: 0.0.0.0/0 - description: >- - List of IPs or CIDR ranges that access tokens can be used - from. By default, each token is given the 0.0.0.0/0 entry - representing all possible IPv4 addresses. - example: ... - default: - - ipAddress: 0.0.0.0/0 - patch: - summary: Update Universal Auth configuration on identity - description: Update Universal Auth configuration on identity - parameters: - - name: identityId - in: path - required: true - schema: - type: string - description: ID of identity to update Universal Auth on - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - identityUniversalAuth: - $ref: '#/components/schemas/IdentityUniversalAuth' - description: Details of updated Universal Auth - '400': - description: Bad Request - security: - - bearerAuth: [] - requestBody: - content: - application/json: - schema: - type: object - properties: - clientSecretTrustedIps: - type: array - items: - type: object - properties: - ipAddress: - type: string - description: IP address to trust - description: >- - List of IPs or CIDR ranges that the Client Secret can be - used from together with the Client ID to get back an access - token. By default, Client Secrets are given the 0.0.0.0/0 - entry representing all possible IPv4 addresses. - example: ... - accessTokenTTL: - type: number - description: >- - The incremental lifetime for an acccess token in seconds; a - value of 0 implies an infinite incremental lifetime. - example: ... - accessTokenMaxTTL: - type: number - description: >- - The maximum lifetime for an acccess token in seconds; a - value of 0 implies an infinite maximum lifetime. - example: ... - accessTokenNumUsesLimit: - type: number - description: >- - The maximum number of times that an access token can be - used; a value of 0 implies infinite number of uses. - example: ... - accessTokenTrustedIps: - type: array - items: - type: object - properties: - ipAddress: - type: string - description: IP address to trust - description: >- - List of IPs or CIDR ranges that access tokens can be used - from. By default, each token is given the 0.0.0.0/0 entry - representing all possible IPv4 addresses. - example: ... - get: - summary: Retrieve Universal Auth configuration on identity - description: Retrieve Universal Auth configuration on identity - parameters: - - name: identityId - in: path - required: true - schema: - type: string - description: ID of identity to retrieve Universal Auth on - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - identityUniversalAuth: - $ref: '#/components/schemas/IdentityUniversalAuth' - description: Details of retrieved Universal Auth - security: - - bearerAuth: [] - /api/v1/auth/universal-auth/identities/{identityId}/client-secrets: - post: - summary: Create Universal Auth Client Secret for identity - description: Create Universal Auth Client Secret for identity - parameters: - - name: identityId - in: path - required: true - schema: - type: string - description: ID of identity to create Universal Auth Client Secret for - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - clientSecret: - type: string - description: The created Client Secret - clientSecretData: - $ref: '#/components/schemas/IdentityUniversalAuthClientSecretData' - description: Details of the created Client Secret - security: - - bearerAuth: [] - requestBody: - content: - application/json: - schema: - type: object - properties: - description: - type: string - description: A description for the Client Secret to create. - example: ... - ttl: - type: number - description: >- - The time-to-live for the Client Secret to create. By - default, the TTL will be set to 0 which implies that the - Client Secret will never expire; a value of 0 implies an - infinite lifetime. - example: ... - default: 0 - numUsesLimit: - type: number - description: >- - The maximum number of times that the Client Secret can be - used together with the Client ID to get back an access - token; a value of 0 implies infinite number of uses. - example: ... - default: 0 - get: - summary: List Universal Auth Client Secrets for identity - description: List Universal Auth Client Secrets for identity - parameters: - - name: identityId - in: path - required: true - schema: - type: string - description: ID of identity for which to get Client Secrets for - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - clientSecretData: - type: array - items: - $ref: >- - #/components/schemas/IdentityUniversalAuthClientSecretData - description: Details of the Client Secrets - security: - - bearerAuth: [] - /api/v1/auth/universal-auth/identities/{identityId}/client-secrets/{clientSecretId}/revoke: - post: - summary: Revoke Universal Auth Client Secret for identity - description: Revoke Universal Auth Client Secret for identity - parameters: - - name: identityId - in: path - required: true - schema: - type: string - description: ID of identity under which Client Secret was issued for - - name: clientSecretId - in: path - required: true - schema: - type: string - description: ID of Client Secret to revoke - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - clientSecretData: - $ref: '#/components/schemas/IdentityUniversalAuthClientSecretData' - description: Details of the revoked Client Secret - security: - - bearerAuth: [] - /api/v1/admin/config: - get: - description: '' - responses: - '200': - description: OK - patch: - description: '' - responses: - '200': - description: OK - /api/v1/admin/signup: - post: - description: '' - parameters: - - name: user-agent - in: header - schema: - type: string - responses: - '200': - description: OK - /api/v1/bot/{workspaceId}: - get: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/bot/{botId}/active: - patch: - description: '' - parameters: - - name: botId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - '400': - description: Bad Request - /api/v1/user/: - get: - description: '' - responses: - '200': - description: OK - /api/v1/user-action/: - post: - description: '' - responses: - '200': - description: OK - get: - description: '' - responses: - '200': - description: OK - /api/v1/organization/: - get: - description: '' - responses: - '200': - description: OK - /api/v1/organization/{organizationId}: - get: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/organization/{organizationId}/users: - get: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/organization/{organizationId}/my-workspaces: - get: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/organization/{organizationId}/name: - patch: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/organization/{organizationId}/incidentContactOrg: - get: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - post: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - delete: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/organization/{organizationId}/customer-portal-session: - post: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/organization/{organizationId}/workspace-memberships: - get: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/workspace/{workspaceId}/keys: - get: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/workspace/{workspaceId}/users: - get: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/workspace/: - get: - description: '' - responses: - '200': - description: OK - post: - description: '' - responses: - '200': - description: OK - '400': - description: Bad Request - /api/v1/workspace/{workspaceId}: - get: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - delete: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/workspace/{workspaceId}/name: - post: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/workspace/{workspaceId}/invite-signup: - post: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/workspace/{workspaceId}/integrations: - get: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/workspace/{workspaceId}/authorizations: - get: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/workspace/{workspaceId}/service-tokens: - get: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/membership-org/membershipOrg/{membershipOrgId}/change-role: - post: - description: '' - parameters: - - name: membershipOrgId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/membership-org/{membershipOrgId}: - delete: - description: '' - parameters: - - name: membershipOrgId - in: path - required: true - schema: - type: string - responses: - default: - description: '' - /api/v1/membership/{workspaceId}/connect: - get: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/membership/{membershipId}: - delete: - description: '' - parameters: - - name: membershipId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/membership/{membershipId}/change-role: - post: - description: '' - parameters: - - name: membershipId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - '400': - description: Bad Request - /api/v1/key/{workspaceId}: - post: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/key/{workspaceId}/latest: - get: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/invite-org/signup: - post: - description: '' - parameters: - - name: host - in: header - schema: - type: string - responses: - '200': - description: OK - '400': - description: Bad Request - /api/v1/invite-org/verify: - post: - description: '' - responses: - '200': - description: OK - /api/v1/secret/{workspaceId}: - post: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - requestBody: - content: - application/json: - schema: - type: object - properties: - secrets: - example: any - keys: - example: any - environment: - example: any - channel: - example: any - get: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - - name: environment - in: query - schema: - type: string - - name: channel - in: query - schema: - type: string - responses: - '200': - description: OK - /api/v1/secret/{workspaceId}/service-token: - get: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - - name: environment - in: query - schema: - type: string - - name: channel - in: query - schema: - type: string - responses: - '200': - description: OK - /api/v1/service-token/: - get: - description: '' - responses: - '200': - description: OK - post: - description: '' - responses: - '200': - description: OK - '400': - description: Bad Request - requestBody: - content: - application/json: - schema: - type: object - properties: - name: - example: any - workspaceId: - example: any - environment: - example: any - expiresIn: - example: any - publicKey: - example: any - encryptedKey: - example: any - nonce: - example: any - /api/v1/password/srp1: - post: - description: '' - responses: - '200': - description: OK - /api/v1/password/change-password: - post: - description: '' - responses: - '200': - description: OK - '400': - description: Bad Request - /api/v1/password/email/password-reset: - post: - description: '' - responses: - '200': - description: OK - /api/v1/password/email/password-reset-verify: - post: - description: '' - responses: - '200': - description: OK - '403': - description: Forbidden - /api/v1/password/backup-private-key: - get: - description: '' - responses: - '200': - description: OK - post: - description: '' - responses: - '200': - description: OK - '400': - description: Bad Request - /api/v1/password/password-reset: - post: - description: '' - responses: - '200': - description: OK - /api/v1/integration/: - post: - description: '' - responses: - '200': - description: OK - /api/v1/integration/{integrationId}: - patch: - description: '' - parameters: - - name: integrationId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - delete: - description: '' - parameters: - - name: integrationId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/integration/manual-sync: - post: - description: '' - responses: - '200': - description: OK - /api/v1/integration-auth/integration-options: - get: - description: '' - responses: - '200': - description: OK - /api/v1/integration-auth/{integrationAuthId}: - get: - description: '' - parameters: - - name: integrationAuthId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - '400': - description: Bad Request - delete: - description: '' - parameters: - - name: integrationAuthId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - '400': - description: Bad Request - /api/v1/integration-auth/oauth-token: - post: - description: '' - responses: - '200': - description: OK - /api/v1/integration-auth/access-token: - post: - description: '' - responses: - '200': - description: OK - /api/v1/integration-auth/{integrationAuthId}/apps: - get: - description: '' - parameters: - - name: integrationAuthId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/integration-auth/{integrationAuthId}/teams: - get: - description: '' - parameters: - - name: integrationAuthId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/integration-auth/{integrationAuthId}/vercel/branches: - get: - description: '' - parameters: - - name: integrationAuthId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/integration-auth/{integrationAuthId}/checkly/groups: - get: - description: '' - parameters: - - name: integrationAuthId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/integration-auth/{integrationAuthId}/qovery/orgs: - get: - description: '' - parameters: - - name: integrationAuthId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/integration-auth/{integrationAuthId}/qovery/projects: - get: - description: '' - parameters: - - name: integrationAuthId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/integration-auth/{integrationAuthId}/qovery/environments: - get: - description: '' - parameters: - - name: integrationAuthId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/integration-auth/{integrationAuthId}/qovery/apps: - get: - description: '' - parameters: - - name: integrationAuthId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/integration-auth/{integrationAuthId}/qovery/containers: - get: - description: '' - parameters: - - name: integrationAuthId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/integration-auth/{integrationAuthId}/qovery/jobs: - get: - description: '' - parameters: - - name: integrationAuthId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/integration-auth/{integrationAuthId}/railway/environments: - get: - description: '' - parameters: - - name: integrationAuthId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/integration-auth/{integrationAuthId}/railway/services: - get: - description: '' - parameters: - - name: integrationAuthId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/integration-auth/{integrationAuthId}/bitbucket/workspaces: - get: - description: '' - parameters: - - name: integrationAuthId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/integration-auth/{integrationAuthId}/northflank/secret-groups: - get: - description: '' - parameters: - - name: integrationAuthId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/integration-auth/{integrationAuthId}/teamcity/build-configs: - get: - description: '' - parameters: - - name: integrationAuthId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/folders/: - post: - summary: Create folder - description: Create folder - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - folder: - type: object - properties: - id: - type: string - description: ID of folder - example: someFolderId - name: - type: string - description: Name of folder - example: my_folder - version: - type: number - description: Version of folder - example: 1 - description: Details of created folder - '400': - description: >- - Bad Request. For example, 'Folder name cannot contain spaces. Only - underscore and dashes' - '401': - description: Unauthorized request. For example, 'Folder Permission Denied' - security: - - apiKeyAuth: [] - bearerAuth: [] - requestBody: - content: - application/json: - schema: - type: object - properties: - workspaceId: - type: string - description: ID of the workspace where to create folder - example: someWorkspaceId - environment: - type: string - description: Slug of environment where to create folder - example: production - folderName: - type: string - description: Name of folder to create - example: my_folder - directory: - type: string - description: Path where to create folder like / or /foo/bar. Default is / - example: /foo/bar - required: - - workspaceId - - environment - - folderName - get: - summary: Get folders - description: Get folders - parameters: - - name: workspaceId - description: ID of the workspace where to get folders from - required: true - in: query - schema: - type: string - - name: environment - description: Slug of environment where to get folders from - required: true - in: query - schema: - type: string - - name: directory - description: Path where to get fodlers from like / or /foo/bar. Default is / - required: false - in: query - schema: - type: string - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - folders: - type: array - items: - type: object - properties: - id: - type: string - example: someFolderId - name: - type: string - example: someFolderName - description: List of folders - '400': - description: Bad Request. For instance, 'The folder doesn't exist' - '401': - description: Unauthorized request. For example, 'Folder Permission Denied' - security: - - apiKeyAuth: [] - bearerAuth: [] - /api/v1/folders/{folderName}: - patch: - summary: Update folder - description: Update folder - parameters: - - name: folderName - in: path - required: true - schema: - type: string - description: Name of folder to update - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - message: - type: string - description: Success message - example: Successfully updated folder - folder: - type: object - properties: - name: - type: string - description: Name of updated folder - example: updated_folder_name - id: - type: string - description: ID of created folder - example: abc123 - description: Details of the updated folder - '400': - description: >- - Bad Request. Reasons can include 'The folder doesn't exist' or - 'Folder name cannot contain spaces. Only underscore and dashes' - '401': - description: Unauthorized request. For example, 'Folder Permission Denied' - security: - - apiKeyAuth: [] - bearerAuth: [] - requestBody: - content: - application/json: - schema: - type: object - properties: - workspaceId: - type: string - description: ID of workspace where to update folder - example: someWorkspaceId - environment: - type: string - description: Slug of environment where to update folder - example: production - name: - type: string - description: Name of folder to update to - example: updated_folder_name - directory: - type: string - description: Path where to update folder like / or /foo/bar. Default is / - example: /foo/bar - required: - - workspaceId - - environment - - name - delete: - summary: Delete folder - description: Delete folder - parameters: - - name: folderName - in: path - required: true - schema: - type: string - description: Name of folder to delete - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - message: - type: string - description: Success message - example: successfully deleted folders - folders: - type: array - items: - type: object - properties: - id: - type: string - description: ID of deleted folder - example: abc123 - name: - type: string - description: Name of deleted folder - example: someFolderName - description: List of IDs and names of deleted folders - '400': - description: Bad Request. Reasons can include 'The folder doesn't exist' - '401': - description: Unauthorized request. For example, 'Folder Permission Denied' - security: - - apiKeyAuth: [] - bearerAuth: [] - requestBody: - content: - application/json: - schema: - type: object - properties: - workspaceId: - type: string - description: ID of the workspace where to delete folder - example: someWorkspaceId - environment: - type: string - description: Slug of environment where to delete folder - example: production - directory: - type: string - description: Path where to delete folder like / or /foo/bar. Default is / - example: /foo/bar - required: - - workspaceId - - environment - /api/v1/secret-scanning/create-installation-session/organization/{organizationId}: - post: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/secret-scanning/link-installation: - post: - description: '' - responses: - '200': - description: OK - /api/v1/secret-scanning/installation-status/organization/{organizationId}: - get: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/secret-scanning/organization/{organizationId}/risks: - get: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/secret-scanning/organization/{organizationId}/risks/{riskId}/status: - post: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - - name: riskId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/webhooks/: - post: - description: '' - responses: - '200': - description: OK - get: - description: '' - responses: - '200': - description: OK - /api/v1/webhooks/{webhookId}: - patch: - description: '' - parameters: - - name: webhookId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - delete: - description: '' - parameters: - - name: webhookId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/webhooks/{webhookId}/test: - post: - description: '' - parameters: - - name: webhookId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - '400': - description: Bad Request - /api/v1/secret-imports/: - post: - summary: Create secret import - description: Create secret import - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - message: - type: string - example: successfully created secret import - description: Confirmation of secret import creation - '400': - description: Bad Request. For example, 'Secret import already exist' - '401': - description: Unauthorized request. For example, 'Folder Permission Denied' - '404': - description: Resource Not Found. For example, 'Failed to find folder' - requestBody: - content: - application/json: - schema: - type: object - properties: - workspaceId: - type: string - description: ID of workspace where to create secret import - example: someWorkspaceId - environment: - type: string - description: Slug of environment where to create secret import - example: dev - directory: - type: string - description: >- - Path where to create secret import like / or /foo/bar. - Default is / - example: /foo/bar - secretImport: - type: object - properties: - environment: - type: string - description: Slug of environment to import from - example: development - secretPath: - type: string - description: Path where to import from like / or /foo/bar. - example: /user/oauth - required: - - workspaceId - - environment - - directory - - secretImport - get: - summary: Get secret imports - description: Get secret imports - parameters: - - name: workspaceId - in: query - description: ID of workspace where to get secret imports from - required: true - example: workspace12345 - schema: - type: string - - name: environment - in: query - description: Slug of environment where to get secret imports from - required: true - example: production - schema: - type: string - - name: directory - in: query - description: >- - Path where to get secret imports from like / or /foo/bar. Default is - / - required: false - example: folder12345 - schema: - type: string - responses: - '200': - description: Successfully retrieved secret import - content: - application/json: - schema: - type: object - properties: - secretImport: - $ref: '#/components/schemas/SecretImport' - '401': - description: Unauthorized access due to invalid token or scope - '403': - description: Forbidden access due to insufficient permissions - /api/v1/secret-imports/{id}: - put: - summary: Update secret import - description: Update secret import - parameters: - - name: id - in: path - required: true - schema: - type: string - description: ID of secret import to update - example: import12345 - responses: - '200': - description: Successfully updated the secret import - content: - application/json: - schema: - type: object - properties: - message: - type: string - example: successfully updated secret import - '400': - description: Bad Request - Import not found - '401': - description: Unauthorized access due to invalid token or scope - '403': - description: Forbidden access due to insufficient permissions - requestBody: - content: - application/json: - schema: - type: object - properties: - secretImports: - type: array - description: List of secret imports to update to - items: - type: object - properties: - environment: - type: string - description: Slug of environment to import from - example: dev - secretPath: - type: string - description: Path where to import secrets from like / or /foo/bar - example: /foo/bar - required: - - environment - - secretPath - required: - - secretImports - delete: - summary: Delete secret import - description: Delete secret import - parameters: - - name: id - in: path - required: true - schema: - type: string - description: >- - ID of parent secret import document from which to delete secret - import - example: 12345abcde - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - message: - type: string - example: successfully delete secret import - description: Confirmation of secret import deletion - requestBody: - content: - application/json: - schema: - type: object - properties: - secretImportEnv: - type: string - description: Slug of environment of import to delete - example: someWorkspaceId - secretImportPath: - type: string - description: Path like / or /foo/bar of import to delete - example: production - required: - - id - - secretImportEnv - - secretImportPath - /api/v1/secret-imports/secrets: - get: - description: '' - responses: - '200': - description: OK - /api/v1/roles/: - post: - description: '' - responses: - '200': - description: OK - get: - description: '' - responses: - '200': - description: OK - /api/v1/roles/{id}: - patch: - description: '' - parameters: - - name: id - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - delete: - description: '' - parameters: - - name: id - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/roles/organization/{orgId}/permissions: - get: - description: '' - parameters: - - name: orgId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/roles/workspace/{workspaceId}/permissions: - get: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/secret-approvals/: - get: - description: '' - responses: - '200': - description: OK - post: - description: '' - responses: - '200': - description: OK - /api/v1/secret-approvals/board: - get: - description: '' - responses: - '200': - description: OK - /api/v1/secret-approvals/{id}: - patch: - description: '' - parameters: - - name: id - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - delete: - description: '' - parameters: - - name: id - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/sso/redirect/google: - get: - description: '' - parameters: - - name: callback_port - in: query - schema: - type: string - responses: - default: - description: '' - /api/v1/sso/google: - get: - description: '' - responses: - default: - description: '' - /api/v1/sso/redirect/github: - get: - description: '' - parameters: - - name: callback_port - in: query - schema: - type: string - responses: - default: - description: '' - /api/v1/sso/github: - get: - description: '' - responses: - default: - description: '' - /api/v1/sso/redirect/gitlab: - get: - description: '' - parameters: - - name: callback_port - in: query - schema: - type: string - responses: - default: - description: '' - /api/v1/sso/gitlab: - get: - description: '' - responses: - default: - description: '' - /api/v1/secret-approval-requests/: - get: - description: '' - responses: - '200': - description: OK - /api/v1/secret-approval-requests/count: - get: - description: '' - responses: - '200': - description: OK - /api/v1/secret-approval-requests/{id}: - get: - description: '' - parameters: - - name: id - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/secret-approval-requests/{id}/merge: - post: - description: '' - parameters: - - name: id - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/secret-approval-requests/{id}/review: - post: - description: '' - parameters: - - name: id - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v1/secret-approval-requests/{id}/status: - post: - description: '' - parameters: - - name: id - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v2/signup/complete-account/signup: - post: - description: '' - parameters: - - name: user-agent - in: header - schema: - type: string - responses: - '200': - description: OK - '403': - description: Forbidden - requestBody: - content: - application/json: - schema: - type: object - properties: - email: - example: any - firstName: - example: any - lastName: - example: any - protectedKey: - example: any - protectedKeyIV: - example: any - protectedKeyTag: - example: any - publicKey: - example: any - encryptedPrivateKey: - example: any - encryptedPrivateKeyIV: - example: any - encryptedPrivateKeyTag: - example: any - salt: - example: any - verifier: - example: any - organizationName: - example: any - /api/v2/signup/complete-account/invite: - post: - description: '' - parameters: - - name: user-agent - in: header - schema: - type: string - responses: - '200': - description: OK - '403': - description: Forbidden - requestBody: - content: - application/json: - schema: - type: object - properties: - email: - example: any - firstName: - example: any - lastName: - example: any - protectedKey: - example: any - protectedKeyIV: - example: any - protectedKeyTag: - example: any - publicKey: - example: any - encryptedPrivateKey: - example: any - encryptedPrivateKeyIV: - example: any - encryptedPrivateKeyTag: - example: any - salt: - example: any - verifier: - example: any - /api/v2/auth/login1: - post: - description: '' - responses: - '200': - description: OK - requestBody: - content: - application/json: - schema: - type: object - properties: - email: - example: any - clientPublicKey: - example: any - /api/v2/auth/login2: - post: - description: '' - parameters: - - name: user-agent - in: header - schema: - type: string - responses: - '200': - description: OK - '400': - description: Bad Request - requestBody: - content: - application/json: - schema: - type: object - properties: - email: - example: any - clientProof: - example: any - /api/v2/auth/mfa/send: - post: - description: '' - responses: - '200': - description: OK - /api/v2/auth/mfa/verify: - post: - description: '' - parameters: - - name: user-agent - in: header - schema: - type: string - responses: - '200': - description: OK - /api/v2/users/me/mfa: - patch: - description: '' - responses: - '200': - description: OK - /api/v2/users/me/name: - patch: - description: '' - responses: - '200': - description: OK - /api/v2/users/me/auth-methods: - put: - description: '' - responses: - '200': - description: OK - '400': - description: Bad Request - /api/v2/users/me/organizations: - get: - summary: Return organizations that current user is part of - description: Return organizations that current user is part of - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - organizations: - type: array - items: - $ref: '#/components/schemas/Organization' - description: Organizations that user is part of - security: - - apiKeyAuth: [] - /api/v2/users/me/api-keys: - get: - description: '' - responses: - '200': - description: OK - post: - description: '' - responses: - '200': - description: OK - /api/v2/users/me/api-keys/{apiKeyDataId}: - delete: - description: '' - parameters: - - name: apiKeyDataId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v2/users/me/sessions: - get: - description: '' - responses: - '200': - description: OK - delete: - description: '' - responses: - '200': - description: OK - /api/v2/users/me: - get: - summary: Retrieve the current user on the request - description: Retrieve the current user on the request - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - user: - type: object - $ref: '#/components/schemas/CurrentUser' - description: Current user on request - security: - - apiKeyAuth: [] - delete: - description: '' - responses: - '200': - description: OK - /api/v2/organizations/{organizationId}/memberships: - get: - summary: Return organization user memberships - description: Return organization user memberships - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - description: ID of organization - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - memberships: - type: array - items: - $ref: '#/components/schemas/MembershipOrg' - description: Memberships of organization - security: - - apiKeyAuth: [] - bearerAuth: [] - /api/v2/organizations/{organizationId}/memberships/{membershipId}: - patch: - summary: Update organization user membership - description: Update organization user membership - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - description: ID of organization - - name: membershipId - in: path - required: true - schema: - type: string - description: ID of organization membership to update - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - membership: - $ref: '#/components/schemas/MembershipOrg' - description: Updated organization membership - '400': - description: Bad Request - security: - - apiKeyAuth: [] - bearerAuth: [] - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - role: - type: string - description: >- - Role of organization membership - either owner, admin, or - member - delete: - summary: Delete organization user membership - description: Delete organization user membership - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - description: ID of organization - - name: membershipId - in: path - required: true - schema: - type: string - description: ID of organization membership to delete - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - membership: - $ref: '#/components/schemas/MembershipOrg' - description: Deleted organization membership - security: - - apiKeyAuth: [] - bearerAuth: [] - /api/v2/organizations/{organizationId}/workspaces: - get: - summary: Return projects in organization that user is part of - description: Return projects in organization that user is part of - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - description: ID of organization - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - workspaces: - type: array - items: - $ref: '#/components/schemas/Project' - description: Projects of organization - security: - - apiKeyAuth: [] - bearerAuth: [] - /api/v2/organizations/: - post: - description: '' - responses: - '200': - description: OK - /api/v2/organizations/{organizationId}: - delete: - description: '' - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v2/organizations/{organizationId}/identity-memberships: - get: - summary: Return organization identity memberships - description: Return organization identity memberships - parameters: - - name: organizationId - in: path - required: true - schema: - type: string - description: ID of organization - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - identityMemberships: - type: array - items: - $ref: '#/components/schemas/IdentityMembershipOrg' - description: Identity memberships of organization - security: - - bearerAuth: [] - /api/v2/workspace/{workspaceId}/memberships: - post: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - get: - summary: Return project user memberships - description: Return project user memberships - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - description: ID of project - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - memberships: - type: array - items: - $ref: '#/components/schemas/Membership' - description: Memberships of project - security: - - apiKeyAuth: [] - bearerAuth: [] - /api/v2/workspace/{workspaceId}/environments: - post: - summary: Create environment - description: Create environment - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - description: ID of workspace where to create environment - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - message: - type: string - description: Sucess message - example: Successfully created environment - workspace: - type: string - description: ID of workspace where environment was created - example: abc123 - environment: - type: object - properties: - name: - type: string - description: Name of created environment - example: Staging - slug: - type: string - description: Slug of created environment - example: staging - description: Details of the created environment - '400': - description: Bad Request - security: - - apiKeyAuth: [] - requestBody: - content: - application/json: - schema: - type: object - properties: - environmentName: - type: string - description: Name of the environment to create - example: development - environmentSlug: - type: string - description: Slug of environment to create - example: dev-environment - required: - - environmentName - - environmentSlug - put: - summary: Update environment - description: Update environment - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - description: ID of workspace where to update environment - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - message: - type: string - description: Success message - example: Successfully update environment - workspace: - type: string - description: ID of workspace where environment was updated - example: abc123 - environment: - type: object - properties: - name: - type: string - description: Name of updated environment - example: Staging-Renamed - slug: - type: string - description: Slug of updated environment - example: staging-renamed - description: Details of the renamed environment - security: - - apiKeyAuth: [] - requestBody: - content: - application/json: - schema: - type: object - properties: - environmentName: - type: string - description: Name of environment to update to - example: Staging-Renamed - environmentSlug: - type: string - description: Slug of environment to update to - example: staging-renamed - oldEnvironmentSlug: - type: string - description: Current slug of environment - example: staging-old - required: - - environmentName - - environmentSlug - - oldEnvironmentSlug - patch: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - delete: - summary: Delete environment - description: Delete environment - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - description: ID of workspace where to delete environment - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - message: - type: string - description: Success message - example: Successfully deleted environment - workspace: - type: string - description: ID of workspace where environment was deleted - example: abc123 - environment: - type: string - description: Slug of deleted environment - example: dev - description: Response after deleting an environment from a workspace - security: - - apiKeyAuth: [] - requestBody: - content: - application/json: - schema: - type: object - properties: - environmentSlug: - type: string - description: Slug of environment to delete - example: dev - required: - - environmentSlug - /api/v2/workspace/{workspaceId}/tags: - get: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - post: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v2/workspace/tags/{tagId}: - delete: - description: '' - parameters: - - name: tagId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v2/workspace/{workspaceId}/secrets: - post: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - requestBody: - content: - application/json: - schema: - type: object - properties: - secrets: - example: any - keys: - example: any - environment: - example: any - channel: - example: any - get: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - - name: environment - in: query - schema: - type: string - - name: channel - in: query - schema: - type: string - responses: - '200': - description: OK - /api/v2/workspace/{workspaceId}/encrypted-key: - get: - summary: Return encrypted project key - description: Return encrypted project key - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - description: ID of project - responses: - '200': - description: OK - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ProjectKey' - description: Encrypted project key for the given project - security: - - apiKeyAuth: [] - /api/v2/workspace/{workspaceId}/service-token-data: - get: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v2/workspace/{workspaceId}/memberships/{membershipId}: - patch: - summary: Update project user membership - description: Update project user membership - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - description: ID of project - - name: membershipId - in: path - required: true - schema: - type: string - description: ID of project membership to update - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - membership: - $ref: '#/components/schemas/Membership' - description: Updated membership - security: - - apiKeyAuth: [] - bearerAuth: [] - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - role: - type: string - description: Role to update to for project membership - delete: - summary: Delete project user membership - description: Delete project user membership - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - description: ID of project - - name: membershipId - in: path - required: true - schema: - type: string - description: ID of project membership to delete - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - membership: - $ref: '#/components/schemas/Membership' - description: Deleted membership - security: - - apiKeyAuth: [] - bearerAuth: [] - /api/v2/workspace/{workspaceId}/auto-capitalization: - patch: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v2/workspace/{workspaceId}/identity-memberships/{identityId}: - post: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - - name: identityId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - patch: - summary: Update project identity membership - description: Update project identity membership - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - description: ID of project - - name: identityId - in: path - required: true - schema: - type: string - description: ID of identity whose membership to update in project - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - identityMembership: - $ref: '#/components/schemas/IdentityMembership' - description: Updated identity membership - security: - - bearerAuth: [] - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - role: - type: string - description: Role to update to for identity project membership - delete: - summary: Delete project identity membership - description: Delete project identity membership - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - description: ID of project - - name: identityId - in: path - required: true - schema: - type: string - description: ID of identity whose membership to delete in project - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - identityMembership: - $ref: '#/components/schemas/IdentityMembership' - description: Deleted identity membership - security: - - bearerAuth: [] - /api/v2/workspace/{workspaceId}/identity-memberships: - get: - summary: Return project identity memberships - description: Return project identity memberships - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - description: ID of project - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - identityMemberships: - type: array - items: - $ref: '#/components/schemas/IdentityMembership' - description: Identity memberships of project - security: - - bearerAuth: [] - /api/v2/secret/batch-create/workspace/{workspaceId}/environment/{environment}: - post: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - - name: environment - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - requestBody: - content: - application/json: - schema: - type: object - properties: - secrets: - example: any - /api/v2/secret/workspace/{workspaceId}/environment/{environment}: - post: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - - name: environment - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - requestBody: - content: - application/json: - schema: - type: object - properties: - secret: - example: any - /api/v2/secret/workspace/{workspaceId}: - get: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - - name: environment - in: query - schema: - type: string - responses: - '200': - description: OK - /api/v2/secret/{secretId}: - get: - description: '' - parameters: - - name: secretId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - delete: - description: '' - parameters: - - name: secretId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v2/secret/batch/workspace/{workspaceId}/environment/{environmentName}: - delete: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - - name: environmentName - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - requestBody: - content: - application/json: - schema: - type: object - properties: - secretIds: - example: any - /api/v2/secret/batch-modify/workspace/{workspaceId}/environment/{environmentName}: - patch: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - - name: environmentName - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - requestBody: - content: - application/json: - schema: - type: object - properties: - secrets: - example: any - /api/v2/secret/workspace/{workspaceId}/environment/{environmentName}: - patch: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - - name: environmentName - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - requestBody: - content: - application/json: - schema: - type: object - properties: - secret: - example: any - /api/v2/secrets/batch: - post: - description: '' - parameters: - - name: user-agent - in: header - schema: - type: string - responses: - '200': - description: OK - /api/v2/secrets/: - post: - summary: Create new secret(s) - description: Create one or many secrets for a given project and environment. - parameters: - - name: user-agent - in: header - schema: - type: string - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - secrets: - type: array - items: - $ref: '#/components/schemas/Secret' - description: >- - Newly-created secrets for the given project and - environment - security: - - apiKeyAuth: [] - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - workspaceId: - type: string - description: ID of project - environment: - type: string - description: Environment within project - secrets: - $ref: '#/components/schemas/CreateSecret' - description: Secret(s) to create - object or array of objects - get: - summary: Read secrets - description: Read secrets from a project and environment - parameters: - - name: workspaceId - description: ID of project - required: true - in: query - schema: - type: string - - name: environment - description: Environment within project - required: true - in: query - schema: - type: string - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - secrets: - type: array - items: - $ref: '#/components/schemas/Secret' - description: Secrets for the given project and environment - security: - - apiKeyAuth: [] - patch: - summary: Update secret(s) - description: Update secret(s) - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - secrets: - type: array - items: - $ref: '#/components/schemas/Secret' - description: Updated secrets - security: - - apiKeyAuth: [] - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - secrets: - $ref: '#/components/schemas/UpdateSecret' - description: Secret(s) to update - object or array of objects - delete: - summary: Delete secret(s) - description: Delete one or many secrets by their ID(s) - parameters: - - name: user-agent - in: header - schema: - type: string - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - secrets: - type: array - items: - $ref: '#/components/schemas/Secret' - description: Deleted secrets - security: - - apiKeyAuth: [] - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - secretIds: - type: string - description: ID(s) of secrets - string or array of strings - /api/v2/service-token/: - get: - summary: Return Infisical Token data - description: Return Infisical Token data - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - serviceTokenData: - type: object - $ref: '#/components/schemas/ServiceTokenData' - description: Details of service token - security: - - bearerAuth: [] - post: - description: '' - responses: - '200': - description: OK - /api/v2/service-token/{serviceTokenDataId}: - delete: - description: '' - parameters: - - name: serviceTokenDataId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v3/auth/login1: - post: - description: '' - responses: - '200': - description: OK - /api/v3/auth/login2: - post: - description: '' - parameters: - - name: user-agent - in: header - schema: - type: string - responses: - '200': - description: OK - '400': - description: Bad Request - /api/v3/secrets/raw: - get: - summary: List secrets - description: List secrets - parameters: - - name: workspaceId - description: ID of workspace where to get secrets from - required: true - in: query - schema: - type: string - - name: environment - description: Slug of environment where to get secrets from - required: true - in: query - schema: - type: string - - name: secretPath - description: Path where to update secret like / or /foo/bar. Default is / - required: false - in: query - schema: - type: string - - name: include_imports - description: Whether or not to include imported secrets. Default is false - required: false - in: query - schema: - type: boolean - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - secrets: - type: array - items: - $ref: '#/components/schemas/RawSecret' - description: List of secrets - security: - - apiKeyAuth: [] - bearerAuth: [] - /api/v3/secrets/raw/{secretName}: - get: - summary: Get secret - description: Get secret - parameters: - - name: secretName - in: path - required: true - schema: - type: string - description: Name of secret to get - - name: workspaceId - description: ID of workspace where to get secret - required: true - in: query - schema: - type: string - - name: environment - description: Slug of environment where to get secret - required: true - in: query - schema: - type: string - - name: secretPath - description: Path where to update secret like / or /foo/bar. Default is / - required: false - in: query - schema: - type: string - - name: type - description: Type of secret to get; either shared or personal. Default is shared. - required: true - in: query - schema: - type: string - - name: include_imports - description: Whether or not to include imported secrets. Default is false - required: false - in: query - schema: - type: boolean - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - secret: - $ref: '#/components/schemas/RawSecret' - security: - - apiKeyAuth: [] - bearerAuth: [] - post: - summary: Create secret - description: Create secret - parameters: - - name: secretName - in: path - required: true - schema: - type: string - description: Name of secret to create - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/RawSecret' - security: - - apiKeyAuth: [] - bearerAuth: [] - requestBody: - content: - application/json: - schema: - type: object - properties: - workspaceId: - type: string - description: ID of the workspace where to create secret - example: someWorkspaceId - environment: - type: string - description: Slug of environment where to create secret - example: dev - secretPath: - type: string - description: Path where to create secret. Default is / - example: /foo/bar - secretValue: - type: string - description: Value of secret to create - example: Some value - secretComment: - type: string - description: Comment for secret to create - example: Some comment - type: - type: string - description: >- - Type of secret to create; either shared or personal. Default - is shared. - example: shared - skipMultilineEncoding: - type: boolean - description: Convert multi line secrets into one line by wrapping - example: 'true' - required: - - workspaceId - - environment - - secretValue - patch: - summary: Update secret - description: Update secret - parameters: - - name: secretName - in: path - required: true - schema: - type: string - description: Name of secret to update - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/RawSecret' - security: - - apiKeyAuth: [] - bearerAuth: [] - requestBody: - content: - application/json: - schema: - type: object - properties: - workspaceId: - type: string - description: ID of the workspace where to update secret - example: someWorkspaceId - environment: - type: string - description: Slug of environment where to update secret - example: dev - secretPath: - type: string - description: Path where to update secret like / or /foo/bar. Default is / - example: /foo/bar - secretValue: - type: string - description: Value of secret to update to - example: Some value - type: - type: string - description: >- - Type of secret to update; either shared or personal. Default - is shared. - example: shared - skipMultilineEncoding: - type: boolean - description: Convert multi line secrets into one line by wrapping - example: 'true' - required: - - workspaceId - - environment - - secretValue - delete: - summary: Delete secret - description: Delete secret - parameters: - - name: secretName - in: path - required: true - schema: - type: string - description: Name of secret to delete - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - secret: - $ref: '#/components/schemas/RawSecret' - description: The deleted secret - security: - - apiKeyAuth: [] - bearerAuth: [] - requestBody: - content: - application/json: - schema: - type: object - properties: - workspaceId: - type: string - description: ID of workspace where to delete secret - example: someWorkspaceId - environment: - type: string - description: Slug of Environment where to delete secret - example: dev - secretPath: - type: string - description: Path where to delete secret. Default is / - example: /foo/bar - type: - type: string - description: >- - Type of secret to delete; either shared or personal. Default - is shared - example: shared - required: - - workspaceId - - environment - /api/v3/secrets/: - get: - description: '' - responses: - '200': - description: OK - /api/v3/secrets/batch: - post: - description: '' - responses: - '200': - description: OK - patch: - description: '' - responses: - '200': - description: OK - delete: - description: '' - responses: - '200': - description: OK - /api/v3/secrets/{secretName}: - post: - description: '' - parameters: - - name: secretName - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - get: - description: '' - parameters: - - name: secretName - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - patch: - description: '' - parameters: - - name: secretName - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - delete: - description: '' - parameters: - - name: secretName - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v3/workspaces/{workspaceId}/secrets/blind-index-status: - get: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v3/workspaces/{workspaceId}/secrets: - get: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v3/workspaces/{workspaceId}/secrets/names: - post: - description: '' - parameters: - - name: workspaceId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - /api/v3/signup/complete-account/signup: - post: - description: '' - parameters: - - name: authorization - in: header - schema: - type: string - - name: user-agent - in: header - schema: - type: string - responses: - '200': - description: OK - '400': - description: Bad Request - '403': - description: Forbidden - /api/v3/us/me/api-keys: - get: - description: '' - responses: - '200': - description: OK - /api/status: - get: - description: '' - responses: - '200': - description: OK -components: - schemas: - CurrentUser: - type: object - properties: - _id: - type: string - example: '' - email: - type: string - example: johndoe@gmail.com - firstName: - type: string - example: John - lastName: - type: string - example: Doe - publicKey: - type: string - example: johns_nacl_public_key - encryptedPrivateKey: - type: string - example: johns_enc_nacl_private_key - iv: - type: string - example: iv_of_enc_nacl_private_key - tag: - type: string - example: tag_of_enc_nacl_private_key - updatedAt: - type: string - example: '2023-01-13T14:16:12.210Z' - createdAt: - type: string - example: '2023-01-13T14:16:12.210Z' - Identity: - type: object - properties: - _id: - type: string - example: '' - name: - type: string - example: Machine 1 - authMethod: - type: string - example: universal-auth - IdentityUniversalAuth: - type: object - properties: - _id: - type: string - example: '' - identity: - type: string - example: '' - clientId: - type: string - example: ... - clientSecretTrustedIps: - type: array - items: - type: object - properties: - ipAddress: - type: string - example: 0.0.0.0 - type: - type: string - example: ipv4 - prefix: - type: string - example: '0' - accessTokenTTL: - type: number - example: 7200 - accessTokenMaxTTL: - type: number - example: 2592000 - accessTokenNumUsesLimit: - type: number - example: 0 - accessTokenTrustedIps: - type: array - items: - type: object - properties: - ipAddress: - type: string - example: 0.0.0.0 - type: - type: string - example: ipv4 - prefix: - type: string - example: '0' - IdentityUniversalAuthClientSecretData: - type: object - properties: - _id: - type: string - example: '' - identityUniversalAuth: - type: string - example: '' - isClientSecretRevoked: - type: boolean - example: false - description: - type: string - example: '' - clientSecretPrefix: - type: string - example: abc - clientSecretNumUses: - type: number - example: 0 - clientSecretNumUsesLimit: - type: number - example: 0 - clientSecretTTL: - type: number - example: 0 - createdAt: - type: string - example: '2023-01-13T14:16:12.210Z' - updatedAt: - type: string - example: '2023-01-13T14:16:12.210Z' - Membership: - type: object - properties: - user: - type: object - properties: - _id: - type: string - example: '' - email: - type: string - example: johndoe@gmail.com - firstName: - type: string - example: John - lastName: - type: string - example: Doe - publicKey: - type: string - example: johns_nacl_public_key - updatedAt: - type: string - example: '2023-01-13T14:16:12.210Z' - createdAt: - type: string - example: '2023-01-13T14:16:12.210Z' - workspace: - type: string - example: '' - role: - type: string - example: admin - MembershipOrg: - type: object - properties: - user: - type: object - properties: - _id: - type: string - example: '' - email: - type: string - example: johndoe@gmail.com - firstName: - type: string - example: John - lastName: - type: string - example: Doe - publicKey: - type: string - example: johns_nacl_public_key - updatedAt: - type: string - example: '2023-01-13T14:16:12.210Z' - createdAt: - type: string - example: '2023-01-13T14:16:12.210Z' - organization: - type: string - example: '' - role: - type: string - example: owner - status: - type: string - example: accepted - IdentityMembership: - type: object - properties: - identity: - type: object - properties: - _id: - type: string - example: '' - name: - type: string - example: Machine 1 - authMethod: - type: string - example: universal-auth - workspace: - type: string - example: '' - role: - type: string - example: member - IdentityMembershipOrg: - type: object - properties: - identity: - type: object - properties: - _id: - type: string - example: '' - name: - type: string - example: Machine 1 - authMethod: - type: string - example: universal-auth - organization: - type: string - example: '' - role: - type: string - example: member - status: - type: string - example: accepted - Organization: - type: object - properties: - _id: - type: string - example: '' - name: - type: string - example: Acme Corp. - customerId: - type: string - example: '' - Project: - type: object - properties: - name: - type: string - example: My Project - organization: - type: string - example: '' - environments: - type: array - items: - type: object - properties: - name: - type: string - example: development - slug: - type: string - example: dev - ProjectKey: - type: object - properties: - encryptedkey: - type: string - example: '' - nonce: - type: string - example: '' - sender: - type: object - properties: - publicKey: - type: string - example: senders_nacl_public_key - receiver: - type: string - example: '' - workspace: - type: string - example: '' - CreateSecret: - type: object - properties: - type: - type: string - example: shared - secretKeyCiphertext: - type: string - example: '' - secretKeyIV: - type: string - example: '' - secretKeyTag: - type: string - example: '' - secretValueCiphertext: - type: string - example: '' - secretValueIV: - type: string - example: '' - secretValueTag: - type: string - example: '' - secretCommentCiphertext: - type: string - example: '' - secretCommentIV: - type: string - example: '' - secretCommentTag: - type: string - example: '' - UpdateSecret: - type: object - properties: - id: - type: string - example: '' - secretKeyCiphertext: - type: string - example: '' - secretKeyIV: - type: string - example: '' - secretKeyTag: - type: string - example: '' - secretValueCiphertext: - type: string - example: '' - secretValueIV: - type: string - example: '' - secretValueTag: - type: string - example: '' - secretCommentCiphertext: - type: string - example: '' - secretCommentIV: - type: string - example: '' - secretCommentTag: - type: string - example: '' - Secret: - type: object - properties: - _id: - type: string - example: '' - version: - type: number - example: 1 - workspace: - type: string - example: '' - type: - type: string - example: shared - user: {} - secretKeyCiphertext: - type: string - example: '' - secretKeyIV: - type: string - example: '' - secretKeyTag: - type: string - example: '' - secretValueCiphertext: - type: string - example: '' - secretValueIV: - type: string - example: '' - secretValueTag: - type: string - example: '' - secretCommentCiphertext: - type: string - example: '' - secretCommentIV: - type: string - example: '' - secretCommentTag: - type: string - example: '' - updatedAt: - type: string - example: '2023-01-13T14:16:12.210Z' - createdAt: - type: string - example: '2023-01-13T14:16:12.210Z' - RawSecret: - type: object - properties: - _id: - type: string - example: abc123 - version: - type: number - example: 1 - workspace: - type: string - example: abc123 - environment: - type: string - example: dev - secretKey: - type: string - example: STRIPE_KEY - secretValue: - type: string - example: abc123 - secretComment: - type: string - example: Lorem ipsum - SecretImport: - type: object - properties: - _id: - type: string - example: '' - workspace: - type: string - example: abc123 - environment: - type: string - example: dev - folderId: - type: string - example: root - imports: - type: array - example: [] - items: {} - updatedAt: - type: string - example: '2023-01-13T14:16:12.210Z' - createdAt: - type: string - example: '2023-01-13T14:16:12.210Z' - Log: - type: object - properties: - _id: - type: string - example: '' - user: - type: object - properties: - _id: - type: string - example: '' - email: - type: string - example: johndoe@gmail.com - firstName: - type: string - example: John - lastName: - type: string - example: Doe - workspace: - type: string - example: '' - actionNames: - type: array - example: - - addSecrets - items: - type: string - actions: - type: array - items: - type: object - properties: - name: - type: string - example: addSecrets - user: - type: string - example: '' - workspace: - type: string - example: '' - payload: - type: array - items: - type: object - properties: - oldSecretVersion: - type: string - example: '' - newSecretVersion: - type: string - example: '' - channel: - type: string - example: cli - ipAddress: - type: string - example: 192.168.0.1 - updatedAt: - type: string - example: '2023-01-13T14:16:12.210Z' - createdAt: - type: string - example: '2023-01-13T14:16:12.210Z' - SecretSnapshot: - type: object - properties: - workspace: - type: string - example: '' - version: - type: number - example: 1 - secretVersions: - type: array - items: - type: object - properties: - _id: - type: string - example: '' - SecretVersion: - type: object - properties: - _id: - type: string - example: '' - secret: - type: string - example: '' - version: - type: number - example: 1 - workspace: - type: string - example: '' - type: - type: string - example: shared - user: - type: string - example: '' - environment: - type: string - example: dev - isDeleted: - type: string - example: '' - secretKeyCiphertext: - type: string - example: '' - secretKeyIV: - type: string - example: '' - secretKeyTag: - type: string - example: '' - secretValueCiphertext: - type: string - example: '' - secretValueIV: - type: string - example: '' - secretValueTag: - type: string - example: '' - ServiceTokenData: - type: object - properties: - _id: - type: string - example: '' - name: - type: string - example: '' - workspace: - type: string - example: '' - environment: - type: string - example: '' - user: - type: object - properties: - _id: - type: string - example: '' - firstName: - type: string - example: '' - lastName: - type: string - example: '' - expiresAt: - type: string - example: '2023-01-13T14:16:12.210Z' - encryptedKey: - type: string - example: '' - iv: - type: string - example: '' - tag: - type: string - example: '' - updatedAt: - type: string - example: '2023-01-13T14:16:12.210Z' - createdAt: - type: string - example: '2023-01-13T14:16:12.210Z' - AuditLog: - type: object - properties: - actor: - type: object - properties: - type: - type: string - example: '' - metadata: - type: object - properties: {} - organization: - type: string - example: '' - workspace: - type: string - example: '' - ipAddress: - type: string - example: '' - event: - type: object - properties: - type: - type: string - example: '' - metadata: - type: object - properties: {} - userAgent: - type: string - example: '' - userAgentType: - type: string - example: '' - expiresAt: - type: string - example: '' - securitySchemes: - bearerAuth: - type: http - scheme: bearer - bearerFormat: JWT - description: An access token in Infisical - apiKeyAuth: - type: apiKey - in: header - name: X-API-Key - description: An API Key in Infisical diff --git a/frontend/src/components/signup/DonwloadBackupPDFStep.tsx b/frontend/src/components/signup/DonwloadBackupPDFStep.tsx index e211c8494d..73082af32a 100644 --- a/frontend/src/components/signup/DonwloadBackupPDFStep.tsx +++ b/frontend/src/components/signup/DonwloadBackupPDFStep.tsx @@ -58,8 +58,8 @@ export default function DonwloadBackupPDFStep({ return (
-

- +

+ {t("signup.step4-message")}

diff --git a/frontend/src/views/admin/SignUpPage/SignUpPage.tsx b/frontend/src/views/admin/SignUpPage/SignUpPage.tsx index 1e38741758..f452e114ec 100644 --- a/frontend/src/views/admin/SignUpPage/SignUpPage.tsx +++ b/frontend/src/views/admin/SignUpPage/SignUpPage.tsx @@ -128,10 +128,10 @@ export const SignUpPage = () => { animate={{ opacity: 1, translateX: 0 }} exit={{ opacity: 0, translateX: 30 }} > -
+
Infisical logo -
Welcome to Infisical
-
Create your first Admin Account
+
Welcome to Infisical
+
Create your first Super Admin Account
@@ -145,7 +145,7 @@ export const SignUpPage = () => { errorText={error?.message} isError={Boolean(error)} > - + )} /> @@ -158,7 +158,7 @@ export const SignUpPage = () => { errorText={error?.message} isError={Boolean(error)} > - + )} /> @@ -168,7 +168,7 @@ export const SignUpPage = () => { name="email" render={({ field, fieldState: { error } }) => ( - + )} /> @@ -181,7 +181,7 @@ export const SignUpPage = () => { errorText={error?.message} isError={Boolean(error)} > - + )} /> @@ -194,13 +194,13 @@ export const SignUpPage = () => { errorText={error?.message} isError={Boolean(error)} > - + )} />
-
diff --git a/frontend/src/views/admin/SignUpPage/components/DownloadBackupKeys/DownloadBackupKeys.tsx b/frontend/src/views/admin/SignUpPage/components/DownloadBackupKeys/DownloadBackupKeys.tsx index d431aae445..2ed56c9307 100644 --- a/frontend/src/views/admin/SignUpPage/components/DownloadBackupKeys/DownloadBackupKeys.tsx +++ b/frontend/src/views/admin/SignUpPage/components/DownloadBackupKeys/DownloadBackupKeys.tsx @@ -15,8 +15,8 @@ export const DownloadBackupKeys = ({ onGenerate }: Props): JSX.Element => { return (
-

- +

+ {t("signup.step4-message")}