Compare commits

..

2 Commits

1004 changed files with 15610 additions and 23702 deletions

View File

@ -107,10 +107,6 @@ INF_APP_CONNECTION_GITHUB_APP_PRIVATE_KEY=
INF_APP_CONNECTION_GITHUB_APP_SLUG= INF_APP_CONNECTION_GITHUB_APP_SLUG=
INF_APP_CONNECTION_GITHUB_APP_ID= INF_APP_CONNECTION_GITHUB_APP_ID=
#gitlab app connection
INF_APP_CONNECTION_GITLAB_OAUTH_CLIENT_ID=
INF_APP_CONNECTION_GITLAB_OAUTH_CLIENT_SECRET=
#github radar app connection #github radar app connection
INF_APP_CONNECTION_GITHUB_RADAR_APP_CLIENT_ID= INF_APP_CONNECTION_GITHUB_RADAR_APP_CLIENT_ID=
INF_APP_CONNECTION_GITHUB_RADAR_APP_CLIENT_SECRET= INF_APP_CONNECTION_GITHUB_RADAR_APP_CLIENT_SECRET=

View File

@ -83,7 +83,7 @@ jobs:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
goreleaser: goreleaser:
runs-on: ubuntu-latest-8-cores runs-on: ubuntu-latest
needs: [cli-integration-tests] needs: [cli-integration-tests]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3

View File

@ -51,18 +51,11 @@ jobs:
--from-literal=ENCRYPTION_KEY=6c1fe4e407b8911c104518103505b218 \ --from-literal=ENCRYPTION_KEY=6c1fe4e407b8911c104518103505b218 \
--from-literal=SITE_URL=http://localhost:8080 --from-literal=SITE_URL=http://localhost:8080
- name: Create bootstrap secret
run: |
kubectl create secret generic infisical-bootstrap-credentials \
--namespace infisical-standalone-postgres \
--from-literal=INFISICAL_ADMIN_EMAIL=admin@example.com \
--from-literal=INFISICAL_ADMIN_PASSWORD=admin-password
- name: Run chart-testing (install) - name: Run chart-testing (install)
run: | run: |
ct install \ ct install \
--config ct.yaml \ --config ct.yaml \
--charts helm-charts/infisical-standalone-postgres \ --charts helm-charts/infisical-standalone-postgres \
--helm-extra-args="--timeout=300s" \ --helm-extra-args="--timeout=300s" \
--helm-extra-set-args="--set ingress.nginx.enabled=false --set infisical.autoDatabaseSchemaMigration=false --set infisical.replicaCount=1 --set infisical.image.tag=v0.132.2-postgres --set infisical.autoBootstrap.enabled=true" \ --helm-extra-set-args="--set ingress.nginx.enabled=false --set infisical.autoDatabaseSchemaMigration=false --set infisical.replicaCount=1 --set infisical.image.tag=v0.132.2-postgres" \
--namespace infisical-standalone-postgres --namespace infisical-standalone-postgres

View File

@ -45,4 +45,3 @@ cli/detect/config/gitleaks.toml:gcp-api-key:582
.github/workflows/helm-release-infisical-core.yml:generic-api-key:48 .github/workflows/helm-release-infisical-core.yml:generic-api-key:48
.github/workflows/helm-release-infisical-core.yml:generic-api-key:47 .github/workflows/helm-release-infisical-core.yml:generic-api-key:47
backend/src/services/smtp/smtp-service.ts:generic-api-key:79 backend/src/services/smtp/smtp-service.ts:generic-api-key:79
frontend/src/components/secret-syncs/forms/SecretSyncDestinationFields/CloudflarePagesSyncFields.tsx:cloudflare-api-key:7

View File

@ -8,9 +8,6 @@ import { Lock } from "@app/lib/red-lock";
export const mockKeyStore = (): TKeyStoreFactory => { export const mockKeyStore = (): TKeyStoreFactory => {
const store: Record<string, string | number | Buffer> = {}; const store: Record<string, string | number | Buffer> = {};
const getRegex = (pattern: string) =>
new RE2(`^${pattern.replace(/[-[\]/{}()+?.\\^$|]/g, "\\$&").replace(/\*/g, ".*")}$`);
return { return {
setItem: async (key, value) => { setItem: async (key, value) => {
store[key] = value; store[key] = value;
@ -26,7 +23,7 @@ export const mockKeyStore = (): TKeyStoreFactory => {
return 1; return 1;
}, },
deleteItems: async ({ pattern, batchSize = 500, delay = 1500, jitter = 200 }) => { deleteItems: async ({ pattern, batchSize = 500, delay = 1500, jitter = 200 }) => {
const regex = getRegex(pattern); const regex = new RE2(`^${pattern.replace(/[-[\]/{}()+?.\\^$|]/g, "\\$&").replace(/\*/g, ".*")}$`);
let totalDeleted = 0; let totalDeleted = 0;
const keys = Object.keys(store); const keys = Object.keys(store);
@ -56,27 +53,6 @@ export const mockKeyStore = (): TKeyStoreFactory => {
incrementBy: async () => { incrementBy: async () => {
return 1; return 1;
}, },
getItems: async (keys) => {
const values = keys.map((key) => {
const value = store[key];
if (typeof value === "string") {
return value;
}
return null;
});
return values;
},
getKeysByPattern: async (pattern) => {
const regex = getRegex(pattern);
const keys = Object.keys(store);
return keys.filter((key) => regex.test(key));
},
deleteItemsByKeyIn: async (keys) => {
for (const key of keys) {
delete store[key];
}
return keys.length;
},
acquireLock: () => { acquireLock: () => {
return Promise.resolve({ return Promise.resolve({
release: () => {} release: () => {}

View File

@ -30,7 +30,6 @@
"@fastify/static": "^7.0.4", "@fastify/static": "^7.0.4",
"@fastify/swagger": "^8.14.0", "@fastify/swagger": "^8.14.0",
"@fastify/swagger-ui": "^2.1.0", "@fastify/swagger-ui": "^2.1.0",
"@gitbeaker/rest": "^42.5.0",
"@google-cloud/kms": "^4.5.0", "@google-cloud/kms": "^4.5.0",
"@infisical/quic": "^1.0.8", "@infisical/quic": "^1.0.8",
"@node-saml/passport-saml": "^5.0.1", "@node-saml/passport-saml": "^5.0.1",
@ -7808,48 +7807,6 @@
"p-limit": "^3.1.0" "p-limit": "^3.1.0"
} }
}, },
"node_modules/@gitbeaker/core": {
"version": "42.5.0",
"resolved": "https://registry.npmjs.org/@gitbeaker/core/-/core-42.5.0.tgz",
"integrity": "sha512-rMWpOPaZi1iLiifnOIoVO57p2EmQQdfIwP4txqNyMvG4WjYP5Ez0U7jRD9Nra41x6K5kTPBZkuQcAdxVWRJcEQ==",
"license": "MIT",
"dependencies": {
"@gitbeaker/requester-utils": "^42.5.0",
"qs": "^6.12.2",
"xcase": "^2.0.1"
},
"engines": {
"node": ">=18.20.0"
}
},
"node_modules/@gitbeaker/requester-utils": {
"version": "42.5.0",
"resolved": "https://registry.npmjs.org/@gitbeaker/requester-utils/-/requester-utils-42.5.0.tgz",
"integrity": "sha512-HLdLS9LPBMVQumvroQg/4qkphLDtwDB+ygEsrD2u4oYCMUtXV4V1xaVqU4yTXjbTJ5sItOtdB43vYRkBcgueBw==",
"license": "MIT",
"dependencies": {
"picomatch-browser": "^2.2.6",
"qs": "^6.12.2",
"rate-limiter-flexible": "^4.0.1",
"xcase": "^2.0.1"
},
"engines": {
"node": ">=18.20.0"
}
},
"node_modules/@gitbeaker/rest": {
"version": "42.5.0",
"resolved": "https://registry.npmjs.org/@gitbeaker/rest/-/rest-42.5.0.tgz",
"integrity": "sha512-oC5cM6jS7aFOp0luTw5mWSRuMgdxwHRLZQ/aWkI+ETMfsprR/HyxsXfljlMY/XJ/fRxTbRJiodR5Axf66WjO3w==",
"license": "MIT",
"dependencies": {
"@gitbeaker/core": "^42.5.0",
"@gitbeaker/requester-utils": "^42.5.0"
},
"engines": {
"node": ">=18.20.0"
}
},
"node_modules/@google-cloud/kms": { "node_modules/@google-cloud/kms": {
"version": "4.5.0", "version": "4.5.0",
"resolved": "https://registry.npmjs.org/@google-cloud/kms/-/kms-4.5.0.tgz", "resolved": "https://registry.npmjs.org/@google-cloud/kms/-/kms-4.5.0.tgz",
@ -24671,18 +24628,6 @@
"url": "https://github.com/sponsors/jonschlinkert" "url": "https://github.com/sponsors/jonschlinkert"
} }
}, },
"node_modules/picomatch-browser": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/picomatch-browser/-/picomatch-browser-2.2.6.tgz",
"integrity": "sha512-0ypsOQt9D4e3hziV8O4elD9uN0z/jtUEfxVRtNaAAtXIyUx9m/SzlO020i8YNL2aL/E6blOvvHQcin6HZlFy/w==",
"license": "MIT",
"engines": {
"node": ">=8.6"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/pify": { "node_modules/pify": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
@ -25617,12 +25562,6 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/rate-limiter-flexible": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/rate-limiter-flexible/-/rate-limiter-flexible-4.0.1.tgz",
"integrity": "sha512-2/dGHpDFpeA0+755oUkW+EKyklqLS9lu0go9pDsbhqQjZcxfRyJ6LA4JI0+HAdZ2bemD/oOjUeZQB2lCZqXQfQ==",
"license": "ISC"
},
"node_modules/raw-body": { "node_modules/raw-body": {
"version": "2.5.2", "version": "2.5.2",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
@ -31100,12 +31039,6 @@
} }
} }
}, },
"node_modules/xcase": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/xcase/-/xcase-2.0.1.tgz",
"integrity": "sha512-UmFXIPU+9Eg3E9m/728Bii0lAIuoc+6nbrNUKaRPJOFp91ih44qqGlWtxMB6kXFrRD6po+86ksHM5XHCfk6iPw==",
"license": "MIT"
},
"node_modules/xml-crypto": { "node_modules/xml-crypto": {
"version": "6.0.1", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/xml-crypto/-/xml-crypto-6.0.1.tgz", "resolved": "https://registry.npmjs.org/xml-crypto/-/xml-crypto-6.0.1.tgz",

View File

@ -149,7 +149,6 @@
"@fastify/static": "^7.0.4", "@fastify/static": "^7.0.4",
"@fastify/swagger": "^8.14.0", "@fastify/swagger": "^8.14.0",
"@fastify/swagger-ui": "^2.1.0", "@fastify/swagger-ui": "^2.1.0",
"@gitbeaker/rest": "^42.5.0",
"@google-cloud/kms": "^4.5.0", "@google-cloud/kms": "^4.5.0",
"@infisical/quic": "^1.0.8", "@infisical/quic": "^1.0.8",
"@node-saml/passport-saml": "^5.0.1", "@node-saml/passport-saml": "^5.0.1",

View File

@ -74,7 +74,6 @@ import { TAllowedFields } from "@app/services/identity-ldap-auth/identity-ldap-a
import { TIdentityOciAuthServiceFactory } from "@app/services/identity-oci-auth/identity-oci-auth-service"; import { TIdentityOciAuthServiceFactory } from "@app/services/identity-oci-auth/identity-oci-auth-service";
import { TIdentityOidcAuthServiceFactory } from "@app/services/identity-oidc-auth/identity-oidc-auth-service"; import { TIdentityOidcAuthServiceFactory } from "@app/services/identity-oidc-auth/identity-oidc-auth-service";
import { TIdentityProjectServiceFactory } from "@app/services/identity-project/identity-project-service"; import { TIdentityProjectServiceFactory } from "@app/services/identity-project/identity-project-service";
import { TIdentityTlsCertAuthServiceFactory } from "@app/services/identity-tls-cert-auth/identity-tls-cert-auth-types";
import { TIdentityTokenAuthServiceFactory } from "@app/services/identity-token-auth/identity-token-auth-service"; import { TIdentityTokenAuthServiceFactory } from "@app/services/identity-token-auth/identity-token-auth-service";
import { TIdentityUaServiceFactory } from "@app/services/identity-ua/identity-ua-service"; import { TIdentityUaServiceFactory } from "@app/services/identity-ua/identity-ua-service";
import { TIntegrationServiceFactory } from "@app/services/integration/integration-service"; import { TIntegrationServiceFactory } from "@app/services/integration/integration-service";
@ -219,7 +218,6 @@ declare module "fastify" {
identityKubernetesAuth: TIdentityKubernetesAuthServiceFactory; identityKubernetesAuth: TIdentityKubernetesAuthServiceFactory;
identityGcpAuth: TIdentityGcpAuthServiceFactory; identityGcpAuth: TIdentityGcpAuthServiceFactory;
identityAliCloudAuth: TIdentityAliCloudAuthServiceFactory; identityAliCloudAuth: TIdentityAliCloudAuthServiceFactory;
identityTlsCertAuth: TIdentityTlsCertAuthServiceFactory;
identityAwsAuth: TIdentityAwsAuthServiceFactory; identityAwsAuth: TIdentityAwsAuthServiceFactory;
identityAzureAuth: TIdentityAzureAuthServiceFactory; identityAzureAuth: TIdentityAzureAuthServiceFactory;
identityOciAuth: TIdentityOciAuthServiceFactory; identityOciAuth: TIdentityOciAuthServiceFactory;

View File

@ -164,9 +164,6 @@ import {
TIdentityProjectMemberships, TIdentityProjectMemberships,
TIdentityProjectMembershipsInsert, TIdentityProjectMembershipsInsert,
TIdentityProjectMembershipsUpdate, TIdentityProjectMembershipsUpdate,
TIdentityTlsCertAuths,
TIdentityTlsCertAuthsInsert,
TIdentityTlsCertAuthsUpdate,
TIdentityTokenAuths, TIdentityTokenAuths,
TIdentityTokenAuthsInsert, TIdentityTokenAuthsInsert,
TIdentityTokenAuthsUpdate, TIdentityTokenAuthsUpdate,
@ -499,6 +496,11 @@ import {
TMicrosoftTeamsIntegrationsInsert, TMicrosoftTeamsIntegrationsInsert,
TMicrosoftTeamsIntegrationsUpdate TMicrosoftTeamsIntegrationsUpdate
} from "@app/db/schemas/microsoft-teams-integrations"; } from "@app/db/schemas/microsoft-teams-integrations";
import {
TPosthogAggregatedEvents,
TPosthogAggregatedEventsInsert,
TPosthogAggregatedEventsUpdate
} from "@app/db/schemas/posthog-aggregated-events";
import { import {
TProjectMicrosoftTeamsConfigs, TProjectMicrosoftTeamsConfigs,
TProjectMicrosoftTeamsConfigsInsert, TProjectMicrosoftTeamsConfigsInsert,
@ -797,11 +799,6 @@ declare module "knex/types/tables" {
TIdentityAlicloudAuthsInsert, TIdentityAlicloudAuthsInsert,
TIdentityAlicloudAuthsUpdate TIdentityAlicloudAuthsUpdate
>; >;
[TableName.IdentityTlsCertAuth]: KnexOriginal.CompositeTableType<
TIdentityTlsCertAuths,
TIdentityTlsCertAuthsInsert,
TIdentityTlsCertAuthsUpdate
>;
[TableName.IdentityAwsAuth]: KnexOriginal.CompositeTableType< [TableName.IdentityAwsAuth]: KnexOriginal.CompositeTableType<
TIdentityAwsAuths, TIdentityAwsAuths,
TIdentityAwsAuthsInsert, TIdentityAwsAuthsInsert,
@ -1211,5 +1208,10 @@ declare module "knex/types/tables" {
TSecretScanningConfigsInsert, TSecretScanningConfigsInsert,
TSecretScanningConfigsUpdate TSecretScanningConfigsUpdate
>; >;
[TableName.PosthogAggregatedEvents]: KnexOriginal.CompositeTableType<
TPosthogAggregatedEvents,
TPosthogAggregatedEventsInsert,
TPosthogAggregatedEventsUpdate
>;
} }
} }

View File

@ -110,8 +110,7 @@ export const initAuditLogDbConnection = ({
}, },
migrations: { migrations: {
tableName: "infisical_migrations" tableName: "infisical_migrations"
}, }
pool: { min: 0, max: 10 }
}); });
// we add these overrides so that auditLogDb and the primary DB are interchangeable // we add these overrides so that auditLogDb and the primary DB are interchangeable

View File

@ -1,28 +0,0 @@
import { Knex } from "knex";
import { TableName } from "../schemas";
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
export async function up(knex: Knex): Promise<void> {
if (!(await knex.schema.hasTable(TableName.IdentityTlsCertAuth))) {
await knex.schema.createTable(TableName.IdentityTlsCertAuth, (t) => {
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
t.bigInteger("accessTokenTTL").defaultTo(7200).notNullable();
t.bigInteger("accessTokenMaxTTL").defaultTo(7200).notNullable();
t.bigInteger("accessTokenNumUsesLimit").defaultTo(0).notNullable();
t.jsonb("accessTokenTrustedIps").notNullable();
t.timestamps(true, true, true);
t.uuid("identityId").notNullable().unique();
t.foreign("identityId").references("id").inTable(TableName.Identity).onDelete("CASCADE");
t.string("allowedCommonNames").nullable();
t.binary("encryptedCaCertificate").notNullable();
});
}
await createOnUpdateTrigger(knex, TableName.IdentityTlsCertAuth);
}
export async function down(knex: Knex): Promise<void> {
await knex.schema.dropTableIfExists(TableName.IdentityTlsCertAuth);
await dropOnUpdateTrigger(knex, TableName.IdentityTlsCertAuth);
}

View File

@ -0,0 +1,26 @@
import { Knex } from "knex";
import { TableName } from "../schemas";
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
export async function up(knex: Knex): Promise<void> {
if (!(await knex.schema.hasTable(TableName.PosthogAggregatedEvents))) {
await knex.schema.createTable(TableName.PosthogAggregatedEvents, (t) => {
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
t.string("distinctId").notNullable();
t.string("event").notNullable();
t.bigInteger("eventCount").defaultTo(0).notNullable();
t.jsonb("properties").notNullable();
t.string("batchId").notNullable();
t.string("organizationId").nullable();
t.timestamps(true, true, true);
});
}
await createOnUpdateTrigger(knex, TableName.PosthogAggregatedEvents);
}
export async function down(knex: Knex): Promise<void> {
await knex.schema.dropTableIfExists(TableName.PosthogAggregatedEvents);
await dropOnUpdateTrigger(knex, TableName.PosthogAggregatedEvents);
}

View File

@ -1,41 +0,0 @@
import { Knex } from "knex";
import { ProjectType, TableName } from "../schemas";
export async function up(knex: Knex): Promise<void> {
const hasTypeColumn = await knex.schema.hasColumn(TableName.Project, "type");
const hasDefaultTypeColumn = await knex.schema.hasColumn(TableName.Project, "defaultProduct");
if (hasTypeColumn && !hasDefaultTypeColumn) {
await knex.schema.alterTable(TableName.Project, (t) => {
t.string("type").nullable().alter();
t.string("defaultProduct").notNullable().defaultTo(ProjectType.SecretManager);
});
await knex(TableName.Project).update({
// eslint-disable-next-line
// @ts-ignore this is because this field is created later
defaultProduct: knex.raw(`
CASE
WHEN "type" IS NULL OR "type" = '' THEN 'secret-manager'
ELSE "type"
END
`)
});
}
const hasTemplateTypeColumn = await knex.schema.hasColumn(TableName.ProjectTemplates, "type");
if (hasTemplateTypeColumn) {
await knex.schema.alterTable(TableName.ProjectTemplates, (t) => {
t.string("type").nullable().alter();
});
}
}
export async function down(knex: Knex): Promise<void> {
const hasDefaultTypeColumn = await knex.schema.hasColumn(TableName.Project, "defaultProduct");
if (hasDefaultTypeColumn) {
await knex.schema.alterTable(TableName.Project, (t) => {
t.dropColumn("defaultProduct");
});
}
}

View File

@ -1,21 +0,0 @@
import { Knex } from "knex";
import { TableName } from "../schemas";
export async function up(knex: Knex): Promise<void> {
const hasColumn = await knex.schema.hasColumn(TableName.SuperAdmin, "encryptedEnvOverrides");
if (!hasColumn) {
await knex.schema.alterTable(TableName.SuperAdmin, (t) => {
t.binary("encryptedEnvOverrides").nullable();
});
}
}
export async function down(knex: Knex): Promise<void> {
const hasColumn = await knex.schema.hasColumn(TableName.SuperAdmin, "encryptedEnvOverrides");
if (hasColumn) {
await knex.schema.alterTable(TableName.SuperAdmin, (t) => {
t.dropColumn("encryptedEnvOverrides");
});
}
}

View File

@ -1,21 +0,0 @@
import { Knex } from "knex";
import { TableName } from "../schemas";
export async function up(knex: Knex): Promise<void> {
const hasColumn = await knex.schema.hasColumn(TableName.OrgMembership, "lastInvitedAt");
await knex.schema.alterTable(TableName.OrgMembership, (t) => {
if (!hasColumn) {
t.datetime("lastInvitedAt").nullable();
}
});
}
export async function down(knex: Knex): Promise<void> {
const hasColumn = await knex.schema.hasColumn(TableName.OrgMembership, "lastInvitedAt");
await knex.schema.alterTable(TableName.OrgMembership, (t) => {
if (hasColumn) {
t.dropColumn("lastInvitedAt");
}
});
}

View File

@ -1,21 +0,0 @@
import { Knex } from "knex";
import { TableName } from "../schemas";
export async function up(knex: Knex): Promise<void> {
const hasColumn = await knex.schema.hasColumn(TableName.OrgMembership, "lastInvitedAt");
if (hasColumn) {
await knex.schema.alterTable(TableName.OrgMembership, (t) => {
t.datetime("lastInvitedAt").nullable().defaultTo(knex.fn.now()).alter();
});
}
}
export async function down(knex: Knex): Promise<void> {
const hasColumn = await knex.schema.hasColumn(TableName.OrgMembership, "lastInvitedAt");
if (hasColumn) {
await knex.schema.alterTable(TableName.OrgMembership, (t) => {
t.datetime("lastInvitedAt").nullable().alter();
});
}
}

View File

@ -1,27 +0,0 @@
// Code generated by automation script, DO NOT EDIT.
// Automated by pulling database and generating zod schema
// To update. Just run npm run generate:schema
// Written by akhilmhdh.
import { z } from "zod";
import { zodBuffer } from "@app/lib/zod";
import { TImmutableDBKeys } from "./models";
export const IdentityTlsCertAuthsSchema = z.object({
id: z.string().uuid(),
accessTokenTTL: z.coerce.number().default(7200),
accessTokenMaxTTL: z.coerce.number().default(7200),
accessTokenNumUsesLimit: z.coerce.number().default(0),
accessTokenTrustedIps: z.unknown(),
createdAt: z.date(),
updatedAt: z.date(),
identityId: z.string().uuid(),
allowedCommonNames: z.string().nullable().optional(),
encryptedCaCertificate: zodBuffer
});
export type TIdentityTlsCertAuths = z.infer<typeof IdentityTlsCertAuthsSchema>;
export type TIdentityTlsCertAuthsInsert = Omit<z.input<typeof IdentityTlsCertAuthsSchema>, TImmutableDBKeys>;
export type TIdentityTlsCertAuthsUpdate = Partial<Omit<z.input<typeof IdentityTlsCertAuthsSchema>, TImmutableDBKeys>>;

View File

@ -52,7 +52,6 @@ export * from "./identity-org-memberships";
export * from "./identity-project-additional-privilege"; export * from "./identity-project-additional-privilege";
export * from "./identity-project-membership-role"; export * from "./identity-project-membership-role";
export * from "./identity-project-memberships"; export * from "./identity-project-memberships";
export * from "./identity-tls-cert-auths";
export * from "./identity-token-auths"; export * from "./identity-token-auths";
export * from "./identity-ua-client-secrets"; export * from "./identity-ua-client-secrets";
export * from "./identity-universal-auths"; export * from "./identity-universal-auths";

View File

@ -86,7 +86,6 @@ export enum TableName {
IdentityOidcAuth = "identity_oidc_auths", IdentityOidcAuth = "identity_oidc_auths",
IdentityJwtAuth = "identity_jwt_auths", IdentityJwtAuth = "identity_jwt_auths",
IdentityLdapAuth = "identity_ldap_auths", IdentityLdapAuth = "identity_ldap_auths",
IdentityTlsCertAuth = "identity_tls_cert_auths",
IdentityOrgMembership = "identity_org_memberships", IdentityOrgMembership = "identity_org_memberships",
IdentityProjectMembership = "identity_project_memberships", IdentityProjectMembership = "identity_project_memberships",
IdentityProjectMembershipRole = "identity_project_membership_role", IdentityProjectMembershipRole = "identity_project_membership_role",
@ -172,7 +171,9 @@ export enum TableName {
SecretScanningResource = "secret_scanning_resources", SecretScanningResource = "secret_scanning_resources",
SecretScanningScan = "secret_scanning_scans", SecretScanningScan = "secret_scanning_scans",
SecretScanningFinding = "secret_scanning_findings", SecretScanningFinding = "secret_scanning_findings",
SecretScanningConfig = "secret_scanning_configs" SecretScanningConfig = "secret_scanning_configs",
// Telemetry
PosthogAggregatedEvents = "posthog_aggregated_events"
} }
export type TImmutableDBKeys = "id" | "createdAt" | "updatedAt" | "commitId"; export type TImmutableDBKeys = "id" | "createdAt" | "updatedAt" | "commitId";
@ -252,7 +253,6 @@ export enum IdentityAuthMethod {
ALICLOUD_AUTH = "alicloud-auth", ALICLOUD_AUTH = "alicloud-auth",
AWS_AUTH = "aws-auth", AWS_AUTH = "aws-auth",
AZURE_AUTH = "azure-auth", AZURE_AUTH = "azure-auth",
TLS_CERT_AUTH = "tls-cert-auth",
OCI_AUTH = "oci-auth", OCI_AUTH = "oci-auth",
OIDC_AUTH = "oidc-auth", OIDC_AUTH = "oidc-auth",
JWT_AUTH = "jwt-auth", JWT_AUTH = "jwt-auth",
@ -267,6 +267,16 @@ export enum ProjectType {
SecretScanning = "secret-scanning" SecretScanning = "secret-scanning"
} }
export enum ActionProjectType {
SecretManager = ProjectType.SecretManager,
CertificateManager = ProjectType.CertificateManager,
KMS = ProjectType.KMS,
SSH = ProjectType.SSH,
SecretScanning = ProjectType.SecretScanning,
// project operations that happen on all types
Any = "any"
}
export enum SortDirection { export enum SortDirection {
ASC = "asc", ASC = "asc",
DESC = "desc" DESC = "desc"

View File

@ -18,8 +18,7 @@ export const OrgMembershipsSchema = z.object({
orgId: z.string().uuid(), orgId: z.string().uuid(),
roleId: z.string().uuid().nullable().optional(), roleId: z.string().uuid().nullable().optional(),
projectFavorites: z.string().array().nullable().optional(), projectFavorites: z.string().array().nullable().optional(),
isActive: z.boolean().default(true), isActive: z.boolean().default(true)
lastInvitedAt: z.date().nullable().optional()
}); });
export type TOrgMemberships = z.infer<typeof OrgMembershipsSchema>; export type TOrgMemberships = z.infer<typeof OrgMembershipsSchema>;

View File

@ -0,0 +1,26 @@
// Code generated by automation script, DO NOT EDIT.
// Automated by pulling database and generating zod schema
// To update. Just run npm run generate:schema
// Written by akhilmhdh.
import { z } from "zod";
import { TImmutableDBKeys } from "./models";
export const PosthogAggregatedEventsSchema = z.object({
id: z.string().uuid(),
distinctId: z.string(),
event: z.string(),
eventCount: z.coerce.number().default(0),
properties: z.unknown(),
batchId: z.string(),
organizationId: z.string().nullable().optional(),
createdAt: z.date(),
updatedAt: z.date()
});
export type TPosthogAggregatedEvents = z.infer<typeof PosthogAggregatedEventsSchema>;
export type TPosthogAggregatedEventsInsert = Omit<z.input<typeof PosthogAggregatedEventsSchema>, TImmutableDBKeys>;
export type TPosthogAggregatedEventsUpdate = Partial<
Omit<z.input<typeof PosthogAggregatedEventsSchema>, TImmutableDBKeys>
>;

View File

@ -16,7 +16,7 @@ export const ProjectTemplatesSchema = z.object({
orgId: z.string().uuid(), orgId: z.string().uuid(),
createdAt: z.date(), createdAt: z.date(),
updatedAt: z.date(), updatedAt: z.date(),
type: z.string().nullable().optional() type: z.string().default("secret-manager")
}); });
export type TProjectTemplates = z.infer<typeof ProjectTemplatesSchema>; export type TProjectTemplates = z.infer<typeof ProjectTemplatesSchema>;

View File

@ -25,12 +25,11 @@ export const ProjectsSchema = z.object({
kmsSecretManagerKeyId: z.string().uuid().nullable().optional(), kmsSecretManagerKeyId: z.string().uuid().nullable().optional(),
kmsSecretManagerEncryptedDataKey: zodBuffer.nullable().optional(), kmsSecretManagerEncryptedDataKey: zodBuffer.nullable().optional(),
description: z.string().nullable().optional(), description: z.string().nullable().optional(),
type: z.string().nullable().optional(), type: z.string(),
enforceCapitalization: z.boolean().default(false), enforceCapitalization: z.boolean().default(false),
hasDeleteProtection: z.boolean().default(false).nullable().optional(), hasDeleteProtection: z.boolean().default(false).nullable().optional(),
secretSharing: z.boolean().default(true), secretSharing: z.boolean().default(true),
showSnapshotsLegacy: z.boolean().default(false), showSnapshotsLegacy: z.boolean().default(false)
defaultProduct: z.string().default("secret-manager")
}); });
export type TProjects = z.infer<typeof ProjectsSchema>; export type TProjects = z.infer<typeof ProjectsSchema>;

View File

@ -34,8 +34,7 @@ export const SuperAdminSchema = z.object({
encryptedGitHubAppConnectionClientSecret: zodBuffer.nullable().optional(), encryptedGitHubAppConnectionClientSecret: zodBuffer.nullable().optional(),
encryptedGitHubAppConnectionSlug: zodBuffer.nullable().optional(), encryptedGitHubAppConnectionSlug: zodBuffer.nullable().optional(),
encryptedGitHubAppConnectionId: zodBuffer.nullable().optional(), encryptedGitHubAppConnectionId: zodBuffer.nullable().optional(),
encryptedGitHubAppConnectionPrivateKey: zodBuffer.nullable().optional(), encryptedGitHubAppConnectionPrivateKey: zodBuffer.nullable().optional()
encryptedEnvOverrides: zodBuffer.nullable().optional()
}); });
export type TSuperAdmin = z.infer<typeof SuperAdminSchema>; export type TSuperAdmin = z.infer<typeof SuperAdminSchema>;

View File

@ -60,8 +60,7 @@ export const registerAccessApprovalRequestRouter = async (server: FastifyZodProv
method: "GET", method: "GET",
schema: { schema: {
querystring: z.object({ querystring: z.object({
projectSlug: z.string().trim(), projectSlug: z.string().trim()
policyId: z.string().trim().optional()
}), }),
response: { response: {
200: z.object({ 200: z.object({
@ -74,7 +73,6 @@ export const registerAccessApprovalRequestRouter = async (server: FastifyZodProv
handler: async (req) => { handler: async (req) => {
const { count } = await server.services.accessApprovalRequest.getCount({ const { count } = await server.services.accessApprovalRequest.getCount({
projectSlug: req.query.projectSlug, projectSlug: req.query.projectSlug,
policyId: req.query.policyId,
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId, actorOrgId: req.permission.orgId,

View File

@ -17,7 +17,6 @@ import { z } from "zod";
import { LdapGroupMapsSchema } from "@app/db/schemas"; import { LdapGroupMapsSchema } from "@app/db/schemas";
import { TLDAPConfig } from "@app/ee/services/ldap-config/ldap-config-types"; import { TLDAPConfig } from "@app/ee/services/ldap-config/ldap-config-types";
import { isValidLdapFilter, searchGroups } from "@app/ee/services/ldap-config/ldap-fns"; import { isValidLdapFilter, searchGroups } from "@app/ee/services/ldap-config/ldap-fns";
import { ApiDocsTags, LdapSso } from "@app/lib/api-docs";
import { getConfig } from "@app/lib/config/env"; import { getConfig } from "@app/lib/config/env";
import { BadRequestError } from "@app/lib/errors"; import { BadRequestError } from "@app/lib/errors";
import { logger } from "@app/lib/logger"; import { logger } from "@app/lib/logger";
@ -133,18 +132,10 @@ export const registerLdapRouter = async (server: FastifyZodProvider) => {
config: { config: {
rateLimit: readLimit rateLimit: readLimit
}, },
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), onRequest: verifyAuth([AuthMode.JWT]),
schema: { schema: {
hide: false,
tags: [ApiDocsTags.LdapSso],
description: "Get LDAP config",
security: [
{
bearerAuth: []
}
],
querystring: z.object({ querystring: z.object({
organizationId: z.string().trim().describe(LdapSso.GET_CONFIG.organizationId) organizationId: z.string().trim()
}), }),
response: { response: {
200: z.object({ 200: z.object({
@ -181,32 +172,23 @@ export const registerLdapRouter = async (server: FastifyZodProvider) => {
config: { config: {
rateLimit: writeLimit rateLimit: writeLimit
}, },
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), onRequest: verifyAuth([AuthMode.JWT]),
schema: { schema: {
hide: false,
tags: [ApiDocsTags.LdapSso],
description: "Create LDAP config",
security: [
{
bearerAuth: []
}
],
body: z.object({ body: z.object({
organizationId: z.string().trim().describe(LdapSso.CREATE_CONFIG.organizationId), organizationId: z.string().trim(),
isActive: z.boolean().describe(LdapSso.CREATE_CONFIG.isActive), isActive: z.boolean(),
url: z.string().trim().describe(LdapSso.CREATE_CONFIG.url), url: z.string().trim(),
bindDN: z.string().trim().describe(LdapSso.CREATE_CONFIG.bindDN), bindDN: z.string().trim(),
bindPass: z.string().trim().describe(LdapSso.CREATE_CONFIG.bindPass), bindPass: z.string().trim(),
uniqueUserAttribute: z.string().trim().default("uidNumber").describe(LdapSso.CREATE_CONFIG.uniqueUserAttribute), uniqueUserAttribute: z.string().trim().default("uidNumber"),
searchBase: z.string().trim().describe(LdapSso.CREATE_CONFIG.searchBase), searchBase: z.string().trim(),
searchFilter: z.string().trim().default("(uid={{username}})").describe(LdapSso.CREATE_CONFIG.searchFilter), searchFilter: z.string().trim().default("(uid={{username}})"),
groupSearchBase: z.string().trim().describe(LdapSso.CREATE_CONFIG.groupSearchBase), groupSearchBase: z.string().trim(),
groupSearchFilter: z groupSearchFilter: z
.string() .string()
.trim() .trim()
.default("(|(memberUid={{.Username}})(member={{.UserDN}})(uniqueMember={{.UserDN}}))") .default("(|(memberUid={{.Username}})(member={{.UserDN}})(uniqueMember={{.UserDN}}))"),
.describe(LdapSso.CREATE_CONFIG.groupSearchFilter), caCert: z.string().trim().default("")
caCert: z.string().trim().default("").describe(LdapSso.CREATE_CONFIG.caCert)
}), }),
response: { response: {
200: SanitizedLdapConfigSchema 200: SanitizedLdapConfigSchema
@ -232,31 +214,23 @@ export const registerLdapRouter = async (server: FastifyZodProvider) => {
config: { config: {
rateLimit: writeLimit rateLimit: writeLimit
}, },
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), onRequest: verifyAuth([AuthMode.JWT]),
schema: { schema: {
hide: false,
tags: [ApiDocsTags.LdapSso],
description: "Update LDAP config",
security: [
{
bearerAuth: []
}
],
body: z body: z
.object({ .object({
isActive: z.boolean().describe(LdapSso.UPDATE_CONFIG.isActive), isActive: z.boolean(),
url: z.string().trim().describe(LdapSso.UPDATE_CONFIG.url), url: z.string().trim(),
bindDN: z.string().trim().describe(LdapSso.UPDATE_CONFIG.bindDN), bindDN: z.string().trim(),
bindPass: z.string().trim().describe(LdapSso.UPDATE_CONFIG.bindPass), bindPass: z.string().trim(),
uniqueUserAttribute: z.string().trim().describe(LdapSso.UPDATE_CONFIG.uniqueUserAttribute), uniqueUserAttribute: z.string().trim(),
searchBase: z.string().trim().describe(LdapSso.UPDATE_CONFIG.searchBase), searchBase: z.string().trim(),
searchFilter: z.string().trim().describe(LdapSso.UPDATE_CONFIG.searchFilter), searchFilter: z.string().trim(),
groupSearchBase: z.string().trim().describe(LdapSso.UPDATE_CONFIG.groupSearchBase), groupSearchBase: z.string().trim(),
groupSearchFilter: z.string().trim().describe(LdapSso.UPDATE_CONFIG.groupSearchFilter), groupSearchFilter: z.string().trim(),
caCert: z.string().trim().describe(LdapSso.UPDATE_CONFIG.caCert) caCert: z.string().trim()
}) })
.partial() .partial()
.merge(z.object({ organizationId: z.string().trim().describe(LdapSso.UPDATE_CONFIG.organizationId) })), .merge(z.object({ organizationId: z.string() })),
response: { response: {
200: SanitizedLdapConfigSchema 200: SanitizedLdapConfigSchema
} }

View File

@ -13,7 +13,6 @@ import { z } from "zod";
import { OidcConfigsSchema } from "@app/db/schemas"; import { OidcConfigsSchema } from "@app/db/schemas";
import { OIDCConfigurationType, OIDCJWTSignatureAlgorithm } from "@app/ee/services/oidc/oidc-config-types"; import { OIDCConfigurationType, OIDCJWTSignatureAlgorithm } from "@app/ee/services/oidc/oidc-config-types";
import { ApiDocsTags, OidcSSo } from "@app/lib/api-docs";
import { getConfig } from "@app/lib/config/env"; import { getConfig } from "@app/lib/config/env";
import { authRateLimit, readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { authRateLimit, readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
@ -154,18 +153,10 @@ export const registerOidcRouter = async (server: FastifyZodProvider) => {
config: { config: {
rateLimit: readLimit rateLimit: readLimit
}, },
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), onRequest: verifyAuth([AuthMode.JWT]),
schema: { schema: {
hide: false,
tags: [ApiDocsTags.OidcSso],
description: "Get OIDC config",
security: [
{
bearerAuth: []
}
],
querystring: z.object({ querystring: z.object({
organizationId: z.string().trim().describe(OidcSSo.GET_CONFIG.organizationId) orgSlug: z.string().trim()
}), }),
response: { response: {
200: SanitizedOidcConfigSchema.pick({ 200: SanitizedOidcConfigSchema.pick({
@ -189,8 +180,9 @@ export const registerOidcRouter = async (server: FastifyZodProvider) => {
} }
}, },
handler: async (req) => { handler: async (req) => {
const { orgSlug } = req.query;
const oidc = await server.services.oidc.getOidc({ const oidc = await server.services.oidc.getOidc({
organizationId: req.query.organizationId, orgSlug,
type: "external", type: "external",
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
@ -208,16 +200,8 @@ export const registerOidcRouter = async (server: FastifyZodProvider) => {
config: { config: {
rateLimit: writeLimit rateLimit: writeLimit
}, },
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), onRequest: verifyAuth([AuthMode.JWT]),
schema: { schema: {
hide: false,
tags: [ApiDocsTags.OidcSso],
description: "Update OIDC config",
security: [
{
bearerAuth: []
}
],
body: z body: z
.object({ .object({
allowedEmailDomains: z allowedEmailDomains: z
@ -232,26 +216,22 @@ export const registerOidcRouter = async (server: FastifyZodProvider) => {
.split(",") .split(",")
.map((id) => id.trim()) .map((id) => id.trim())
.join(", "); .join(", ");
}) }),
.describe(OidcSSo.UPDATE_CONFIG.allowedEmailDomains), discoveryURL: z.string().trim(),
discoveryURL: z.string().trim().describe(OidcSSo.UPDATE_CONFIG.discoveryURL), configurationType: z.nativeEnum(OIDCConfigurationType),
configurationType: z.nativeEnum(OIDCConfigurationType).describe(OidcSSo.UPDATE_CONFIG.configurationType), issuer: z.string().trim(),
issuer: z.string().trim().describe(OidcSSo.UPDATE_CONFIG.issuer), authorizationEndpoint: z.string().trim(),
authorizationEndpoint: z.string().trim().describe(OidcSSo.UPDATE_CONFIG.authorizationEndpoint), jwksUri: z.string().trim(),
jwksUri: z.string().trim().describe(OidcSSo.UPDATE_CONFIG.jwksUri), tokenEndpoint: z.string().trim(),
tokenEndpoint: z.string().trim().describe(OidcSSo.UPDATE_CONFIG.tokenEndpoint), userinfoEndpoint: z.string().trim(),
userinfoEndpoint: z.string().trim().describe(OidcSSo.UPDATE_CONFIG.userinfoEndpoint), clientId: z.string().trim(),
clientId: z.string().trim().describe(OidcSSo.UPDATE_CONFIG.clientId), clientSecret: z.string().trim(),
clientSecret: z.string().trim().describe(OidcSSo.UPDATE_CONFIG.clientSecret), isActive: z.boolean(),
isActive: z.boolean().describe(OidcSSo.UPDATE_CONFIG.isActive), manageGroupMemberships: z.boolean().optional(),
manageGroupMemberships: z.boolean().optional().describe(OidcSSo.UPDATE_CONFIG.manageGroupMemberships), jwtSignatureAlgorithm: z.nativeEnum(OIDCJWTSignatureAlgorithm).optional()
jwtSignatureAlgorithm: z
.nativeEnum(OIDCJWTSignatureAlgorithm)
.optional()
.describe(OidcSSo.UPDATE_CONFIG.jwtSignatureAlgorithm)
}) })
.partial() .partial()
.merge(z.object({ organizationId: z.string().describe(OidcSSo.UPDATE_CONFIG.organizationId) })), .merge(z.object({ orgSlug: z.string() })),
response: { response: {
200: SanitizedOidcConfigSchema.pick({ 200: SanitizedOidcConfigSchema.pick({
id: true, id: true,
@ -287,16 +267,8 @@ export const registerOidcRouter = async (server: FastifyZodProvider) => {
config: { config: {
rateLimit: writeLimit rateLimit: writeLimit
}, },
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), onRequest: verifyAuth([AuthMode.JWT]),
schema: { schema: {
hide: false,
tags: [ApiDocsTags.OidcSso],
description: "Create OIDC config",
security: [
{
bearerAuth: []
}
],
body: z body: z
.object({ .object({
allowedEmailDomains: z allowedEmailDomains: z
@ -311,34 +283,23 @@ export const registerOidcRouter = async (server: FastifyZodProvider) => {
.split(",") .split(",")
.map((id) => id.trim()) .map((id) => id.trim())
.join(", "); .join(", ");
}) }),
.describe(OidcSSo.CREATE_CONFIG.allowedEmailDomains), configurationType: z.nativeEnum(OIDCConfigurationType),
configurationType: z.nativeEnum(OIDCConfigurationType).describe(OidcSSo.CREATE_CONFIG.configurationType), issuer: z.string().trim().optional().default(""),
issuer: z.string().trim().optional().default("").describe(OidcSSo.CREATE_CONFIG.issuer), discoveryURL: z.string().trim().optional().default(""),
discoveryURL: z.string().trim().optional().default("").describe(OidcSSo.CREATE_CONFIG.discoveryURL), authorizationEndpoint: z.string().trim().optional().default(""),
authorizationEndpoint: z jwksUri: z.string().trim().optional().default(""),
.string() tokenEndpoint: z.string().trim().optional().default(""),
.trim() userinfoEndpoint: z.string().trim().optional().default(""),
.optional() clientId: z.string().trim(),
.default("") clientSecret: z.string().trim(),
.describe(OidcSSo.CREATE_CONFIG.authorizationEndpoint), isActive: z.boolean(),
jwksUri: z.string().trim().optional().default("").describe(OidcSSo.CREATE_CONFIG.jwksUri), orgSlug: z.string().trim(),
tokenEndpoint: z.string().trim().optional().default("").describe(OidcSSo.CREATE_CONFIG.tokenEndpoint), manageGroupMemberships: z.boolean().optional().default(false),
userinfoEndpoint: z.string().trim().optional().default("").describe(OidcSSo.CREATE_CONFIG.userinfoEndpoint),
clientId: z.string().trim().describe(OidcSSo.CREATE_CONFIG.clientId),
clientSecret: z.string().trim().describe(OidcSSo.CREATE_CONFIG.clientSecret),
isActive: z.boolean().describe(OidcSSo.CREATE_CONFIG.isActive),
organizationId: z.string().trim().describe(OidcSSo.CREATE_CONFIG.organizationId),
manageGroupMemberships: z
.boolean()
.optional()
.default(false)
.describe(OidcSSo.CREATE_CONFIG.manageGroupMemberships),
jwtSignatureAlgorithm: z jwtSignatureAlgorithm: z
.nativeEnum(OIDCJWTSignatureAlgorithm) .nativeEnum(OIDCJWTSignatureAlgorithm)
.optional() .optional()
.default(OIDCJWTSignatureAlgorithm.RS256) .default(OIDCJWTSignatureAlgorithm.RS256)
.describe(OidcSSo.CREATE_CONFIG.jwtSignatureAlgorithm)
}) })
.superRefine((data, ctx) => { .superRefine((data, ctx) => {
if (data.configurationType === OIDCConfigurationType.CUSTOM) { if (data.configurationType === OIDCConfigurationType.CUSTOM) {

View File

@ -111,38 +111,15 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
params: z.object({ params: z.object({
workspaceId: z.string().trim().describe(AUDIT_LOGS.EXPORT.projectId) workspaceId: z.string().trim().describe(AUDIT_LOGS.EXPORT.projectId)
}), }),
querystring: z querystring: z.object({
.object({ eventType: z.nativeEnum(EventType).optional().describe(AUDIT_LOGS.EXPORT.eventType),
eventType: z.nativeEnum(EventType).optional().describe(AUDIT_LOGS.EXPORT.eventType), userAgentType: z.nativeEnum(UserAgentType).optional().describe(AUDIT_LOGS.EXPORT.userAgentType),
userAgentType: z.nativeEnum(UserAgentType).optional().describe(AUDIT_LOGS.EXPORT.userAgentType), startDate: z.string().datetime().optional().describe(AUDIT_LOGS.EXPORT.startDate),
startDate: z.string().datetime().optional().describe(AUDIT_LOGS.EXPORT.startDate), endDate: z.string().datetime().optional().describe(AUDIT_LOGS.EXPORT.endDate),
endDate: z.string().datetime().optional().describe(AUDIT_LOGS.EXPORT.endDate), offset: z.coerce.number().default(0).describe(AUDIT_LOGS.EXPORT.offset),
offset: z.coerce.number().default(0).describe(AUDIT_LOGS.EXPORT.offset), limit: z.coerce.number().default(20).describe(AUDIT_LOGS.EXPORT.limit),
limit: z.coerce.number().max(1000).default(20).describe(AUDIT_LOGS.EXPORT.limit), actor: z.string().optional().describe(AUDIT_LOGS.EXPORT.actor)
actor: z.string().optional().describe(AUDIT_LOGS.EXPORT.actor) }),
})
.superRefine((el, ctx) => {
if (el.endDate && el.startDate) {
const startDate = new Date(el.startDate);
const endDate = new Date(el.endDate);
const maxAllowedDate = new Date(startDate);
maxAllowedDate.setMonth(maxAllowedDate.getMonth() + 3);
if (endDate < startDate) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["endDate"],
message: "End date cannot be before start date"
});
}
if (endDate > maxAllowedDate) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["endDate"],
message: "Dates must be within 3 months"
});
}
}
}),
response: { response: {
200: z.object({ 200: z.object({
auditLogs: AuditLogsSchema.omit({ auditLogs: AuditLogsSchema.omit({
@ -184,7 +161,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
filter: { filter: {
...req.query, ...req.query,
projectId: req.params.workspaceId, projectId: req.params.workspaceId,
endDate: req.query.endDate || new Date().toISOString(), endDate: req.query.endDate,
startDate: req.query.startDate || getLastMidnightDateISO(), startDate: req.query.startDate || getLastMidnightDateISO(),
auditLogActorId: req.query.actor, auditLogActorId: req.query.actor,
eventType: req.query.eventType ? [req.query.eventType] : undefined eventType: req.query.eventType ? [req.query.eventType] : undefined

View File

@ -1,6 +1,6 @@
import { z } from "zod"; import { z } from "zod";
import { ProjectMembershipRole, ProjectTemplatesSchema } from "@app/db/schemas"; import { ProjectMembershipRole, ProjectTemplatesSchema, ProjectType } from "@app/db/schemas";
import { EventType } from "@app/ee/services/audit-log/audit-log-types"; import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission"; import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
import { isInfisicalProjectTemplate } from "@app/ee/services/project-template/project-template-fns"; import { isInfisicalProjectTemplate } from "@app/ee/services/project-template/project-template-fns";
@ -104,6 +104,9 @@ export const registerProjectTemplateRouter = async (server: FastifyZodProvider)
hide: false, hide: false,
tags: [ApiDocsTags.ProjectTemplates], tags: [ApiDocsTags.ProjectTemplates],
description: "List project templates for the current organization.", description: "List project templates for the current organization.",
querystring: z.object({
type: z.nativeEnum(ProjectType).optional().describe(ProjectTemplates.LIST.type)
}),
response: { response: {
200: z.object({ 200: z.object({
projectTemplates: SanitizedProjectTemplateSchema.array() projectTemplates: SanitizedProjectTemplateSchema.array()
@ -112,7 +115,8 @@ export const registerProjectTemplateRouter = async (server: FastifyZodProvider)
}, },
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => { handler: async (req) => {
const projectTemplates = await server.services.projectTemplate.listProjectTemplatesByOrg(req.permission); const { type } = req.query;
const projectTemplates = await server.services.projectTemplate.listProjectTemplatesByOrg(req.permission, type);
const auditTemplates = projectTemplates.filter((template) => !isInfisicalProjectTemplate(template.name)); const auditTemplates = projectTemplates.filter((template) => !isInfisicalProjectTemplate(template.name));
@ -184,6 +188,7 @@ export const registerProjectTemplateRouter = async (server: FastifyZodProvider)
tags: [ApiDocsTags.ProjectTemplates], tags: [ApiDocsTags.ProjectTemplates],
description: "Create a project template.", description: "Create a project template.",
body: z.object({ body: z.object({
type: z.nativeEnum(ProjectType).describe(ProjectTemplates.CREATE.type),
name: slugSchema({ field: "name" }) name: slugSchema({ field: "name" })
.refine((val) => !isInfisicalProjectTemplate(val), { .refine((val) => !isInfisicalProjectTemplate(val), {
message: `The requested project template name is reserved.` message: `The requested project template name is reserved.`
@ -279,6 +284,7 @@ export const registerProjectTemplateRouter = async (server: FastifyZodProvider)
tags: [ApiDocsTags.ProjectTemplates], tags: [ApiDocsTags.ProjectTemplates],
description: "Delete a project template.", description: "Delete a project template.",
params: z.object({ templateId: z.string().uuid().describe(ProjectTemplates.DELETE.templateId) }), params: z.object({ templateId: z.string().uuid().describe(ProjectTemplates.DELETE.templateId) }),
response: { response: {
200: z.object({ 200: z.object({
projectTemplate: SanitizedProjectTemplateSchema projectTemplate: SanitizedProjectTemplateSchema

View File

@ -13,7 +13,6 @@ import { FastifyRequest } from "fastify";
import { z } from "zod"; import { z } from "zod";
import { SamlProviders, TGetSamlCfgDTO } from "@app/ee/services/saml-config/saml-config-types"; import { SamlProviders, TGetSamlCfgDTO } from "@app/ee/services/saml-config/saml-config-types";
import { ApiDocsTags, SamlSso } from "@app/lib/api-docs";
import { getConfig } from "@app/lib/config/env"; import { getConfig } from "@app/lib/config/env";
import { BadRequestError } from "@app/lib/errors"; import { BadRequestError } from "@app/lib/errors";
import { logger } from "@app/lib/logger"; import { logger } from "@app/lib/logger";
@ -150,8 +149,8 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
firstName, firstName,
lastName: lastName as string, lastName: lastName as string,
relayState: (req.body as { RelayState?: string }).RelayState, relayState: (req.body as { RelayState?: string }).RelayState,
authProvider: (req as unknown as FastifyRequest).ssoConfig?.authProvider, authProvider: (req as unknown as FastifyRequest).ssoConfig?.authProvider as string,
orgId: (req as unknown as FastifyRequest).ssoConfig?.orgId, orgId: (req as unknown as FastifyRequest).ssoConfig?.orgId as string,
metadata: userMetadata metadata: userMetadata
}); });
cb(null, { isUserCompleted, providerAuthToken }); cb(null, { isUserCompleted, providerAuthToken });
@ -263,31 +262,25 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
config: { config: {
rateLimit: readLimit rateLimit: readLimit
}, },
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), onRequest: verifyAuth([AuthMode.JWT]),
schema: { schema: {
hide: false,
tags: [ApiDocsTags.SamlSso],
description: "Get SAML config",
security: [
{
bearerAuth: []
}
],
querystring: z.object({ querystring: z.object({
organizationId: z.string().trim().describe(SamlSso.GET_CONFIG.organizationId) organizationId: z.string().trim()
}), }),
response: { response: {
200: z.object({ 200: z
id: z.string(), .object({
organization: z.string(), id: z.string(),
orgId: z.string(), organization: z.string(),
authProvider: z.string(), orgId: z.string(),
isActive: z.boolean(), authProvider: z.string(),
entryPoint: z.string(), isActive: z.boolean(),
issuer: z.string(), entryPoint: z.string(),
cert: z.string(), issuer: z.string(),
lastUsed: z.date().nullable().optional() cert: z.string(),
}) lastUsed: z.date().nullable().optional()
})
.optional()
} }
}, },
handler: async (req) => { handler: async (req) => {
@ -309,23 +302,15 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
config: { config: {
rateLimit: writeLimit rateLimit: writeLimit
}, },
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), onRequest: verifyAuth([AuthMode.JWT]),
schema: { schema: {
hide: false,
tags: [ApiDocsTags.SamlSso],
description: "Create SAML config",
security: [
{
bearerAuth: []
}
],
body: z.object({ body: z.object({
organizationId: z.string().trim().describe(SamlSso.CREATE_CONFIG.organizationId), organizationId: z.string(),
authProvider: z.nativeEnum(SamlProviders).describe(SamlSso.CREATE_CONFIG.authProvider), authProvider: z.nativeEnum(SamlProviders),
isActive: z.boolean().describe(SamlSso.CREATE_CONFIG.isActive), isActive: z.boolean(),
entryPoint: z.string().trim().describe(SamlSso.CREATE_CONFIG.entryPoint), entryPoint: z.string(),
issuer: z.string().trim().describe(SamlSso.CREATE_CONFIG.issuer), issuer: z.string(),
cert: z.string().trim().describe(SamlSso.CREATE_CONFIG.cert) cert: z.string()
}), }),
response: { response: {
200: SanitizedSamlConfigSchema 200: SanitizedSamlConfigSchema
@ -356,26 +341,18 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
config: { config: {
rateLimit: writeLimit rateLimit: writeLimit
}, },
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), onRequest: verifyAuth([AuthMode.JWT]),
schema: { schema: {
hide: false,
tags: [ApiDocsTags.SamlSso],
description: "Update SAML config",
security: [
{
bearerAuth: []
}
],
body: z body: z
.object({ .object({
authProvider: z.nativeEnum(SamlProviders).describe(SamlSso.UPDATE_CONFIG.authProvider), authProvider: z.nativeEnum(SamlProviders),
isActive: z.boolean().describe(SamlSso.UPDATE_CONFIG.isActive), isActive: z.boolean(),
entryPoint: z.string().trim().describe(SamlSso.UPDATE_CONFIG.entryPoint), entryPoint: z.string(),
issuer: z.string().trim().describe(SamlSso.UPDATE_CONFIG.issuer), issuer: z.string(),
cert: z.string().trim().describe(SamlSso.UPDATE_CONFIG.cert) cert: z.string()
}) })
.partial() .partial()
.merge(z.object({ organizationId: z.string().trim().describe(SamlSso.UPDATE_CONFIG.organizationId) })), .merge(z.object({ organizationId: z.string() })),
response: { response: {
200: SanitizedSamlConfigSchema 200: SanitizedSamlConfigSchema
} }

View File

@ -94,8 +94,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
}, },
schema: { schema: {
querystring: z.object({ querystring: z.object({
workspaceId: z.string().trim(), workspaceId: z.string().trim()
policyId: z.string().trim().optional()
}), }),
response: { response: {
200: z.object({ 200: z.object({
@ -113,8 +112,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
actorId: req.permission.id, actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod, actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId, actorOrgId: req.permission.orgId,
projectId: req.query.workspaceId, projectId: req.query.workspaceId
policyId: req.query.policyId
}); });
return { approvals }; return { approvals };
} }

View File

@ -1,5 +1,6 @@
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError } from "@casl/ability";
import { ActionProjectType } from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors"; import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
@ -96,7 +97,8 @@ export const accessApprovalPolicyServiceFactory = ({
actorId, actorId,
projectId: project.id, projectId: project.id,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
@ -246,7 +248,8 @@ export const accessApprovalPolicyServiceFactory = ({
actorId, actorId,
projectId: project.id, projectId: project.id,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
const accessApprovalPolicies = await accessApprovalPolicyDAL.find({ projectId: project.id, deletedAt: null }); const accessApprovalPolicies = await accessApprovalPolicyDAL.find({ projectId: project.id, deletedAt: null });
@ -298,7 +301,8 @@ export const accessApprovalPolicyServiceFactory = ({
actorId, actorId,
projectId: accessApprovalPolicy.projectId, projectId: accessApprovalPolicy.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.SecretApproval); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.SecretApproval);
@ -494,7 +498,8 @@ export const accessApprovalPolicyServiceFactory = ({
actorId, actorId,
projectId: policy.projectId, projectId: policy.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Delete, ProjectPermissionActions.Delete,
@ -544,7 +549,8 @@ export const accessApprovalPolicyServiceFactory = ({
actorId, actorId,
projectId: project.id, projectId: project.id,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
if (!membership) { if (!membership) {
throw new ForbiddenRequestError({ message: "You are not a member of this project" }); throw new ForbiddenRequestError({ message: "You are not a member of this project" });
@ -583,7 +589,8 @@ export const accessApprovalPolicyServiceFactory = ({
actorId, actorId,
projectId: policy.projectId, projectId: policy.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretApproval); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretApproval);

View File

@ -220,7 +220,7 @@ export interface TAccessApprovalRequestDALFactory extends Omit<TOrmify<TableName
bypassers: string[]; bypassers: string[];
}[] }[]
>; >;
getCount: ({ projectId }: { projectId: string; policyId?: string }) => Promise<{ getCount: ({ projectId }: { projectId: string }) => Promise<{
pendingCount: number; pendingCount: number;
finalizedCount: number; finalizedCount: number;
}>; }>;
@ -702,7 +702,7 @@ export const accessApprovalRequestDALFactory = (db: TDbClient): TAccessApprovalR
} }
}; };
const getCount: TAccessApprovalRequestDALFactory["getCount"] = async ({ projectId, policyId }) => { const getCount: TAccessApprovalRequestDALFactory["getCount"] = async ({ projectId }) => {
try { try {
const accessRequests = await db const accessRequests = await db
.replicaNode()(TableName.AccessApprovalRequest) .replicaNode()(TableName.AccessApprovalRequest)
@ -723,10 +723,8 @@ export const accessApprovalRequestDALFactory = (db: TDbClient): TAccessApprovalR
`${TableName.AccessApprovalRequest}.id`, `${TableName.AccessApprovalRequest}.id`,
`${TableName.AccessApprovalRequestReviewer}.requestId` `${TableName.AccessApprovalRequestReviewer}.requestId`
) )
.where(`${TableName.Environment}.projectId`, projectId) .where(`${TableName.Environment}.projectId`, projectId)
.where((qb) => {
if (policyId) void qb.where(`${TableName.AccessApprovalPolicy}.id`, policyId);
})
.select(selectAllTableCols(TableName.AccessApprovalRequest)) .select(selectAllTableCols(TableName.AccessApprovalRequest))
.select(db.ref("status").withSchema(TableName.AccessApprovalRequestReviewer).as("reviewerStatus")) .select(db.ref("status").withSchema(TableName.AccessApprovalRequestReviewer).as("reviewerStatus"))
.select(db.ref("reviewerUserId").withSchema(TableName.AccessApprovalRequestReviewer).as("reviewerUserId")) .select(db.ref("reviewerUserId").withSchema(TableName.AccessApprovalRequestReviewer).as("reviewerUserId"))

View File

@ -1,7 +1,7 @@
import slugify from "@sindresorhus/slugify"; import slugify from "@sindresorhus/slugify";
import msFn from "ms"; import msFn from "ms";
import { ProjectMembershipRole } from "@app/db/schemas"; import { ActionProjectType, ProjectMembershipRole } from "@app/db/schemas";
import { getConfig } from "@app/lib/config/env"; import { getConfig } from "@app/lib/config/env";
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors"; import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
import { groupBy } from "@app/lib/fn"; import { groupBy } from "@app/lib/fn";
@ -107,7 +107,8 @@ export const accessApprovalRequestServiceFactory = ({
actorId, actorId,
projectId: project.id, projectId: project.id,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
if (!membership) { if (!membership) {
throw new ForbiddenRequestError({ message: "You are not a member of this project" }); throw new ForbiddenRequestError({ message: "You are not a member of this project" });
@ -216,7 +217,7 @@ export const accessApprovalRequestServiceFactory = ({
); );
const requesterFullName = `${requestedByUser.firstName} ${requestedByUser.lastName}`; const requesterFullName = `${requestedByUser.firstName} ${requestedByUser.lastName}`;
const approvalUrl = `${cfg.SITE_URL}/projects/${project.id}/secret-manager/approval`; const approvalUrl = `${cfg.SITE_URL}/secret-manager/${project.id}/approval`;
await triggerWorkflowIntegrationNotification({ await triggerWorkflowIntegrationNotification({
input: { input: {
@ -289,7 +290,8 @@ export const accessApprovalRequestServiceFactory = ({
actorId, actorId,
projectId: project.id, projectId: project.id,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
if (!membership) { if (!membership) {
throw new ForbiddenRequestError({ message: "You are not a member of this project" }); throw new ForbiddenRequestError({ message: "You are not a member of this project" });
@ -335,7 +337,8 @@ export const accessApprovalRequestServiceFactory = ({
actorId, actorId,
projectId: accessApprovalRequest.projectId, projectId: accessApprovalRequest.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
if (!membership) { if (!membership) {
@ -347,12 +350,6 @@ export const accessApprovalRequestServiceFactory = ({
const canBypass = !policy.bypassers.length || policy.bypassers.some((bypasser) => bypasser.userId === actorId); const canBypass = !policy.bypassers.length || policy.bypassers.some((bypasser) => bypasser.userId === actorId);
const cannotBypassUnderSoftEnforcement = !(isSoftEnforcement && canBypass); const cannotBypassUnderSoftEnforcement = !(isSoftEnforcement && canBypass);
// Calculate break glass attempt before sequence checks
const isBreakGlassApprovalAttempt =
policy.enforcementLevel === EnforcementLevel.Soft &&
actorId === accessApprovalRequest.requestedByUserId &&
status === ApprovalStatus.APPROVED;
const isApprover = policy.approvers.find((approver) => approver.userId === actorId); const isApprover = policy.approvers.find((approver) => approver.userId === actorId);
// If user is (not an approver OR cant self approve) AND can't bypass policy // If user is (not an approver OR cant self approve) AND can't bypass policy
if ((!isApprover || (!policy.allowedSelfApprovals && isSelfApproval)) && cannotBypassUnderSoftEnforcement) { if ((!isApprover || (!policy.allowedSelfApprovals && isSelfApproval)) && cannotBypassUnderSoftEnforcement) {
@ -412,14 +409,15 @@ export const accessApprovalRequestServiceFactory = ({
const isApproverOfTheSequence = policy.approvers.find( const isApproverOfTheSequence = policy.approvers.find(
(el) => el.sequence === presentSequence.step && el.userId === actorId (el) => el.sequence === presentSequence.step && el.userId === actorId
); );
if (!isApproverOfTheSequence) throw new BadRequestError({ message: "You are not reviewer in this step" });
// Only throw if actor is not the approver and not bypassing
if (!isApproverOfTheSequence && !isBreakGlassApprovalAttempt) {
throw new BadRequestError({ message: "You are not a reviewer in this step" });
}
} }
const reviewStatus = await accessApprovalRequestReviewerDAL.transaction(async (tx) => { const reviewStatus = await accessApprovalRequestReviewerDAL.transaction(async (tx) => {
const isBreakGlassApprovalAttempt =
policy.enforcementLevel === EnforcementLevel.Soft &&
actorId === accessApprovalRequest.requestedByUserId &&
status === ApprovalStatus.APPROVED;
let reviewForThisActorProcessing: { let reviewForThisActorProcessing: {
id: string; id: string;
requestId: string; requestId: string;
@ -545,7 +543,7 @@ export const accessApprovalRequestServiceFactory = ({
bypassReason: bypassReason || "No reason provided", bypassReason: bypassReason || "No reason provided",
secretPath: policy.secretPath || "/", secretPath: policy.secretPath || "/",
environment, environment,
approvalUrl: `${cfg.SITE_URL}/projects/${project.id}/secret-manager/approval`, approvalUrl: `${cfg.SITE_URL}/secret-manager/${project.id}/approval`,
requestType: "access" requestType: "access"
}, },
template: SmtpTemplates.AccessSecretRequestBypassed template: SmtpTemplates.AccessSecretRequestBypassed
@ -562,7 +560,6 @@ export const accessApprovalRequestServiceFactory = ({
const getCount: TAccessApprovalRequestServiceFactory["getCount"] = async ({ const getCount: TAccessApprovalRequestServiceFactory["getCount"] = async ({
projectSlug, projectSlug,
policyId,
actor, actor,
actorAuthMethod, actorAuthMethod,
actorId, actorId,
@ -576,13 +573,14 @@ export const accessApprovalRequestServiceFactory = ({
actorId, actorId,
projectId: project.id, projectId: project.id,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
if (!membership) { if (!membership) {
throw new ForbiddenRequestError({ message: "You are not a member of this project" }); throw new ForbiddenRequestError({ message: "You are not a member of this project" });
} }
const count = await accessApprovalRequestDAL.getCount({ projectId: project.id, policyId }); const count = await accessApprovalRequestDAL.getCount({ projectId: project.id });
return { count }; return { count };
}; };

View File

@ -12,7 +12,6 @@ export type TVerifyPermission = {
export type TGetAccessRequestCountDTO = { export type TGetAccessRequestCountDTO = {
projectSlug: string; projectSlug: string;
policyId?: string;
} & Omit<TProjectPermission, "projectId">; } & Omit<TProjectPermission, "projectId">;
export type TReviewAccessRequestDTO = { export type TReviewAccessRequestDTO = {

View File

@ -1,6 +1,7 @@
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError } from "@casl/ability";
import jwt from "jsonwebtoken"; import jwt from "jsonwebtoken";
import { ActionProjectType } from "@app/db/schemas";
import { getConfig } from "@app/lib/config/env"; import { getConfig } from "@app/lib/config/env";
import { ForbiddenRequestError, NotFoundError } from "@app/lib/errors"; import { ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
import { ActorType } from "@app/services/auth/auth-type"; import { ActorType } from "@app/services/auth/auth-type";
@ -37,7 +38,8 @@ export const assumePrivilegeServiceFactory = ({
actorId: actorPermissionDetails.id, actorId: actorPermissionDetails.id,
projectId, projectId,
actorAuthMethod: actorPermissionDetails.authMethod, actorAuthMethod: actorPermissionDetails.authMethod,
actorOrgId: actorPermissionDetails.orgId actorOrgId: actorPermissionDetails.orgId,
actionProjectType: ActionProjectType.Any
}); });
if (targetActorType === ActorType.USER) { if (targetActorType === ActorType.USER) {
@ -58,7 +60,8 @@ export const assumePrivilegeServiceFactory = ({
actorId: targetActorId, actorId: targetActorId,
projectId, projectId,
actorAuthMethod: actorPermissionDetails.authMethod, actorAuthMethod: actorPermissionDetails.authMethod,
actorOrgId: actorPermissionDetails.orgId actorOrgId: actorPermissionDetails.orgId,
actionProjectType: ActionProjectType.Any
}); });
const appCfg = getConfig(); const appCfg = getConfig();

View File

@ -1,21 +0,0 @@
export function providerSpecificPayload(url: string) {
const { hostname } = new URL(url);
const payload: Record<string, string> = {};
switch (hostname) {
case "http-intake.logs.datadoghq.com":
case "http-intake.logs.us3.datadoghq.com":
case "http-intake.logs.us5.datadoghq.com":
case "http-intake.logs.datadoghq.eu":
case "http-intake.logs.ap1.datadoghq.com":
case "http-intake.logs.ddog-gov.com":
payload.ddsource = "infisical";
payload.service = "audit-logs";
break;
default:
break;
}
return payload;
}

View File

@ -13,7 +13,6 @@ import { TLicenseServiceFactory } from "../license/license-service";
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission"; import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
import { TPermissionServiceFactory } from "../permission/permission-service-types"; import { TPermissionServiceFactory } from "../permission/permission-service-types";
import { TAuditLogStreamDALFactory } from "./audit-log-stream-dal"; import { TAuditLogStreamDALFactory } from "./audit-log-stream-dal";
import { providerSpecificPayload } from "./audit-log-stream-fns";
import { LogStreamHeaders, TAuditLogStreamServiceFactory } from "./audit-log-stream-types"; import { LogStreamHeaders, TAuditLogStreamServiceFactory } from "./audit-log-stream-types";
type TAuditLogStreamServiceFactoryDep = { type TAuditLogStreamServiceFactoryDep = {
@ -70,11 +69,10 @@ export const auditLogStreamServiceFactory = ({
headers.forEach(({ key, value }) => { headers.forEach(({ key, value }) => {
streamHeaders[key] = value; streamHeaders[key] = value;
}); });
await request await request
.post( .post(
url, url,
{ ...providerSpecificPayload(url), ping: "ok" }, { ping: "ok" },
{ {
headers: streamHeaders, headers: streamHeaders,
// request timeout // request timeout
@ -139,7 +137,7 @@ export const auditLogStreamServiceFactory = ({
await request await request
.post( .post(
url || logStream.url, url || logStream.url,
{ ...providerSpecificPayload(url || logStream.url), ping: "ok" }, { ping: "ok" },
{ {
headers: streamHeaders, headers: streamHeaders,
// request timeout // request timeout

View File

@ -30,10 +30,10 @@ type TFindQuery = {
actor?: string; actor?: string;
projectId?: string; projectId?: string;
environment?: string; environment?: string;
orgId: string; orgId?: string;
eventType?: string; eventType?: string;
startDate: string; startDate?: string;
endDate: string; endDate?: string;
userAgentType?: string; userAgentType?: string;
limit?: number; limit?: number;
offset?: number; offset?: number;
@ -61,15 +61,18 @@ export const auditLogDALFactory = (db: TDbClient) => {
}, },
tx tx
) => { ) => {
if (!orgId && !projectId) {
throw new Error("Either orgId or projectId must be provided");
}
try { try {
// Find statements // Find statements
const sqlQuery = (tx || db.replicaNode())(TableName.AuditLog) const sqlQuery = (tx || db.replicaNode())(TableName.AuditLog)
.where(`${TableName.AuditLog}.orgId`, orgId)
.whereRaw(`"${TableName.AuditLog}"."createdAt" >= ?::timestamptz`, [startDate])
.andWhereRaw(`"${TableName.AuditLog}"."createdAt" < ?::timestamptz`, [endDate])
// eslint-disable-next-line func-names // eslint-disable-next-line func-names
.where(function () { .where(function () {
if (projectId) { if (orgId) {
void this.where(`${TableName.AuditLog}.orgId`, orgId);
} else if (projectId) {
void this.where(`${TableName.AuditLog}.projectId`, projectId); void this.where(`${TableName.AuditLog}.projectId`, projectId);
} }
}); });
@ -132,6 +135,14 @@ export const auditLogDALFactory = (db: TDbClient) => {
void sqlQuery.whereIn("eventType", eventType); void sqlQuery.whereIn("eventType", eventType);
} }
// Filter by date range
if (startDate) {
void sqlQuery.whereRaw(`"${TableName.AuditLog}"."createdAt" >= ?::timestamptz`, [startDate]);
}
if (endDate) {
void sqlQuery.whereRaw(`"${TableName.AuditLog}"."createdAt" <= ?::timestamptz`, [endDate]);
}
// we timeout long running queries to prevent DB resource issues (2 minutes) // we timeout long running queries to prevent DB resource issues (2 minutes)
const docs = await sqlQuery.timeout(1000 * 120); const docs = await sqlQuery.timeout(1000 * 120);
@ -163,8 +174,6 @@ export const auditLogDALFactory = (db: TDbClient) => {
try { try {
const findExpiredLogSubQuery = (tx || db)(TableName.AuditLog) const findExpiredLogSubQuery = (tx || db)(TableName.AuditLog)
.where("expiresAt", "<", today) .where("expiresAt", "<", today)
.where("createdAt", "<", today) // to use audit log partition
.orderBy(`${TableName.AuditLog}.createdAt`, "desc")
.select("id") .select("id")
.limit(AUDIT_LOG_PRUNE_BATCH_SIZE); .limit(AUDIT_LOG_PRUNE_BATCH_SIZE);

View File

@ -1,15 +1,13 @@
import { AxiosError, RawAxiosRequestHeaders } from "axios"; import { RawAxiosRequestHeaders } from "axios";
import { SecretKeyEncoding } from "@app/db/schemas"; import { SecretKeyEncoding } from "@app/db/schemas";
import { getConfig } from "@app/lib/config/env"; import { getConfig } from "@app/lib/config/env";
import { request } from "@app/lib/config/request"; import { request } from "@app/lib/config/request";
import { infisicalSymmetricDecrypt } from "@app/lib/crypto/encryption"; import { infisicalSymmetricDecrypt } from "@app/lib/crypto/encryption";
import { logger } from "@app/lib/logger";
import { QueueJobs, QueueName, TQueueServiceFactory } from "@app/queue"; import { QueueJobs, QueueName, TQueueServiceFactory } from "@app/queue";
import { TProjectDALFactory } from "@app/services/project/project-dal"; import { TProjectDALFactory } from "@app/services/project/project-dal";
import { TAuditLogStreamDALFactory } from "../audit-log-stream/audit-log-stream-dal"; import { TAuditLogStreamDALFactory } from "../audit-log-stream/audit-log-stream-dal";
import { providerSpecificPayload } from "../audit-log-stream/audit-log-stream-fns";
import { LogStreamHeaders } from "../audit-log-stream/audit-log-stream-types"; import { LogStreamHeaders } from "../audit-log-stream/audit-log-stream-types";
import { TLicenseServiceFactory } from "../license/license-service"; import { TLicenseServiceFactory } from "../license/license-service";
import { TAuditLogDALFactory } from "./audit-log-dal"; import { TAuditLogDALFactory } from "./audit-log-dal";
@ -130,25 +128,13 @@ export const auditLogQueueServiceFactory = async ({
headers[key] = value; headers[key] = value;
}); });
try { return request.post(url, auditLog, {
const response = await request.post( headers,
url, // request timeout
{ ...providerSpecificPayload(url), ...auditLog }, timeout: AUDIT_LOG_STREAM_TIMEOUT,
{ // connection timeout
headers, signal: AbortSignal.timeout(AUDIT_LOG_STREAM_TIMEOUT)
// request timeout });
timeout: AUDIT_LOG_STREAM_TIMEOUT,
// connection timeout
signal: AbortSignal.timeout(AUDIT_LOG_STREAM_TIMEOUT)
}
);
return response;
} catch (error) {
logger.error(
`Failed to stream audit log [url=${url}] for org [orgId=${orgId}] [error=${(error as AxiosError).message}]`
);
return error;
}
} }
) )
); );
@ -232,25 +218,13 @@ export const auditLogQueueServiceFactory = async ({
headers[key] = value; headers[key] = value;
}); });
try { return request.post(url, auditLog, {
const response = await request.post( headers,
url, // request timeout
{ ...providerSpecificPayload(url), ...auditLog }, timeout: AUDIT_LOG_STREAM_TIMEOUT,
{ // connection timeout
headers, signal: AbortSignal.timeout(AUDIT_LOG_STREAM_TIMEOUT)
// request timeout });
timeout: AUDIT_LOG_STREAM_TIMEOUT,
// connection timeout
signal: AbortSignal.timeout(AUDIT_LOG_STREAM_TIMEOUT)
}
);
return response;
} catch (error) {
logger.error(
`Failed to stream audit log [url=${url}] for org [orgId=${orgId}] [error=${(error as AxiosError).message}]`
);
return error;
}
} }
) )
); );

View File

@ -1,6 +1,7 @@
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError } from "@casl/ability";
import { requestContext } from "@fastify/request-context"; import { requestContext } from "@fastify/request-context";
import { ActionProjectType } from "@app/db/schemas";
import { getConfig } from "@app/lib/config/env"; import { getConfig } from "@app/lib/config/env";
import { BadRequestError } from "@app/lib/errors"; import { BadRequestError } from "@app/lib/errors";
import { ActorType } from "@app/services/auth/auth-type"; import { ActorType } from "@app/services/auth/auth-type";
@ -37,7 +38,8 @@ export const auditLogServiceFactory = ({
actorId, actorId,
projectId: filter.projectId, projectId: filter.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.AuditLogs); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.AuditLogs);
} else { } else {
@ -67,8 +69,7 @@ export const auditLogServiceFactory = ({
secretPath: filter.secretPath, secretPath: filter.secretPath,
secretKey: filter.secretKey, secretKey: filter.secretKey,
environment: filter.environment, environment: filter.environment,
orgId: actorOrgId, ...(filter.projectId ? { projectId: filter.projectId } : { orgId: actorOrgId })
...(filter.projectId ? { projectId: filter.projectId } : {})
}); });
return auditLogs.map(({ eventType: logEventType, actor: eActor, actorMetadata, eventMetadata, ...el }) => ({ return auditLogs.map(({ eventType: logEventType, actor: eActor, actorMetadata, eventMetadata, ...el }) => ({

View File

@ -56,8 +56,8 @@ export type TListProjectAuditLogDTO = {
eventType?: EventType[]; eventType?: EventType[];
offset?: number; offset?: number;
limit: number; limit: number;
endDate: string; endDate?: string;
startDate: string; startDate?: string;
projectId?: string; projectId?: string;
environment?: string; environment?: string;
auditLogActorId?: string; auditLogActorId?: string;
@ -202,12 +202,6 @@ export enum EventType {
REVOKE_IDENTITY_ALICLOUD_AUTH = "revoke-identity-alicloud-auth", REVOKE_IDENTITY_ALICLOUD_AUTH = "revoke-identity-alicloud-auth",
GET_IDENTITY_ALICLOUD_AUTH = "get-identity-alicloud-auth", GET_IDENTITY_ALICLOUD_AUTH = "get-identity-alicloud-auth",
LOGIN_IDENTITY_TLS_CERT_AUTH = "login-identity-tls-cert-auth",
ADD_IDENTITY_TLS_CERT_AUTH = "add-identity-tls-cert-auth",
UPDATE_IDENTITY_TLS_CERT_AUTH = "update-identity-tls-cert-auth",
REVOKE_IDENTITY_TLS_CERT_AUTH = "revoke-identity-tls-cert-auth",
GET_IDENTITY_TLS_CERT_AUTH = "get-identity-tls-cert-auth",
LOGIN_IDENTITY_AWS_AUTH = "login-identity-aws-auth", LOGIN_IDENTITY_AWS_AUTH = "login-identity-aws-auth",
ADD_IDENTITY_AWS_AUTH = "add-identity-aws-auth", ADD_IDENTITY_AWS_AUTH = "add-identity-aws-auth",
UPDATE_IDENTITY_AWS_AUTH = "update-identity-aws-auth", UPDATE_IDENTITY_AWS_AUTH = "update-identity-aws-auth",
@ -1147,53 +1141,6 @@ interface GetIdentityAliCloudAuthEvent {
}; };
} }
interface LoginIdentityTlsCertAuthEvent {
type: EventType.LOGIN_IDENTITY_TLS_CERT_AUTH;
metadata: {
identityId: string;
identityTlsCertAuthId: string;
identityAccessTokenId: string;
};
}
interface AddIdentityTlsCertAuthEvent {
type: EventType.ADD_IDENTITY_TLS_CERT_AUTH;
metadata: {
identityId: string;
allowedCommonNames: string | null | undefined;
accessTokenTTL: number;
accessTokenMaxTTL: number;
accessTokenNumUsesLimit: number;
accessTokenTrustedIps: Array<TIdentityTrustedIp>;
};
}
interface DeleteIdentityTlsCertAuthEvent {
type: EventType.REVOKE_IDENTITY_TLS_CERT_AUTH;
metadata: {
identityId: string;
};
}
interface UpdateIdentityTlsCertAuthEvent {
type: EventType.UPDATE_IDENTITY_TLS_CERT_AUTH;
metadata: {
identityId: string;
allowedCommonNames: string | null | undefined;
accessTokenTTL?: number;
accessTokenMaxTTL?: number;
accessTokenNumUsesLimit?: number;
accessTokenTrustedIps?: Array<TIdentityTrustedIp>;
};
}
interface GetIdentityTlsCertAuthEvent {
type: EventType.GET_IDENTITY_TLS_CERT_AUTH;
metadata: {
identityId: string;
};
}
interface LoginIdentityOciAuthEvent { interface LoginIdentityOciAuthEvent {
type: EventType.LOGIN_IDENTITY_OCI_AUTH; type: EventType.LOGIN_IDENTITY_OCI_AUTH;
metadata: { metadata: {
@ -3411,11 +3358,6 @@ export type Event =
| UpdateIdentityAliCloudAuthEvent | UpdateIdentityAliCloudAuthEvent
| GetIdentityAliCloudAuthEvent | GetIdentityAliCloudAuthEvent
| DeleteIdentityAliCloudAuthEvent | DeleteIdentityAliCloudAuthEvent
| LoginIdentityTlsCertAuthEvent
| AddIdentityTlsCertAuthEvent
| UpdateIdentityTlsCertAuthEvent
| GetIdentityTlsCertAuthEvent
| DeleteIdentityTlsCertAuthEvent
| LoginIdentityOciAuthEvent | LoginIdentityOciAuthEvent
| AddIdentityOciAuthEvent | AddIdentityOciAuthEvent
| UpdateIdentityOciAuthEvent | UpdateIdentityOciAuthEvent

View File

@ -1,6 +1,7 @@
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError } from "@casl/ability";
import * as x509 from "@peculiar/x509"; import * as x509 from "@peculiar/x509";
import { ActionProjectType } from "@app/db/schemas";
import { TCertificateAuthorityCrlDALFactory } from "@app/ee/services/certificate-authority-crl/certificate-authority-crl-dal"; import { TCertificateAuthorityCrlDALFactory } from "@app/ee/services/certificate-authority-crl/certificate-authority-crl-dal";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
@ -77,7 +78,8 @@ export const certificateAuthorityCrlServiceFactory = ({
actorId, actorId,
projectId: ca.projectId, projectId: ca.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(

View File

@ -1,6 +1,7 @@
import { ForbiddenError, subject } from "@casl/ability"; import { ForbiddenError, subject } from "@casl/ability";
import RE2 from "re2"; import RE2 from "re2";
import { ActionProjectType } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service"; import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { import {
@ -84,7 +85,8 @@ export const dynamicSecretLeaseServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
const plan = await licenseService.getPlan(actorOrgId); const plan = await licenseService.getPlan(actorOrgId);
@ -200,7 +202,8 @@ export const dynamicSecretLeaseServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({ const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
@ -297,7 +300,8 @@ export const dynamicSecretLeaseServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({ const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
@ -385,7 +389,8 @@ export const dynamicSecretLeaseServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path); const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
@ -432,7 +437,8 @@ export const dynamicSecretLeaseServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path); const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);

View File

@ -1,5 +1,6 @@
import { ForbiddenError, subject } from "@casl/ability"; import { ForbiddenError, subject } from "@casl/ability";
import { ActionProjectType } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service"; import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { import {
@ -77,7 +78,8 @@ export const dynamicSecretServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
@ -200,7 +202,8 @@ export const dynamicSecretServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
const plan = await licenseService.getPlan(actorOrgId); const plan = await licenseService.getPlan(actorOrgId);
@ -351,7 +354,8 @@ export const dynamicSecretServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path); const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
@ -416,7 +420,8 @@ export const dynamicSecretServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path); const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
@ -480,7 +485,8 @@ export const dynamicSecretServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
// verify user has access to each env in request // verify user has access to each env in request
@ -523,7 +529,8 @@ export const dynamicSecretServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionDynamicSecretActions.ReadRootCredential, ProjectPermissionDynamicSecretActions.ReadRootCredential,
@ -571,7 +578,8 @@ export const dynamicSecretServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path); const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
@ -608,7 +616,8 @@ export const dynamicSecretServiceFactory = ({
actorId: actor.id, actorId: actor.id,
projectId, projectId,
actorAuthMethod: actor.authMethod, actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretManager
}); });
const userAccessibleFolderMappings = folderMappings.filter(({ path, environment }) => const userAccessibleFolderMappings = folderMappings.filter(({ path, environment }) =>
@ -652,7 +661,8 @@ export const dynamicSecretServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
const folders = await folderDAL.findBySecretPathMultiEnv(projectId, environmentSlugs, path); const folders = await folderDAL.findBySecretPathMultiEnv(projectId, environmentSlugs, path);

View File

@ -1,5 +1,5 @@
import axios from "axios"; import axios from "axios";
import jwt from "jsonwebtoken"; import * as jwt from "jsonwebtoken";
import { BadRequestError, InternalServerError } from "@app/lib/errors"; import { BadRequestError, InternalServerError } from "@app/lib/errors";
import { alphaNumericNanoId } from "@app/lib/nanoid"; import { alphaNumericNanoId } from "@app/lib/nanoid";

View File

@ -1,7 +1,7 @@
import { ForbiddenError, subject } from "@casl/ability"; import { ForbiddenError, subject } from "@casl/ability";
import { packRules } from "@casl/ability/extra"; import { packRules } from "@casl/ability/extra";
import { TableName } from "@app/db/schemas"; import { ActionProjectType, TableName } from "@app/db/schemas";
import { BadRequestError, NotFoundError, PermissionBoundaryError } from "@app/lib/errors"; import { BadRequestError, NotFoundError, PermissionBoundaryError } from "@app/lib/errors";
import { ms } from "@app/lib/ms"; import { ms } from "@app/lib/ms";
import { validateHandlebarTemplate } from "@app/lib/template/validate-handlebars"; import { validateHandlebarTemplate } from "@app/lib/template/validate-handlebars";
@ -61,7 +61,8 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
actorId, actorId,
projectId: identityProjectMembership.projectId, projectId: identityProjectMembership.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionIdentityActions.Edit, ProjectPermissionIdentityActions.Edit,
@ -72,7 +73,8 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
actorId: identityId, actorId: identityId,
projectId: identityProjectMembership.projectId, projectId: identityProjectMembership.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
// we need to validate that the privilege given is not higher than the assigning users permission // we need to validate that the privilege given is not higher than the assigning users permission
@ -158,7 +160,8 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
actorId, actorId,
projectId: identityProjectMembership.projectId, projectId: identityProjectMembership.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionIdentityActions.Edit, ProjectPermissionIdentityActions.Edit,
@ -169,7 +172,8 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
actorId: identityProjectMembership.identityId, actorId: identityProjectMembership.identityId,
projectId: identityProjectMembership.projectId, projectId: identityProjectMembership.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
// we need to validate that the privilege given is not higher than the assigning users permission // we need to validate that the privilege given is not higher than the assigning users permission
@ -256,7 +260,8 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
actorId, actorId,
projectId: identityProjectMembership.projectId, projectId: identityProjectMembership.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionIdentityActions.Edit, ProjectPermissionIdentityActions.Edit,
@ -267,7 +272,8 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
actorId: identityProjectMembership.identityId, actorId: identityProjectMembership.identityId,
projectId: identityProjectMembership.projectId, projectId: identityProjectMembership.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
const permissionBoundary = validatePrivilegeChangeOperation( const permissionBoundary = validatePrivilegeChangeOperation(
membership.shouldUseNewPrivilegeSystem, membership.shouldUseNewPrivilegeSystem,
@ -315,7 +321,8 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
actorId, actorId,
projectId: identityProjectMembership.projectId, projectId: identityProjectMembership.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionIdentityActions.Read, ProjectPermissionIdentityActions.Read,
@ -349,7 +356,8 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
actorId, actorId,
projectId: identityProjectMembership.projectId, projectId: identityProjectMembership.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionIdentityActions.Read, ProjectPermissionIdentityActions.Read,
@ -384,7 +392,8 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
actorId, actorId,
projectId: identityProjectMembership.projectId, projectId: identityProjectMembership.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionIdentityActions.Read, ProjectPermissionIdentityActions.Read,

View File

@ -1,6 +1,7 @@
import { ForbiddenError, MongoAbility, RawRuleOf, subject } from "@casl/ability"; import { ForbiddenError, MongoAbility, RawRuleOf, subject } from "@casl/ability";
import { PackRule, packRules, unpackRules } from "@casl/ability/extra"; import { PackRule, packRules, unpackRules } from "@casl/ability/extra";
import { ActionProjectType } from "@app/db/schemas";
import { BadRequestError, NotFoundError, PermissionBoundaryError } from "@app/lib/errors"; import { BadRequestError, NotFoundError, PermissionBoundaryError } from "@app/lib/errors";
import { ms } from "@app/lib/ms"; import { ms } from "@app/lib/ms";
import { validateHandlebarTemplate } from "@app/lib/template/validate-handlebars"; import { validateHandlebarTemplate } from "@app/lib/template/validate-handlebars";
@ -72,7 +73,8 @@ export const identityProjectAdditionalPrivilegeServiceFactory = ({
actorId, actorId,
projectId: identityProjectMembership.projectId, projectId: identityProjectMembership.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
@ -85,7 +87,8 @@ export const identityProjectAdditionalPrivilegeServiceFactory = ({
actorId: identityId, actorId: identityId,
projectId: identityProjectMembership.projectId, projectId: identityProjectMembership.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
// we need to validate that the privilege given is not higher than the assigning users permission // we need to validate that the privilege given is not higher than the assigning users permission
@ -172,7 +175,8 @@ export const identityProjectAdditionalPrivilegeServiceFactory = ({
actorId, actorId,
projectId: identityProjectMembership.projectId, projectId: identityProjectMembership.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
@ -185,7 +189,8 @@ export const identityProjectAdditionalPrivilegeServiceFactory = ({
actorId: identityProjectMembership.identityId, actorId: identityProjectMembership.identityId,
projectId: identityProjectMembership.projectId, projectId: identityProjectMembership.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
// we need to validate that the privilege given is not higher than the assigning users permission // we need to validate that the privilege given is not higher than the assigning users permission
@ -288,7 +293,8 @@ export const identityProjectAdditionalPrivilegeServiceFactory = ({
actorId, actorId,
projectId: identityProjectMembership.projectId, projectId: identityProjectMembership.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionIdentityActions.Edit, ProjectPermissionIdentityActions.Edit,
@ -300,7 +306,8 @@ export const identityProjectAdditionalPrivilegeServiceFactory = ({
actorId: identityProjectMembership.identityId, actorId: identityProjectMembership.identityId,
projectId: identityProjectMembership.projectId, projectId: identityProjectMembership.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
const permissionBoundary = validatePrivilegeChangeOperation( const permissionBoundary = validatePrivilegeChangeOperation(
membership.shouldUseNewPrivilegeSystem, membership.shouldUseNewPrivilegeSystem,
@ -359,7 +366,8 @@ export const identityProjectAdditionalPrivilegeServiceFactory = ({
actorId, actorId,
projectId: identityProjectMembership.projectId, projectId: identityProjectMembership.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionIdentityActions.Read, ProjectPermissionIdentityActions.Read,
@ -401,7 +409,8 @@ export const identityProjectAdditionalPrivilegeServiceFactory = ({
actorId, actorId,
projectId: identityProjectMembership.projectId, projectId: identityProjectMembership.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(

View File

@ -24,7 +24,7 @@ type TKmipOperationServiceFactoryDep = {
kmsService: TKmsServiceFactory; kmsService: TKmsServiceFactory;
kmsDAL: TKmsKeyDALFactory; kmsDAL: TKmsKeyDALFactory;
kmipClientDAL: TKmipClientDALFactory; kmipClientDAL: TKmipClientDALFactory;
projectDAL: Pick<TProjectDALFactory, "findById">; projectDAL: Pick<TProjectDALFactory, "getProjectFromSplitId" | "findById">;
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">; permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
}; };

View File

@ -2,6 +2,7 @@ import { ForbiddenError } from "@casl/ability";
import * as x509 from "@peculiar/x509"; import * as x509 from "@peculiar/x509";
import crypto, { KeyObject } from "crypto"; import crypto, { KeyObject } from "crypto";
import { ActionProjectType } from "@app/db/schemas";
import { BadRequestError, InternalServerError, NotFoundError } from "@app/lib/errors"; import { BadRequestError, InternalServerError, NotFoundError } from "@app/lib/errors";
import { isValidIp } from "@app/lib/ip"; import { isValidIp } from "@app/lib/ip";
import { ms } from "@app/lib/ms"; import { ms } from "@app/lib/ms";
@ -72,7 +73,8 @@ export const kmipServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.KMS
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
@ -125,7 +127,8 @@ export const kmipServiceFactory = ({
actorId, actorId,
projectId: kmipClient.projectId, projectId: kmipClient.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.KMS
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
@ -156,7 +159,8 @@ export const kmipServiceFactory = ({
actorId, actorId,
projectId: kmipClient.projectId, projectId: kmipClient.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.KMS
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
@ -189,7 +193,8 @@ export const kmipServiceFactory = ({
actorId, actorId,
projectId: kmipClient.projectId, projectId: kmipClient.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.KMS
}); });
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionKmipActions.ReadClients, ProjectPermissionSub.Kmip); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionKmipActions.ReadClients, ProjectPermissionSub.Kmip);
@ -210,7 +215,8 @@ export const kmipServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.KMS
}); });
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionKmipActions.ReadClients, ProjectPermissionSub.Kmip); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionKmipActions.ReadClients, ProjectPermissionSub.Kmip);
@ -246,7 +252,8 @@ export const kmipServiceFactory = ({
actorId, actorId,
projectId: kmipClient.projectId, projectId: kmipClient.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.KMS
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(

View File

@ -107,26 +107,34 @@ export const oidcConfigServiceFactory = ({
kmsService kmsService
}: TOidcConfigServiceFactoryDep) => { }: TOidcConfigServiceFactoryDep) => {
const getOidc = async (dto: TGetOidcCfgDTO) => { const getOidc = async (dto: TGetOidcCfgDTO) => {
const oidcCfg = await oidcConfigDAL.findOne({ const org = await orgDAL.findOne({ slug: dto.orgSlug });
orgId: dto.organizationId if (!org) {
});
if (!oidcCfg) {
throw new NotFoundError({ throw new NotFoundError({
message: `OIDC configuration for organization with ID '${dto.organizationId}' not found` message: `Organization with slug '${dto.orgSlug}' not found`,
name: "OrgNotFound"
}); });
} }
if (dto.type === "external") { if (dto.type === "external") {
const { permission } = await permissionService.getOrgPermission( const { permission } = await permissionService.getOrgPermission(
dto.actor, dto.actor,
dto.actorId, dto.actorId,
dto.organizationId, org.id,
dto.actorAuthMethod, dto.actorAuthMethod,
dto.actorOrgId dto.actorOrgId
); );
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Sso); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Sso);
} }
const oidcCfg = await oidcConfigDAL.findOne({
orgId: org.id
});
if (!oidcCfg) {
throw new NotFoundError({
message: `OIDC configuration for organization with slug '${dto.orgSlug}' not found`
});
}
const { decryptor } = await kmsService.createCipherPairWithDataKey({ const { decryptor } = await kmsService.createCipherPairWithDataKey({
type: KmsDataKey.Organization, type: KmsDataKey.Organization,
orgId: oidcCfg.orgId orgId: oidcCfg.orgId
@ -457,7 +465,7 @@ export const oidcConfigServiceFactory = ({
}; };
const updateOidcCfg = async ({ const updateOidcCfg = async ({
organizationId, orgSlug,
allowedEmailDomains, allowedEmailDomains,
configurationType, configurationType,
discoveryURL, discoveryURL,
@ -476,11 +484,13 @@ export const oidcConfigServiceFactory = ({
manageGroupMemberships, manageGroupMemberships,
jwtSignatureAlgorithm jwtSignatureAlgorithm
}: TUpdateOidcCfgDTO) => { }: TUpdateOidcCfgDTO) => {
const org = await orgDAL.findOne({ id: organizationId }); const org = await orgDAL.findOne({
slug: orgSlug
});
if (!org) { if (!org) {
throw new NotFoundError({ throw new NotFoundError({
message: `Organization with ID '${organizationId}' not found` message: `Organization with slug '${orgSlug}' not found`
}); });
} }
@ -545,7 +555,7 @@ export const oidcConfigServiceFactory = ({
}; };
const createOidcCfg = async ({ const createOidcCfg = async ({
organizationId, orgSlug,
allowedEmailDomains, allowedEmailDomains,
configurationType, configurationType,
discoveryURL, discoveryURL,
@ -564,10 +574,12 @@ export const oidcConfigServiceFactory = ({
manageGroupMemberships, manageGroupMemberships,
jwtSignatureAlgorithm jwtSignatureAlgorithm
}: TCreateOidcCfgDTO) => { }: TCreateOidcCfgDTO) => {
const org = await orgDAL.findOne({ id: organizationId }); const org = await orgDAL.findOne({
slug: orgSlug
});
if (!org) { if (!org) {
throw new NotFoundError({ throw new NotFoundError({
message: `Organization with ID '${organizationId}' not found` message: `Organization with slug '${orgSlug}' not found`
}); });
} }
@ -627,7 +639,7 @@ export const oidcConfigServiceFactory = ({
const oidcCfg = await getOidc({ const oidcCfg = await getOidc({
type: "internal", type: "internal",
organizationId: org.id orgSlug
}); });
if (!oidcCfg || !oidcCfg.isActive) { if (!oidcCfg || !oidcCfg.isActive) {

View File

@ -26,11 +26,11 @@ export type TOidcLoginDTO = {
export type TGetOidcCfgDTO = export type TGetOidcCfgDTO =
| ({ | ({
type: "external"; type: "external";
organizationId: string; orgSlug: string;
} & TGenericPermission) } & TGenericPermission)
| { | {
type: "internal"; type: "internal";
organizationId: string; orgSlug: string;
}; };
export type TCreateOidcCfgDTO = { export type TCreateOidcCfgDTO = {
@ -45,7 +45,7 @@ export type TCreateOidcCfgDTO = {
clientId: string; clientId: string;
clientSecret: string; clientSecret: string;
isActive: boolean; isActive: boolean;
organizationId: string; orgSlug: string;
manageGroupMemberships: boolean; manageGroupMemberships: boolean;
jwtSignatureAlgorithm: OIDCJWTSignatureAlgorithm; jwtSignatureAlgorithm: OIDCJWTSignatureAlgorithm;
} & TGenericPermission; } & TGenericPermission;
@ -62,7 +62,7 @@ export type TUpdateOidcCfgDTO = Partial<{
clientId: string; clientId: string;
clientSecret: string; clientSecret: string;
isActive: boolean; isActive: boolean;
organizationId: string; orgSlug: string;
manageGroupMemberships: boolean; manageGroupMemberships: boolean;
jwtSignatureAlgorithm: OIDCJWTSignatureAlgorithm; jwtSignatureAlgorithm: OIDCJWTSignatureAlgorithm;
}> & }> &

View File

@ -91,7 +91,7 @@ export interface TPermissionDALFactory {
userId: string; userId: string;
projectId: string; projectId: string;
username: string; username: string;
projectType?: string | null; projectType: string;
id: string; id: string;
createdAt: Date; createdAt: Date;
updatedAt: Date; updatedAt: Date;
@ -163,7 +163,7 @@ export interface TPermissionDALFactory {
createdAt: Date; createdAt: Date;
updatedAt: Date; updatedAt: Date;
orgId: string; orgId: string;
projectType?: string | null; projectType: string;
shouldUseNewPrivilegeSystem: boolean; shouldUseNewPrivilegeSystem: boolean;
orgAuthEnforced: boolean; orgAuthEnforced: boolean;
metadata: { metadata: {
@ -201,7 +201,7 @@ export interface TPermissionDALFactory {
userId: string; userId: string;
projectId: string; projectId: string;
username: string; username: string;
projectType?: string | null; projectType: string;
id: string; id: string;
createdAt: Date; createdAt: Date;
updatedAt: Date; updatedAt: Date;
@ -267,7 +267,7 @@ export interface TPermissionDALFactory {
createdAt: Date; createdAt: Date;
updatedAt: Date; updatedAt: Date;
orgId: string; orgId: string;
projectType?: string | null; projectType: string;
orgAuthEnforced: boolean; orgAuthEnforced: boolean;
metadata: { metadata: {
id: string; id: string;

View File

@ -1,6 +1,7 @@
import { MongoAbility, RawRuleOf } from "@casl/ability"; import { MongoAbility, RawRuleOf } from "@casl/ability";
import { MongoQuery } from "@ucast/mongo2js"; import { MongoQuery } from "@ucast/mongo2js";
import { ActionProjectType } from "@app/db/schemas";
import { ActorAuthMethod, ActorType } from "@app/services/auth/auth-type"; import { ActorAuthMethod, ActorType } from "@app/services/auth/auth-type";
import { OrgPermissionSet } from "./org-permission"; import { OrgPermissionSet } from "./org-permission";
@ -20,6 +21,7 @@ export type TGetUserProjectPermissionArg = {
userId: string; userId: string;
projectId: string; projectId: string;
authMethod: ActorAuthMethod; authMethod: ActorAuthMethod;
actionProjectType: ActionProjectType;
userOrgId?: string; userOrgId?: string;
}; };
@ -27,12 +29,14 @@ export type TGetIdentityProjectPermissionArg = {
identityId: string; identityId: string;
projectId: string; projectId: string;
identityOrgId?: string; identityOrgId?: string;
actionProjectType: ActionProjectType;
}; };
export type TGetServiceTokenProjectPermissionArg = { export type TGetServiceTokenProjectPermissionArg = {
serviceTokenId: string; serviceTokenId: string;
projectId: string; projectId: string;
actorOrgId?: string; actorOrgId?: string;
actionProjectType: ActionProjectType;
}; };
export type TGetProjectPermissionArg = { export type TGetProjectPermissionArg = {
@ -41,6 +45,7 @@ export type TGetProjectPermissionArg = {
projectId: string; projectId: string;
actorAuthMethod: ActorAuthMethod; actorAuthMethod: ActorAuthMethod;
actorOrgId?: string; actorOrgId?: string;
actionProjectType: ActionProjectType;
}; };
export type TPermissionServiceFactory = { export type TPermissionServiceFactory = {
@ -138,7 +143,13 @@ export type TPermissionServiceFactory = {
}; };
} }
>; >;
getUserProjectPermission: ({ userId, projectId, authMethod, userOrgId }: TGetUserProjectPermissionArg) => Promise<{ getUserProjectPermission: ({
userId,
projectId,
authMethod,
userOrgId,
actionProjectType
}: TGetUserProjectPermissionArg) => Promise<{
permission: MongoAbility<ProjectPermissionSet, MongoQuery>; permission: MongoAbility<ProjectPermissionSet, MongoQuery>;
membership: { membership: {
id: string; id: string;

View File

@ -5,6 +5,7 @@ import { MongoQuery } from "@ucast/mongo2js";
import handlebars from "handlebars"; import handlebars from "handlebars";
import { import {
ActionProjectType,
OrgMembershipRole, OrgMembershipRole,
ProjectMembershipRole, ProjectMembershipRole,
ServiceTokenScopes, ServiceTokenScopes,
@ -213,7 +214,8 @@ export const permissionServiceFactory = ({
userId, userId,
projectId, projectId,
authMethod, authMethod,
userOrgId userOrgId,
actionProjectType
}: TGetUserProjectPermissionArg): Promise<TProjectPermissionRT<ActorType.USER>> => { }: TGetUserProjectPermissionArg): Promise<TProjectPermissionRT<ActorType.USER>> => {
const userProjectPermission = await permissionDAL.getProjectPermission(userId, projectId); const userProjectPermission = await permissionDAL.getProjectPermission(userId, projectId);
if (!userProjectPermission) throw new ForbiddenRequestError({ name: "User not a part of the specified project" }); if (!userProjectPermission) throw new ForbiddenRequestError({ name: "User not a part of the specified project" });
@ -240,6 +242,12 @@ export const permissionServiceFactory = ({
userProjectPermission.orgRole userProjectPermission.orgRole
); );
if (actionProjectType !== ActionProjectType.Any && actionProjectType !== userProjectPermission.projectType) {
throw new BadRequestError({
message: `The project is of type ${userProjectPermission.projectType}. Operations of type ${actionProjectType} are not allowed.`
});
}
// join two permissions and pass to build the final permission set // join two permissions and pass to build the final permission set
const rolePermissions = userProjectPermission.roles?.map(({ role, permissions }) => ({ role, permissions })) || []; const rolePermissions = userProjectPermission.roles?.map(({ role, permissions }) => ({ role, permissions })) || [];
const additionalPrivileges = const additionalPrivileges =
@ -287,7 +295,8 @@ export const permissionServiceFactory = ({
const getIdentityProjectPermission = async ({ const getIdentityProjectPermission = async ({
identityId, identityId,
projectId, projectId,
identityOrgId identityOrgId,
actionProjectType
}: TGetIdentityProjectPermissionArg): Promise<TProjectPermissionRT<ActorType.IDENTITY>> => { }: TGetIdentityProjectPermissionArg): Promise<TProjectPermissionRT<ActorType.IDENTITY>> => {
const identityProjectPermission = await permissionDAL.getProjectIdentityPermission(identityId, projectId); const identityProjectPermission = await permissionDAL.getProjectIdentityPermission(identityId, projectId);
if (!identityProjectPermission) if (!identityProjectPermission)
@ -307,6 +316,12 @@ export const permissionServiceFactory = ({
throw new ForbiddenRequestError({ name: "Identity is not a member of the specified organization" }); throw new ForbiddenRequestError({ name: "Identity is not a member of the specified organization" });
} }
if (actionProjectType !== ActionProjectType.Any && actionProjectType !== identityProjectPermission.projectType) {
throw new BadRequestError({
message: `The project is of type ${identityProjectPermission.projectType}. Operations of type ${actionProjectType} are not allowed.`
});
}
const rolePermissions = const rolePermissions =
identityProjectPermission.roles?.map(({ role, permissions }) => ({ role, permissions })) || []; identityProjectPermission.roles?.map(({ role, permissions }) => ({ role, permissions })) || [];
const additionalPrivileges = const additionalPrivileges =
@ -361,7 +376,8 @@ export const permissionServiceFactory = ({
const getServiceTokenProjectPermission = async ({ const getServiceTokenProjectPermission = async ({
serviceTokenId, serviceTokenId,
projectId, projectId,
actorOrgId actorOrgId,
actionProjectType
}: TGetServiceTokenProjectPermissionArg) => { }: TGetServiceTokenProjectPermissionArg) => {
const serviceToken = await serviceTokenDAL.findById(serviceTokenId); const serviceToken = await serviceTokenDAL.findById(serviceTokenId);
if (!serviceToken) throw new NotFoundError({ message: `Service token with ID '${serviceTokenId}' not found` }); if (!serviceToken) throw new NotFoundError({ message: `Service token with ID '${serviceTokenId}' not found` });
@ -386,6 +402,12 @@ export const permissionServiceFactory = ({
}); });
} }
if (actionProjectType !== ActionProjectType.Any && actionProjectType !== serviceTokenProject.type) {
throw new BadRequestError({
message: `The project is of type ${serviceTokenProject.type}. Operations of type ${actionProjectType} are not allowed.`
});
}
const scopes = ServiceTokenScopes.parse(serviceToken.scopes || []); const scopes = ServiceTokenScopes.parse(serviceToken.scopes || []);
return { return {
permission: buildServiceTokenProjectPermission(scopes, serviceToken.permissions), permission: buildServiceTokenProjectPermission(scopes, serviceToken.permissions),
@ -537,7 +559,8 @@ export const permissionServiceFactory = ({
actorId: inputActorId, actorId: inputActorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType
}: TGetProjectPermissionArg): Promise<TProjectPermissionRT<T>> => { }: TGetProjectPermissionArg): Promise<TProjectPermissionRT<T>> => {
let actor = inputActor; let actor = inputActor;
let actorId = inputActorId; let actorId = inputActorId;
@ -558,19 +581,22 @@ export const permissionServiceFactory = ({
userId: actorId, userId: actorId,
projectId, projectId,
authMethod: actorAuthMethod, authMethod: actorAuthMethod,
userOrgId: actorOrgId userOrgId: actorOrgId,
actionProjectType
}) as Promise<TProjectPermissionRT<T>>; }) as Promise<TProjectPermissionRT<T>>;
case ActorType.SERVICE: case ActorType.SERVICE:
return getServiceTokenProjectPermission({ return getServiceTokenProjectPermission({
serviceTokenId: actorId, serviceTokenId: actorId,
projectId, projectId,
actorOrgId actorOrgId,
actionProjectType
}) as Promise<TProjectPermissionRT<T>>; }) as Promise<TProjectPermissionRT<T>>;
case ActorType.IDENTITY: case ActorType.IDENTITY:
return getIdentityProjectPermission({ return getIdentityProjectPermission({
identityId: actorId, identityId: actorId,
projectId, projectId,
identityOrgId: actorOrgId identityOrgId: actorOrgId,
actionProjectType
}) as Promise<TProjectPermissionRT<T>>; }) as Promise<TProjectPermissionRT<T>>;
default: default:
throw new BadRequestError({ throw new BadRequestError({

View File

@ -1,6 +1,7 @@
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError } from "@casl/ability";
import { ActionProjectType } from "@app/db/schemas";
import { ProjectPermissionCommitsActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { ProjectPermissionCommitsActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { NotFoundError } from "@app/lib/errors"; import { NotFoundError } from "@app/lib/errors";
import { logger } from "@app/lib/logger"; import { logger } from "@app/lib/logger";
@ -320,7 +321,8 @@ export const pitServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
ForbiddenError.from(userPermission).throwUnlessCan( ForbiddenError.from(userPermission).throwUnlessCan(

View File

@ -1,3 +1,4 @@
import { ProjectType } from "@app/db/schemas";
import { import {
InfisicalProjectTemplate, InfisicalProjectTemplate,
TUnpackedPermission TUnpackedPermission
@ -6,18 +7,21 @@ import { getPredefinedRoles } from "@app/services/project-role/project-role-fns"
import { ProjectTemplateDefaultEnvironments } from "./project-template-constants"; import { ProjectTemplateDefaultEnvironments } from "./project-template-constants";
export const getDefaultProjectTemplate = (orgId: string) => ({ export const getDefaultProjectTemplate = (orgId: string, type: ProjectType) => ({
id: "b11b49a9-09a9-4443-916a-4246f9ff2c69", // random ID to appease zod id: "b11b49a9-09a9-4443-916a-4246f9ff2c69", // random ID to appease zod
type,
name: InfisicalProjectTemplate.Default, name: InfisicalProjectTemplate.Default,
createdAt: new Date(), createdAt: new Date(),
updatedAt: new Date(), updatedAt: new Date(),
description: `Infisical's default project template`, description: `Infisical's ${type} default project template`,
environments: ProjectTemplateDefaultEnvironments, environments: type === ProjectType.SecretManager ? ProjectTemplateDefaultEnvironments : null,
roles: getPredefinedRoles({ projectId: "project-template" }) as Array<{ roles: [...getPredefinedRoles({ projectId: "project-template", projectType: type })].map(
name: string; ({ name, slug, permissions }) => ({
slug: string; name,
permissions: TUnpackedPermission[]; slug,
}>, permissions: permissions as TUnpackedPermission[]
})
),
orgId orgId
}); });

View File

@ -1,7 +1,7 @@
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError } from "@casl/ability";
import { packRules } from "@casl/ability/extra"; import { packRules } from "@casl/ability/extra";
import { TProjectTemplates } from "@app/db/schemas"; import { ProjectType, TProjectTemplates } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service"; import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission"; import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
@ -29,11 +29,13 @@ const $unpackProjectTemplate = ({ roles, environments, ...rest }: TProjectTempla
...rest, ...rest,
environments: environments as TProjectTemplateEnvironment[], environments: environments as TProjectTemplateEnvironment[],
roles: [ roles: [
...getPredefinedRoles({ projectId: "project-template" }).map(({ name, slug, permissions }) => ({ ...getPredefinedRoles({ projectId: "project-template", projectType: rest.type as ProjectType }).map(
name, ({ name, slug, permissions }) => ({
slug, name,
permissions: permissions as TUnpackedPermission[] slug,
})), permissions: permissions as TUnpackedPermission[]
})
),
...(roles as TProjectTemplateRole[]).map((role) => ({ ...(roles as TProjectTemplateRole[]).map((role) => ({
...role, ...role,
permissions: unpackPermissions(role.permissions) permissions: unpackPermissions(role.permissions)
@ -46,7 +48,10 @@ export const projectTemplateServiceFactory = ({
permissionService, permissionService,
projectTemplateDAL projectTemplateDAL
}: TProjectTemplatesServiceFactoryDep): TProjectTemplateServiceFactory => { }: TProjectTemplatesServiceFactoryDep): TProjectTemplateServiceFactory => {
const listProjectTemplatesByOrg: TProjectTemplateServiceFactory["listProjectTemplatesByOrg"] = async (actor) => { const listProjectTemplatesByOrg: TProjectTemplateServiceFactory["listProjectTemplatesByOrg"] = async (
actor,
type
) => {
const plan = await licenseService.getPlan(actor.orgId); const plan = await licenseService.getPlan(actor.orgId);
if (!plan.projectTemplates) if (!plan.projectTemplates)
@ -65,11 +70,14 @@ export const projectTemplateServiceFactory = ({
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.ProjectTemplates); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.ProjectTemplates);
const projectTemplates = await projectTemplateDAL.find({ const projectTemplates = await projectTemplateDAL.find({
orgId: actor.orgId orgId: actor.orgId,
...(type ? { type } : {})
}); });
return [ return [
getDefaultProjectTemplate(actor.orgId), ...(type
? [getDefaultProjectTemplate(actor.orgId, type)]
: Object.values(ProjectType).map((projectType) => getDefaultProjectTemplate(actor.orgId, projectType))),
...projectTemplates.map((template) => $unpackProjectTemplate(template)) ...projectTemplates.map((template) => $unpackProjectTemplate(template))
]; ];
}; };
@ -134,7 +142,7 @@ export const projectTemplateServiceFactory = ({
}; };
const createProjectTemplate: TProjectTemplateServiceFactory["createProjectTemplate"] = async ( const createProjectTemplate: TProjectTemplateServiceFactory["createProjectTemplate"] = async (
{ roles, environments, ...params }, { roles, environments, type, ...params },
actor actor
) => { ) => {
const plan = await licenseService.getPlan(actor.orgId); const plan = await licenseService.getPlan(actor.orgId);
@ -154,6 +162,10 @@ export const projectTemplateServiceFactory = ({
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.ProjectTemplates); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.ProjectTemplates);
if (environments && type !== ProjectType.SecretManager) {
throw new BadRequestError({ message: "Cannot configure environments for non-SecretManager project templates" });
}
if (environments && plan.environmentLimit !== null && environments.length > plan.environmentLimit) { if (environments && plan.environmentLimit !== null && environments.length > plan.environmentLimit) {
throw new BadRequestError({ throw new BadRequestError({
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
@ -176,8 +188,10 @@ export const projectTemplateServiceFactory = ({
const projectTemplate = await projectTemplateDAL.create({ const projectTemplate = await projectTemplateDAL.create({
...params, ...params,
roles: JSON.stringify(roles.map((role) => ({ ...role, permissions: packRules(role.permissions) }))), roles: JSON.stringify(roles.map((role) => ({ ...role, permissions: packRules(role.permissions) }))),
environments: environments ? JSON.stringify(environments ?? ProjectTemplateDefaultEnvironments) : null, environments:
orgId: actor.orgId type === ProjectType.SecretManager ? JSON.stringify(environments ?? ProjectTemplateDefaultEnvironments) : null,
orgId: actor.orgId,
type
}); });
return $unpackProjectTemplate(projectTemplate); return $unpackProjectTemplate(projectTemplate);
@ -209,6 +223,12 @@ export const projectTemplateServiceFactory = ({
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.ProjectTemplates); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.ProjectTemplates);
if (projectTemplate.type !== ProjectType.SecretManager && environments)
throw new BadRequestError({ message: "Cannot configure environments for non-SecretManager project templates" });
if (projectTemplate.type === ProjectType.SecretManager && environments === null)
throw new BadRequestError({ message: "Environments cannot be removed for SecretManager project templates" });
if (environments && plan.environmentLimit !== null && environments.length > plan.environmentLimit) { if (environments && plan.environmentLimit !== null && environments.length > plan.environmentLimit) {
throw new BadRequestError({ throw new BadRequestError({
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions // eslint-disable-next-line @typescript-eslint/restrict-template-expressions

View File

@ -1,6 +1,6 @@
import { z } from "zod"; import { z } from "zod";
import { ProjectMembershipRole, TProjectEnvironments } from "@app/db/schemas"; import { ProjectMembershipRole, ProjectType, TProjectEnvironments } from "@app/db/schemas";
import { TProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission"; import { TProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
import { OrgServiceActor } from "@app/lib/types"; import { OrgServiceActor } from "@app/lib/types";
import { UnpackedPermissionSchema } from "@app/server/routes/sanitizedSchema/permission"; import { UnpackedPermissionSchema } from "@app/server/routes/sanitizedSchema/permission";
@ -16,6 +16,7 @@ export type TProjectTemplateRole = {
export type TCreateProjectTemplateDTO = { export type TCreateProjectTemplateDTO = {
name: string; name: string;
description?: string; description?: string;
type: ProjectType;
roles: TProjectTemplateRole[]; roles: TProjectTemplateRole[];
environments?: TProjectTemplateEnvironment[] | null; environments?: TProjectTemplateEnvironment[] | null;
}; };
@ -29,10 +30,14 @@ export enum InfisicalProjectTemplate {
} }
export type TProjectTemplateServiceFactory = { export type TProjectTemplateServiceFactory = {
listProjectTemplatesByOrg: (actor: OrgServiceActor) => Promise< listProjectTemplatesByOrg: (
actor: OrgServiceActor,
type?: ProjectType
) => Promise<
( (
| { | {
id: string; id: string;
type: ProjectType;
name: InfisicalProjectTemplate; name: InfisicalProjectTemplate;
createdAt: Date; createdAt: Date;
updatedAt: Date; updatedAt: Date;
@ -69,6 +74,7 @@ export type TProjectTemplateServiceFactory = {
name: string; name: string;
}[]; }[];
name: string; name: string;
type: string;
orgId: string; orgId: string;
id: string; id: string;
createdAt: Date; createdAt: Date;
@ -93,6 +99,7 @@ export type TProjectTemplateServiceFactory = {
name: string; name: string;
}[]; }[];
name: string; name: string;
type: string;
orgId: string; orgId: string;
id: string; id: string;
createdAt: Date; createdAt: Date;
@ -116,6 +123,7 @@ export type TProjectTemplateServiceFactory = {
name: string; name: string;
}[]; }[];
name: string; name: string;
type: string;
orgId: string; orgId: string;
id: string; id: string;
createdAt: Date; createdAt: Date;
@ -138,6 +146,7 @@ export type TProjectTemplateServiceFactory = {
name: string; name: string;
}[]; }[];
name: string; name: string;
type: string;
orgId: string; orgId: string;
id: string; id: string;
createdAt: Date; createdAt: Date;
@ -161,6 +170,7 @@ export type TProjectTemplateServiceFactory = {
name: string; name: string;
}[]; }[];
name: string; name: string;
type: string;
orgId: string; orgId: string;
id: string; id: string;
createdAt: Date; createdAt: Date;
@ -184,6 +194,7 @@ export type TProjectTemplateServiceFactory = {
name: string; name: string;
}[]; }[];
name: string; name: string;
type: string;
orgId: string; orgId: string;
id: string; id: string;
createdAt: Date; createdAt: Date;

View File

@ -1,7 +1,7 @@
import { ForbiddenError, MongoAbility, RawRuleOf } from "@casl/ability"; import { ForbiddenError, MongoAbility, RawRuleOf } from "@casl/ability";
import { PackRule, packRules, unpackRules } from "@casl/ability/extra"; import { PackRule, packRules, unpackRules } from "@casl/ability/extra";
import { TableName } from "@app/db/schemas"; import { ActionProjectType, TableName } from "@app/db/schemas";
import { BadRequestError, NotFoundError, PermissionBoundaryError } from "@app/lib/errors"; import { BadRequestError, NotFoundError, PermissionBoundaryError } from "@app/lib/errors";
import { ms } from "@app/lib/ms"; import { ms } from "@app/lib/ms";
import { validateHandlebarTemplate } from "@app/lib/template/validate-handlebars"; import { validateHandlebarTemplate } from "@app/lib/template/validate-handlebars";
@ -61,7 +61,8 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
actorId, actorId,
projectId: projectMembership.projectId, projectId: projectMembership.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Edit, ProjectPermissionSub.Member); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Edit, ProjectPermissionSub.Member);
const { permission: targetUserPermission, membership } = await permissionService.getProjectPermission({ const { permission: targetUserPermission, membership } = await permissionService.getProjectPermission({
@ -69,7 +70,8 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
actorId: projectMembership.userId, actorId: projectMembership.userId,
projectId: projectMembership.projectId, projectId: projectMembership.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
// we need to validate that the privilege given is not higher than the assigning users permission // we need to validate that the privilege given is not higher than the assigning users permission
@ -164,7 +166,8 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
actorId, actorId,
projectId: projectMembership.projectId, projectId: projectMembership.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Edit, ProjectPermissionSub.Member); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Edit, ProjectPermissionSub.Member);
const { permission: targetUserPermission } = await permissionService.getProjectPermission({ const { permission: targetUserPermission } = await permissionService.getProjectPermission({
@ -172,7 +175,8 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
actorId: projectMembership.userId, actorId: projectMembership.userId,
projectId: projectMembership.projectId, projectId: projectMembership.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
// we need to validate that the privilege given is not higher than the assigning users permission // we need to validate that the privilege given is not higher than the assigning users permission
@ -272,7 +276,8 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
actorId, actorId,
projectId: projectMembership.projectId, projectId: projectMembership.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Edit, ProjectPermissionSub.Member); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Edit, ProjectPermissionSub.Member);
@ -317,7 +322,8 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
actorId, actorId,
projectId: projectMembership.projectId, projectId: projectMembership.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Read, ProjectPermissionSub.Member); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Read, ProjectPermissionSub.Member);
@ -343,7 +349,8 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
actorId, actorId,
projectId: projectMembership.projectId, projectId: projectMembership.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Read, ProjectPermissionSub.Member); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Read, ProjectPermissionSub.Member);

View File

@ -148,18 +148,10 @@ export const samlConfigServiceFactory = ({
let samlConfig: TSamlConfigs | undefined; let samlConfig: TSamlConfigs | undefined;
if (dto.type === "org") { if (dto.type === "org") {
samlConfig = await samlConfigDAL.findOne({ orgId: dto.orgId }); samlConfig = await samlConfigDAL.findOne({ orgId: dto.orgId });
if (!samlConfig) { if (!samlConfig) return;
throw new NotFoundError({
message: `SAML configuration for organization with ID '${dto.orgId}' not found`
});
}
} else if (dto.type === "orgSlug") { } else if (dto.type === "orgSlug") {
const org = await orgDAL.findOne({ slug: dto.orgSlug }); const org = await orgDAL.findOne({ slug: dto.orgSlug });
if (!org) { if (!org) return;
throw new NotFoundError({
message: `Organization with slug '${dto.orgSlug}' not found`
});
}
samlConfig = await samlConfigDAL.findOne({ orgId: org.id }); samlConfig = await samlConfigDAL.findOne({ orgId: org.id });
} else if (dto.type === "ssoId") { } else if (dto.type === "ssoId") {
// TODO: // TODO:

View File

@ -61,17 +61,20 @@ export type TSamlLoginDTO = {
export type TSamlConfigServiceFactory = { export type TSamlConfigServiceFactory = {
createSamlCfg: (arg: TCreateSamlCfgDTO) => Promise<TSamlConfigs>; createSamlCfg: (arg: TCreateSamlCfgDTO) => Promise<TSamlConfigs>;
updateSamlCfg: (arg: TUpdateSamlCfgDTO) => Promise<TSamlConfigs>; updateSamlCfg: (arg: TUpdateSamlCfgDTO) => Promise<TSamlConfigs>;
getSaml: (arg: TGetSamlCfgDTO) => Promise<{ getSaml: (arg: TGetSamlCfgDTO) => Promise<
id: string; | {
organization: string; id: string;
orgId: string; organization: string;
authProvider: string; orgId: string;
isActive: boolean; authProvider: string;
entryPoint: string; isActive: boolean;
issuer: string; entryPoint: string;
cert: string; issuer: string;
lastUsed: Date | null | undefined; cert: string;
}>; lastUsed: Date | null | undefined;
}
| undefined
>;
samlLogin: (arg: TSamlLoginDTO) => Promise<{ samlLogin: (arg: TSamlLoginDTO) => Promise<{
isUserCompleted: boolean; isUserCompleted: boolean;
providerAuthToken: string; providerAuthToken: string;

View File

@ -1,6 +1,7 @@
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError } from "@casl/ability";
import picomatch from "picomatch"; import picomatch from "picomatch";
import { ActionProjectType } from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { BadRequestError, NotFoundError } from "@app/lib/errors"; import { BadRequestError, NotFoundError } from "@app/lib/errors";
@ -90,7 +91,8 @@ export const secretApprovalPolicyServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Create, ProjectPermissionActions.Create,
@ -265,7 +267,8 @@ export const secretApprovalPolicyServiceFactory = ({
actorId, actorId,
projectId: secretApprovalPolicy.projectId, projectId: secretApprovalPolicy.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.SecretApproval); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.SecretApproval);
@ -420,7 +423,8 @@ export const secretApprovalPolicyServiceFactory = ({
actorId, actorId,
projectId: sapPolicy.projectId, projectId: sapPolicy.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Delete, ProjectPermissionActions.Delete,
@ -459,7 +463,8 @@ export const secretApprovalPolicyServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretApproval); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretApproval);
@ -503,7 +508,8 @@ export const secretApprovalPolicyServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
return getSecretApprovalPolicy(projectId, environment, secretPath); return getSecretApprovalPolicy(projectId, environment, secretPath);
@ -529,7 +535,8 @@ export const secretApprovalPolicyServiceFactory = ({
actorId, actorId,
projectId: sapPolicy.projectId, projectId: sapPolicy.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretApproval); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretApproval);

View File

@ -290,7 +290,7 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => {
} }
}; };
const findProjectRequestCount = async (projectId: string, userId: string, policyId?: string, tx?: Knex) => { const findProjectRequestCount = async (projectId: string, userId: string, tx?: Knex) => {
try { try {
const docs = await (tx || db) const docs = await (tx || db)
.with( .with(
@ -309,9 +309,6 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => {
`${TableName.SecretApprovalPolicy}.id` `${TableName.SecretApprovalPolicy}.id`
) )
.where({ projectId }) .where({ projectId })
.where((qb) => {
if (policyId) void qb.where(`${TableName.SecretApprovalPolicy}.id`, policyId);
})
.andWhere( .andWhere(
(bd) => (bd) =>
void bd void bd

View File

@ -36,7 +36,7 @@ export const sendApprovalEmailsFn = async ({
firstName: reviewerUser.firstName, firstName: reviewerUser.firstName,
projectName: project.name, projectName: project.name,
organizationName: project.organization.name, organizationName: project.organization.name,
approvalUrl: `${cfg.SITE_URL}/projects/${project.id}/secret-manager/approval?requestId=${secretApprovalRequest.id}` approvalUrl: `${cfg.SITE_URL}/secret-manager/${project.id}/approval?requestId=${secretApprovalRequest.id}`
}, },
template: SmtpTemplates.SecretApprovalRequestNeedsReview template: SmtpTemplates.SecretApprovalRequestNeedsReview
}); });

View File

@ -2,6 +2,7 @@
import { ForbiddenError, subject } from "@casl/ability"; import { ForbiddenError, subject } from "@casl/ability";
import { import {
ActionProjectType,
ProjectMembershipRole, ProjectMembershipRole,
SecretEncryptionAlgo, SecretEncryptionAlgo,
SecretKeyEncoding, SecretKeyEncoding,
@ -167,14 +168,7 @@ export const secretApprovalRequestServiceFactory = ({
microsoftTeamsService, microsoftTeamsService,
folderCommitService folderCommitService
}: TSecretApprovalRequestServiceFactoryDep) => { }: TSecretApprovalRequestServiceFactoryDep) => {
const requestCount = async ({ const requestCount = async ({ projectId, actor, actorId, actorOrgId, actorAuthMethod }: TApprovalRequestCountDTO) => {
projectId,
policyId,
actor,
actorId,
actorOrgId,
actorAuthMethod
}: TApprovalRequestCountDTO) => {
if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" }); if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" });
await permissionService.getProjectPermission({ await permissionService.getProjectPermission({
@ -182,10 +176,11 @@ export const secretApprovalRequestServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
const count = await secretApprovalRequestDAL.findProjectRequestCount(projectId, actorId, policyId); const count = await secretApprovalRequestDAL.findProjectRequestCount(projectId, actorId);
return count; return count;
}; };
@ -209,7 +204,8 @@ export const secretApprovalRequestServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
const { shouldUseSecretV2Bridge } = await projectBotService.getBotKey(projectId); const { shouldUseSecretV2Bridge } = await projectBotService.getBotKey(projectId);
@ -261,7 +257,8 @@ export const secretApprovalRequestServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
if ( if (
!hasRole(ProjectMembershipRole.Admin) && !hasRole(ProjectMembershipRole.Admin) &&
@ -410,7 +407,8 @@ export const secretApprovalRequestServiceFactory = ({
actorId, actorId,
projectId: secretApprovalRequest.projectId, projectId: secretApprovalRequest.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
if ( if (
!hasRole(ProjectMembershipRole.Admin) && !hasRole(ProjectMembershipRole.Admin) &&
@ -479,7 +477,8 @@ export const secretApprovalRequestServiceFactory = ({
actorId, actorId,
projectId: secretApprovalRequest.projectId, projectId: secretApprovalRequest.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
if ( if (
!hasRole(ProjectMembershipRole.Admin) && !hasRole(ProjectMembershipRole.Admin) &&
@ -535,7 +534,8 @@ export const secretApprovalRequestServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
if ( if (
@ -951,7 +951,7 @@ export const secretApprovalRequestServiceFactory = ({
bypassReason, bypassReason,
secretPath: policy.secretPath, secretPath: policy.secretPath,
environment: env.name, environment: env.name,
approvalUrl: `${cfg.SITE_URL}/projects/${project.id}/secret-manager/approval` approvalUrl: `${cfg.SITE_URL}/secret-manager/${project.id}/approval`
}, },
template: SmtpTemplates.AccessSecretRequestBypassed template: SmtpTemplates.AccessSecretRequestBypassed
}); });
@ -980,7 +980,8 @@ export const secretApprovalRequestServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
throwIfMissingSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.ReadValue, { throwIfMissingSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.ReadValue, {
@ -1270,7 +1271,8 @@ export const secretApprovalRequestServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
const folder = await folderDAL.findBySecretPath(projectId, environment, secretPath); const folder = await folderDAL.findBySecretPath(projectId, environment, secretPath);
if (!folder) if (!folder)

View File

@ -84,7 +84,7 @@ export type TReviewRequestDTO = {
comment?: string; comment?: string;
} & Omit<TProjectPermission, "projectId">; } & Omit<TProjectPermission, "projectId">;
export type TApprovalRequestCountDTO = TProjectPermission & { policyId?: string }; export type TApprovalRequestCountDTO = TProjectPermission;
export type TListApprovalsDTO = { export type TListApprovalsDTO = {
projectId: string; projectId: string;

View File

@ -166,9 +166,7 @@ export const secretRotationV2QueueServiceFactory = async ({
secretPath: folder.path, secretPath: folder.path,
environment: environment.name, environment: environment.name,
projectName: project.name, projectName: project.name,
rotationUrl: encodeURI( rotationUrl: encodeURI(`${appCfg.SITE_URL}/secret-manager/${projectId}/secrets/${environment.slug}`)
`${appCfg.SITE_URL}/projects/${projectId}/secret-manager/secrets/${environment.slug}`
)
} }
}); });
} catch (error) { } catch (error) {

View File

@ -2,7 +2,7 @@ import { ForbiddenError, subject } from "@casl/ability";
import { Knex } from "knex"; import { Knex } from "knex";
import isEqual from "lodash.isequal"; import isEqual from "lodash.isequal";
import { SecretType, TableName } from "@app/db/schemas"; import { ActionProjectType, SecretType, TableName } from "@app/db/schemas";
import { EventType, TAuditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-types"; import { EventType, TAuditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-types";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service"; import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { hasSecretReadValueOrDescribePermission } from "@app/ee/services/permission/permission-fns"; import { hasSecretReadValueOrDescribePermission } from "@app/ee/services/permission/permission-fns";
@ -218,7 +218,7 @@ export const secretRotationV2ServiceFactory = ({
actorId: actor.id, actorId: actor.id,
actorAuthMethod: actor.authMethod, actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId, actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretManager,
projectId projectId
}); });
@ -269,7 +269,7 @@ export const secretRotationV2ServiceFactory = ({
actorId: actor.id, actorId: actor.id,
actorAuthMethod: actor.authMethod, actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId, actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretManager,
projectId projectId
}); });
@ -315,7 +315,7 @@ export const secretRotationV2ServiceFactory = ({
actorId: actor.id, actorId: actor.id,
actorAuthMethod: actor.authMethod, actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId, actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretManager,
projectId projectId
}); });
@ -380,7 +380,7 @@ export const secretRotationV2ServiceFactory = ({
actorId: actor.id, actorId: actor.id,
actorAuthMethod: actor.authMethod, actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId, actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretManager,
projectId projectId
}); });
@ -424,7 +424,7 @@ export const secretRotationV2ServiceFactory = ({
actorId: actor.id, actorId: actor.id,
actorAuthMethod: actor.authMethod, actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId, actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretManager,
projectId projectId
}); });
@ -625,7 +625,7 @@ export const secretRotationV2ServiceFactory = ({
actorId: actor.id, actorId: actor.id,
actorAuthMethod: actor.authMethod, actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId, actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretManager,
projectId projectId
}); });
@ -775,7 +775,7 @@ export const secretRotationV2ServiceFactory = ({
actorId: actor.id, actorId: actor.id,
actorAuthMethod: actor.authMethod, actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId, actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretManager,
projectId projectId
}); });
@ -1105,7 +1105,7 @@ export const secretRotationV2ServiceFactory = ({
actorId: actor.id, actorId: actor.id,
actorAuthMethod: actor.authMethod, actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId, actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretManager,
projectId projectId
}); });
@ -1152,7 +1152,7 @@ export const secretRotationV2ServiceFactory = ({
actorId: actor.id, actorId: actor.id,
actorAuthMethod: actor.authMethod, actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId, actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretManager,
projectId projectId
}); });
@ -1204,7 +1204,7 @@ export const secretRotationV2ServiceFactory = ({
actorId: actor.id, actorId: actor.id,
actorAuthMethod: actor.authMethod, actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId, actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretManager,
projectId projectId
}); });
@ -1320,7 +1320,8 @@ export const secretRotationV2ServiceFactory = ({
actorId: actor.id, actorId: actor.id,
projectId, projectId,
actorAuthMethod: actor.authMethod, actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretManager
}); });
const permissiveFolderMappings = folderMappings.filter(({ path, environment }) => const permissiveFolderMappings = folderMappings.filter(({ path, environment }) =>

View File

@ -1,7 +1,7 @@
import { ForbiddenError, subject } from "@casl/ability"; import { ForbiddenError, subject } from "@casl/ability";
import Ajv from "ajv"; import Ajv from "ajv";
import { ProjectVersion, TableName } from "@app/db/schemas"; import { ActionProjectType, ProjectVersion, TableName } from "@app/db/schemas";
import { decryptSymmetric128BitHexKeyUTF8 } from "@app/lib/crypto/encryption"; import { decryptSymmetric128BitHexKeyUTF8 } from "@app/lib/crypto/encryption";
import { BadRequestError, NotFoundError } from "@app/lib/errors"; import { BadRequestError, NotFoundError } from "@app/lib/errors";
import { TProjectPermission } from "@app/lib/types"; import { TProjectPermission } from "@app/lib/types";
@ -66,7 +66,8 @@ export const secretRotationServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionSecretRotationActions.Read, ProjectPermissionSecretRotationActions.Read,
@ -97,7 +98,8 @@ export const secretRotationServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionSecretRotationActions.Read, ProjectPermissionSecretRotationActions.Read,
@ -213,7 +215,8 @@ export const secretRotationServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionSecretRotationActions.Read, ProjectPermissionSecretRotationActions.Read,
@ -261,7 +264,8 @@ export const secretRotationServiceFactory = ({
actorId, actorId,
projectId: project.id, projectId: project.id,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionSecretRotationActions.Edit, ProjectPermissionSecretRotationActions.Edit,
@ -281,7 +285,8 @@ export const secretRotationServiceFactory = ({
actorId, actorId,
projectId: doc.projectId, projectId: doc.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionSecretRotationActions.Delete, ProjectPermissionSecretRotationActions.Delete,

View File

@ -318,7 +318,7 @@ export const secretScanningV2QueueServiceFactory = async ({
}, },
{ {
batchSize: 1, batchSize: 1,
workerCount: 2, workerCount: 20,
pollingIntervalSeconds: 1 pollingIntervalSeconds: 1
} }
); );
@ -539,7 +539,7 @@ export const secretScanningV2QueueServiceFactory = async ({
}, },
{ {
batchSize: 1, batchSize: 1,
workerCount: 2, workerCount: 20,
pollingIntervalSeconds: 1 pollingIntervalSeconds: 1
} }
); );
@ -588,7 +588,7 @@ export const secretScanningV2QueueServiceFactory = async ({
numberOfSecrets: payload.numberOfSecrets, numberOfSecrets: payload.numberOfSecrets,
isDiffScan: payload.isDiffScan, isDiffScan: payload.isDiffScan,
url: encodeURI( url: encodeURI(
`${appCfg.SITE_URL}/projects/${projectId}/secret-scanning/findings?search=scanId:${payload.scanId}` `${appCfg.SITE_URL}/secret-scanning/${projectId}/findings?search=scanId:${payload.scanId}`
), ),
timestamp timestamp
} }
@ -599,7 +599,7 @@ export const secretScanningV2QueueServiceFactory = async ({
timestamp, timestamp,
errorMessage: payload.errorMessage, errorMessage: payload.errorMessage,
url: encodeURI( url: encodeURI(
`${appCfg.SITE_URL}/projects/${projectId}/secret-scanning/data-sources/${dataSource.type}/${dataSource.id}` `${appCfg.SITE_URL}/secret-scanning/${projectId}/data-sources/${dataSource.type}/${dataSource.id}`
) )
} }
}); });
@ -613,7 +613,7 @@ export const secretScanningV2QueueServiceFactory = async ({
}, },
{ {
batchSize: 1, batchSize: 1,
workerCount: 2, workerCount: 5,
pollingIntervalSeconds: 1 pollingIntervalSeconds: 1
} }
); );

View File

@ -1,6 +1,7 @@
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError } from "@casl/ability";
import { join } from "path"; import { join } from "path";
import { ActionProjectType } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service"; import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { import {
@ -91,7 +92,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id, actorId: actor.id,
actorAuthMethod: actor.authMethod, actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId, actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId projectId
}); });
@ -153,7 +154,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id, actorId: actor.id,
actorAuthMethod: actor.authMethod, actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId, actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId: dataSource.projectId projectId: dataSource.projectId
}); });
@ -198,7 +199,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id, actorId: actor.id,
actorAuthMethod: actor.authMethod, actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId, actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId projectId
}); });
@ -232,7 +233,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id, actorId: actor.id,
actorAuthMethod: actor.authMethod, actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId, actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId: payload.projectId projectId: payload.projectId
}); });
@ -345,7 +346,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id, actorId: actor.id,
actorAuthMethod: actor.authMethod, actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId, actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId: dataSource.projectId projectId: dataSource.projectId
}); });
@ -398,7 +399,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id, actorId: actor.id,
actorAuthMethod: actor.authMethod, actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId, actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId: dataSource.projectId projectId: dataSource.projectId
}); });
@ -443,7 +444,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id, actorId: actor.id,
actorAuthMethod: actor.authMethod, actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId, actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId: dataSource.projectId projectId: dataSource.projectId
}); });
@ -507,7 +508,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id, actorId: actor.id,
actorAuthMethod: actor.authMethod, actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId, actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId: dataSource.projectId projectId: dataSource.projectId
}); });
@ -552,7 +553,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id, actorId: actor.id,
actorAuthMethod: actor.authMethod, actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId, actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId: dataSource.projectId projectId: dataSource.projectId
}); });
@ -595,7 +596,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id, actorId: actor.id,
actorAuthMethod: actor.authMethod, actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId, actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId: dataSource.projectId projectId: dataSource.projectId
}); });
@ -638,7 +639,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id, actorId: actor.id,
actorAuthMethod: actor.authMethod, actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId, actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId: dataSource.projectId projectId: dataSource.projectId
}); });
@ -671,7 +672,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id, actorId: actor.id,
actorAuthMethod: actor.authMethod, actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId, actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId projectId
}); });
@ -705,7 +706,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id, actorId: actor.id,
actorAuthMethod: actor.authMethod, actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId, actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId projectId
}); });
@ -745,7 +746,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id, actorId: actor.id,
actorAuthMethod: actor.authMethod, actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId, actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId: finding.projectId projectId: finding.projectId
}); });
@ -776,7 +777,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id, actorId: actor.id,
actorAuthMethod: actor.authMethod, actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId, actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId projectId
}); });
@ -811,7 +812,7 @@ export const secretScanningV2ServiceFactory = ({
actorId: actor.id, actorId: actor.id,
actorAuthMethod: actor.authMethod, actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId, actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.SecretScanning,
projectId projectId
}); });

View File

@ -1,11 +1,17 @@
import { InternalServerError } from "@app/lib/errors"; import { ProbotOctokit } from "probot";
import { TQueueServiceFactory } from "@app/queue";
import { OrgMembershipRole, TableName } from "@app/db/schemas";
import { getConfig } from "@app/lib/config/env";
import { logger } from "@app/lib/logger";
import { QueueJobs, QueueName, TQueueServiceFactory } from "@app/queue";
import { TOrgDALFactory } from "@app/services/org/org-dal"; import { TOrgDALFactory } from "@app/services/org/org-dal";
import { TSmtpService } from "@app/services/smtp/smtp-service"; import { SmtpTemplates, TSmtpService } from "@app/services/smtp/smtp-service";
import { TTelemetryServiceFactory } from "@app/services/telemetry/telemetry-service"; import { TTelemetryServiceFactory } from "@app/services/telemetry/telemetry-service";
import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
import { TSecretScanningDALFactory } from "../secret-scanning-dal"; import { TSecretScanningDALFactory } from "../secret-scanning-dal";
import { TScanFullRepoEventPayload, TScanPushEventPayload } from "./secret-scanning-queue-types"; import { scanContentAndGetFindings, scanFullRepoContentAndGetFindings } from "./secret-scanning-fns";
import { SecretMatch, TScanFullRepoEventPayload, TScanPushEventPayload } from "./secret-scanning-queue-types";
type TSecretScanningQueueFactoryDep = { type TSecretScanningQueueFactoryDep = {
queueService: TQueueServiceFactory; queueService: TQueueServiceFactory;
@ -17,21 +23,227 @@ type TSecretScanningQueueFactoryDep = {
export type TSecretScanningQueueFactory = ReturnType<typeof secretScanningQueueFactory>; export type TSecretScanningQueueFactory = ReturnType<typeof secretScanningQueueFactory>;
// eslint-disable-next-line @typescript-eslint/no-unused-vars export const secretScanningQueueFactory = ({
export const secretScanningQueueFactory = (_props: TSecretScanningQueueFactoryDep) => { queueService,
// eslint-disable-next-line @typescript-eslint/no-unused-vars secretScanningDAL,
const startFullRepoScan = async (_payload: TScanFullRepoEventPayload) => { smtpService,
throw new InternalServerError({ telemetryService,
message: "Secret Scanning V1 has been deprecated. Please migrate to Secret Scanning V2" orgMembershipDAL: orgMemberDAL
}: TSecretScanningQueueFactoryDep) => {
const startFullRepoScan = async (payload: TScanFullRepoEventPayload) => {
await queueService.queue(QueueName.SecretFullRepoScan, QueueJobs.SecretScan, payload, {
attempts: 3,
backoff: {
type: "exponential",
delay: 5000
},
removeOnComplete: true,
removeOnFail: {
count: 20 // keep the most recent 20 jobs
}
}); });
}; };
// eslint-disable-next-line @typescript-eslint/no-unused-vars const startPushEventScan = async (payload: TScanPushEventPayload) => {
const startPushEventScan = async (_payload: TScanPushEventPayload) => { await queueService.queue(QueueName.SecretPushEventScan, QueueJobs.SecretScan, payload, {
throw new InternalServerError({ attempts: 3,
message: "Secret Scanning V1 has been deprecated. Please migrate to Secret Scanning V2" backoff: {
type: "exponential",
delay: 5000
},
removeOnComplete: true,
removeOnFail: {
count: 20 // keep the most recent 20 jobs
}
}); });
}; };
const getOrgAdminEmails = async (organizationId: string) => {
// get emails of admins
const adminsOfWork = await orgMemberDAL.findMembership({
[`${TableName.Organization}.id` as string]: organizationId,
role: OrgMembershipRole.Admin
});
return adminsOfWork.filter((userObject) => userObject.email).map((userObject) => userObject.email as string);
};
queueService.start(QueueName.SecretPushEventScan, async (job) => {
const appCfg = getConfig();
const { organizationId, commits, pusher, repository, installationId } = job.data;
const [owner, repo] = repository.fullName.split("/");
const octokit = new ProbotOctokit({
auth: {
appId: appCfg.SECRET_SCANNING_GIT_APP_ID,
privateKey: appCfg.SECRET_SCANNING_PRIVATE_KEY,
installationId
}
});
const allFindingsByFingerprint: { [key: string]: SecretMatch } = {};
for (const commit of commits) {
for (const filepath of [...commit.added, ...commit.modified]) {
// eslint-disable-next-line
const fileContentsResponse = await octokit.repos.getContent({
owner,
repo,
path: filepath
});
const { data } = fileContentsResponse;
const fileContent = Buffer.from((data as { content: string }).content, "base64").toString();
// eslint-disable-next-line
const findings = await scanContentAndGetFindings(`\n${fileContent}`); // extra line to count lines correctly
for (const finding of findings) {
const fingerPrintWithCommitId = `${commit.id}:${filepath}:${finding.RuleID}:${finding.StartLine}`;
const fingerPrintWithoutCommitId = `${filepath}:${finding.RuleID}:${finding.StartLine}`;
finding.Fingerprint = fingerPrintWithCommitId;
finding.FingerPrintWithoutCommitId = fingerPrintWithoutCommitId;
finding.Commit = commit.id;
finding.File = filepath;
finding.Author = commit.author.name;
finding.Email = commit?.author?.email ? commit?.author?.email : "";
allFindingsByFingerprint[fingerPrintWithCommitId] = finding;
}
}
}
await secretScanningDAL.transaction(async (tx) => {
if (!Object.keys(allFindingsByFingerprint).length) return;
await secretScanningDAL.upsert(
Object.keys(allFindingsByFingerprint).map((key) => ({
installationId,
email: allFindingsByFingerprint[key].Email,
author: allFindingsByFingerprint[key].Author,
date: allFindingsByFingerprint[key].Date,
file: allFindingsByFingerprint[key].File,
tags: allFindingsByFingerprint[key].Tags,
commit: allFindingsByFingerprint[key].Commit,
ruleID: allFindingsByFingerprint[key].RuleID,
endLine: String(allFindingsByFingerprint[key].EndLine),
entropy: String(allFindingsByFingerprint[key].Entropy),
message: allFindingsByFingerprint[key].Message,
endColumn: String(allFindingsByFingerprint[key].EndColumn),
startLine: String(allFindingsByFingerprint[key].StartLine),
startColumn: String(allFindingsByFingerprint[key].StartColumn),
fingerPrintWithoutCommitId: allFindingsByFingerprint[key].FingerPrintWithoutCommitId,
description: allFindingsByFingerprint[key].Description,
symlinkFile: allFindingsByFingerprint[key].SymlinkFile,
orgId: organizationId,
pusherEmail: pusher.email,
pusherName: pusher.name,
repositoryFullName: repository.fullName,
repositoryId: String(repository.id),
fingerprint: allFindingsByFingerprint[key].Fingerprint
})),
tx
);
});
const adminEmails = await getOrgAdminEmails(organizationId);
if (pusher?.email) {
adminEmails.push(pusher.email);
}
if (Object.keys(allFindingsByFingerprint).length) {
await smtpService.sendMail({
template: SmtpTemplates.SecretLeakIncident,
subjectLine: `Incident alert: leaked secrets found in Github repository ${repository.fullName}`,
recipients: adminEmails.filter((email) => email).map((email) => email),
substitutions: {
numberOfSecrets: Object.keys(allFindingsByFingerprint).length,
pusher_email: pusher.email,
pusher_name: pusher.name
}
});
}
await telemetryService.sendPostHogEvents({
event: PostHogEventTypes.SecretScannerPush,
distinctId: repository.fullName,
properties: {
numberOfRisks: Object.keys(allFindingsByFingerprint).length
}
});
});
queueService.start(QueueName.SecretFullRepoScan, async (job) => {
const appCfg = getConfig();
const { organizationId, repository, installationId } = job.data;
const octokit = new ProbotOctokit({
auth: {
appId: appCfg.SECRET_SCANNING_GIT_APP_ID,
privateKey: appCfg.SECRET_SCANNING_PRIVATE_KEY,
installationId
}
});
const findings = await scanFullRepoContentAndGetFindings(
// this is because of collision of octokit in probot and github
// eslint-disable-next-line
octokit as any,
installationId,
repository.fullName
);
await secretScanningDAL.transaction(async (tx) => {
if (!findings.length) return;
// eslint-disable-next-line
await secretScanningDAL.upsert(
findings.map((finding) => ({
installationId,
email: finding.Email,
author: finding.Author,
date: finding.Date,
file: finding.File,
tags: finding.Tags,
commit: finding.Commit,
ruleID: finding.RuleID,
endLine: String(finding.EndLine),
entropy: String(finding.Entropy),
message: finding.Message,
endColumn: String(finding.EndColumn),
startLine: String(finding.StartLine),
startColumn: String(finding.StartColumn),
fingerPrintWithoutCommitId: finding.FingerPrintWithoutCommitId,
description: finding.Description,
symlinkFile: finding.SymlinkFile,
orgId: organizationId,
repositoryFullName: repository.fullName,
repositoryId: String(repository.id),
fingerprint: finding.Fingerprint
})),
tx
);
});
const adminEmails = await getOrgAdminEmails(organizationId);
if (findings.length) {
await smtpService.sendMail({
template: SmtpTemplates.SecretLeakIncident,
subjectLine: `Incident alert: leaked secrets found in Github repository ${repository.fullName}`,
recipients: adminEmails.filter((email) => email).map((email) => email),
substitutions: {
numberOfSecrets: findings.length
}
});
}
await telemetryService.sendPostHogEvents({
event: PostHogEventTypes.SecretScannerFull,
distinctId: repository.fullName,
properties: {
numberOfRisks: findings.length
}
});
});
queueService.listen(QueueName.SecretPushEventScan, "failed", (job, err) => {
logger.error(err, "Failed to secret scan on push", job?.data);
});
queueService.listen(QueueName.SecretFullRepoScan, "failed", (job, err) => {
logger.error(err, "Failed to do full repo secret scan", job?.data);
});
return { startFullRepoScan, startPushEventScan }; return { startFullRepoScan, startPushEventScan };
}; };

View File

@ -98,7 +98,6 @@ export const secretScanningServiceFactory = ({
if (canUseSecretScanning(actorOrgId)) { if (canUseSecretScanning(actorOrgId)) {
await Promise.all( await Promise.all(
repositories.map(({ id, full_name }) => repositories.map(({ id, full_name }) =>
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-return,@typescript-eslint/no-unsafe-member-access
secretScanningQueue.startFullRepoScan({ secretScanningQueue.startFullRepoScan({
organizationId: session.orgId, organizationId: session.orgId,
installationId, installationId,
@ -181,7 +180,6 @@ export const secretScanningServiceFactory = ({
if (!installationLink) return; if (!installationLink) return;
if (canUseSecretScanning(installationLink.orgId)) { if (canUseSecretScanning(installationLink.orgId)) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-return,@typescript-eslint/no-unsafe-member-access
await secretScanningQueue.startPushEventScan({ await secretScanningQueue.startPushEventScan({
commits, commits,
pusher: { name: pusher.name, email: pusher.email }, pusher: { name: pusher.name, email: pusher.email },

View File

@ -2,7 +2,7 @@
// akhilmhdh: I did this, quite strange bug with eslint. Everything do have a type stil has this error // akhilmhdh: I did this, quite strange bug with eslint. Everything do have a type stil has this error
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError } from "@casl/ability";
import { TableName, TSecretTagJunctionInsert, TSecretV2TagJunctionInsert } from "@app/db/schemas"; import { ActionProjectType, TableName, TSecretTagJunctionInsert, TSecretV2TagJunctionInsert } from "@app/db/schemas";
import { decryptSymmetric128BitHexKeyUTF8 } from "@app/lib/crypto"; import { decryptSymmetric128BitHexKeyUTF8 } from "@app/lib/crypto";
import { InternalServerError, NotFoundError } from "@app/lib/errors"; import { InternalServerError, NotFoundError } from "@app/lib/errors";
import { groupBy } from "@app/lib/fn"; import { groupBy } from "@app/lib/fn";
@ -103,7 +103,8 @@ export const secretSnapshotServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
@ -139,7 +140,8 @@ export const secretSnapshotServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
@ -167,7 +169,8 @@ export const secretSnapshotServiceFactory = ({
actorId, actorId,
projectId: snapshot.projectId, projectId: snapshot.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
@ -387,7 +390,8 @@ export const secretSnapshotServiceFactory = ({
actorId, actorId,
projectId: snapshot.projectId, projectId: snapshot.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SecretManager
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Create, ProjectPermissionActions.Create,

View File

@ -1,5 +1,6 @@
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError } from "@casl/ability";
import { ActionProjectType } from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { BadRequestError, NotFoundError } from "@app/lib/errors"; import { BadRequestError, NotFoundError } from "@app/lib/errors";
@ -58,7 +59,8 @@ export const sshCertificateTemplateServiceFactory = ({
actorId, actorId,
projectId: ca.projectId, projectId: ca.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SSH
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
@ -130,7 +132,8 @@ export const sshCertificateTemplateServiceFactory = ({
actorId, actorId,
projectId: certTemplate.projectId, projectId: certTemplate.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SSH
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
@ -198,7 +201,8 @@ export const sshCertificateTemplateServiceFactory = ({
actorId, actorId,
projectId: certificateTemplate.projectId, projectId: certificateTemplate.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SSH
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
@ -224,7 +228,8 @@ export const sshCertificateTemplateServiceFactory = ({
actorId, actorId,
projectId: certTemplate.projectId, projectId: certTemplate.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SSH
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(

View File

@ -1,5 +1,6 @@
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError } from "@casl/ability";
import { ActionProjectType } from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { TSshHostDALFactory } from "@app/ee/services/ssh-host/ssh-host-dal"; import { TSshHostDALFactory } from "@app/ee/services/ssh-host/ssh-host-dal";
@ -79,7 +80,8 @@ export const sshHostGroupServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SSH
}); });
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.SshHostGroups); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.SshHostGroups);
@ -171,7 +173,8 @@ export const sshHostGroupServiceFactory = ({
actorId, actorId,
projectId: sshHostGroup.projectId, projectId: sshHostGroup.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SSH
}); });
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.SshHostGroups); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.SshHostGroups);
@ -267,7 +270,8 @@ export const sshHostGroupServiceFactory = ({
actorId, actorId,
projectId: sshHostGroup.projectId, projectId: sshHostGroup.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SSH
}); });
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SshHostGroups); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SshHostGroups);
@ -290,7 +294,8 @@ export const sshHostGroupServiceFactory = ({
actorId, actorId,
projectId: sshHostGroup.projectId, projectId: sshHostGroup.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SSH
}); });
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.SshHostGroups); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.SshHostGroups);
@ -316,7 +321,8 @@ export const sshHostGroupServiceFactory = ({
actorId, actorId,
projectId: sshHostGroup.projectId, projectId: sshHostGroup.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SSH
}); });
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SshHostGroups); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SshHostGroups);
@ -354,7 +360,8 @@ export const sshHostGroupServiceFactory = ({
actorId, actorId,
projectId: sshHostGroup.projectId, projectId: sshHostGroup.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SSH
}); });
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.SshHostGroups); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.SshHostGroups);
@ -393,7 +400,8 @@ export const sshHostGroupServiceFactory = ({
actorId, actorId,
projectId: sshHostGroup.projectId, projectId: sshHostGroup.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SSH
}); });
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.SshHostGroups); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.SshHostGroups);

View File

@ -1,5 +1,6 @@
import { Knex } from "knex"; import { Knex } from "knex";
import { ActionProjectType } from "@app/db/schemas";
import { BadRequestError } from "@app/lib/errors"; import { BadRequestError } from "@app/lib/errors";
import { ProjectPermissionSshHostActions, ProjectPermissionSub } from "../permission/project-permission"; import { ProjectPermissionSshHostActions, ProjectPermissionSub } from "../permission/project-permission";
@ -62,7 +63,8 @@ export const createSshLoginMappings = async ({
userId: user.id, userId: user.id,
projectId, projectId,
authMethod: actorAuthMethod, authMethod: actorAuthMethod,
userOrgId: actorOrgId userOrgId: actorOrgId,
actionProjectType: ActionProjectType.SSH
}); });
} }

View File

@ -1,5 +1,6 @@
import { ForbiddenError, subject } from "@casl/ability"; import { ForbiddenError, subject } from "@casl/ability";
import { ActionProjectType, ProjectType } from "@app/db/schemas";
import { TGroupDALFactory } from "@app/ee/services/group/group-dal"; import { TGroupDALFactory } from "@app/ee/services/group/group-dal";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { ProjectPermissionSshHostActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { ProjectPermissionSshHostActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
@ -11,13 +12,11 @@ import { SshCertKeyAlgorithm } from "@app/ee/services/ssh-certificate/ssh-certif
import { TSshHostDALFactory } from "@app/ee/services/ssh-host/ssh-host-dal"; import { TSshHostDALFactory } from "@app/ee/services/ssh-host/ssh-host-dal";
import { TSshHostLoginUserMappingDALFactory } from "@app/ee/services/ssh-host/ssh-host-login-user-mapping-dal"; import { TSshHostLoginUserMappingDALFactory } from "@app/ee/services/ssh-host/ssh-host-login-user-mapping-dal";
import { TSshHostLoginUserDALFactory } from "@app/ee/services/ssh-host/ssh-login-user-dal"; import { TSshHostLoginUserDALFactory } from "@app/ee/services/ssh-host/ssh-login-user-dal";
import { PgSqlLock } from "@app/keystore/keystore";
import { BadRequestError, NotFoundError, UnauthorizedError } from "@app/lib/errors"; import { BadRequestError, NotFoundError, UnauthorizedError } from "@app/lib/errors";
import { ActorType } from "@app/services/auth/auth-type"; import { ActorType } from "@app/services/auth/auth-type";
import { TKmsServiceFactory } from "@app/services/kms/kms-service"; import { TKmsServiceFactory } from "@app/services/kms/kms-service";
import { KmsDataKey } from "@app/services/kms/kms-types"; import { KmsDataKey } from "@app/services/kms/kms-types";
import { TProjectDALFactory } from "@app/services/project/project-dal"; import { TProjectDALFactory } from "@app/services/project/project-dal";
import { bootstrapSshProject } from "@app/services/project/project-fns";
import { TProjectSshConfigDALFactory } from "@app/services/project/project-ssh-config-dal"; import { TProjectSshConfigDALFactory } from "@app/services/project/project-ssh-config-dal";
import { TUserDALFactory } from "@app/services/user/user-dal"; import { TUserDALFactory } from "@app/services/user/user-dal";
@ -44,9 +43,9 @@ type TSshHostServiceFactoryDep = {
userDAL: Pick<TUserDALFactory, "findById" | "find">; userDAL: Pick<TUserDALFactory, "findById" | "find">;
groupDAL: Pick<TGroupDALFactory, "findGroupsByProjectId">; groupDAL: Pick<TGroupDALFactory, "findGroupsByProjectId">;
projectDAL: Pick<TProjectDALFactory, "find">; projectDAL: Pick<TProjectDALFactory, "find">;
projectSshConfigDAL: Pick<TProjectSshConfigDALFactory, "findOne" | "transaction" | "create">; projectSshConfigDAL: Pick<TProjectSshConfigDALFactory, "findOne">;
sshCertificateAuthorityDAL: Pick<TSshCertificateAuthorityDALFactory, "findOne" | "transaction" | "create">; sshCertificateAuthorityDAL: Pick<TSshCertificateAuthorityDALFactory, "findOne">;
sshCertificateAuthoritySecretDAL: Pick<TSshCertificateAuthoritySecretDALFactory, "findOne" | "create">; sshCertificateAuthoritySecretDAL: Pick<TSshCertificateAuthoritySecretDALFactory, "findOne">;
sshCertificateDAL: Pick<TSshCertificateDALFactory, "create" | "transaction">; sshCertificateDAL: Pick<TSshCertificateDALFactory, "create" | "transaction">;
sshCertificateBodyDAL: Pick<TSshCertificateBodyDALFactory, "create">; sshCertificateBodyDAL: Pick<TSshCertificateBodyDALFactory, "create">;
userGroupMembershipDAL: Pick<TUserGroupMembershipDALFactory, "findGroupMembershipsByUserIdInOrg">; userGroupMembershipDAL: Pick<TUserGroupMembershipDALFactory, "findGroupMembershipsByUserIdInOrg">;
@ -99,7 +98,8 @@ export const sshHostServiceFactory = ({
} }
const sshProjects = await projectDAL.find({ const sshProjects = await projectDAL.find({
orgId: actorOrgId orgId: actorOrgId,
type: ProjectType.SSH
}); });
const allowedHosts = []; const allowedHosts = [];
@ -111,7 +111,8 @@ export const sshHostServiceFactory = ({
actorId, actorId,
projectId: project.id, projectId: project.id,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SSH
}); });
const projectHosts = await sshHostDAL.findUserAccessibleSshHosts([project.id], actorId); const projectHosts = await sshHostDAL.findUserAccessibleSshHosts([project.id], actorId);
@ -144,7 +145,8 @@ export const sshHostServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SSH
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
@ -182,25 +184,7 @@ export const sshHostServiceFactory = ({
return ca.id; return ca.id;
}; };
let projectSshConfig = await projectSshConfigDAL.findOne({ projectId }); const projectSshConfig = await projectSshConfigDAL.findOne({ projectId });
if (!projectSshConfig) {
projectSshConfig = await projectSshConfigDAL.transaction(async (tx) => {
await tx.raw("SELECT pg_advisory_xact_lock(?)", [PgSqlLock.SshInit(projectId)]);
let sshConfig = await projectSshConfigDAL.findOne({ projectId }, tx);
if (sshConfig) return sshConfig;
sshConfig = await bootstrapSshProject({
projectId,
sshCertificateAuthorityDAL,
sshCertificateAuthoritySecretDAL,
kmsService,
projectSshConfigDAL,
tx
});
return sshConfig;
});
}
const userSshCaId = await resolveSshCaId({ const userSshCaId = await resolveSshCaId({
requestedId: requestedUserSshCaId, requestedId: requestedUserSshCaId,
@ -273,7 +257,8 @@ export const sshHostServiceFactory = ({
actorId, actorId,
projectId: host.projectId, projectId: host.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SSH
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
@ -334,7 +319,8 @@ export const sshHostServiceFactory = ({
actorId, actorId,
projectId: host.projectId, projectId: host.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SSH
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
@ -362,7 +348,8 @@ export const sshHostServiceFactory = ({
actorId, actorId,
projectId: host.projectId, projectId: host.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SSH
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
@ -401,7 +388,8 @@ export const sshHostServiceFactory = ({
actorId, actorId,
projectId: host.projectId, projectId: host.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SSH
}); });
const internalPrincipals = await convertActorToPrincipals({ const internalPrincipals = await convertActorToPrincipals({
@ -520,7 +508,8 @@ export const sshHostServiceFactory = ({
actorId, actorId,
projectId: host.projectId, projectId: host.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SSH
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(

View File

@ -1,5 +1,6 @@
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError } from "@casl/ability";
import { ActionProjectType } from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { TSshCertificateAuthorityDALFactory } from "@app/ee/services/ssh/ssh-certificate-authority-dal"; import { TSshCertificateAuthorityDALFactory } from "@app/ee/services/ssh/ssh-certificate-authority-dal";
@ -72,7 +73,8 @@ export const sshCertificateAuthorityServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SSH
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
@ -107,7 +109,8 @@ export const sshCertificateAuthorityServiceFactory = ({
actorId, actorId,
projectId: ca.projectId, projectId: ca.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SSH
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
@ -175,7 +178,8 @@ export const sshCertificateAuthorityServiceFactory = ({
actorId, actorId,
projectId: ca.projectId, projectId: ca.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SSH
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
@ -213,7 +217,8 @@ export const sshCertificateAuthorityServiceFactory = ({
actorId, actorId,
projectId: ca.projectId, projectId: ca.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SSH
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
@ -254,7 +259,8 @@ export const sshCertificateAuthorityServiceFactory = ({
actorId, actorId,
projectId: sshCertificateTemplate.projectId, projectId: sshCertificateTemplate.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SSH
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
@ -375,7 +381,8 @@ export const sshCertificateAuthorityServiceFactory = ({
actorId, actorId,
projectId: sshCertificateTemplate.projectId, projectId: sshCertificateTemplate.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SSH
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
@ -472,7 +479,8 @@ export const sshCertificateAuthorityServiceFactory = ({
actorId, actorId,
projectId: ca.projectId, projectId: ca.projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.SSH
}); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(

View File

@ -1,5 +1,6 @@
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError } from "@casl/ability";
import { ActionProjectType } from "@app/db/schemas";
import { BadRequestError } from "@app/lib/errors"; import { BadRequestError } from "@app/lib/errors";
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip"; import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
import { TProjectDALFactory } from "@app/services/project/project-dal"; import { TProjectDALFactory } from "@app/services/project/project-dal";
@ -35,7 +36,8 @@ export const trustedIpServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.IpAllowList); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.IpAllowList);
const trustedIps = await trustedIpDAL.find({ const trustedIps = await trustedIpDAL.find({
@ -59,7 +61,8 @@ export const trustedIpServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.IpAllowList); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.IpAllowList);
@ -104,7 +107,8 @@ export const trustedIpServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.IpAllowList); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.IpAllowList);
@ -149,7 +153,8 @@ export const trustedIpServiceFactory = ({
actorId, actorId,
projectId, projectId,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId,
actionProjectType: ActionProjectType.Any
}); });
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.IpAllowList); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.IpAllowList);

View File

@ -11,9 +11,7 @@ export const PgSqlLock = {
OrgGatewayRootCaInit: (orgId: string) => pgAdvisoryLockHashText(`org-gateway-root-ca:${orgId}`), OrgGatewayRootCaInit: (orgId: string) => pgAdvisoryLockHashText(`org-gateway-root-ca:${orgId}`),
OrgGatewayCertExchange: (orgId: string) => pgAdvisoryLockHashText(`org-gateway-cert-exchange:${orgId}`), OrgGatewayCertExchange: (orgId: string) => pgAdvisoryLockHashText(`org-gateway-cert-exchange:${orgId}`),
SecretRotationV2Creation: (folderId: string) => pgAdvisoryLockHashText(`secret-rotation-v2-creation:${folderId}`), SecretRotationV2Creation: (folderId: string) => pgAdvisoryLockHashText(`secret-rotation-v2-creation:${folderId}`),
CreateProject: (orgId: string) => pgAdvisoryLockHashText(`create-project:${orgId}`), CreateProject: (orgId: string) => pgAdvisoryLockHashText(`create-project:${orgId}`)
CreateFolder: (envId: string, projectId: string) => pgAdvisoryLockHashText(`create-folder:${envId}-${projectId}`),
SshInit: (projectId: string) => pgAdvisoryLockHashText(`ssh-bootstrap:${projectId}`)
} as const; } as const;
// all the key prefixes used must be set here to avoid conflict // all the key prefixes used must be set here to avoid conflict
@ -74,7 +72,6 @@ type TWaitTillReady = {
export type TKeyStoreFactory = { export type TKeyStoreFactory = {
setItem: (key: string, value: string | number | Buffer, prefix?: string) => Promise<"OK">; setItem: (key: string, value: string | number | Buffer, prefix?: string) => Promise<"OK">;
getItem: (key: string, prefix?: string) => Promise<string | null>; getItem: (key: string, prefix?: string) => Promise<string | null>;
getItems: (keys: string[], prefix?: string) => Promise<(string | null)[]>;
setExpiry: (key: string, expiryInSeconds: number) => Promise<number>; setExpiry: (key: string, expiryInSeconds: number) => Promise<number>;
setItemWithExpiry: ( setItemWithExpiry: (
key: string, key: string,
@ -83,7 +80,6 @@ export type TKeyStoreFactory = {
prefix?: string prefix?: string
) => Promise<"OK">; ) => Promise<"OK">;
deleteItem: (key: string) => Promise<number>; deleteItem: (key: string) => Promise<number>;
deleteItemsByKeyIn: (keys: string[]) => Promise<number>;
deleteItems: (arg: TDeleteItems) => Promise<number>; deleteItems: (arg: TDeleteItems) => Promise<number>;
incrementBy: (key: string, value: number) => Promise<number>; incrementBy: (key: string, value: number) => Promise<number>;
acquireLock( acquireLock(
@ -92,7 +88,6 @@ export type TKeyStoreFactory = {
settings?: Partial<Settings> settings?: Partial<Settings>
): Promise<{ release: () => Promise<ExecutionResult> }>; ): Promise<{ release: () => Promise<ExecutionResult> }>;
waitTillReady: ({ key, waitingCb, keyCheckCb, waitIteration, delay, jitter }: TWaitTillReady) => Promise<void>; waitTillReady: ({ key, waitingCb, keyCheckCb, waitIteration, delay, jitter }: TWaitTillReady) => Promise<void>;
getKeysByPattern: (pattern: string, limit?: number) => Promise<string[]>;
}; };
export const keyStoreFactory = (redisConfigKeys: TRedisConfigKeys): TKeyStoreFactory => { export const keyStoreFactory = (redisConfigKeys: TRedisConfigKeys): TKeyStoreFactory => {
@ -104,9 +99,6 @@ export const keyStoreFactory = (redisConfigKeys: TRedisConfigKeys): TKeyStoreFac
const getItem = async (key: string, prefix?: string) => redis.get(prefix ? `${prefix}:${key}` : key); const getItem = async (key: string, prefix?: string) => redis.get(prefix ? `${prefix}:${key}` : key);
const getItems = async (keys: string[], prefix?: string) =>
redis.mget(keys.map((key) => (prefix ? `${prefix}:${key}` : key)));
const setItemWithExpiry = async ( const setItemWithExpiry = async (
key: string, key: string,
expiryInSeconds: number | string, expiryInSeconds: number | string,
@ -116,11 +108,6 @@ export const keyStoreFactory = (redisConfigKeys: TRedisConfigKeys): TKeyStoreFac
const deleteItem = async (key: string) => redis.del(key); const deleteItem = async (key: string) => redis.del(key);
const deleteItemsByKeyIn = async (keys: string[]) => {
if (keys.length === 0) return 0;
return redis.del(keys);
};
const deleteItems = async ({ pattern, batchSize = 500, delay = 1500, jitter = 200 }: TDeleteItems) => { const deleteItems = async ({ pattern, batchSize = 500, delay = 1500, jitter = 200 }: TDeleteItems) => {
let cursor = "0"; let cursor = "0";
let totalDeleted = 0; let totalDeleted = 0;
@ -176,24 +163,6 @@ export const keyStoreFactory = (redisConfigKeys: TRedisConfigKeys): TKeyStoreFac
} }
}; };
const getKeysByPattern = async (pattern: string, limit?: number) => {
let cursor = "0";
const allKeys: string[] = [];
do {
// eslint-disable-next-line no-await-in-loop
const [nextCursor, keys] = await redis.scan(cursor, "MATCH", pattern, "COUNT", 1000);
cursor = nextCursor;
allKeys.push(...keys);
if (limit && allKeys.length >= limit) {
return allKeys.slice(0, limit);
}
} while (cursor !== "0");
return allKeys;
};
return { return {
setItem, setItem,
getItem, getItem,
@ -205,9 +174,6 @@ export const keyStoreFactory = (redisConfigKeys: TRedisConfigKeys): TKeyStoreFac
acquireLock(resources: string[], duration: number, settings?: Partial<Settings>) { acquireLock(resources: string[], duration: number, settings?: Partial<Settings>) {
return redisLock.acquire(resources, duration, settings); return redisLock.acquire(resources, duration, settings);
}, },
waitTillReady, waitTillReady
getKeysByPattern,
deleteItemsByKeyIn,
getItems
}; };
}; };

View File

@ -8,8 +8,6 @@ import { TKeyStoreFactory } from "./keystore";
export const inMemoryKeyStore = (): TKeyStoreFactory => { export const inMemoryKeyStore = (): TKeyStoreFactory => {
const store: Record<string, string | number | Buffer> = {}; const store: Record<string, string | number | Buffer> = {};
const getRegex = (pattern: string) =>
new RE2(`^${pattern.replace(/[-[\]/{}()+?.\\^$|]/g, "\\$&").replace(/\*/g, ".*")}$`);
return { return {
setItem: async (key, value) => { setItem: async (key, value) => {
@ -26,7 +24,7 @@ export const inMemoryKeyStore = (): TKeyStoreFactory => {
return 1; return 1;
}, },
deleteItems: async ({ pattern, batchSize = 500, delay = 1500, jitter = 200 }) => { deleteItems: async ({ pattern, batchSize = 500, delay = 1500, jitter = 200 }) => {
const regex = getRegex(pattern); const regex = new RE2(`^${pattern.replace(/[-[\]/{}()+?.\\^$|]/g, "\\$&").replace(/\*/g, ".*")}$`);
let totalDeleted = 0; let totalDeleted = 0;
const keys = Object.keys(store); const keys = Object.keys(store);
@ -61,27 +59,6 @@ export const inMemoryKeyStore = (): TKeyStoreFactory => {
release: () => {} release: () => {}
}) as Promise<Lock>; }) as Promise<Lock>;
}, },
waitTillReady: async () => {}, waitTillReady: async () => {}
getKeysByPattern: async (pattern) => {
const regex = getRegex(pattern);
const keys = Object.keys(store);
return keys.filter((key) => regex.test(key));
},
deleteItemsByKeyIn: async (keys) => {
for (const key of keys) {
delete store[key];
}
return keys.length;
},
getItems: async (keys) => {
const values = keys.map((key) => {
const value = store[key];
if (typeof value === "string") {
return value;
}
return null;
});
return values;
}
}; };
}; };

View File

@ -22,7 +22,6 @@ export enum ApiDocsTags {
UniversalAuth = "Universal Auth", UniversalAuth = "Universal Auth",
GcpAuth = "GCP Auth", GcpAuth = "GCP Auth",
AliCloudAuth = "Alibaba Cloud Auth", AliCloudAuth = "Alibaba Cloud Auth",
TlsCertAuth = "TLS Certificate Auth",
AwsAuth = "AWS Auth", AwsAuth = "AWS Auth",
OciAuth = "OCI Auth", OciAuth = "OCI Auth",
AzureAuth = "Azure Auth", AzureAuth = "Azure Auth",
@ -66,10 +65,7 @@ export enum ApiDocsTags {
KmsKeys = "KMS Keys", KmsKeys = "KMS Keys",
KmsEncryption = "KMS Encryption", KmsEncryption = "KMS Encryption",
KmsSigning = "KMS Signing", KmsSigning = "KMS Signing",
SecretScanning = "Secret Scanning", SecretScanning = "Secret Scanning"
OidcSso = "OIDC SSO",
SamlSso = "SAML SSO",
LdapSso = "LDAP SSO"
} }
export const GROUPS = { export const GROUPS = {
@ -287,38 +283,6 @@ export const ALICLOUD_AUTH = {
} }
} as const; } as const;
export const TLS_CERT_AUTH = {
LOGIN: {
identityId: "The ID of the identity to login."
},
ATTACH: {
identityId: "The ID of the identity to attach the configuration onto.",
allowedCommonNames:
"The comma-separated list of trusted common names that are allowed to authenticate with Infisical.",
caCertificate: "The PEM-encoded CA certificate to validate client certificates.",
accessTokenTTL: "The lifetime for an access token in seconds.",
accessTokenMaxTTL: "The maximum lifetime for an access token in seconds.",
accessTokenNumUsesLimit: "The maximum number of times that an access token can be used.",
accessTokenTrustedIps: "The IPs or CIDR ranges that access tokens can be used from."
},
UPDATE: {
identityId: "The ID of the identity to update the auth method for.",
allowedCommonNames:
"The comma-separated list of trusted common names that are allowed to authenticate with Infisical.",
caCertificate: "The PEM-encoded CA certificate to validate client certificates.",
accessTokenTTL: "The new lifetime for an access token in seconds.",
accessTokenMaxTTL: "The new maximum lifetime for an access token in seconds.",
accessTokenNumUsesLimit: "The new maximum number of times that an access token can be used.",
accessTokenTrustedIps: "The new IPs or CIDR ranges that access tokens can be used from."
},
RETRIEVE: {
identityId: "The ID of the identity to retrieve the auth method for."
},
REVOKE: {
identityId: "The ID of the identity to revoke the auth method for."
}
} as const;
export const AWS_AUTH = { export const AWS_AUTH = {
LOGIN: { LOGIN: {
identityId: "The ID of the identity to login.", identityId: "The ID of the identity to login.",
@ -703,8 +667,7 @@ export const PROJECTS = {
slug: "An optional slug for the project. (must be unique within the organization)", slug: "An optional slug for the project. (must be unique within the organization)",
hasDeleteProtection: "Enable or disable delete protection for the project.", hasDeleteProtection: "Enable or disable delete protection for the project.",
secretSharing: "Enable or disable secret sharing for the project.", secretSharing: "Enable or disable secret sharing for the project.",
showSnapshotsLegacy: "Enable or disable legacy snapshots for the project.", showSnapshotsLegacy: "Enable or disable legacy snapshots for the project."
defaultProduct: "The default product in which the project will open"
}, },
GET_KEY: { GET_KEY: {
workspaceId: "The ID of the project to get the key from." workspaceId: "The ID of the project to get the key from."
@ -2265,16 +2228,6 @@ export const AppConnections = {
}, },
FLYIO: { FLYIO: {
accessToken: "The Access Token used to access fly.io." accessToken: "The Access Token used to access fly.io."
},
GITLAB: {
instanceUrl: "The GitLab instance URL to connect with.",
accessToken: "The Access Token used to access GitLab.",
code: "The OAuth code to use to connect with GitLab.",
accessTokenType: "The type of token used to connect with GitLab."
},
ZABBIX: {
apiToken: "The API Token used to access Zabbix.",
instanceUrl: "The Zabbix instance URL to connect with."
} }
} }
}; };
@ -2435,8 +2388,7 @@ export const SecretSyncs = {
keyOcid: "The OCID (Oracle Cloud Identifier) of the encryption key to use when creating secrets in the vault." keyOcid: "The OCID (Oracle Cloud Identifier) of the encryption key to use when creating secrets in the vault."
}, },
ONEPASS: { ONEPASS: {
vaultId: "The ID of the 1Password vault to sync secrets to.", vaultId: "The ID of the 1Password vault to sync secrets to."
valueLabel: "The label of the entry that holds the secret value."
}, },
HEROKU: { HEROKU: {
app: "The ID of the Heroku app to sync secrets to.", app: "The ID of the Heroku app to sync secrets to.",
@ -2449,27 +2401,6 @@ export const SecretSyncs = {
}, },
FLYIO: { FLYIO: {
appId: "The ID of the Fly.io app to sync secrets to." appId: "The ID of the Fly.io app to sync secrets to."
},
GITLAB: {
projectId: "The GitLab Project ID to sync secrets to.",
projectName: "The GitLab Project Name to sync secrets to.",
groupId: "The GitLab Group ID to sync secrets to.",
groupName: "The GitLab Group Name to sync secrets to.",
scope: "The GitLab scope that secrets should be synced to. (default: project)",
targetEnvironment: "The GitLab environment scope that secrets should be synced to. (default: *)",
shouldProtectSecrets: "Whether variables should be protected",
shouldMaskSecrets: "Whether variables should be masked in logs",
shouldHideSecrets: "Whether variables should be hidden"
},
CLOUDFLARE_PAGES: {
projectName: "The name of the Cloudflare Pages project to sync secrets to.",
environment: "The environment of the Cloudflare Pages project to sync secrets to."
},
ZABBIX: {
scope: "The Zabbix scope that secrets should be synced to.",
hostId: "The ID of the Zabbix host to sync secrets to.",
hostName: "The name of the Zabbix host to sync secrets to.",
macroType: "The type of macro to sync secrets to. (0: Text, 1: Secret)"
} }
} }
}; };
@ -2665,113 +2596,3 @@ export const SecretScanningConfigs = {
content: "The contents of the Secret Scanning Configuration file." content: "The contents of the Secret Scanning Configuration file."
} }
}; };
export const OidcSSo = {
GET_CONFIG: {
organizationId: "The ID of the organization to get the OIDC config for."
},
UPDATE_CONFIG: {
organizationId: "The ID of the organization to update the OIDC config for.",
allowedEmailDomains:
"A list of allowed email domains that users can use to authenticate with. This field is comma separated. Example: 'example.com,acme.com'",
discoveryURL: "The URL of the OIDC discovery endpoint.",
configurationType: "The configuration type to use for the OIDC configuration.",
issuer:
"The issuer for the OIDC configuration. This is only supported when the OIDC configuration type is set to 'custom'.",
authorizationEndpoint:
"The endpoint to use for OIDC authorization. This is only supported when the OIDC configuration type is set to 'custom'.",
jwksUri: "The URL of the OIDC JWKS endpoint.",
tokenEndpoint: "The token endpoint to use for OIDC token exchange.",
userinfoEndpoint: "The userinfo endpoint to get user information from the OIDC provider.",
clientId: "The client ID to use for OIDC authentication.",
clientSecret: "The client secret to use for OIDC authentication.",
isActive: "Whether to enable or disable this OIDC configuration.",
manageGroupMemberships:
"Whether to manage group memberships for the OIDC configuration. If enabled, users will automatically be assigned groups when they sign in, based on which groups they are a member of in the OIDC provider.",
jwtSignatureAlgorithm: "The algorithm to use for JWT signature verification."
},
CREATE_CONFIG: {
organizationId: "The ID of the organization to create the OIDC config for.",
allowedEmailDomains:
"A list of allowed email domains that users can use to authenticate with. This field is comma separated.",
discoveryURL: "The URL of the OIDC discovery endpoint.",
configurationType: "The configuration type to use for the OIDC configuration.",
issuer:
"The issuer for the OIDC configuration. This is only supported when the OIDC configuration type is set to 'custom'.",
authorizationEndpoint:
"The authorization endpoint to use for OIDC authorization. This is only supported when the OIDC configuration type is set to 'custom'.",
jwksUri: "The URL of the OIDC JWKS endpoint.",
tokenEndpoint: "The token endpoint to use for OIDC token exchange.",
userinfoEndpoint: "The userinfo endpoint to get user information from the OIDC provider.",
clientId: "The client ID to use for OIDC authentication.",
clientSecret: "The client secret to use for OIDC authentication.",
isActive: "Whether to enable or disable this OIDC configuration.",
manageGroupMemberships:
"Whether to manage group memberships for the OIDC configuration. If enabled, users will automatically be assigned groups when they sign in, based on which groups they are a member of in the OIDC provider.",
jwtSignatureAlgorithm: "The algorithm to use for JWT signature verification."
}
};
export const SamlSso = {
GET_CONFIG: {
organizationId: "The ID of the organization to get the SAML config for."
},
UPDATE_CONFIG: {
organizationId: "The ID of the organization to update the SAML config for.",
authProvider: "Authentication provider to use for SAML authentication.",
isActive: "Whether to enable or disable this SAML configuration.",
entryPoint:
"The entry point for the SAML authentication. This is the URL that the user will be redirected to after they have authenticated with the SAML provider.",
issuer: "The SAML provider issuer URL or entity ID.",
cert: "The certificate to use for SAML authentication."
},
CREATE_CONFIG: {
organizationId: "The ID of the organization to create the SAML config for.",
authProvider: "Authentication provider to use for SAML authentication.",
isActive: "Whether to enable or disable this SAML configuration.",
entryPoint:
"The entry point for the SAML authentication. This is the URL that the user will be redirected to after they have authenticated with the SAML provider.",
issuer: "The SAML provider issuer URL or entity ID.",
cert: "The certificate to use for SAML authentication."
}
};
export const LdapSso = {
GET_CONFIG: {
organizationId: "The ID of the organization to get the LDAP config for."
},
CREATE_CONFIG: {
organizationId: "The ID of the organization to create the LDAP config for.",
isActive: "Whether to enable or disable this LDAP configuration.",
url: "The LDAP server to connect to such as `ldap://ldap.your-org.com`, `ldaps://ldap.myorg.com:636` (for connection over SSL/TLS), etc.",
bindDN:
"The distinguished name of the object to bind when performing the user search such as `cn=infisical,ou=Users,dc=acme,dc=com`",
bindPass: "The password to use along with Bind DN when performing the user search.",
searchBase: "The base DN to use for the user search such as `ou=Users,dc=acme,dc=com`",
uniqueUserAttribute:
"The attribute to use as the unique identifier of LDAP users such as `sAMAccountName`, `cn`, `uid`, `objectGUID`. If left blank, defaults to uidNumber",
searchFilter:
"The template used to construct the LDAP user search filter such as `(uid={{username}})` uses literal `{{username}}` to have the given username used in the search. The default is `(uid={{username}})` which is compatible with several common directory schemas.",
groupSearchBase: "LDAP search base to use for group membership search such as `ou=Groups,dc=acme,dc=com`",
groupSearchFilter:
"The template used when constructing the group membership query such as `(&(objectClass=posixGroup)(memberUid={{.Username}}))`. The template can access the following context variables: `[UserDN, UserName]`. The default is `(|(memberUid={{.Username}})(member={{.UserDN}})(uniqueMember={{.UserDN}}))` which is compatible with several common directory schemas.",
caCert: "The CA certificate to use when verifying the LDAP server certificate."
},
UPDATE_CONFIG: {
organizationId: "The ID of the organization to update the LDAP config for.",
isActive: "Whether to enable or disable this LDAP configuration.",
url: "The LDAP server to connect to such as `ldap://ldap.your-org.com`, `ldaps://ldap.myorg.com:636` (for connection over SSL/TLS), etc.",
bindDN:
"The distinguished name of object to bind when performing the user search such as `cn=infisical,ou=Users,dc=acme,dc=com`",
bindPass: "The password to use along with Bind DN when performing the user search.",
uniqueUserAttribute:
"The attribute to use as the unique identifier of LDAP users such as `sAMAccountName`, `cn`, `uid`, `objectGUID`. If left blank, defaults to uidNumber",
searchFilter:
"The template used to construct the LDAP user search filter such as `(uid={{username}})` uses literal `{{username}}` to have the given username used in the search. The default is `(uid={{username}})` which is compatible with several common directory schemas.",
searchBase: "The base DN to use for the user search such as `ou=Users,dc=acme,dc=com`",
groupSearchBase: "LDAP search base to use for group membership search such as `ou=Groups,dc=acme,dc=com`",
groupSearchFilter:
"The template used when constructing the group membership query such as `(&(objectClass=posixGroup)(memberUid={{.Username}}))`. The template can access the following context variables: `[UserDN, UserName]`. The default is `(|(memberUid={{.Username}})(member={{.UserDN}})(uniqueMember={{.UserDN}}))` which is compatible with several common directory schemas.",
caCert: "The CA certificate to use when verifying the LDAP server certificate."
}
};

View File

@ -2,7 +2,6 @@ import { z } from "zod";
import { QueueWorkerProfile } from "@app/lib/types"; import { QueueWorkerProfile } from "@app/lib/types";
import { BadRequestError } from "../errors";
import { removeTrailingSlash } from "../fn"; import { removeTrailingSlash } from "../fn";
import { CustomLogger } from "../logger/logger"; import { CustomLogger } from "../logger/logger";
import { zpStr } from "../zod"; import { zpStr } from "../zod";
@ -194,9 +193,6 @@ const envSchema = z
PYLON_API_KEY: zpStr(z.string().optional()), PYLON_API_KEY: zpStr(z.string().optional()),
DISABLE_AUDIT_LOG_GENERATION: zodStrBool.default("false"), DISABLE_AUDIT_LOG_GENERATION: zodStrBool.default("false"),
SSL_CLIENT_CERTIFICATE_HEADER_KEY: zpStr(z.string().optional()).default("x-ssl-client-cert"), SSL_CLIENT_CERTIFICATE_HEADER_KEY: zpStr(z.string().optional()).default("x-ssl-client-cert"),
IDENTITY_TLS_CERT_AUTH_CLIENT_CERTIFICATE_HEADER_KEY: zpStr(z.string().optional()).default(
"x-identity-tls-cert-auth-client-cert"
),
WORKFLOW_SLACK_CLIENT_ID: zpStr(z.string().optional()), WORKFLOW_SLACK_CLIENT_ID: zpStr(z.string().optional()),
WORKFLOW_SLACK_CLIENT_SECRET: zpStr(z.string().optional()), WORKFLOW_SLACK_CLIENT_SECRET: zpStr(z.string().optional()),
ENABLE_MSSQL_SECRET_ROTATION_ENCRYPT: zodStrBool.default("true"), ENABLE_MSSQL_SECRET_ROTATION_ENCRYPT: zodStrBool.default("true"),
@ -251,10 +247,6 @@ const envSchema = z
INF_APP_CONNECTION_GITHUB_RADAR_APP_ID: zpStr(z.string().optional()), INF_APP_CONNECTION_GITHUB_RADAR_APP_ID: zpStr(z.string().optional()),
INF_APP_CONNECTION_GITHUB_RADAR_APP_WEBHOOK_SECRET: zpStr(z.string().optional()), INF_APP_CONNECTION_GITHUB_RADAR_APP_WEBHOOK_SECRET: zpStr(z.string().optional()),
// gitlab oauth
INF_APP_CONNECTION_GITLAB_OAUTH_CLIENT_ID: zpStr(z.string().optional()),
INF_APP_CONNECTION_GITLAB_OAUTH_CLIENT_SECRET: zpStr(z.string().optional()),
// gcp app // gcp app
INF_APP_CONNECTION_GCP_SERVICE_ACCOUNT_CREDENTIAL: zpStr(z.string().optional()), INF_APP_CONNECTION_GCP_SERVICE_ACCOUNT_CREDENTIAL: zpStr(z.string().optional()),
@ -342,11 +334,8 @@ const envSchema = z
export type TEnvConfig = Readonly<z.infer<typeof envSchema>>; export type TEnvConfig = Readonly<z.infer<typeof envSchema>>;
let envCfg: TEnvConfig; let envCfg: TEnvConfig;
let originalEnvConfig: TEnvConfig;
export const getConfig = () => envCfg; export const getConfig = () => envCfg;
export const getOriginalConfig = () => originalEnvConfig;
// cannot import singleton logger directly as it needs config to load various transport // cannot import singleton logger directly as it needs config to load various transport
export const initEnvConfig = (logger?: CustomLogger) => { export const initEnvConfig = (logger?: CustomLogger) => {
const parsedEnv = envSchema.safeParse(process.env); const parsedEnv = envSchema.safeParse(process.env);
@ -356,115 +345,10 @@ export const initEnvConfig = (logger?: CustomLogger) => {
process.exit(-1); process.exit(-1);
} }
const config = Object.freeze(parsedEnv.data); envCfg = Object.freeze(parsedEnv.data);
envCfg = config;
if (!originalEnvConfig) {
originalEnvConfig = config;
}
return envCfg; return envCfg;
}; };
// A list of environment variables that can be overwritten
export const overwriteSchema: {
[key: string]: {
name: string;
fields: { key: keyof TEnvConfig; description?: string }[];
};
} = {
azure: {
name: "Azure",
fields: [
{
key: "INF_APP_CONNECTION_AZURE_CLIENT_ID",
description: "The Application (Client) ID of your Azure application."
},
{
key: "INF_APP_CONNECTION_AZURE_CLIENT_SECRET",
description: "The Client Secret of your Azure application."
}
]
},
google_sso: {
name: "Google SSO",
fields: [
{
key: "CLIENT_ID_GOOGLE_LOGIN",
description: "The Client ID of your GCP OAuth2 application."
},
{
key: "CLIENT_SECRET_GOOGLE_LOGIN",
description: "The Client Secret of your GCP OAuth2 application."
}
]
},
github_sso: {
name: "GitHub SSO",
fields: [
{
key: "CLIENT_ID_GITHUB_LOGIN",
description: "The Client ID of your GitHub OAuth application."
},
{
key: "CLIENT_SECRET_GITHUB_LOGIN",
description: "The Client Secret of your GitHub OAuth application."
}
]
},
gitlab_sso: {
name: "GitLab SSO",
fields: [
{
key: "CLIENT_ID_GITLAB_LOGIN",
description: "The Client ID of your GitLab application."
},
{
key: "CLIENT_SECRET_GITLAB_LOGIN",
description: "The Secret of your GitLab application."
},
{
key: "CLIENT_GITLAB_LOGIN_URL",
description:
"The URL of your self-hosted instance of GitLab where the OAuth application is registered. If no URL is passed in, this will default to https://gitlab.com."
}
]
}
};
export const overridableKeys = new Set(
Object.values(overwriteSchema).flatMap(({ fields }) => fields.map(({ key }) => key))
);
export const validateOverrides = (config: Record<string, string>) => {
const allowedOverrides = Object.fromEntries(
Object.entries(config).filter(([key]) => overridableKeys.has(key as keyof z.input<typeof envSchema>))
);
const tempEnv: Record<string, unknown> = { ...process.env, ...allowedOverrides };
const parsedResult = envSchema.safeParse(tempEnv);
if (!parsedResult.success) {
const errorDetails = parsedResult.error.issues
.map((issue) => `Key: "${issue.path.join(".")}", Error: ${issue.message}`)
.join("\n");
throw new BadRequestError({ message: errorDetails });
}
};
export const overrideEnvConfig = (config: Record<string, string>) => {
const allowedOverrides = Object.fromEntries(
Object.entries(config).filter(([key]) => overridableKeys.has(key as keyof z.input<typeof envSchema>))
);
const tempEnv: Record<string, unknown> = { ...process.env, ...allowedOverrides };
const parsedResult = envSchema.safeParse(tempEnv);
if (parsedResult.success) {
envCfg = Object.freeze(parsedResult.data);
}
};
export const formatSmtpConfig = () => { export const formatSmtpConfig = () => {
const tlsOptions: { const tlsOptions: {
rejectUnauthorized: boolean; rejectUnauthorized: boolean;

View File

@ -193,8 +193,6 @@ import { identityOidcAuthServiceFactory } from "@app/services/identity-oidc-auth
import { identityProjectDALFactory } from "@app/services/identity-project/identity-project-dal"; import { identityProjectDALFactory } from "@app/services/identity-project/identity-project-dal";
import { identityProjectMembershipRoleDALFactory } from "@app/services/identity-project/identity-project-membership-role-dal"; import { identityProjectMembershipRoleDALFactory } from "@app/services/identity-project/identity-project-membership-role-dal";
import { identityProjectServiceFactory } from "@app/services/identity-project/identity-project-service"; import { identityProjectServiceFactory } from "@app/services/identity-project/identity-project-service";
import { identityTlsCertAuthDALFactory } from "@app/services/identity-tls-cert-auth/identity-tls-cert-auth-dal";
import { identityTlsCertAuthServiceFactory } from "@app/services/identity-tls-cert-auth/identity-tls-cert-auth-service";
import { identityTokenAuthDALFactory } from "@app/services/identity-token-auth/identity-token-auth-dal"; import { identityTokenAuthDALFactory } from "@app/services/identity-token-auth/identity-token-auth-dal";
import { identityTokenAuthServiceFactory } from "@app/services/identity-token-auth/identity-token-auth-service"; import { identityTokenAuthServiceFactory } from "@app/services/identity-token-auth/identity-token-auth-service";
import { identityUaClientSecretDALFactory } from "@app/services/identity-ua/identity-ua-client-secret-dal"; import { identityUaClientSecretDALFactory } from "@app/services/identity-ua/identity-ua-client-secret-dal";
@ -280,6 +278,7 @@ import { TSmtpService } from "@app/services/smtp/smtp-service";
import { invalidateCacheQueueFactory } from "@app/services/super-admin/invalidate-cache-queue"; import { invalidateCacheQueueFactory } from "@app/services/super-admin/invalidate-cache-queue";
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal"; import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
import { getServerCfg, superAdminServiceFactory } from "@app/services/super-admin/super-admin-service"; import { getServerCfg, superAdminServiceFactory } from "@app/services/super-admin/super-admin-service";
import { posthogAggregatedEventsDALFactory } from "@app/services/telemetry/posthog-aggregated-events-dal";
import { telemetryDALFactory } from "@app/services/telemetry/telemetry-dal"; import { telemetryDALFactory } from "@app/services/telemetry/telemetry-dal";
import { telemetryQueueServiceFactory } from "@app/services/telemetry/telemetry-queue"; import { telemetryQueueServiceFactory } from "@app/services/telemetry/telemetry-queue";
import { telemetryServiceFactory } from "@app/services/telemetry/telemetry-service"; import { telemetryServiceFactory } from "@app/services/telemetry/telemetry-service";
@ -299,8 +298,8 @@ import { injectAssumePrivilege } from "../plugins/auth/inject-assume-privilege";
import { injectIdentity } from "../plugins/auth/inject-identity"; import { injectIdentity } from "../plugins/auth/inject-identity";
import { injectPermission } from "../plugins/auth/inject-permission"; import { injectPermission } from "../plugins/auth/inject-permission";
import { injectRateLimits } from "../plugins/inject-rate-limits"; import { injectRateLimits } from "../plugins/inject-rate-limits";
import { registerSecretScannerGhApp } from "../plugins/secret-scanner";
import { registerV1Routes } from "./v1"; import { registerV1Routes } from "./v1";
import { initializeOauthConfigSync } from "./v1/sso-router";
import { registerV2Routes } from "./v2"; import { registerV2Routes } from "./v2";
import { registerV3Routes } from "./v3"; import { registerV3Routes } from "./v3";
@ -328,6 +327,7 @@ export const registerRoutes = async (
} }
) => { ) => {
const appCfg = getConfig(); const appCfg = getConfig();
await server.register(registerSecretScannerGhApp, { prefix: "/ss-webhook" });
await server.register(registerSecretScanningV2Webhooks, { await server.register(registerSecretScanningV2Webhooks, {
prefix: "/secret-scanning/webhooks" prefix: "/secret-scanning/webhooks"
}); });
@ -387,7 +387,6 @@ export const registerRoutes = async (
const identityKubernetesAuthDAL = identityKubernetesAuthDALFactory(db); const identityKubernetesAuthDAL = identityKubernetesAuthDALFactory(db);
const identityUaClientSecretDAL = identityUaClientSecretDALFactory(db); const identityUaClientSecretDAL = identityUaClientSecretDALFactory(db);
const identityAliCloudAuthDAL = identityAliCloudAuthDALFactory(db); const identityAliCloudAuthDAL = identityAliCloudAuthDALFactory(db);
const identityTlsCertAuthDAL = identityTlsCertAuthDALFactory(db);
const identityAwsAuthDAL = identityAwsAuthDALFactory(db); const identityAwsAuthDAL = identityAwsAuthDALFactory(db);
const identityGcpAuthDAL = identityGcpAuthDALFactory(db); const identityGcpAuthDAL = identityGcpAuthDALFactory(db);
const identityOciAuthDAL = identityOciAuthDALFactory(db); const identityOciAuthDAL = identityOciAuthDALFactory(db);
@ -400,6 +399,7 @@ export const registerRoutes = async (
const auditLogStreamDAL = auditLogStreamDALFactory(db); const auditLogStreamDAL = auditLogStreamDALFactory(db);
const trustedIpDAL = trustedIpDALFactory(db); const trustedIpDAL = trustedIpDALFactory(db);
const telemetryDAL = telemetryDALFactory(db); const telemetryDAL = telemetryDALFactory(db);
const posthogAggregatedEventsDAL = posthogAggregatedEventsDALFactory(db);
const appConnectionDAL = appConnectionDALFactory(db); const appConnectionDAL = appConnectionDALFactory(db);
const secretSyncDAL = secretSyncDALFactory(db, folderDAL); const secretSyncDAL = secretSyncDALFactory(db, folderDAL);
@ -683,7 +683,8 @@ export const registerRoutes = async (
const telemetryService = telemetryServiceFactory({ const telemetryService = telemetryServiceFactory({
keyStore, keyStore,
licenseService licenseService,
posthogAggregatedEventsDAL
}); });
const telemetryQueue = telemetryQueueServiceFactory({ const telemetryQueue = telemetryQueueServiceFactory({
keyStore, keyStore,
@ -996,7 +997,8 @@ export const registerRoutes = async (
pkiAlertDAL, pkiAlertDAL,
pkiCollectionDAL, pkiCollectionDAL,
permissionService, permissionService,
smtpService smtpService,
projectDAL
}); });
const pkiCollectionService = pkiCollectionServiceFactory({ const pkiCollectionService = pkiCollectionServiceFactory({
@ -1004,7 +1006,8 @@ export const registerRoutes = async (
pkiCollectionItemDAL, pkiCollectionItemDAL,
certificateAuthorityDAL, certificateAuthorityDAL,
certificateDAL, certificateDAL,
permissionService permissionService,
projectDAL
}); });
const projectTemplateService = projectTemplateServiceFactory({ const projectTemplateService = projectTemplateServiceFactory({
@ -1188,9 +1191,7 @@ export const registerRoutes = async (
projectEnvDAL, projectEnvDAL,
snapshotService, snapshotService,
projectDAL, projectDAL,
folderCommitService, folderCommitService
secretApprovalPolicyService,
secretV2BridgeDAL
}); });
const secretImportService = secretImportServiceFactory({ const secretImportService = secretImportServiceFactory({
@ -1420,8 +1421,7 @@ export const registerRoutes = async (
const identityAccessTokenService = identityAccessTokenServiceFactory({ const identityAccessTokenService = identityAccessTokenServiceFactory({
identityAccessTokenDAL, identityAccessTokenDAL,
identityOrgMembershipDAL, identityOrgMembershipDAL,
accessTokenQueue, accessTokenQueue
identityDAL
}); });
const identityProjectService = identityProjectServiceFactory({ const identityProjectService = identityProjectServiceFactory({
@ -1497,15 +1497,6 @@ export const registerRoutes = async (
permissionService permissionService
}); });
const identityTlsCertAuthService = identityTlsCertAuthServiceFactory({
identityAccessTokenDAL,
identityTlsCertAuthDAL,
identityOrgMembershipDAL,
licenseService,
permissionService,
kmsService
});
const identityAwsAuthService = identityAwsAuthServiceFactory({ const identityAwsAuthService = identityAwsAuthServiceFactory({
identityAccessTokenDAL, identityAccessTokenDAL,
identityAwsAuthDAL, identityAwsAuthDAL,
@ -1616,8 +1607,7 @@ export const registerRoutes = async (
secretSharingDAL, secretSharingDAL,
secretVersionV2DAL: secretVersionV2BridgeDAL, secretVersionV2DAL: secretVersionV2BridgeDAL,
identityUniversalAuthClientSecretDAL: identityUaClientSecretDAL, identityUniversalAuthClientSecretDAL: identityUaClientSecretDAL,
serviceTokenService, serviceTokenService
orgService
}); });
const dailyExpiringPkiItemAlert = dailyExpiringPkiItemAlertQueueServiceFactory({ const dailyExpiringPkiItemAlert = dailyExpiringPkiItemAlertQueueServiceFactory({
@ -1665,7 +1655,8 @@ export const registerRoutes = async (
const cmekService = cmekServiceFactory({ const cmekService = cmekServiceFactory({
kmsDAL, kmsDAL,
kmsService, kmsService,
permissionService permissionService,
projectDAL
}); });
const externalMigrationQueue = externalMigrationQueueFactory({ const externalMigrationQueue = externalMigrationQueueFactory({
@ -1807,6 +1798,7 @@ export const registerRoutes = async (
const certificateAuthorityService = certificateAuthorityServiceFactory({ const certificateAuthorityService = certificateAuthorityServiceFactory({
certificateAuthorityDAL, certificateAuthorityDAL,
projectDAL,
permissionService, permissionService,
appConnectionDAL, appConnectionDAL,
appConnectionService, appConnectionService,
@ -1816,8 +1808,7 @@ export const registerRoutes = async (
certificateBodyDAL, certificateBodyDAL,
certificateSecretDAL, certificateSecretDAL,
kmsService, kmsService,
pkiSubscriberDAL, pkiSubscriberDAL
projectDAL
}); });
const internalCaFns = InternalCertificateAuthorityFns({ const internalCaFns = InternalCertificateAuthorityFns({
@ -1911,7 +1902,6 @@ export const registerRoutes = async (
await hsmService.startService(); await hsmService.startService();
await telemetryQueue.startTelemetryCheck(); await telemetryQueue.startTelemetryCheck();
await telemetryQueue.startAggregatedEventsJob();
await dailyResourceCleanUp.startCleanUp(); await dailyResourceCleanUp.startCleanUp();
await dailyExpiringPkiItemAlert.startSendingAlerts(); await dailyExpiringPkiItemAlert.startSendingAlerts();
await pkiSubscriberQueue.startDailyAutoRenewalJob(); await pkiSubscriberQueue.startDailyAutoRenewalJob();
@ -1961,7 +1951,6 @@ export const registerRoutes = async (
identityAwsAuth: identityAwsAuthService, identityAwsAuth: identityAwsAuthService,
identityAzureAuth: identityAzureAuthService, identityAzureAuth: identityAzureAuthService,
identityOciAuth: identityOciAuthService, identityOciAuth: identityOciAuthService,
identityTlsCertAuth: identityTlsCertAuthService,
identityOidcAuth: identityOidcAuthService, identityOidcAuth: identityOidcAuthService,
identityJwtAuth: identityJwtAuthService, identityJwtAuth: identityJwtAuthService,
identityLdapAuth: identityLdapAuthService, identityLdapAuth: identityLdapAuthService,
@ -2048,16 +2037,6 @@ export const registerRoutes = async (
} }
} }
const configSyncJob = await superAdminService.initializeEnvConfigSync();
if (configSyncJob) {
cronJobs.push(configSyncJob);
}
const oauthConfigSyncJob = await initializeOauthConfigSync();
if (oauthConfigSyncJob) {
cronJobs.push(oauthConfigSyncJob);
}
server.decorate<FastifyZodProvider["store"]>("store", { server.decorate<FastifyZodProvider["store"]>("store", {
user: userDAL, user: userDAL,
kmipClient: kmipClientDAL kmipClient: kmipClientDAL

View File

@ -251,7 +251,6 @@ export const SanitizedProjectSchema = ProjectsSchema.pick({
name: true, name: true,
description: true, description: true,
type: true, type: true,
defaultProduct: true,
slug: true, slug: true,
autoCapitalization: true, autoCapitalization: true,
orgId: true, orgId: true,

View File

@ -8,7 +8,7 @@ import {
SuperAdminSchema, SuperAdminSchema,
UsersSchema UsersSchema
} from "@app/db/schemas"; } from "@app/db/schemas";
import { getConfig, overridableKeys } from "@app/lib/config/env"; import { getConfig } from "@app/lib/config/env";
import { BadRequestError } from "@app/lib/errors"; import { BadRequestError } from "@app/lib/errors";
import { invalidateCacheLimit, readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { invalidateCacheLimit, readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { getTelemetryDistinctId } from "@app/server/lib/telemetry"; import { getTelemetryDistinctId } from "@app/server/lib/telemetry";
@ -42,8 +42,7 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
encryptedGitHubAppConnectionClientSecret: true, encryptedGitHubAppConnectionClientSecret: true,
encryptedGitHubAppConnectionSlug: true, encryptedGitHubAppConnectionSlug: true,
encryptedGitHubAppConnectionId: true, encryptedGitHubAppConnectionId: true,
encryptedGitHubAppConnectionPrivateKey: true, encryptedGitHubAppConnectionPrivateKey: true
encryptedEnvOverrides: true
}).extend({ }).extend({
isMigrationModeOn: z.boolean(), isMigrationModeOn: z.boolean(),
defaultAuthOrgSlug: z.string().nullable(), defaultAuthOrgSlug: z.string().nullable(),
@ -111,14 +110,11 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
.refine((content) => DOMPurify.sanitize(content) === content, { .refine((content) => DOMPurify.sanitize(content) === content, {
message: "Page frame content contains unsafe HTML." message: "Page frame content contains unsafe HTML."
}) })
.optional(), .optional()
envOverrides: z.record(z.enum(Array.from(overridableKeys) as [string, ...string[]]), z.string()).optional()
}), }),
response: { response: {
200: z.object({ 200: z.object({
config: SuperAdminSchema.omit({ config: SuperAdminSchema.extend({
encryptedEnvOverrides: true
}).extend({
defaultAuthOrgSlug: z.string().nullable() defaultAuthOrgSlug: z.string().nullable()
}) })
}) })
@ -385,41 +381,6 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
} }
}); });
server.route({
method: "GET",
url: "/env-overrides",
config: {
rateLimit: readLimit
},
schema: {
response: {
200: z.record(
z.string(),
z.object({
name: z.string(),
fields: z
.object({
key: z.string(),
value: z.string(),
hasEnvEntry: z.boolean(),
description: z.string().optional()
})
.array()
})
)
}
},
onRequest: (req, res, done) => {
verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN])(req, res, () => {
verifySuperAdmin(req, res, done);
});
},
handler: async () => {
const envOverrides = await server.services.superAdmin.getEnvOverridesOrganized();
return envOverrides;
}
});
server.route({ server.route({
method: "DELETE", method: "DELETE",
url: "/user-management/users/:userId", url: "/user-management/users/:userId",

View File

@ -35,10 +35,6 @@ import {
CamundaConnectionListItemSchema, CamundaConnectionListItemSchema,
SanitizedCamundaConnectionSchema SanitizedCamundaConnectionSchema
} from "@app/services/app-connection/camunda"; } from "@app/services/app-connection/camunda";
import {
CloudflareConnectionListItemSchema,
SanitizedCloudflareConnectionSchema
} from "@app/services/app-connection/cloudflare/cloudflare-connection-schema";
import { import {
DatabricksConnectionListItemSchema, DatabricksConnectionListItemSchema,
SanitizedDatabricksConnectionSchema SanitizedDatabricksConnectionSchema
@ -50,7 +46,6 @@ import {
GitHubRadarConnectionListItemSchema, GitHubRadarConnectionListItemSchema,
SanitizedGitHubRadarConnectionSchema SanitizedGitHubRadarConnectionSchema
} from "@app/services/app-connection/github-radar"; } from "@app/services/app-connection/github-radar";
import { GitLabConnectionListItemSchema, SanitizedGitLabConnectionSchema } from "@app/services/app-connection/gitlab";
import { import {
HCVaultConnectionListItemSchema, HCVaultConnectionListItemSchema,
SanitizedHCVaultConnectionSchema SanitizedHCVaultConnectionSchema
@ -84,7 +79,6 @@ import {
SanitizedWindmillConnectionSchema, SanitizedWindmillConnectionSchema,
WindmillConnectionListItemSchema WindmillConnectionListItemSchema
} from "@app/services/app-connection/windmill"; } from "@app/services/app-connection/windmill";
import { SanitizedZabbixConnectionSchema, ZabbixConnectionListItemSchema } from "@app/services/app-connection/zabbix";
import { AuthMode } from "@app/services/auth/auth-type"; import { AuthMode } from "@app/services/auth/auth-type";
// can't use discriminated due to multiple schemas for certain apps // can't use discriminated due to multiple schemas for certain apps
@ -115,10 +109,7 @@ const SanitizedAppConnectionSchema = z.union([
...SanitizedOnePassConnectionSchema.options, ...SanitizedOnePassConnectionSchema.options,
...SanitizedHerokuConnectionSchema.options, ...SanitizedHerokuConnectionSchema.options,
...SanitizedRenderConnectionSchema.options, ...SanitizedRenderConnectionSchema.options,
...SanitizedFlyioConnectionSchema.options, ...SanitizedFlyioConnectionSchema.options
...SanitizedGitLabConnectionSchema.options,
...SanitizedCloudflareConnectionSchema.options,
...SanitizedZabbixConnectionSchema.options
]); ]);
const AppConnectionOptionsSchema = z.discriminatedUnion("app", [ const AppConnectionOptionsSchema = z.discriminatedUnion("app", [
@ -148,10 +139,7 @@ const AppConnectionOptionsSchema = z.discriminatedUnion("app", [
OnePassConnectionListItemSchema, OnePassConnectionListItemSchema,
HerokuConnectionListItemSchema, HerokuConnectionListItemSchema,
RenderConnectionListItemSchema, RenderConnectionListItemSchema,
FlyioConnectionListItemSchema, FlyioConnectionListItemSchema
GitLabConnectionListItemSchema,
CloudflareConnectionListItemSchema,
ZabbixConnectionListItemSchema
]); ]);
export const registerAppConnectionRouter = async (server: FastifyZodProvider) => { export const registerAppConnectionRouter = async (server: FastifyZodProvider) => {

View File

@ -1,53 +0,0 @@
import z from "zod";
import { readLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
import {
CreateCloudflareConnectionSchema,
SanitizedCloudflareConnectionSchema,
UpdateCloudflareConnectionSchema
} from "@app/services/app-connection/cloudflare/cloudflare-connection-schema";
import { AuthMode } from "@app/services/auth/auth-type";
import { registerAppConnectionEndpoints } from "./app-connection-endpoints";
export const registerCloudflareConnectionRouter = async (server: FastifyZodProvider) => {
registerAppConnectionEndpoints({
app: AppConnection.Cloudflare,
server,
sanitizedResponseSchema: SanitizedCloudflareConnectionSchema,
createSchema: CreateCloudflareConnectionSchema,
updateSchema: UpdateCloudflareConnectionSchema
});
// The below endpoints are not exposed and for Infisical App use
server.route({
method: "GET",
url: `/:connectionId/cloudflare-pages-projects`,
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
connectionId: z.string().uuid()
}),
response: {
200: z
.object({
id: z.string(),
name: z.string()
})
.array()
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const { connectionId } = req.params;
const projects = await server.services.appConnection.cloudflare.listPagesProjects(connectionId, req.permission);
return projects;
}
});
};

View File

@ -1,90 +0,0 @@
import z from "zod";
import { readLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
import {
CreateGitLabConnectionSchema,
SanitizedGitLabConnectionSchema,
TGitLabGroup,
TGitLabProject,
UpdateGitLabConnectionSchema
} from "@app/services/app-connection/gitlab";
import { AuthMode } from "@app/services/auth/auth-type";
import { registerAppConnectionEndpoints } from "./app-connection-endpoints";
export const registerGitLabConnectionRouter = async (server: FastifyZodProvider) => {
registerAppConnectionEndpoints({
app: AppConnection.GitLab,
server,
sanitizedResponseSchema: SanitizedGitLabConnectionSchema,
createSchema: CreateGitLabConnectionSchema,
updateSchema: UpdateGitLabConnectionSchema
});
// The below endpoints are not exposed and for Infisical App use
server.route({
method: "GET",
url: `/:connectionId/projects`,
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
connectionId: z.string().uuid()
}),
response: {
200: z
.object({
id: z.string(),
name: z.string()
})
.array()
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const { connectionId } = req.params;
const projects: TGitLabProject[] = await server.services.appConnection.gitlab.listProjects(
connectionId,
req.permission
);
return projects;
}
});
server.route({
method: "GET",
url: `/:connectionId/groups`,
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
connectionId: z.string().uuid()
}),
response: {
200: z
.object({
id: z.string(),
name: z.string()
})
.array()
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const { connectionId } = req.params;
const groups: TGitLabGroup[] = await server.services.appConnection.gitlab.listGroups(
connectionId,
req.permission
);
return groups;
}
});
};

View File

@ -10,13 +10,11 @@ import { registerAzureClientSecretsConnectionRouter } from "./azure-client-secre
import { registerAzureDevOpsConnectionRouter } from "./azure-devops-connection-router"; import { registerAzureDevOpsConnectionRouter } from "./azure-devops-connection-router";
import { registerAzureKeyVaultConnectionRouter } from "./azure-key-vault-connection-router"; import { registerAzureKeyVaultConnectionRouter } from "./azure-key-vault-connection-router";
import { registerCamundaConnectionRouter } from "./camunda-connection-router"; import { registerCamundaConnectionRouter } from "./camunda-connection-router";
import { registerCloudflareConnectionRouter } from "./cloudflare-connection-router";
import { registerDatabricksConnectionRouter } from "./databricks-connection-router"; import { registerDatabricksConnectionRouter } from "./databricks-connection-router";
import { registerFlyioConnectionRouter } from "./flyio-connection-router"; import { registerFlyioConnectionRouter } from "./flyio-connection-router";
import { registerGcpConnectionRouter } from "./gcp-connection-router"; import { registerGcpConnectionRouter } from "./gcp-connection-router";
import { registerGitHubConnectionRouter } from "./github-connection-router"; import { registerGitHubConnectionRouter } from "./github-connection-router";
import { registerGitHubRadarConnectionRouter } from "./github-radar-connection-router"; import { registerGitHubRadarConnectionRouter } from "./github-radar-connection-router";
import { registerGitLabConnectionRouter } from "./gitlab-connection-router";
import { registerHCVaultConnectionRouter } from "./hc-vault-connection-router"; import { registerHCVaultConnectionRouter } from "./hc-vault-connection-router";
import { registerHerokuConnectionRouter } from "./heroku-connection-router"; import { registerHerokuConnectionRouter } from "./heroku-connection-router";
import { registerHumanitecConnectionRouter } from "./humanitec-connection-router"; import { registerHumanitecConnectionRouter } from "./humanitec-connection-router";
@ -29,7 +27,6 @@ import { registerTeamCityConnectionRouter } from "./teamcity-connection-router";
import { registerTerraformCloudConnectionRouter } from "./terraform-cloud-router"; import { registerTerraformCloudConnectionRouter } from "./terraform-cloud-router";
import { registerVercelConnectionRouter } from "./vercel-connection-router"; import { registerVercelConnectionRouter } from "./vercel-connection-router";
import { registerWindmillConnectionRouter } from "./windmill-connection-router"; import { registerWindmillConnectionRouter } from "./windmill-connection-router";
import { registerZabbixConnectionRouter } from "./zabbix-connection-router";
export * from "./app-connection-router"; export * from "./app-connection-router";
@ -61,8 +58,5 @@ export const APP_CONNECTION_REGISTER_ROUTER_MAP: Record<AppConnection, (server:
[AppConnection.OnePass]: registerOnePassConnectionRouter, [AppConnection.OnePass]: registerOnePassConnectionRouter,
[AppConnection.Heroku]: registerHerokuConnectionRouter, [AppConnection.Heroku]: registerHerokuConnectionRouter,
[AppConnection.Render]: registerRenderConnectionRouter, [AppConnection.Render]: registerRenderConnectionRouter,
[AppConnection.Flyio]: registerFlyioConnectionRouter, [AppConnection.Flyio]: registerFlyioConnectionRouter
[AppConnection.GitLab]: registerGitLabConnectionRouter,
[AppConnection.Cloudflare]: registerCloudflareConnectionRouter,
[AppConnection.Zabbix]: registerZabbixConnectionRouter
}; };

View File

@ -1,51 +0,0 @@
import z from "zod";
import { readLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
import {
CreateZabbixConnectionSchema,
SanitizedZabbixConnectionSchema,
UpdateZabbixConnectionSchema
} from "@app/services/app-connection/zabbix";
import { AuthMode } from "@app/services/auth/auth-type";
import { registerAppConnectionEndpoints } from "./app-connection-endpoints";
export const registerZabbixConnectionRouter = async (server: FastifyZodProvider) => {
registerAppConnectionEndpoints({
app: AppConnection.Zabbix,
server,
sanitizedResponseSchema: SanitizedZabbixConnectionSchema,
createSchema: CreateZabbixConnectionSchema,
updateSchema: UpdateZabbixConnectionSchema
});
// The following endpoints are for internal Infisical App use only and not part of the public API
server.route({
method: "GET",
url: `/:connectionId/hosts`,
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
connectionId: z.string().uuid()
}),
response: {
200: z
.object({
hostId: z.string(),
host: z.string()
})
.array()
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const { connectionId } = req.params;
const hosts = await server.services.appConnection.zabbix.listHosts(connectionId, req.permission);
return hosts;
}
});
};

View File

@ -1,396 +0,0 @@
import crypto from "node:crypto";
import { z } from "zod";
import { IdentityTlsCertAuthsSchema } from "@app/db/schemas";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { ApiDocsTags, TLS_CERT_AUTH } from "@app/lib/api-docs";
import { getConfig } from "@app/lib/config/env";
import { BadRequestError } from "@app/lib/errors";
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
import { TIdentityTrustedIp } from "@app/services/identity/identity-types";
import { isSuperAdmin } from "@app/services/super-admin/super-admin-fns";
const validateCommonNames = z
.string()
.min(1)
.trim()
.transform((el) =>
el
.split(",")
.map((i) => i.trim())
.join(",")
);
const validateCaCertificate = (caCert: string) => {
if (!caCert) return true;
try {
// eslint-disable-next-line no-new
new crypto.X509Certificate(caCert);
return true;
} catch (err) {
return false;
}
};
export const registerIdentityTlsCertAuthRouter = async (server: FastifyZodProvider) => {
server.route({
method: "POST",
url: "/login",
config: {
rateLimit: writeLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.TlsCertAuth],
description: "Login with TLS Certificate Auth",
body: z.object({
identityId: z.string().trim().describe(TLS_CERT_AUTH.LOGIN.identityId)
}),
response: {
200: z.object({
accessToken: z.string(),
expiresIn: z.coerce.number(),
accessTokenMaxTTL: z.coerce.number(),
tokenType: z.literal("Bearer")
})
}
},
handler: async (req) => {
const appCfg = getConfig();
const clientCertificate = req.headers[appCfg.IDENTITY_TLS_CERT_AUTH_CLIENT_CERTIFICATE_HEADER_KEY];
if (!clientCertificate) {
throw new BadRequestError({ message: "Missing TLS certificate in header" });
}
const { identityTlsCertAuth, accessToken, identityAccessToken, identityMembershipOrg } =
await server.services.identityTlsCertAuth.login({
identityId: req.body.identityId,
clientCertificate: clientCertificate as string
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: identityMembershipOrg?.orgId,
event: {
type: EventType.LOGIN_IDENTITY_TLS_CERT_AUTH,
metadata: {
identityId: identityTlsCertAuth.identityId,
identityAccessTokenId: identityAccessToken.id,
identityTlsCertAuthId: identityTlsCertAuth.id
}
}
});
return {
accessToken,
tokenType: "Bearer" as const,
expiresIn: identityTlsCertAuth.accessTokenTTL,
accessTokenMaxTTL: identityTlsCertAuth.accessTokenMaxTTL
};
}
});
server.route({
method: "POST",
url: "/identities/:identityId",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
hide: false,
tags: [ApiDocsTags.TlsCertAuth],
description: "Attach TLS Certificate Auth configuration onto identity",
security: [
{
bearerAuth: []
}
],
params: z.object({
identityId: z.string().trim().describe(TLS_CERT_AUTH.ATTACH.identityId)
}),
body: z
.object({
allowedCommonNames: validateCommonNames
.optional()
.nullable()
.describe(TLS_CERT_AUTH.ATTACH.allowedCommonNames),
caCertificate: z
.string()
.min(1)
.max(10240)
.refine(validateCaCertificate, "Invalid CA Certificate.")
.describe(TLS_CERT_AUTH.ATTACH.caCertificate),
accessTokenTrustedIps: z
.object({
ipAddress: z.string().trim()
})
.array()
.min(1)
.default([{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }])
.describe(TLS_CERT_AUTH.ATTACH.accessTokenTrustedIps),
accessTokenTTL: z
.number()
.int()
.min(0)
.max(315360000)
.default(2592000)
.describe(TLS_CERT_AUTH.ATTACH.accessTokenTTL),
accessTokenMaxTTL: z
.number()
.int()
.min(1)
.max(315360000)
.default(2592000)
.describe(TLS_CERT_AUTH.ATTACH.accessTokenMaxTTL),
accessTokenNumUsesLimit: z
.number()
.int()
.min(0)
.default(0)
.describe(TLS_CERT_AUTH.ATTACH.accessTokenNumUsesLimit)
})
.refine(
(val) => val.accessTokenTTL <= val.accessTokenMaxTTL,
"Access Token TTL cannot be greater than Access Token Max TTL."
),
response: {
200: z.object({
identityTlsCertAuth: IdentityTlsCertAuthsSchema
})
}
},
handler: async (req) => {
const identityTlsCertAuth = await server.services.identityTlsCertAuth.attachTlsCertAuth({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.body,
identityId: req.params.identityId,
isActorSuperAdmin: isSuperAdmin(req.auth)
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: req.permission.orgId,
event: {
type: EventType.ADD_IDENTITY_TLS_CERT_AUTH,
metadata: {
identityId: identityTlsCertAuth.identityId,
allowedCommonNames: identityTlsCertAuth.allowedCommonNames,
accessTokenTTL: identityTlsCertAuth.accessTokenTTL,
accessTokenMaxTTL: identityTlsCertAuth.accessTokenMaxTTL,
accessTokenTrustedIps: identityTlsCertAuth.accessTokenTrustedIps as TIdentityTrustedIp[],
accessTokenNumUsesLimit: identityTlsCertAuth.accessTokenNumUsesLimit
}
}
});
return { identityTlsCertAuth };
}
});
server.route({
method: "PATCH",
url: "/identities/:identityId",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
hide: false,
tags: [ApiDocsTags.TlsCertAuth],
description: "Update TLS Certificate Auth configuration on identity",
security: [
{
bearerAuth: []
}
],
params: z.object({
identityId: z.string().describe(TLS_CERT_AUTH.UPDATE.identityId)
}),
body: z
.object({
caCertificate: z
.string()
.min(1)
.max(10240)
.refine(validateCaCertificate, "Invalid CA Certificate.")
.optional()
.describe(TLS_CERT_AUTH.UPDATE.caCertificate),
allowedCommonNames: validateCommonNames
.optional()
.nullable()
.describe(TLS_CERT_AUTH.UPDATE.allowedCommonNames),
accessTokenTrustedIps: z
.object({
ipAddress: z.string().trim()
})
.array()
.min(1)
.optional()
.describe(TLS_CERT_AUTH.UPDATE.accessTokenTrustedIps),
accessTokenTTL: z
.number()
.int()
.min(0)
.max(315360000)
.optional()
.describe(TLS_CERT_AUTH.UPDATE.accessTokenTTL),
accessTokenNumUsesLimit: z
.number()
.int()
.min(0)
.optional()
.describe(TLS_CERT_AUTH.UPDATE.accessTokenNumUsesLimit),
accessTokenMaxTTL: z
.number()
.int()
.max(315360000)
.min(0)
.optional()
.describe(TLS_CERT_AUTH.UPDATE.accessTokenMaxTTL)
})
.refine(
(val) => (val.accessTokenMaxTTL && val.accessTokenTTL ? val.accessTokenTTL <= val.accessTokenMaxTTL : true),
"Access Token TTL cannot be greater than Access Token Max TTL."
),
response: {
200: z.object({
identityTlsCertAuth: IdentityTlsCertAuthsSchema
})
}
},
handler: async (req) => {
const identityTlsCertAuth = await server.services.identityTlsCertAuth.updateTlsCertAuth({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.body,
identityId: req.params.identityId
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: req.permission.orgId,
event: {
type: EventType.UPDATE_IDENTITY_TLS_CERT_AUTH,
metadata: {
identityId: identityTlsCertAuth.identityId,
allowedCommonNames: identityTlsCertAuth.allowedCommonNames,
accessTokenTTL: identityTlsCertAuth.accessTokenTTL,
accessTokenMaxTTL: identityTlsCertAuth.accessTokenMaxTTL,
accessTokenTrustedIps: identityTlsCertAuth.accessTokenTrustedIps as TIdentityTrustedIp[],
accessTokenNumUsesLimit: identityTlsCertAuth.accessTokenNumUsesLimit
}
}
});
return { identityTlsCertAuth };
}
});
server.route({
method: "GET",
url: "/identities/:identityId",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
hide: false,
tags: [ApiDocsTags.TlsCertAuth],
description: "Retrieve TLS Certificate Auth configuration on identity",
security: [
{
bearerAuth: []
}
],
params: z.object({
identityId: z.string().describe(TLS_CERT_AUTH.RETRIEVE.identityId)
}),
response: {
200: z.object({
identityTlsCertAuth: IdentityTlsCertAuthsSchema.extend({
caCertificate: z.string()
})
})
}
},
handler: async (req) => {
const identityTlsCertAuth = await server.services.identityTlsCertAuth.getTlsCertAuth({
identityId: req.params.identityId,
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
actorAuthMethod: req.permission.authMethod
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: req.permission.orgId,
event: {
type: EventType.GET_IDENTITY_TLS_CERT_AUTH,
metadata: {
identityId: identityTlsCertAuth.identityId
}
}
});
return { identityTlsCertAuth };
}
});
server.route({
method: "DELETE",
url: "/identities/:identityId",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
hide: false,
tags: [ApiDocsTags.TlsCertAuth],
description: "Delete TLS Certificate Auth configuration on identity",
security: [
{
bearerAuth: []
}
],
params: z.object({
identityId: z.string().describe(TLS_CERT_AUTH.REVOKE.identityId)
}),
response: {
200: z.object({
identityTlsCertAuth: IdentityTlsCertAuthsSchema
})
}
},
handler: async (req) => {
const identityTlsCertAuth = await server.services.identityTlsCertAuth.revokeTlsCertAuth({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
identityId: req.params.identityId
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: req.permission.orgId,
event: {
type: EventType.REVOKE_IDENTITY_TLS_CERT_AUTH,
metadata: {
identityId: identityTlsCertAuth.identityId
}
}
});
return { identityTlsCertAuth };
}
});
};

View File

@ -25,7 +25,6 @@ import { registerIdentityLdapAuthRouter } from "./identity-ldap-auth-router";
import { registerIdentityOciAuthRouter } from "./identity-oci-auth-router"; import { registerIdentityOciAuthRouter } from "./identity-oci-auth-router";
import { registerIdentityOidcAuthRouter } from "./identity-oidc-auth-router"; import { registerIdentityOidcAuthRouter } from "./identity-oidc-auth-router";
import { registerIdentityRouter } from "./identity-router"; import { registerIdentityRouter } from "./identity-router";
import { registerIdentityTlsCertAuthRouter } from "./identity-tls-cert-auth-router";
import { registerIdentityTokenAuthRouter } from "./identity-token-auth-router"; import { registerIdentityTokenAuthRouter } from "./identity-token-auth-router";
import { registerIdentityUaRouter } from "./identity-universal-auth-router"; import { registerIdentityUaRouter } from "./identity-universal-auth-router";
import { registerIntegrationAuthRouter } from "./integration-auth-router"; import { registerIntegrationAuthRouter } from "./integration-auth-router";
@ -67,7 +66,6 @@ export const registerV1Routes = async (server: FastifyZodProvider) => {
await authRouter.register(registerIdentityAccessTokenRouter); await authRouter.register(registerIdentityAccessTokenRouter);
await authRouter.register(registerIdentityAliCloudAuthRouter); await authRouter.register(registerIdentityAliCloudAuthRouter);
await authRouter.register(registerIdentityAwsAuthRouter); await authRouter.register(registerIdentityAwsAuthRouter);
await authRouter.register(registerIdentityTlsCertAuthRouter, { prefix: "/tls-cert-auth" });
await authRouter.register(registerIdentityAzureAuthRouter); await authRouter.register(registerIdentityAzureAuthRouter);
await authRouter.register(registerIdentityOciAuthRouter); await authRouter.register(registerIdentityOciAuthRouter);
await authRouter.register(registerIdentityOidcAuthRouter); await authRouter.register(registerIdentityOidcAuthRouter);

View File

@ -113,73 +113,52 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
hide: false, hide: false,
tags: [ApiDocsTags.AuditLogs], tags: [ApiDocsTags.AuditLogs],
description: "Get all audit logs for an organization", description: "Get all audit logs for an organization",
querystring: z querystring: z.object({
.object({ projectId: z.string().optional().describe(AUDIT_LOGS.EXPORT.projectId),
projectId: z.string().optional().describe(AUDIT_LOGS.EXPORT.projectId), environment: z.string().optional().describe(AUDIT_LOGS.EXPORT.environment),
environment: z.string().optional().describe(AUDIT_LOGS.EXPORT.environment), actorType: z.nativeEnum(ActorType).optional(),
actorType: z.nativeEnum(ActorType).optional(), secretPath: z
secretPath: z .string()
.string() .optional()
.optional() .transform((val) => (!val ? val : removeTrailingSlash(val)))
.transform((val) => (!val ? val : removeTrailingSlash(val))) .describe(AUDIT_LOGS.EXPORT.secretPath),
.describe(AUDIT_LOGS.EXPORT.secretPath), secretKey: z.string().optional().describe(AUDIT_LOGS.EXPORT.secretKey),
secretKey: z.string().optional().describe(AUDIT_LOGS.EXPORT.secretKey),
// eventType is split with , for multiple values, we need to transform it to array
eventType: z
.string()
.optional()
.transform((val) => (val ? val.split(",") : undefined)),
userAgentType: z.nativeEnum(UserAgentType).optional().describe(AUDIT_LOGS.EXPORT.userAgentType),
eventMetadata: z
.string()
.optional()
.transform((val) => {
if (!val) {
return undefined;
}
const pairs = val.split(","); // eventType is split with , for multiple values, we need to transform it to array
eventType: z
.string()
.optional()
.transform((val) => (val ? val.split(",") : undefined)),
userAgentType: z.nativeEnum(UserAgentType).optional().describe(AUDIT_LOGS.EXPORT.userAgentType),
eventMetadata: z
.string()
.optional()
.transform((val) => {
if (!val) {
return undefined;
}
const pairs = val.split(",");
return pairs.reduce(
(acc, pair) => {
const [key, value] = pair.split("=");
if (key && value) {
acc[key] = value;
}
return acc;
},
{} as Record<string, string>
);
})
.describe(AUDIT_LOGS.EXPORT.eventMetadata),
startDate: z.string().datetime().optional().describe(AUDIT_LOGS.EXPORT.startDate),
endDate: z.string().datetime().optional().describe(AUDIT_LOGS.EXPORT.endDate),
offset: z.coerce.number().default(0).describe(AUDIT_LOGS.EXPORT.offset),
limit: z.coerce.number().default(20).describe(AUDIT_LOGS.EXPORT.limit),
actor: z.string().optional().describe(AUDIT_LOGS.EXPORT.actor)
}),
return pairs.reduce(
(acc, pair) => {
const [key, value] = pair.split("=");
if (key && value) {
acc[key] = value;
}
return acc;
},
{} as Record<string, string>
);
})
.describe(AUDIT_LOGS.EXPORT.eventMetadata),
startDate: z.string().datetime().optional().describe(AUDIT_LOGS.EXPORT.startDate),
endDate: z.string().datetime().optional().describe(AUDIT_LOGS.EXPORT.endDate),
offset: z.coerce.number().default(0).describe(AUDIT_LOGS.EXPORT.offset),
limit: z.coerce.number().max(1000).default(20).describe(AUDIT_LOGS.EXPORT.limit),
actor: z.string().optional().describe(AUDIT_LOGS.EXPORT.actor)
})
.superRefine((el, ctx) => {
if (el.endDate && el.startDate) {
const startDate = new Date(el.startDate);
const endDate = new Date(el.endDate);
const maxAllowedDate = new Date(startDate);
maxAllowedDate.setMonth(maxAllowedDate.getMonth() + 3);
if (endDate < startDate) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["endDate"],
message: "End date cannot be before start date"
});
}
if (endDate > maxAllowedDate) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["endDate"],
message: "Dates must be within 3 months"
});
}
}
}),
response: { response: {
200: z.object({ 200: z.object({
auditLogs: AuditLogsSchema.omit({ auditLogs: AuditLogsSchema.omit({
@ -209,13 +188,14 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
const auditLogs = await server.services.auditLog.listAuditLogs({ const auditLogs = await server.services.auditLog.listAuditLogs({
filter: { filter: {
...req.query, ...req.query,
endDate: req.query.endDate || new Date().toISOString(), endDate: req.query.endDate,
projectId: req.query.projectId, projectId: req.query.projectId,
startDate: req.query.startDate || getLastMidnightDateISO(), startDate: req.query.startDate || getLastMidnightDateISO(),
auditLogActorId: req.query.actor, auditLogActorId: req.query.actor,
actorType: req.query.actorType, actorType: req.query.actorType,
eventType: req.query.eventType as EventType[] | undefined eventType: req.query.eventType as EventType[] | undefined
}, },
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId, actorOrgId: req.permission.orgId,
actorAuthMethod: req.permission.authMethod, actorAuthMethod: req.permission.authMethod,

View File

@ -158,7 +158,17 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
includeRoles: z includeRoles: z
.enum(["true", "false"]) .enum(["true", "false"])
.default("false") .default("false")
.transform((value) => value === "true") .transform((value) => value === "true"),
type: z
.enum([
ProjectType.SecretManager,
ProjectType.KMS,
ProjectType.CertificateManager,
ProjectType.SSH,
ProjectType.SecretScanning,
"all"
])
.optional()
}), }),
response: { response: {
200: z.object({ 200: z.object({
@ -177,7 +187,8 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
actorId: req.permission.id, actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod, actorAuthMethod: req.permission.authMethod,
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId actorOrgId: req.permission.orgId,
type: req.query.type
}); });
return { workspaces }; return { workspaces };
} }
@ -366,8 +377,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
.optional() .optional()
.describe(PROJECTS.UPDATE.slug), .describe(PROJECTS.UPDATE.slug),
secretSharing: z.boolean().optional().describe(PROJECTS.UPDATE.secretSharing), secretSharing: z.boolean().optional().describe(PROJECTS.UPDATE.secretSharing),
showSnapshotsLegacy: z.boolean().optional().describe(PROJECTS.UPDATE.showSnapshotsLegacy), showSnapshotsLegacy: z.boolean().optional().describe(PROJECTS.UPDATE.showSnapshotsLegacy)
defaultProduct: z.nativeEnum(ProjectType).optional().describe(PROJECTS.UPDATE.defaultProduct)
}), }),
response: { response: {
200: z.object({ 200: z.object({
@ -386,7 +396,6 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
name: req.body.name, name: req.body.name,
description: req.body.description, description: req.body.description,
autoCapitalization: req.body.autoCapitalization, autoCapitalization: req.body.autoCapitalization,
defaultProduct: req.body.defaultProduct,
hasDeleteProtection: req.body.hasDeleteProtection, hasDeleteProtection: req.body.hasDeleteProtection,
slug: req.body.slug, slug: req.body.slug,
secretSharing: req.body.secretSharing, secretSharing: req.body.secretSharing,
@ -1050,6 +1059,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
body: z.object({ body: z.object({
limit: z.number().default(100), limit: z.number().default(100),
offset: z.number().default(0), offset: z.number().default(0),
type: z.nativeEnum(ProjectType).optional(),
orderBy: z.nativeEnum(SearchProjectSortBy).optional().default(SearchProjectSortBy.NAME), orderBy: z.nativeEnum(SearchProjectSortBy).optional().default(SearchProjectSortBy.NAME),
orderDirection: z.nativeEnum(SortDirection).optional().default(SortDirection.ASC), orderDirection: z.nativeEnum(SortDirection).optional().default(SortDirection.ASC),
name: z name: z

View File

@ -1,17 +0,0 @@
import {
CloudflarePagesSyncSchema,
CreateCloudflarePagesSyncSchema,
UpdateCloudflarePagesSyncSchema
} from "@app/services/secret-sync/cloudflare-pages/cloudflare-pages-schema";
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
import { registerSyncSecretsEndpoints } from "./secret-sync-endpoints";
export const registerCloudflarePagesSyncRouter = async (server: FastifyZodProvider) =>
registerSyncSecretsEndpoints({
destination: SecretSync.CloudflarePages,
server,
responseSchema: CloudflarePagesSyncSchema,
createSchema: CreateCloudflarePagesSyncSchema,
updateSchema: UpdateCloudflarePagesSyncSchema
});

View File

@ -1,13 +0,0 @@
import { CreateGitLabSyncSchema, GitLabSyncSchema, UpdateGitLabSyncSchema } from "@app/services/secret-sync/gitlab";
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
import { registerSyncSecretsEndpoints } from "./secret-sync-endpoints";
export const registerGitLabSyncRouter = async (server: FastifyZodProvider) =>
registerSyncSecretsEndpoints({
destination: SecretSync.GitLab,
server,
responseSchema: GitLabSyncSchema,
createSchema: CreateGitLabSyncSchema,
updateSchema: UpdateGitLabSyncSchema
});

View File

@ -8,12 +8,10 @@ import { registerAzureAppConfigurationSyncRouter } from "./azure-app-configurati
import { registerAzureDevOpsSyncRouter } from "./azure-devops-sync-router"; import { registerAzureDevOpsSyncRouter } from "./azure-devops-sync-router";
import { registerAzureKeyVaultSyncRouter } from "./azure-key-vault-sync-router"; import { registerAzureKeyVaultSyncRouter } from "./azure-key-vault-sync-router";
import { registerCamundaSyncRouter } from "./camunda-sync-router"; import { registerCamundaSyncRouter } from "./camunda-sync-router";
import { registerCloudflarePagesSyncRouter } from "./cloudflare-pages-sync-router";
import { registerDatabricksSyncRouter } from "./databricks-sync-router"; import { registerDatabricksSyncRouter } from "./databricks-sync-router";
import { registerFlyioSyncRouter } from "./flyio-sync-router"; import { registerFlyioSyncRouter } from "./flyio-sync-router";
import { registerGcpSyncRouter } from "./gcp-sync-router"; import { registerGcpSyncRouter } from "./gcp-sync-router";
import { registerGitHubSyncRouter } from "./github-sync-router"; import { registerGitHubSyncRouter } from "./github-sync-router";
import { registerGitLabSyncRouter } from "./gitlab-sync-router";
import { registerHCVaultSyncRouter } from "./hc-vault-sync-router"; import { registerHCVaultSyncRouter } from "./hc-vault-sync-router";
import { registerHerokuSyncRouter } from "./heroku-sync-router"; import { registerHerokuSyncRouter } from "./heroku-sync-router";
import { registerHumanitecSyncRouter } from "./humanitec-sync-router"; import { registerHumanitecSyncRouter } from "./humanitec-sync-router";
@ -22,7 +20,6 @@ import { registerTeamCitySyncRouter } from "./teamcity-sync-router";
import { registerTerraformCloudSyncRouter } from "./terraform-cloud-sync-router"; import { registerTerraformCloudSyncRouter } from "./terraform-cloud-sync-router";
import { registerVercelSyncRouter } from "./vercel-sync-router"; import { registerVercelSyncRouter } from "./vercel-sync-router";
import { registerWindmillSyncRouter } from "./windmill-sync-router"; import { registerWindmillSyncRouter } from "./windmill-sync-router";
import { registerZabbixSyncRouter } from "./zabbix-sync-router";
export * from "./secret-sync-router"; export * from "./secret-sync-router";
@ -46,8 +43,5 @@ export const SECRET_SYNC_REGISTER_ROUTER_MAP: Record<SecretSync, (server: Fastif
[SecretSync.OnePass]: registerOnePassSyncRouter, [SecretSync.OnePass]: registerOnePassSyncRouter,
[SecretSync.Heroku]: registerHerokuSyncRouter, [SecretSync.Heroku]: registerHerokuSyncRouter,
[SecretSync.Render]: registerRenderSyncRouter, [SecretSync.Render]: registerRenderSyncRouter,
[SecretSync.Flyio]: registerFlyioSyncRouter, [SecretSync.Flyio]: registerFlyioSyncRouter
[SecretSync.GitLab]: registerGitLabSyncRouter,
[SecretSync.CloudflarePages]: registerCloudflarePagesSyncRouter,
[SecretSync.Zabbix]: registerZabbixSyncRouter
}; };

Some files were not shown because too many files have changed in this diff Show More