mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-13 14:29:35 +00:00
Merge branch 'main' into fix-approval-policy-org-check
This commit is contained in:
@@ -1,57 +0,0 @@
|
|||||||
## @section Common parameters
|
|
||||||
##
|
|
||||||
|
|
||||||
## @param nameOverride Override release name
|
|
||||||
##
|
|
||||||
nameOverride: ""
|
|
||||||
## @param fullnameOverride Override release fullname
|
|
||||||
##
|
|
||||||
fullnameOverride: ""
|
|
||||||
|
|
||||||
## @section Infisical backend parameters
|
|
||||||
## Documentation : https://infisical.com/docs/self-hosting/deployments/kubernetes
|
|
||||||
##
|
|
||||||
|
|
||||||
infisical:
|
|
||||||
autoDatabaseSchemaMigration: false
|
|
||||||
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
name: infisical
|
|
||||||
replicaCount: 3
|
|
||||||
image:
|
|
||||||
repository: infisical/staging_infisical
|
|
||||||
tag: "latest"
|
|
||||||
pullPolicy: Always
|
|
||||||
|
|
||||||
deploymentAnnotations:
|
|
||||||
secrets.infisical.com/auto-reload: "true"
|
|
||||||
|
|
||||||
kubeSecretRef: "managed-secret"
|
|
||||||
|
|
||||||
ingress:
|
|
||||||
## @param ingress.enabled Enable ingress
|
|
||||||
##
|
|
||||||
enabled: true
|
|
||||||
## @param ingress.ingressClassName Ingress class name
|
|
||||||
##
|
|
||||||
ingressClassName: nginx
|
|
||||||
## @param ingress.nginx.enabled Ingress controller
|
|
||||||
##
|
|
||||||
# nginx:
|
|
||||||
# enabled: true
|
|
||||||
## @param ingress.annotations Ingress annotations
|
|
||||||
##
|
|
||||||
annotations:
|
|
||||||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
|
||||||
hostName: "gamma.infisical.com"
|
|
||||||
tls:
|
|
||||||
- secretName: letsencrypt-prod
|
|
||||||
hosts:
|
|
||||||
- gamma.infisical.com
|
|
||||||
|
|
||||||
postgresql:
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
redis:
|
|
||||||
enabled: false
|
|
||||||
@@ -30,6 +30,6 @@ jobs:
|
|||||||
- name: 🏗️ Run Type check
|
- name: 🏗️ Run Type check
|
||||||
run: npm run type:check
|
run: npm run type:check
|
||||||
working-directory: frontend
|
working-directory: frontend
|
||||||
- name: 🏗️ Run Link check
|
- name: 🏗️ Run Lint check
|
||||||
run: npm run lint:fix
|
run: npm run lint
|
||||||
working-directory: frontend
|
working-directory: frontend
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ jobs:
|
|||||||
|
|
||||||
- name: Set up chart-testing
|
- name: Set up chart-testing
|
||||||
uses: helm/[email protected]
|
uses: helm/[email protected]
|
||||||
|
with:
|
||||||
|
yamale_version: "6.0.0"
|
||||||
|
|
||||||
- name: Run chart-testing (lint)
|
- name: Run chart-testing (lint)
|
||||||
run: ct lint --config ct.yaml --charts helm-charts/infisical-standalone-postgres
|
run: ct lint --config ct.yaml --charts helm-charts/infisical-standalone-postgres
|
||||||
@@ -54,7 +56,7 @@ jobs:
|
|||||||
--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" \
|
--helm-extra-set-args="--set ingress.nginx.enabled=false --set infisical.replicaCount=1 --set infisical.image.tag=v0.151.0" \
|
||||||
--namespace infisical-standalone-postgres
|
--namespace infisical-standalone-postgres
|
||||||
|
|
||||||
release:
|
release:
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
name: Generate Nightly Tag
|
name: Generate Nightly Tag
|
||||||
|
|
||||||
on:
|
on:
|
||||||
schedule:
|
|
||||||
- cron: '0 0 * * *' # Run daily at midnight UTC
|
|
||||||
workflow_dispatch: # Allow manual triggering for testing
|
workflow_dispatch: # Allow manual triggering for testing
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
|
|||||||
@@ -65,6 +65,15 @@ jobs:
|
|||||||
INFISICAL_PLATFORM_VERSION=${{ steps.extract_version.outputs.version }}
|
INFISICAL_PLATFORM_VERSION=${{ steps.extract_version.outputs.version }}
|
||||||
DD_GIT_REPOSITORY_URL=${{ github.server_url }}/${{ github.repository }}
|
DD_GIT_REPOSITORY_URL=${{ github.server_url }}/${{ github.repository }}
|
||||||
DD_GIT_COMMIT_SHA=${{ github.sha }}
|
DD_GIT_COMMIT_SHA=${{ github.sha }}
|
||||||
|
- name: Snyk to check Docker image for vulnerabilities
|
||||||
|
continue-on-error: true
|
||||||
|
uses: snyk/actions/docker@master
|
||||||
|
env:
|
||||||
|
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
||||||
|
with:
|
||||||
|
image: infisical/infisical:${{ steps.extract_version.outputs.version }}
|
||||||
|
command: monitor
|
||||||
|
args: --file=Dockerfile.standalone-infisical --project-name="infisical-core-docker-image"
|
||||||
|
|
||||||
infisical-fips-standalone:
|
infisical-fips-standalone:
|
||||||
name: Build infisical standalone image postgres
|
name: Build infisical standalone image postgres
|
||||||
@@ -126,7 +135,9 @@ jobs:
|
|||||||
TAG_NAME="${{ github.ref_name }}"
|
TAG_NAME="${{ github.ref_name }}"
|
||||||
echo "Checking for tag: $TAG_NAME"
|
echo "Checking for tag: $TAG_NAME"
|
||||||
|
|
||||||
if gh api repos/Infisical/infisical-omnibus/git/refs/tags/$TAG_NAME --silent 2>/dev/null; then
|
EXACT_MATCH=$(gh api repos/Infisical/infisical-omnibus/git/refs/tags/$TAG_NAME | jq -r 'if type == "array" then .[].ref else .ref end' | grep -x "refs/tags/$TAG_NAME")
|
||||||
|
|
||||||
|
if [ "$EXACT_MATCH" == "refs/tags/$TAG_NAME" ]; then
|
||||||
echo "Tag $TAG_NAME already exists, skipping..."
|
echo "Tag $TAG_NAME already exists, skipping..."
|
||||||
else
|
else
|
||||||
echo "Creating tag in Infisical/infisical-omnibus: $TAG_NAME"
|
echo "Creating tag in Infisical/infisical-omnibus: $TAG_NAME"
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ jobs:
|
|||||||
|
|
||||||
- name: Set up chart-testing
|
- name: Set up chart-testing
|
||||||
uses: helm/[email protected]
|
uses: helm/[email protected]
|
||||||
|
with:
|
||||||
|
yamale_version: "6.0.0"
|
||||||
|
|
||||||
- name: Run chart-testing (lint)
|
- name: Run chart-testing (lint)
|
||||||
run: ct lint --config ct.yaml --charts helm-charts/infisical-standalone-postgres
|
run: ct lint --config ct.yaml --charts helm-charts/infisical-standalone-postgres
|
||||||
@@ -64,5 +66,5 @@ jobs:
|
|||||||
--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.replicaCount=1 --set infisical.image.tag=v0.151.0 --set infisical.autoBootstrap.enabled=true" \
|
||||||
--namespace infisical-standalone-postgres
|
--namespace infisical-standalone-postgres
|
||||||
|
|||||||
@@ -3,7 +3,10 @@ ARG POSTHOG_API_KEY=posthog-api-key
|
|||||||
ARG INTERCOM_ID=intercom-id
|
ARG INTERCOM_ID=intercom-id
|
||||||
ARG CAPTCHA_SITE_KEY=captcha-site-key
|
ARG CAPTCHA_SITE_KEY=captcha-site-key
|
||||||
|
|
||||||
FROM node:20-slim AS base
|
FROM node:20.19.5-trixie-slim AS base
|
||||||
|
|
||||||
|
# Fixes NPM vulnerability: https://security.snyk.io/vuln/SNYK-JS-CROSSSPAWN-8303230
|
||||||
|
RUN npm install -g [email protected]
|
||||||
|
|
||||||
FROM base AS frontend-dependencies
|
FROM base AS frontend-dependencies
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
@@ -155,7 +158,7 @@ RUN wget https://www.openssl.org/source/openssl-3.1.2.tar.gz \
|
|||||||
|
|
||||||
# Install Infisical CLI
|
# Install Infisical CLI
|
||||||
RUN curl -1sLf 'https://artifacts-cli.infisical.com/setup.deb.sh' | bash \
|
RUN curl -1sLf 'https://artifacts-cli.infisical.com/setup.deb.sh' | bash \
|
||||||
&& apt-get update && apt-get install -y infisical=0.41.89 \
|
&& apt-get update && apt-get install -y infisical=0.43.14 \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
RUN groupadd -r -g 1001 nodejs && useradd -r -u 1001 -g nodejs non-root-user
|
RUN groupadd -r -g 1001 nodejs && useradd -r -u 1001 -g nodejs non-root-user
|
||||||
|
|||||||
@@ -3,7 +3,10 @@ ARG POSTHOG_API_KEY=posthog-api-key
|
|||||||
ARG INTERCOM_ID=intercom-id
|
ARG INTERCOM_ID=intercom-id
|
||||||
ARG CAPTCHA_SITE_KEY=captcha-site-key
|
ARG CAPTCHA_SITE_KEY=captcha-site-key
|
||||||
|
|
||||||
FROM node:20-slim AS base
|
FROM node:20.19.5-trixie-slim AS base
|
||||||
|
|
||||||
|
# Fixes NPM vulnerability: https://security.snyk.io/vuln/SNYK-JS-CROSSSPAWN-8303230
|
||||||
|
RUN npm install -g [email protected]
|
||||||
|
|
||||||
FROM base AS frontend-dependencies
|
FROM base AS frontend-dependencies
|
||||||
|
|
||||||
@@ -139,7 +142,7 @@ RUN apt-get update && apt-get install -y \
|
|||||||
|
|
||||||
# Install Infisical CLI
|
# Install Infisical CLI
|
||||||
RUN curl -1sLf 'https://artifacts-cli.infisical.com/setup.deb.sh' | bash \
|
RUN curl -1sLf 'https://artifacts-cli.infisical.com/setup.deb.sh' | bash \
|
||||||
&& apt-get update && apt-get install -y infisical=0.41.89 \
|
&& apt-get update && apt-get install -y infisical=0.43.14 \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
WORKDIR /
|
WORKDIR /
|
||||||
|
|||||||
+3
-3
@@ -1,5 +1,5 @@
|
|||||||
# Build stage
|
# Build stage
|
||||||
FROM node:20-slim AS build
|
FROM node:20.19.5-trixie-slim AS build
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ COPY . .
|
|||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
# Production stage
|
# Production stage
|
||||||
FROM node:20-slim
|
FROM node:20.19.5-trixie-slim
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
ENV npm_config_cache /home/node/.npm
|
ENV npm_config_cache /home/node/.npm
|
||||||
@@ -55,7 +55,7 @@ COPY --from=build /app .
|
|||||||
# Install Infisical CLI
|
# Install Infisical CLI
|
||||||
RUN apt-get install -y curl bash && \
|
RUN apt-get install -y curl bash && \
|
||||||
curl -1sLf 'https://artifacts-cli.infisical.com/setup.deb.sh' | bash && \
|
curl -1sLf 'https://artifacts-cli.infisical.com/setup.deb.sh' | bash && \
|
||||||
apt-get update && apt-get install -y infisical=0.41.89 git
|
apt-get update && apt-get install -y infisical=0.43.14 git
|
||||||
|
|
||||||
HEALTHCHECK --interval=10s --timeout=3s --start-period=10s \
|
HEALTHCHECK --interval=10s --timeout=3s --start-period=10s \
|
||||||
CMD node healthcheck.js
|
CMD node healthcheck.js
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM node:20-slim
|
FROM node:20.19.5-trixie-slim
|
||||||
|
|
||||||
# ? Setup a test SoftHSM module. In production a real HSM is used.
|
# ? Setup a test SoftHSM module. In production a real HSM is used.
|
||||||
|
|
||||||
@@ -49,25 +49,26 @@ RUN rm -fr ${SOFTHSM2_SOURCES}
|
|||||||
# Install pkcs11-tool
|
# Install pkcs11-tool
|
||||||
RUN apt-get install -y opensc
|
RUN apt-get install -y opensc
|
||||||
|
|
||||||
RUN mkdir -p /etc/softhsm2/tokens && \
|
|
||||||
softhsm2-util --init-token --slot 0 --label "auth-app" --pin 1234 --so-pin 0000
|
|
||||||
|
|
||||||
# ? App setup
|
# ? App setup
|
||||||
|
|
||||||
# Install Infisical CLI
|
# Install Infisical CLI
|
||||||
RUN curl -1sLf 'https://artifacts-cli.infisical.com/setup.deb.sh' | bash && \
|
RUN curl -1sLf 'https://artifacts-cli.infisical.com/setup.deb.sh' | bash && \
|
||||||
apt-get update && \
|
apt-get update && \
|
||||||
apt-get install -y infisical=0.41.89
|
apt-get install -y infisical=0.43.14
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY package.json package.json
|
COPY package.json package.json
|
||||||
COPY package-lock.json package-lock.json
|
COPY package-lock.json package-lock.json
|
||||||
|
|
||||||
|
COPY dev-entrypoint.sh dev-entrypoint.sh
|
||||||
|
RUN chmod +x dev-entrypoint.sh
|
||||||
|
|
||||||
RUN npm install
|
RUN npm install
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
ENV HOST=0.0.0.0
|
ENV HOST=0.0.0.0
|
||||||
|
|
||||||
|
ENTRYPOINT ["/app/dev-entrypoint.sh"]
|
||||||
CMD ["npm", "run", "dev:docker"]
|
CMD ["npm", "run", "dev:docker"]
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM node:20-slim
|
FROM node:20.19.5-trixie-slim
|
||||||
|
|
||||||
# ? Setup a test SoftHSM module. In production a real HSM is used.
|
# ? Setup a test SoftHSM module. In production a real HSM is used.
|
||||||
|
|
||||||
@@ -50,9 +50,6 @@ RUN rm -fr ${SOFTHSM2_SOURCES}
|
|||||||
# Install pkcs11-tool
|
# Install pkcs11-tool
|
||||||
RUN apt-get install -y opensc
|
RUN apt-get install -y opensc
|
||||||
|
|
||||||
RUN mkdir -p /etc/softhsm2/tokens && \
|
|
||||||
softhsm2-util --init-token --slot 0 --label "auth-app" --pin 1234 --so-pin 0000
|
|
||||||
|
|
||||||
WORKDIR /openssl-build
|
WORKDIR /openssl-build
|
||||||
RUN wget https://www.openssl.org/source/openssl-3.1.2.tar.gz \
|
RUN wget https://www.openssl.org/source/openssl-3.1.2.tar.gz \
|
||||||
&& tar -xf openssl-3.1.2.tar.gz \
|
&& tar -xf openssl-3.1.2.tar.gz \
|
||||||
@@ -70,13 +67,16 @@ RUN wget https://www.openssl.org/source/openssl-3.1.2.tar.gz \
|
|||||||
# Install Infisical CLI
|
# Install Infisical CLI
|
||||||
RUN curl -1sLf 'https://artifacts-cli.infisical.com/setup.deb.sh' | bash && \
|
RUN curl -1sLf 'https://artifacts-cli.infisical.com/setup.deb.sh' | bash && \
|
||||||
apt-get update && \
|
apt-get update && \
|
||||||
apt-get install -y infisical=0.41.89
|
apt-get install -y infisical=0.43.14
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY package.json package.json
|
COPY package.json package.json
|
||||||
COPY package-lock.json package-lock.json
|
COPY package-lock.json package-lock.json
|
||||||
|
|
||||||
|
COPY dev-entrypoint.sh dev-entrypoint.sh
|
||||||
|
RUN chmod +x dev-entrypoint.sh
|
||||||
|
|
||||||
RUN npm install
|
RUN npm install
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
@@ -87,4 +87,5 @@ ENV OPENSSL_MODULES=/usr/local/lib/ossl-modules
|
|||||||
# ENV NODE_OPTIONS=--force-fips # Note(Daniel): We can't set this on the node options because it may break for existing folks using the infisical/infisical-fips image. Instead we call crypto.setFips(true) at runtime.
|
# ENV NODE_OPTIONS=--force-fips # Note(Daniel): We can't set this on the node options because it may break for existing folks using the infisical/infisical-fips image. Instead we call crypto.setFips(true) at runtime.
|
||||||
ENV FIPS_ENABLED=true
|
ENV FIPS_ENABLED=true
|
||||||
|
|
||||||
|
ENTRYPOINT ["/app/dev-entrypoint.sh"]
|
||||||
CMD ["npm", "run", "dev:docker"]
|
CMD ["npm", "run", "dev:docker"]
|
||||||
|
|||||||
Executable
+16
@@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
update-ca-certificates
|
||||||
|
|
||||||
|
# Initialize SoftHSM token if it doesn't exist
|
||||||
|
if [ ! -f /etc/softhsm2/tokens/auth-app.db ]; then
|
||||||
|
echo "Initializing SoftHSM token..."
|
||||||
|
mkdir -p /etc/softhsm2/tokens
|
||||||
|
softhsm2-util --init-token --slot 0 --label "auth-app" --pin 1234 --so-pin 0000
|
||||||
|
echo "SoftHSM token initialized"
|
||||||
|
else
|
||||||
|
echo "SoftHSM token already exists, skipping initialization"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
exec "$@"
|
||||||
@@ -40,7 +40,7 @@ describe("Secret Folder Router", async () => {
|
|||||||
{ name: "folder1", path: "/" }, // one in root
|
{ name: "folder1", path: "/" }, // one in root
|
||||||
{ name: "folder1", path: "/level1/level2" }, // then create a deep one creating intermediate ones
|
{ name: "folder1", path: "/level1/level2" }, // then create a deep one creating intermediate ones
|
||||||
{ name: "folder2", path: "/" },
|
{ name: "folder2", path: "/" },
|
||||||
{ name: "folder1", path: "/level1/level2" } // this should not create folder return same thing
|
{ name: "folder3", path: "/level1/level2" }
|
||||||
])("Create folder $name in $path", async ({ name, path }) => {
|
])("Create folder $name in $path", async ({ name, path }) => {
|
||||||
const createdFolder = await createFolder({ path, name });
|
const createdFolder = await createFolder({ path, name });
|
||||||
// check for default environments
|
// check for default environments
|
||||||
@@ -57,7 +57,7 @@ describe("Secret Folder Router", async () => {
|
|||||||
{
|
{
|
||||||
path: "/",
|
path: "/",
|
||||||
expected: {
|
expected: {
|
||||||
folders: [{ name: "folder1" }, { name: "level1" }, { name: "folder2" }],
|
folders: [{ name: "folder4" }, { name: "level2" }, { name: "folder5" }],
|
||||||
length: 3
|
length: 3
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -162,4 +162,25 @@ describe("Secret Folder Router", async () => {
|
|||||||
expect(updatedFolderList).toHaveProperty("folders");
|
expect(updatedFolderList).toHaveProperty("folders");
|
||||||
expect(updatedFolderList.folders.length).toEqual(0);
|
expect(updatedFolderList.folders.length).toEqual(0);
|
||||||
});
|
});
|
||||||
|
test("Creating a duplicate folder should return a 400 error", async () => {
|
||||||
|
const newFolder = await createFolder({ name: "folder-duplicate", path: "/level1/level2" });
|
||||||
|
|
||||||
|
const res = await testServer.inject({
|
||||||
|
method: "POST",
|
||||||
|
url: `/api/v1/folders`,
|
||||||
|
headers: {
|
||||||
|
authorization: `Bearer ${jwtAuthToken}`
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
workspaceId: seedData1.project.id,
|
||||||
|
environment: seedData1.environment.slug,
|
||||||
|
name: "folder-duplicate",
|
||||||
|
path: "/level1/level2"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
expect(res.statusCode).toBe(400);
|
||||||
|
const payload = JSON.parse(res.payload);
|
||||||
|
expect(payload).toHaveProperty("error");
|
||||||
|
await deleteFolder({ path: "/level1/level2", id: newFolder.id });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ const createFolder = async (dto: { path: string; name: string }) => {
|
|||||||
return res.json().folder;
|
return res.json().folder;
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteFolder = async (dto: { path: string; id: string }) => {
|
const deleteFolder = async (dto: { path: string; id: string; forceDelete?: boolean }) => {
|
||||||
const res = await testServer.inject({
|
const res = await testServer.inject({
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
url: `/api/v2/folders/${dto.id}`,
|
url: `/api/v2/folders/${dto.id}`,
|
||||||
@@ -28,7 +28,8 @@ const deleteFolder = async (dto: { path: string; id: string }) => {
|
|||||||
body: {
|
body: {
|
||||||
projectId: seedData1.project.id,
|
projectId: seedData1.project.id,
|
||||||
environment: seedData1.environment.slug,
|
environment: seedData1.environment.slug,
|
||||||
path: dto.path
|
path: dto.path,
|
||||||
|
forceDelete: dto.forceDelete ?? false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
expect(res.statusCode).toBe(200);
|
expect(res.statusCode).toBe(200);
|
||||||
@@ -40,7 +41,7 @@ describe("Secret Folder Router", async () => {
|
|||||||
{ name: "folder1", path: "/" }, // one in root
|
{ name: "folder1", path: "/" }, // one in root
|
||||||
{ name: "folder1", path: "/level1/level2" }, // then create a deep one creating intermediate ones
|
{ name: "folder1", path: "/level1/level2" }, // then create a deep one creating intermediate ones
|
||||||
{ name: "folder2", path: "/" },
|
{ name: "folder2", path: "/" },
|
||||||
{ name: "folder1", path: "/level1/level2" } // this should not create folder return same thing
|
{ name: "folder3", path: "/level1/level2" }
|
||||||
])("Create folder $name in $path", async ({ name, path }) => {
|
])("Create folder $name in $path", async ({ name, path }) => {
|
||||||
const createdFolder = await createFolder({ path, name });
|
const createdFolder = await createFolder({ path, name });
|
||||||
// check for default environments
|
// check for default environments
|
||||||
@@ -57,7 +58,7 @@ describe("Secret Folder Router", async () => {
|
|||||||
{
|
{
|
||||||
path: "/",
|
path: "/",
|
||||||
expected: {
|
expected: {
|
||||||
folders: [{ name: "folder1" }, { name: "level1" }, { name: "folder2" }],
|
folders: [{ name: "folder4" }, { name: "level2" }, { name: "folder5" }],
|
||||||
length: 3
|
length: 3
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -86,7 +87,7 @@ describe("Secret Folder Router", async () => {
|
|||||||
folders: expect.arrayContaining(expected.folders.map((el) => expect.objectContaining(el)))
|
folders: expect.arrayContaining(expected.folders.map((el) => expect.objectContaining(el)))
|
||||||
});
|
});
|
||||||
|
|
||||||
await Promise.all(newFolders.map(({ id }) => deleteFolder({ path, id })));
|
await Promise.all(newFolders.map(({ id }) => deleteFolder({ path, id, forceDelete: true })));
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Update a deep folder", async () => {
|
test("Update a deep folder", async () => {
|
||||||
@@ -162,4 +163,26 @@ describe("Secret Folder Router", async () => {
|
|||||||
expect(updatedFolderList).toHaveProperty("folders");
|
expect(updatedFolderList).toHaveProperty("folders");
|
||||||
expect(updatedFolderList.folders.length).toEqual(0);
|
expect(updatedFolderList.folders.length).toEqual(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("Creating a duplicate folder should return a 400 error", async () => {
|
||||||
|
const newFolder = await createFolder({ name: "folder-duplicate", path: "/level1/level2" });
|
||||||
|
|
||||||
|
const res = await testServer.inject({
|
||||||
|
method: "POST",
|
||||||
|
url: `/api/v2/folders`,
|
||||||
|
headers: {
|
||||||
|
authorization: `Bearer ${jwtAuthToken}`
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
projectId: seedData1.project.id,
|
||||||
|
environment: seedData1.environment.slug,
|
||||||
|
name: "folder-duplicate",
|
||||||
|
path: "/level1/level2"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
expect(res.statusCode).toBe(400);
|
||||||
|
const payload = JSON.parse(res.payload);
|
||||||
|
expect(payload).toHaveProperty("error");
|
||||||
|
await deleteFolder({ path: "/level1/level2", id: newFolder.id });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -146,7 +146,8 @@ describe("Service token secret ops", async () => {
|
|||||||
let folderId = "";
|
let folderId = "";
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
initLogger();
|
initLogger();
|
||||||
await initEnvConfig(testSuperAdminDAL, logger);
|
|
||||||
|
await initEnvConfig(testHsmService, testKmsRootConfigDAL, testSuperAdminDAL, logger);
|
||||||
|
|
||||||
serviceToken = await createServiceToken(
|
serviceToken = await createServiceToken(
|
||||||
[{ secretPath: "/**", environment: seedData1.environment.slug }],
|
[{ secretPath: "/**", environment: seedData1.environment.slug }],
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ describe("Secret V3 Router", async () => {
|
|||||||
let folderId = "";
|
let folderId = "";
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
initLogger();
|
initLogger();
|
||||||
await initEnvConfig(testSuperAdminDAL, logger);
|
await initEnvConfig(testHsmService, testKmsRootConfigDAL, testSuperAdminDAL, logger);
|
||||||
|
|
||||||
const projectKeyRes = await testServer.inject({
|
const projectKeyRes = await testServer.inject({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { crypto } from "@app/lib/crypto/cryptography";
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
|
|
||||||
import { seedData1 } from "@app/db/seed-data";
|
import { seedData1 } from "@app/db/seed-data";
|
||||||
import { getDatabaseCredentials, initEnvConfig } from "@app/lib/config/env";
|
import { getDatabaseCredentials, getHsmConfig, initEnvConfig } from "@app/lib/config/env";
|
||||||
import { initLogger } from "@app/lib/logger";
|
import { initLogger } from "@app/lib/logger";
|
||||||
import { main } from "@app/server/app";
|
import { main } from "@app/server/app";
|
||||||
import { AuthMethod, AuthTokenType } from "@app/services/auth/auth-type";
|
import { AuthMethod, AuthTokenType } from "@app/services/auth/auth-type";
|
||||||
@@ -20,6 +20,8 @@ import { initializeHsmModule } from "@app/ee/services/hsm/hsm-fns";
|
|||||||
import { buildRedisFromConfig } from "@app/lib/config/redis";
|
import { buildRedisFromConfig } from "@app/lib/config/redis";
|
||||||
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||||
import { bootstrapCheck } from "@app/server/boot-strap-check";
|
import { bootstrapCheck } from "@app/server/boot-strap-check";
|
||||||
|
import { hsmServiceFactory } from "@app/ee/services/hsm/hsm-service";
|
||||||
|
import { kmsRootConfigDALFactory } from "@app/services/kms/kms-root-config-dal";
|
||||||
|
|
||||||
dotenv.config({ path: path.join(__dirname, "../../.env.test"), debug: true });
|
dotenv.config({ path: path.join(__dirname, "../../.env.test"), debug: true });
|
||||||
export default {
|
export default {
|
||||||
@@ -28,6 +30,7 @@ export default {
|
|||||||
async setup() {
|
async setup() {
|
||||||
const logger = initLogger();
|
const logger = initLogger();
|
||||||
const databaseCredentials = getDatabaseCredentials(logger);
|
const databaseCredentials = getDatabaseCredentials(logger);
|
||||||
|
const hsmConfig = getHsmConfig(logger);
|
||||||
|
|
||||||
const db = initDbConnection({
|
const db = initDbConnection({
|
||||||
dbConnectionUri: databaseCredentials.dbConnectionUri,
|
dbConnectionUri: databaseCredentials.dbConnectionUri,
|
||||||
@@ -35,7 +38,19 @@ export default {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const superAdminDAL = superAdminDALFactory(db);
|
const superAdminDAL = superAdminDALFactory(db);
|
||||||
const envCfg = await initEnvConfig(superAdminDAL, logger);
|
const kmsRootConfigDAL = kmsRootConfigDALFactory(db);
|
||||||
|
|
||||||
|
const hsmModule = initializeHsmModule(hsmConfig);
|
||||||
|
hsmModule.initialize();
|
||||||
|
|
||||||
|
const hsmService = hsmServiceFactory({
|
||||||
|
hsmModule: hsmModule.getModule(),
|
||||||
|
envConfig: hsmConfig
|
||||||
|
});
|
||||||
|
|
||||||
|
await hsmService.startService();
|
||||||
|
|
||||||
|
const envCfg = await initEnvConfig(hsmService, kmsRootConfigDAL, superAdminDAL, logger);
|
||||||
|
|
||||||
const redis = buildRedisFromConfig(envCfg);
|
const redis = buildRedisFromConfig(envCfg);
|
||||||
await redis.flushdb("SYNC");
|
await redis.flushdb("SYNC");
|
||||||
@@ -68,16 +83,14 @@ export default {
|
|||||||
|
|
||||||
await queue.initialize();
|
await queue.initialize();
|
||||||
|
|
||||||
const hsmModule = initializeHsmModule(envCfg);
|
|
||||||
hsmModule.initialize();
|
|
||||||
|
|
||||||
const server = await main({
|
const server = await main({
|
||||||
db,
|
db,
|
||||||
smtp,
|
smtp,
|
||||||
logger,
|
logger,
|
||||||
queue,
|
queue,
|
||||||
keyStore,
|
keyStore,
|
||||||
hsmModule: hsmModule.getModule(),
|
hsmService,
|
||||||
|
kmsRootConfigDAL,
|
||||||
superAdminDAL,
|
superAdminDAL,
|
||||||
redis,
|
redis,
|
||||||
envConfig: envCfg
|
envConfig: envCfg
|
||||||
@@ -92,6 +105,10 @@ export default {
|
|||||||
// @ts-expect-error type
|
// @ts-expect-error type
|
||||||
globalThis.testSuperAdminDAL = superAdminDAL;
|
globalThis.testSuperAdminDAL = superAdminDAL;
|
||||||
// @ts-expect-error type
|
// @ts-expect-error type
|
||||||
|
globalThis.testKmsRootConfigDAL = kmsRootConfigDAL;
|
||||||
|
// @ts-expect-error type
|
||||||
|
globalThis.testHsmService = hsmService;
|
||||||
|
// @ts-expect-error type
|
||||||
globalThis.jwtAuthToken = crypto.jwt().sign(
|
globalThis.jwtAuthToken = crypto.jwt().sign(
|
||||||
{
|
{
|
||||||
authTokenType: AuthTokenType.ACCESS_TOKEN,
|
authTokenType: AuthTokenType.ACCESS_TOKEN,
|
||||||
|
|||||||
Generated
+4249
-625
File diff suppressed because it is too large
Load Diff
@@ -79,12 +79,17 @@
|
|||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
|
"overrides": {
|
||||||
|
"cipher-base": "1.0.5",
|
||||||
|
"sha.js": "2.4.12"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/cli": "^7.18.10",
|
"@babel/cli": "^7.18.10",
|
||||||
"@babel/core": "^7.18.10",
|
"@babel/core": "^7.18.10",
|
||||||
"@babel/plugin-syntax-import-attributes": "^7.24.7",
|
"@babel/plugin-syntax-import-attributes": "^7.24.7",
|
||||||
"@babel/preset-env": "^7.18.10",
|
"@babel/preset-env": "^7.18.10",
|
||||||
"@babel/preset-react": "^7.24.7",
|
"@babel/preset-react": "^7.24.7",
|
||||||
|
"@react-email/preview-server": "^4.3.0",
|
||||||
"@smithy/types": "^4.3.1",
|
"@smithy/types": "^4.3.1",
|
||||||
"@types/bcrypt": "^5.0.2",
|
"@types/bcrypt": "^5.0.2",
|
||||||
"@types/jmespath": "^0.15.2",
|
"@types/jmespath": "^0.15.2",
|
||||||
@@ -120,7 +125,7 @@
|
|||||||
"nodemon": "^3.0.2",
|
"nodemon": "^3.0.2",
|
||||||
"pino-pretty": "^10.2.3",
|
"pino-pretty": "^10.2.3",
|
||||||
"prompt-sync": "^4.2.0",
|
"prompt-sync": "^4.2.0",
|
||||||
"react-email": "4.0.7",
|
"react-email": "^4.3.0",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^5.0.5",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"tsc-alias": "^1.8.8",
|
"tsc-alias": "^1.8.8",
|
||||||
@@ -138,7 +143,7 @@
|
|||||||
"@aws-sdk/client-secrets-manager": "^3.504.0",
|
"@aws-sdk/client-secrets-manager": "^3.504.0",
|
||||||
"@aws-sdk/client-sts": "^3.600.0",
|
"@aws-sdk/client-sts": "^3.600.0",
|
||||||
"@casl/ability": "^6.5.0",
|
"@casl/ability": "^6.5.0",
|
||||||
"@elastic/elasticsearch": "^8.15.0",
|
"@elastic/elasticsearch": "^9.1.1",
|
||||||
"@fastify/cookie": "^9.3.1",
|
"@fastify/cookie": "^9.3.1",
|
||||||
"@fastify/cors": "^8.5.0",
|
"@fastify/cors": "^8.5.0",
|
||||||
"@fastify/etag": "^5.1.0",
|
"@fastify/etag": "^5.1.0",
|
||||||
@@ -185,7 +190,7 @@
|
|||||||
"ajv": "^8.12.0",
|
"ajv": "^8.12.0",
|
||||||
"argon2": "^0.31.2",
|
"argon2": "^0.31.2",
|
||||||
"aws-sdk": "^2.1553.0",
|
"aws-sdk": "^2.1553.0",
|
||||||
"axios": "^1.11.0",
|
"axios": "^1.12.0",
|
||||||
"axios-ntlm": "^1.4.4",
|
"axios-ntlm": "^1.4.4",
|
||||||
"axios-retry": "^4.0.0",
|
"axios-retry": "^4.0.0",
|
||||||
"bcrypt": "^5.1.1",
|
"bcrypt": "^5.1.1",
|
||||||
@@ -196,7 +201,7 @@
|
|||||||
"cron": "^3.1.7",
|
"cron": "^3.1.7",
|
||||||
"dd-trace": "^5.40.0",
|
"dd-trace": "^5.40.0",
|
||||||
"dotenv": "^16.4.1",
|
"dotenv": "^16.4.1",
|
||||||
"fastify": "^4.28.1",
|
"fastify": "^4.29.1",
|
||||||
"fastify-plugin": "^4.5.1",
|
"fastify-plugin": "^4.5.1",
|
||||||
"google-auth-library": "^9.9.0",
|
"google-auth-library": "^9.9.0",
|
||||||
"googleapis": "^137.1.0",
|
"googleapis": "^137.1.0",
|
||||||
|
|||||||
@@ -85,10 +85,9 @@ const getZodDefaultValue = (type: unknown, value: string | number | boolean | Ob
|
|||||||
};
|
};
|
||||||
|
|
||||||
const bigIntegerColumns: Record<string, string[]> = {
|
const bigIntegerColumns: Record<string, string[]> = {
|
||||||
"folder_commits": ["commitId"]
|
folder_commits: ["commitId"]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const main = async () => {
|
const main = async () => {
|
||||||
const tables = (
|
const tables = (
|
||||||
await db("information_schema.tables")
|
await db("information_schema.tables")
|
||||||
@@ -99,6 +98,7 @@ const main = async () => {
|
|||||||
(el) =>
|
(el) =>
|
||||||
!el.tableName.includes("_migrations") &&
|
!el.tableName.includes("_migrations") &&
|
||||||
!el.tableName.includes("audit_logs_") &&
|
!el.tableName.includes("audit_logs_") &&
|
||||||
|
!el.tableName.includes("user_notifications_") &&
|
||||||
!el.tableName.includes("active_locks") &&
|
!el.tableName.includes("active_locks") &&
|
||||||
el.tableName !== "intermediate_audit_logs"
|
el.tableName !== "intermediate_audit_logs"
|
||||||
);
|
);
|
||||||
|
|||||||
Vendored
+4
@@ -1,7 +1,9 @@
|
|||||||
import { FastifyInstance, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerDefault } from "fastify";
|
import { FastifyInstance, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerDefault } from "fastify";
|
||||||
|
|
||||||
|
import { THsmServiceFactory } from "@app/ee/services/hsm/hsm-service";
|
||||||
import { CustomLogger } from "@app/lib/logger/logger";
|
import { CustomLogger } from "@app/lib/logger/logger";
|
||||||
import { ZodTypeProvider } from "@app/server/plugins/fastify-zod";
|
import { ZodTypeProvider } from "@app/server/plugins/fastify-zod";
|
||||||
|
import { TKmsRootConfigDALFactory } from "@app/services/kms/kms-root-config-dal";
|
||||||
import { TSuperAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
import { TSuperAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
@@ -16,5 +18,7 @@ declare global {
|
|||||||
// used only for testing
|
// used only for testing
|
||||||
const testServer: FastifyZodProvider;
|
const testServer: FastifyZodProvider;
|
||||||
const testSuperAdminDAL: TSuperAdminDALFactory;
|
const testSuperAdminDAL: TSuperAdminDALFactory;
|
||||||
|
const testKmsRootConfigDAL: TKmsRootConfigDALFactory;
|
||||||
|
const testHsmService: THsmServiceFactory;
|
||||||
const jwtAuthToken: string;
|
const jwtAuthToken: string;
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+33
-10
@@ -20,18 +20,19 @@ import { TGatewayV2ServiceFactory } from "@app/ee/services/gateway-v2/gateway-v2
|
|||||||
import { TGithubOrgSyncServiceFactory } from "@app/ee/services/github-org-sync/github-org-sync-service";
|
import { TGithubOrgSyncServiceFactory } from "@app/ee/services/github-org-sync/github-org-sync-service";
|
||||||
import { TGroupServiceFactory } from "@app/ee/services/group/group-service";
|
import { TGroupServiceFactory } from "@app/ee/services/group/group-service";
|
||||||
import { TIdentityAuthTemplateServiceFactory } from "@app/ee/services/identity-auth-template";
|
import { TIdentityAuthTemplateServiceFactory } from "@app/ee/services/identity-auth-template";
|
||||||
import { TIdentityProjectAdditionalPrivilegeServiceFactory } from "@app/ee/services/identity-project-additional-privilege/identity-project-additional-privilege-service";
|
|
||||||
import { TIdentityProjectAdditionalPrivilegeV2ServiceFactory } from "@app/ee/services/identity-project-additional-privilege-v2/identity-project-additional-privilege-v2-service";
|
|
||||||
import { TKmipClientDALFactory } from "@app/ee/services/kmip/kmip-client-dal";
|
import { TKmipClientDALFactory } from "@app/ee/services/kmip/kmip-client-dal";
|
||||||
import { TKmipOperationServiceFactory } from "@app/ee/services/kmip/kmip-operation-service";
|
import { TKmipOperationServiceFactory } from "@app/ee/services/kmip/kmip-operation-service";
|
||||||
import { TKmipServiceFactory } from "@app/ee/services/kmip/kmip-service";
|
import { TKmipServiceFactory } from "@app/ee/services/kmip/kmip-service";
|
||||||
import { TLdapConfigServiceFactory } from "@app/ee/services/ldap-config/ldap-config-service";
|
import { TLdapConfigServiceFactory } from "@app/ee/services/ldap-config/ldap-config-service";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { TOidcConfigServiceFactory } from "@app/ee/services/oidc/oidc-config-service";
|
import { TOidcConfigServiceFactory } from "@app/ee/services/oidc/oidc-config-service";
|
||||||
|
import { TPamAccountServiceFactory } from "@app/ee/services/pam-account/pam-account-service";
|
||||||
|
import { TPamFolderServiceFactory } from "@app/ee/services/pam-folder/pam-folder-service";
|
||||||
|
import { TPamResourceServiceFactory } from "@app/ee/services/pam-resource/pam-resource-service";
|
||||||
|
import { TPamSessionServiceFactory } from "@app/ee/services/pam-session/pam-session-service";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import { TPitServiceFactory } from "@app/ee/services/pit/pit-service";
|
import { TPitServiceFactory } from "@app/ee/services/pit/pit-service";
|
||||||
import { TProjectTemplateServiceFactory } from "@app/ee/services/project-template/project-template-types";
|
import { TProjectTemplateServiceFactory } from "@app/ee/services/project-template/project-template-types";
|
||||||
import { TProjectUserAdditionalPrivilegeServiceFactory } from "@app/ee/services/project-user-additional-privilege/project-user-additional-privilege-types";
|
|
||||||
import { RateLimitConfiguration, TRateLimitServiceFactory } from "@app/ee/services/rate-limit/rate-limit-types";
|
import { RateLimitConfiguration, TRateLimitServiceFactory } from "@app/ee/services/rate-limit/rate-limit-types";
|
||||||
import { TRelayServiceFactory } from "@app/ee/services/relay/relay-service";
|
import { TRelayServiceFactory } from "@app/ee/services/relay/relay-service";
|
||||||
import { TSamlConfigServiceFactory } from "@app/ee/services/saml-config/saml-config-types";
|
import { TSamlConfigServiceFactory } from "@app/ee/services/saml-config/saml-config-types";
|
||||||
@@ -47,8 +48,10 @@ import { TSshCertificateAuthorityServiceFactory } from "@app/ee/services/ssh/ssh
|
|||||||
import { TSshCertificateTemplateServiceFactory } from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-service";
|
import { TSshCertificateTemplateServiceFactory } from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-service";
|
||||||
import { TSshHostServiceFactory } from "@app/ee/services/ssh-host/ssh-host-service";
|
import { TSshHostServiceFactory } from "@app/ee/services/ssh-host/ssh-host-service";
|
||||||
import { TSshHostGroupServiceFactory } from "@app/ee/services/ssh-host-group/ssh-host-group-service";
|
import { TSshHostGroupServiceFactory } from "@app/ee/services/ssh-host-group/ssh-host-group-service";
|
||||||
|
import { TSubOrgServiceFactory } from "@app/ee/services/sub-org/sub-org-service";
|
||||||
import { TTrustedIpServiceFactory } from "@app/ee/services/trusted-ip/trusted-ip-types";
|
import { TTrustedIpServiceFactory } from "@app/ee/services/trusted-ip/trusted-ip-types";
|
||||||
import { TAuthMode } from "@app/server/plugins/auth/inject-identity";
|
import { TAuthMode } from "@app/server/plugins/auth/inject-identity";
|
||||||
|
import { TAdditionalPrivilegeServiceFactory } from "@app/services/additional-privilege/additional-privilege-service";
|
||||||
import { TApiKeyServiceFactory } from "@app/services/api-key/api-key-service";
|
import { TApiKeyServiceFactory } from "@app/services/api-key/api-key-service";
|
||||||
import { TAppConnectionServiceFactory } from "@app/services/app-connection/app-connection-service";
|
import { TAppConnectionServiceFactory } from "@app/services/app-connection/app-connection-service";
|
||||||
import { TAuthLoginFactory } from "@app/services/auth/auth-login-service";
|
import { TAuthLoginFactory } from "@app/services/auth/auth-login-service";
|
||||||
@@ -59,8 +62,13 @@ import { TAuthTokenServiceFactory } from "@app/services/auth-token/auth-token-se
|
|||||||
import { TCertificateServiceFactory } from "@app/services/certificate/certificate-service";
|
import { TCertificateServiceFactory } from "@app/services/certificate/certificate-service";
|
||||||
import { TCertificateAuthorityServiceFactory } from "@app/services/certificate-authority/certificate-authority-service";
|
import { TCertificateAuthorityServiceFactory } from "@app/services/certificate-authority/certificate-authority-service";
|
||||||
import { TInternalCertificateAuthorityServiceFactory } from "@app/services/certificate-authority/internal/internal-certificate-authority-service";
|
import { TInternalCertificateAuthorityServiceFactory } from "@app/services/certificate-authority/internal/internal-certificate-authority-service";
|
||||||
|
import { TCertificateEstV3ServiceFactory } from "@app/services/certificate-est-v3/certificate-est-v3-service";
|
||||||
|
import { TCertificateProfileServiceFactory } from "@app/services/certificate-profile/certificate-profile-service";
|
||||||
import { TCertificateTemplateServiceFactory } from "@app/services/certificate-template/certificate-template-service";
|
import { TCertificateTemplateServiceFactory } from "@app/services/certificate-template/certificate-template-service";
|
||||||
|
import { TCertificateTemplateV2ServiceFactory } from "@app/services/certificate-template-v2/certificate-template-v2-service";
|
||||||
|
import { TCertificateV3ServiceFactory } from "@app/services/certificate-v3/certificate-v3-service";
|
||||||
import { TCmekServiceFactory } from "@app/services/cmek/cmek-service";
|
import { TCmekServiceFactory } from "@app/services/cmek/cmek-service";
|
||||||
|
import { TConvertorServiceFactory } from "@app/services/convertor/convertor-service";
|
||||||
import { TExternalGroupOrgRoleMappingServiceFactory } from "@app/services/external-group-org-role-mapping/external-group-org-role-mapping-service";
|
import { TExternalGroupOrgRoleMappingServiceFactory } from "@app/services/external-group-org-role-mapping/external-group-org-role-mapping-service";
|
||||||
import { TExternalMigrationServiceFactory } from "@app/services/external-migration/external-migration-service";
|
import { TExternalMigrationServiceFactory } from "@app/services/external-migration/external-migration-service";
|
||||||
import { TFolderCommitServiceFactory } from "@app/services/folder-commit/folder-commit-service";
|
import { TFolderCommitServiceFactory } from "@app/services/folder-commit/folder-commit-service";
|
||||||
@@ -84,10 +92,12 @@ import { TIdentityTokenAuthServiceFactory } from "@app/services/identity-token-a
|
|||||||
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";
|
||||||
import { TIntegrationAuthServiceFactory } from "@app/services/integration-auth/integration-auth-service";
|
import { TIntegrationAuthServiceFactory } from "@app/services/integration-auth/integration-auth-service";
|
||||||
|
import { TMembershipGroupServiceFactory } from "@app/services/membership-group/membership-group-service";
|
||||||
|
import { TMembershipIdentityServiceFactory } from "@app/services/membership-identity/membership-identity-service";
|
||||||
|
import { TMembershipUserServiceFactory } from "@app/services/membership-user/membership-user-service";
|
||||||
import { TMicrosoftTeamsServiceFactory } from "@app/services/microsoft-teams/microsoft-teams-service";
|
import { TMicrosoftTeamsServiceFactory } from "@app/services/microsoft-teams/microsoft-teams-service";
|
||||||
import { TNotificationServiceFactory } from "@app/services/notification/notification-service";
|
import { TNotificationServiceFactory } from "@app/services/notification/notification-service";
|
||||||
import { TOfflineUsageReportServiceFactory } from "@app/services/offline-usage-report/offline-usage-report-service";
|
import { TOfflineUsageReportServiceFactory } from "@app/services/offline-usage-report/offline-usage-report-service";
|
||||||
import { TOrgRoleServiceFactory } from "@app/services/org/org-role-service";
|
|
||||||
import { TOrgServiceFactory } from "@app/services/org/org-service";
|
import { TOrgServiceFactory } from "@app/services/org/org-service";
|
||||||
import { TOrgAdminServiceFactory } from "@app/services/org-admin/org-admin-service";
|
import { TOrgAdminServiceFactory } from "@app/services/org-admin/org-admin-service";
|
||||||
import { TPkiAlertServiceFactory } from "@app/services/pki-alert/pki-alert-service";
|
import { TPkiAlertServiceFactory } from "@app/services/pki-alert/pki-alert-service";
|
||||||
@@ -100,8 +110,8 @@ import { TProjectBotServiceFactory } from "@app/services/project-bot/project-bot
|
|||||||
import { TProjectEnvServiceFactory } from "@app/services/project-env/project-env-service";
|
import { TProjectEnvServiceFactory } from "@app/services/project-env/project-env-service";
|
||||||
import { TProjectKeyServiceFactory } from "@app/services/project-key/project-key-service";
|
import { TProjectKeyServiceFactory } from "@app/services/project-key/project-key-service";
|
||||||
import { TProjectMembershipServiceFactory } from "@app/services/project-membership/project-membership-service";
|
import { TProjectMembershipServiceFactory } from "@app/services/project-membership/project-membership-service";
|
||||||
import { TProjectRoleServiceFactory } from "@app/services/project-role/project-role-service";
|
|
||||||
import { TReminderServiceFactory } from "@app/services/reminder/reminder-types";
|
import { TReminderServiceFactory } from "@app/services/reminder/reminder-types";
|
||||||
|
import { TRoleServiceFactory } from "@app/services/role/role-service";
|
||||||
import { TSecretServiceFactory } from "@app/services/secret/secret-service";
|
import { TSecretServiceFactory } from "@app/services/secret/secret-service";
|
||||||
import { TSecretBlindIndexServiceFactory } from "@app/services/secret-blind-index/secret-blind-index-service";
|
import { TSecretBlindIndexServiceFactory } from "@app/services/secret-blind-index/secret-blind-index-service";
|
||||||
import { TSecretFolderServiceFactory } from "@app/services/secret-folder/secret-folder-service";
|
import { TSecretFolderServiceFactory } from "@app/services/secret-folder/secret-folder-service";
|
||||||
@@ -173,6 +183,8 @@ declare module "fastify" {
|
|||||||
type: ActorType;
|
type: ActorType;
|
||||||
id: string;
|
id: string;
|
||||||
orgId: string;
|
orgId: string;
|
||||||
|
parentOrgId: string;
|
||||||
|
rootOrgId: string;
|
||||||
};
|
};
|
||||||
rateLimits: RateLimitConfiguration;
|
rateLimits: RateLimitConfiguration;
|
||||||
// passport data
|
// passport data
|
||||||
@@ -209,7 +221,6 @@ declare module "fastify" {
|
|||||||
authToken: TAuthTokenServiceFactory;
|
authToken: TAuthTokenServiceFactory;
|
||||||
permission: TPermissionServiceFactory;
|
permission: TPermissionServiceFactory;
|
||||||
org: TOrgServiceFactory;
|
org: TOrgServiceFactory;
|
||||||
orgRole: TOrgRoleServiceFactory;
|
|
||||||
oidc: TOidcConfigServiceFactory;
|
oidc: TOidcConfigServiceFactory;
|
||||||
superAdmin: TSuperAdminServiceFactory;
|
superAdmin: TSuperAdminServiceFactory;
|
||||||
user: TUserServiceFactory;
|
user: TUserServiceFactory;
|
||||||
@@ -221,7 +232,6 @@ declare module "fastify" {
|
|||||||
projectMembership: TProjectMembershipServiceFactory;
|
projectMembership: TProjectMembershipServiceFactory;
|
||||||
projectEnv: TProjectEnvServiceFactory;
|
projectEnv: TProjectEnvServiceFactory;
|
||||||
projectKey: TProjectKeyServiceFactory;
|
projectKey: TProjectKeyServiceFactory;
|
||||||
projectRole: TProjectRoleServiceFactory;
|
|
||||||
secret: TSecretServiceFactory;
|
secret: TSecretServiceFactory;
|
||||||
secretReplication: TSecretReplicationServiceFactory;
|
secretReplication: TSecretReplicationServiceFactory;
|
||||||
secretTag: TSecretTagServiceFactory;
|
secretTag: TSecretTagServiceFactory;
|
||||||
@@ -259,7 +269,10 @@ declare module "fastify" {
|
|||||||
auditLog: TAuditLogServiceFactory;
|
auditLog: TAuditLogServiceFactory;
|
||||||
auditLogStream: TAuditLogStreamServiceFactory;
|
auditLogStream: TAuditLogStreamServiceFactory;
|
||||||
certificate: TCertificateServiceFactory;
|
certificate: TCertificateServiceFactory;
|
||||||
|
certificateV3: TCertificateV3ServiceFactory;
|
||||||
certificateTemplate: TCertificateTemplateServiceFactory;
|
certificateTemplate: TCertificateTemplateServiceFactory;
|
||||||
|
certificateTemplateV2: TCertificateTemplateV2ServiceFactory;
|
||||||
|
certificateProfile: TCertificateProfileServiceFactory;
|
||||||
sshCertificateAuthority: TSshCertificateAuthorityServiceFactory;
|
sshCertificateAuthority: TSshCertificateAuthorityServiceFactory;
|
||||||
sshCertificateTemplate: TSshCertificateTemplateServiceFactory;
|
sshCertificateTemplate: TSshCertificateTemplateServiceFactory;
|
||||||
sshHost: TSshHostServiceFactory;
|
sshHost: TSshHostServiceFactory;
|
||||||
@@ -267,6 +280,7 @@ declare module "fastify" {
|
|||||||
certificateAuthority: TCertificateAuthorityServiceFactory;
|
certificateAuthority: TCertificateAuthorityServiceFactory;
|
||||||
certificateAuthorityCrl: TCertificateAuthorityCrlServiceFactory;
|
certificateAuthorityCrl: TCertificateAuthorityCrlServiceFactory;
|
||||||
certificateEst: TCertificateEstServiceFactory;
|
certificateEst: TCertificateEstServiceFactory;
|
||||||
|
certificateEstV3: TCertificateEstV3ServiceFactory;
|
||||||
pkiCollection: TPkiCollectionServiceFactory;
|
pkiCollection: TPkiCollectionServiceFactory;
|
||||||
pkiSubscriber: TPkiSubscriberServiceFactory;
|
pkiSubscriber: TPkiSubscriberServiceFactory;
|
||||||
pkiSync: TPkiSyncServiceFactory;
|
pkiSync: TPkiSyncServiceFactory;
|
||||||
@@ -277,9 +291,6 @@ declare module "fastify" {
|
|||||||
telemetry: TTelemetryServiceFactory;
|
telemetry: TTelemetryServiceFactory;
|
||||||
dynamicSecret: TDynamicSecretServiceFactory;
|
dynamicSecret: TDynamicSecretServiceFactory;
|
||||||
dynamicSecretLease: TDynamicSecretLeaseServiceFactory;
|
dynamicSecretLease: TDynamicSecretLeaseServiceFactory;
|
||||||
projectUserAdditionalPrivilege: TProjectUserAdditionalPrivilegeServiceFactory;
|
|
||||||
identityProjectAdditionalPrivilege: TIdentityProjectAdditionalPrivilegeServiceFactory;
|
|
||||||
identityProjectAdditionalPrivilegeV2: TIdentityProjectAdditionalPrivilegeV2ServiceFactory;
|
|
||||||
secretSharing: TSecretSharingServiceFactory;
|
secretSharing: TSecretSharingServiceFactory;
|
||||||
rateLimit: TRateLimitServiceFactory;
|
rateLimit: TRateLimitServiceFactory;
|
||||||
userEngagement: TUserEngagementServiceFactory;
|
userEngagement: TUserEngagementServiceFactory;
|
||||||
@@ -315,7 +326,19 @@ declare module "fastify" {
|
|||||||
identityAuthTemplate: TIdentityAuthTemplateServiceFactory;
|
identityAuthTemplate: TIdentityAuthTemplateServiceFactory;
|
||||||
notification: TNotificationServiceFactory;
|
notification: TNotificationServiceFactory;
|
||||||
offlineUsageReport: TOfflineUsageReportServiceFactory;
|
offlineUsageReport: TOfflineUsageReportServiceFactory;
|
||||||
|
pamFolder: TPamFolderServiceFactory;
|
||||||
|
pamResource: TPamResourceServiceFactory;
|
||||||
|
pamAccount: TPamAccountServiceFactory;
|
||||||
|
pamSession: TPamSessionServiceFactory;
|
||||||
upgradePath: TUpgradePathService;
|
upgradePath: TUpgradePathService;
|
||||||
|
|
||||||
|
membershipUser: TMembershipUserServiceFactory;
|
||||||
|
membershipIdentity: TMembershipIdentityServiceFactory;
|
||||||
|
membershipGroup: TMembershipGroupServiceFactory;
|
||||||
|
additionalPrivilege: TAdditionalPrivilegeServiceFactory;
|
||||||
|
role: TRoleServiceFactory;
|
||||||
|
convertor: TConvertorServiceFactory;
|
||||||
|
subOrganization: TSubOrgServiceFactory;
|
||||||
};
|
};
|
||||||
// this is exclusive use for middlewares in which we need to inject data
|
// this is exclusive use for middlewares in which we need to inject data
|
||||||
// everywhere else access using service layer
|
// everywhere else access using service layer
|
||||||
|
|||||||
Vendored
+77
@@ -17,6 +17,9 @@ import {
|
|||||||
TAccessApprovalRequestsReviewersInsert,
|
TAccessApprovalRequestsReviewersInsert,
|
||||||
TAccessApprovalRequestsReviewersUpdate,
|
TAccessApprovalRequestsReviewersUpdate,
|
||||||
TAccessApprovalRequestsUpdate,
|
TAccessApprovalRequestsUpdate,
|
||||||
|
TAdditionalPrivileges,
|
||||||
|
TAdditionalPrivilegesInsert,
|
||||||
|
TAdditionalPrivilegesUpdate,
|
||||||
TApiKeys,
|
TApiKeys,
|
||||||
TApiKeysInsert,
|
TApiKeysInsert,
|
||||||
TApiKeysUpdate,
|
TApiKeysUpdate,
|
||||||
@@ -227,6 +230,15 @@ import {
|
|||||||
TLdapGroupMaps,
|
TLdapGroupMaps,
|
||||||
TLdapGroupMapsInsert,
|
TLdapGroupMapsInsert,
|
||||||
TLdapGroupMapsUpdate,
|
TLdapGroupMapsUpdate,
|
||||||
|
TMembershipRoles,
|
||||||
|
TMembershipRolesInsert,
|
||||||
|
TMembershipRolesUpdate,
|
||||||
|
TMemberships,
|
||||||
|
TMembershipsInsert,
|
||||||
|
TMembershipsUpdate,
|
||||||
|
TNamespaces,
|
||||||
|
TNamespacesInsert,
|
||||||
|
TNamespacesUpdate,
|
||||||
TOidcConfigs,
|
TOidcConfigs,
|
||||||
TOidcConfigsInsert,
|
TOidcConfigsInsert,
|
||||||
TOidcConfigsUpdate,
|
TOidcConfigsUpdate,
|
||||||
@@ -254,12 +266,24 @@ import {
|
|||||||
TPkiAlerts,
|
TPkiAlerts,
|
||||||
TPkiAlertsInsert,
|
TPkiAlertsInsert,
|
||||||
TPkiAlertsUpdate,
|
TPkiAlertsUpdate,
|
||||||
|
TPkiApiEnrollmentConfigs,
|
||||||
|
TPkiApiEnrollmentConfigsInsert,
|
||||||
|
TPkiApiEnrollmentConfigsUpdate,
|
||||||
|
TPkiCertificateProfiles,
|
||||||
|
TPkiCertificateProfilesInsert,
|
||||||
|
TPkiCertificateProfilesUpdate,
|
||||||
|
TPkiCertificateTemplatesV2,
|
||||||
|
TPkiCertificateTemplatesV2Insert,
|
||||||
|
TPkiCertificateTemplatesV2Update,
|
||||||
TPkiCollectionItems,
|
TPkiCollectionItems,
|
||||||
TPkiCollectionItemsInsert,
|
TPkiCollectionItemsInsert,
|
||||||
TPkiCollectionItemsUpdate,
|
TPkiCollectionItemsUpdate,
|
||||||
TPkiCollections,
|
TPkiCollections,
|
||||||
TPkiCollectionsInsert,
|
TPkiCollectionsInsert,
|
||||||
TPkiCollectionsUpdate,
|
TPkiCollectionsUpdate,
|
||||||
|
TPkiEstEnrollmentConfigs,
|
||||||
|
TPkiEstEnrollmentConfigsInsert,
|
||||||
|
TPkiEstEnrollmentConfigsUpdate,
|
||||||
TPkiSubscribers,
|
TPkiSubscribers,
|
||||||
TPkiSubscribersInsert,
|
TPkiSubscribersInsert,
|
||||||
TPkiSubscribersUpdate,
|
TPkiSubscribersUpdate,
|
||||||
@@ -314,6 +338,9 @@ import {
|
|||||||
TResourceMetadata,
|
TResourceMetadata,
|
||||||
TResourceMetadataInsert,
|
TResourceMetadataInsert,
|
||||||
TResourceMetadataUpdate,
|
TResourceMetadataUpdate,
|
||||||
|
TRoles,
|
||||||
|
TRolesInsert,
|
||||||
|
TRolesUpdate,
|
||||||
TSamlConfigs,
|
TSamlConfigs,
|
||||||
TSamlConfigsInsert,
|
TSamlConfigsInsert,
|
||||||
TSamlConfigsUpdate,
|
TSamlConfigsUpdate,
|
||||||
@@ -503,6 +530,9 @@ import {
|
|||||||
TUsers,
|
TUsers,
|
||||||
TUsersInsert,
|
TUsersInsert,
|
||||||
TUsersUpdate,
|
TUsersUpdate,
|
||||||
|
TVaultExternalMigrationConfigs,
|
||||||
|
TVaultExternalMigrationConfigsInsert,
|
||||||
|
TVaultExternalMigrationConfigsUpdate,
|
||||||
TWebhooks,
|
TWebhooks,
|
||||||
TWebhooksInsert,
|
TWebhooksInsert,
|
||||||
TWebhooksUpdate,
|
TWebhooksUpdate,
|
||||||
@@ -530,6 +560,10 @@ import {
|
|||||||
TMicrosoftTeamsIntegrationsInsert,
|
TMicrosoftTeamsIntegrationsInsert,
|
||||||
TMicrosoftTeamsIntegrationsUpdate
|
TMicrosoftTeamsIntegrationsUpdate
|
||||||
} from "@app/db/schemas/microsoft-teams-integrations";
|
} from "@app/db/schemas/microsoft-teams-integrations";
|
||||||
|
import { TPamAccounts, TPamAccountsInsert, TPamAccountsUpdate } from "@app/db/schemas/pam-accounts";
|
||||||
|
import { TPamFolders, TPamFoldersInsert, TPamFoldersUpdate } from "@app/db/schemas/pam-folders";
|
||||||
|
import { TPamResources, TPamResourcesInsert, TPamResourcesUpdate } from "@app/db/schemas/pam-resources";
|
||||||
|
import { TPamSessions, TPamSessionsInsert, TPamSessionsUpdate } from "@app/db/schemas/pam-sessions";
|
||||||
import {
|
import {
|
||||||
TProjectMicrosoftTeamsConfigs,
|
TProjectMicrosoftTeamsConfigs,
|
||||||
TProjectMicrosoftTeamsConfigsInsert,
|
TProjectMicrosoftTeamsConfigsInsert,
|
||||||
@@ -652,6 +686,26 @@ declare module "knex/types/tables" {
|
|||||||
TCertificateTemplatesInsert,
|
TCertificateTemplatesInsert,
|
||||||
TCertificateTemplatesUpdate
|
TCertificateTemplatesUpdate
|
||||||
>;
|
>;
|
||||||
|
[TableName.PkiCertificateTemplateV2]: KnexOriginal.CompositeTableType<
|
||||||
|
TPkiCertificateTemplatesV2,
|
||||||
|
TPkiCertificateTemplatesV2Insert,
|
||||||
|
TPkiCertificateTemplatesV2Update
|
||||||
|
>;
|
||||||
|
[TableName.PkiCertificateProfile]: KnexOriginal.CompositeTableType<
|
||||||
|
TPkiCertificateProfiles,
|
||||||
|
TPkiCertificateProfilesInsert,
|
||||||
|
TPkiCertificateProfilesUpdate
|
||||||
|
>;
|
||||||
|
[TableName.PkiEstEnrollmentConfig]: KnexOriginal.CompositeTableType<
|
||||||
|
TPkiEstEnrollmentConfigs,
|
||||||
|
TPkiEstEnrollmentConfigsInsert,
|
||||||
|
TPkiEstEnrollmentConfigsUpdate
|
||||||
|
>;
|
||||||
|
[TableName.PkiApiEnrollmentConfig]: KnexOriginal.CompositeTableType<
|
||||||
|
TPkiApiEnrollmentConfigs,
|
||||||
|
TPkiApiEnrollmentConfigsInsert,
|
||||||
|
TPkiApiEnrollmentConfigsUpdate
|
||||||
|
>;
|
||||||
[TableName.CertificateTemplateEstConfig]: KnexOriginal.CompositeTableType<
|
[TableName.CertificateTemplateEstConfig]: KnexOriginal.CompositeTableType<
|
||||||
TCertificateTemplateEstConfigs,
|
TCertificateTemplateEstConfigs,
|
||||||
TCertificateTemplateEstConfigsInsert,
|
TCertificateTemplateEstConfigsInsert,
|
||||||
@@ -1308,5 +1362,28 @@ declare module "knex/types/tables" {
|
|||||||
TKeyValueStoreInsert,
|
TKeyValueStoreInsert,
|
||||||
TKeyValueStoreUpdate
|
TKeyValueStoreUpdate
|
||||||
>;
|
>;
|
||||||
|
[TableName.PamFolder]: KnexOriginal.CompositeTableType<TPamFolders, TPamFoldersInsert, TPamFoldersUpdate>;
|
||||||
|
[TableName.PamResource]: KnexOriginal.CompositeTableType<TPamResources, TPamResourcesInsert, TPamResourcesUpdate>;
|
||||||
|
[TableName.PamAccount]: KnexOriginal.CompositeTableType<TPamAccounts, TPamAccountsInsert, TPamAccountsUpdate>;
|
||||||
|
[TableName.PamSession]: KnexOriginal.CompositeTableType<TPamSessions, TPamSessionsInsert, TPamSessionsUpdate>;
|
||||||
|
|
||||||
|
[TableName.Namespace]: KnexOriginal.CompositeTableType<TNamespaces, TNamespacesInsert, TNamespacesUpdate>;
|
||||||
|
[TableName.Membership]: KnexOriginal.CompositeTableType<TMemberships, TMembershipsInsert, TMembershipsUpdate>;
|
||||||
|
[TableName.MembershipRole]: KnexOriginal.CompositeTableType<
|
||||||
|
TMembershipRoles,
|
||||||
|
TMembershipRolesInsert,
|
||||||
|
TMembershipRolesUpdate
|
||||||
|
>;
|
||||||
|
[TableName.Role]: KnexOriginal.CompositeTableType<TRoles, TRolesInsert, TRolesUpdate>;
|
||||||
|
[TableName.AdditionalPrivilege]: KnexOriginal.CompositeTableType<
|
||||||
|
TAdditionalPrivileges,
|
||||||
|
TAdditionalPrivilegesInsert,
|
||||||
|
TAdditionalPrivilegesUpdate
|
||||||
|
>;
|
||||||
|
[TableName.VaultExternalMigrationConfig]: KnexOriginal.CompositeTableType<
|
||||||
|
TVaultExternalMigrationConfigs,
|
||||||
|
TVaultExternalMigrationConfigsInsert,
|
||||||
|
TVaultExternalMigrationConfigsUpdate
|
||||||
|
>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+41
-27
@@ -1,5 +1,29 @@
|
|||||||
import knex, { Knex } from "knex";
|
import knex, { Knex } from "knex";
|
||||||
|
|
||||||
|
const parseSslConfig = (dbConnectionUri: string, dbRootCert?: string) => {
|
||||||
|
let modifiedDbConnectionUri = dbConnectionUri;
|
||||||
|
let sslConfig: { rejectUnauthorized: boolean; ca: string } | boolean = dbRootCert
|
||||||
|
? { rejectUnauthorized: true, ca: Buffer.from(dbRootCert, "base64").toString("ascii") }
|
||||||
|
: false;
|
||||||
|
|
||||||
|
if (dbRootCert) {
|
||||||
|
const url = new URL(dbConnectionUri);
|
||||||
|
const sslMode = url.searchParams.get("sslmode");
|
||||||
|
|
||||||
|
if (sslMode && sslMode !== "disable") {
|
||||||
|
url.searchParams.delete("sslmode");
|
||||||
|
modifiedDbConnectionUri = url.toString();
|
||||||
|
|
||||||
|
sslConfig = {
|
||||||
|
rejectUnauthorized: ["verify-ca", "verify-full"].includes(sslMode),
|
||||||
|
ca: Buffer.from(dbRootCert, "base64").toString("ascii")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { modifiedDbConnectionUri, sslConfig };
|
||||||
|
};
|
||||||
|
|
||||||
export type TDbClient = Knex;
|
export type TDbClient = Knex;
|
||||||
export const initDbConnection = ({
|
export const initDbConnection = ({
|
||||||
dbConnectionUri,
|
dbConnectionUri,
|
||||||
@@ -32,23 +56,18 @@ export const initDbConnection = ({
|
|||||||
return selectedReplica;
|
return selectedReplica;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { modifiedDbConnectionUri, sslConfig } = parseSslConfig(dbConnectionUri, dbRootCert);
|
||||||
|
|
||||||
db = knex({
|
db = knex({
|
||||||
client: "pg",
|
client: "pg",
|
||||||
connection: {
|
connection: {
|
||||||
connectionString: dbConnectionUri,
|
connectionString: modifiedDbConnectionUri,
|
||||||
host: process.env.DB_HOST,
|
host: process.env.DB_HOST,
|
||||||
// @ts-expect-error I have no clue why only for the port there is a type error
|
port: process.env.DB_PORT ? parseInt(process.env.DB_PORT, 10) : undefined,
|
||||||
// eslint-disable-next-line
|
|
||||||
port: process.env.DB_PORT,
|
|
||||||
user: process.env.DB_USER,
|
user: process.env.DB_USER,
|
||||||
database: process.env.DB_NAME,
|
database: process.env.DB_NAME,
|
||||||
password: process.env.DB_PASSWORD,
|
password: process.env.DB_PASSWORD,
|
||||||
ssl: dbRootCert
|
ssl: sslConfig
|
||||||
? {
|
|
||||||
rejectUnauthorized: true,
|
|
||||||
ca: Buffer.from(dbRootCert, "base64").toString("ascii")
|
|
||||||
}
|
|
||||||
: false
|
|
||||||
},
|
},
|
||||||
// https://knexjs.org/guide/#pool
|
// https://knexjs.org/guide/#pool
|
||||||
pool: { min: 0, max: 10 },
|
pool: { min: 0, max: 10 },
|
||||||
@@ -59,16 +78,16 @@ export const initDbConnection = ({
|
|||||||
|
|
||||||
readReplicaDbs = readReplicas.map((el) => {
|
readReplicaDbs = readReplicas.map((el) => {
|
||||||
const replicaDbCertificate = el.dbRootCert || dbRootCert;
|
const replicaDbCertificate = el.dbRootCert || dbRootCert;
|
||||||
|
const { modifiedDbConnectionUri: replicaUri, sslConfig: replicaSslConfig } = parseSslConfig(
|
||||||
|
el.dbConnectionUri,
|
||||||
|
replicaDbCertificate
|
||||||
|
);
|
||||||
|
|
||||||
return knex({
|
return knex({
|
||||||
client: "pg",
|
client: "pg",
|
||||||
connection: {
|
connection: {
|
||||||
connectionString: el.dbConnectionUri,
|
connectionString: replicaUri,
|
||||||
ssl: replicaDbCertificate
|
ssl: replicaSslConfig
|
||||||
? {
|
|
||||||
rejectUnauthorized: true,
|
|
||||||
ca: Buffer.from(replicaDbCertificate, "base64").toString("ascii")
|
|
||||||
}
|
|
||||||
: false
|
|
||||||
},
|
},
|
||||||
migrations: {
|
migrations: {
|
||||||
tableName: "infisical_migrations"
|
tableName: "infisical_migrations"
|
||||||
@@ -87,26 +106,21 @@ export const initAuditLogDbConnection = ({
|
|||||||
dbConnectionUri: string;
|
dbConnectionUri: string;
|
||||||
dbRootCert?: string;
|
dbRootCert?: string;
|
||||||
}) => {
|
}) => {
|
||||||
|
const { modifiedDbConnectionUri, sslConfig } = parseSslConfig(dbConnectionUri, dbRootCert);
|
||||||
|
|
||||||
// akhilmhdh: the default Knex is knex.Knex<any, any[]>. but when assigned with knex({<config>}) the value is knex.Knex<any, unknown[]>
|
// akhilmhdh: the default Knex is knex.Knex<any, any[]>. but when assigned with knex({<config>}) the value is knex.Knex<any, unknown[]>
|
||||||
// this was causing issue with files like `snapshot-dal` `findRecursivelySnapshots` this i am explicitly putting the any and unknown[]
|
// this was causing issue with files like `snapshot-dal` `findRecursivelySnapshots` this i am explicitly putting the any and unknown[]
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
const db: Knex<any, unknown[]> = knex({
|
const db: Knex<any, unknown[]> = knex({
|
||||||
client: "pg",
|
client: "pg",
|
||||||
connection: {
|
connection: {
|
||||||
connectionString: dbConnectionUri,
|
connectionString: modifiedDbConnectionUri,
|
||||||
host: process.env.AUDIT_LOGS_DB_HOST,
|
host: process.env.AUDIT_LOGS_DB_HOST,
|
||||||
// @ts-expect-error I have no clue why only for the port there is a type error
|
port: process.env.AUDIT_LOGS_DB_PORT ? parseInt(process.env.AUDIT_LOGS_DB_PORT, 10) : undefined,
|
||||||
// eslint-disable-next-line
|
|
||||||
port: process.env.AUDIT_LOGS_DB_PORT,
|
|
||||||
user: process.env.AUDIT_LOGS_DB_USER,
|
user: process.env.AUDIT_LOGS_DB_USER,
|
||||||
database: process.env.AUDIT_LOGS_DB_NAME,
|
database: process.env.AUDIT_LOGS_DB_NAME,
|
||||||
password: process.env.AUDIT_LOGS_DB_PASSWORD,
|
password: process.env.AUDIT_LOGS_DB_PASSWORD,
|
||||||
ssl: dbRootCert
|
ssl: sslConfig
|
||||||
? {
|
|
||||||
rejectUnauthorized: true,
|
|
||||||
ca: Buffer.from(dbRootCert, "base64").toString("ascii")
|
|
||||||
}
|
|
||||||
: false
|
|
||||||
},
|
},
|
||||||
migrations: {
|
migrations: {
|
||||||
tableName: "infisical_migrations"
|
tableName: "infisical_migrations"
|
||||||
|
|||||||
@@ -127,7 +127,8 @@ export async function down(knex: Knex): Promise<void> {
|
|||||||
});
|
});
|
||||||
await knex.schema.alterTable(TableName.SecretApprovalPolicyApprover, (tb) => {
|
await knex.schema.alterTable(TableName.SecretApprovalPolicyApprover, (tb) => {
|
||||||
tb.dropColumn("approverUserId");
|
tb.dropColumn("approverUserId");
|
||||||
tb.uuid("approverId").notNullable().alter();
|
// akhilmhdh: i had to comment this out and is not possible as membership is now changed in structure
|
||||||
|
// tb.uuid("approverId").notNullable().alter();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,13 +3,14 @@ import { Knex } from "knex";
|
|||||||
import { inMemoryKeyStore } from "@app/keystore/memory";
|
import { inMemoryKeyStore } from "@app/keystore/memory";
|
||||||
import { crypto } from "@app/lib/crypto/cryptography";
|
import { crypto } from "@app/lib/crypto/cryptography";
|
||||||
import { initLogger } from "@app/lib/logger";
|
import { initLogger } from "@app/lib/logger";
|
||||||
|
import { kmsRootConfigDALFactory } from "@app/services/kms/kms-root-config-dal";
|
||||||
import { KmsDataKey } from "@app/services/kms/kms-types";
|
import { KmsDataKey } from "@app/services/kms/kms-types";
|
||||||
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||||
|
|
||||||
import { SecretKeyEncoding, TableName } from "../schemas";
|
import { SecretKeyEncoding, TableName } from "../schemas";
|
||||||
import { getMigrationEnvConfig } from "./utils/env-config";
|
import { getMigrationEnvConfig, getMigrationHsmConfig } from "./utils/env-config";
|
||||||
import { createCircularCache } from "./utils/ring-buffer";
|
import { createCircularCache } from "./utils/ring-buffer";
|
||||||
import { getMigrationEncryptionServices } from "./utils/services";
|
import { getMigrationEncryptionServices, getMigrationHsmService } from "./utils/services";
|
||||||
|
|
||||||
const BATCH_SIZE = 500;
|
const BATCH_SIZE = 500;
|
||||||
export async function up(knex: Knex): Promise<void> {
|
export async function up(knex: Knex): Promise<void> {
|
||||||
@@ -25,10 +26,12 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
if (hasUrl) t.string("url").nullable().alter();
|
if (hasUrl) t.string("url").nullable().alter();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
initLogger();
|
initLogger();
|
||||||
|
|
||||||
|
const { hsmService } = await getMigrationHsmService({ envConfig: getMigrationHsmConfig() });
|
||||||
const superAdminDAL = superAdminDALFactory(knex);
|
const superAdminDAL = superAdminDALFactory(knex);
|
||||||
const envConfig = await getMigrationEnvConfig(superAdminDAL);
|
const kmsRootConfigDAL = kmsRootConfigDALFactory(knex);
|
||||||
|
const envConfig = await getMigrationEnvConfig(superAdminDAL, hsmService, kmsRootConfigDAL);
|
||||||
|
|
||||||
const keyStore = inMemoryKeyStore();
|
const keyStore = inMemoryKeyStore();
|
||||||
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
||||||
|
|||||||
@@ -4,13 +4,14 @@ import { inMemoryKeyStore } from "@app/keystore/memory";
|
|||||||
import { crypto } from "@app/lib/crypto/cryptography";
|
import { crypto } from "@app/lib/crypto/cryptography";
|
||||||
import { selectAllTableCols } from "@app/lib/knex";
|
import { selectAllTableCols } from "@app/lib/knex";
|
||||||
import { initLogger } from "@app/lib/logger";
|
import { initLogger } from "@app/lib/logger";
|
||||||
|
import { kmsRootConfigDALFactory } from "@app/services/kms/kms-root-config-dal";
|
||||||
import { KmsDataKey } from "@app/services/kms/kms-types";
|
import { KmsDataKey } from "@app/services/kms/kms-types";
|
||||||
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||||
|
|
||||||
import { SecretKeyEncoding, TableName } from "../schemas";
|
import { SecretKeyEncoding, TableName } from "../schemas";
|
||||||
import { getMigrationEnvConfig } from "./utils/env-config";
|
import { getMigrationEnvConfig, getMigrationHsmConfig } from "./utils/env-config";
|
||||||
import { createCircularCache } from "./utils/ring-buffer";
|
import { createCircularCache } from "./utils/ring-buffer";
|
||||||
import { getMigrationEncryptionServices } from "./utils/services";
|
import { getMigrationEncryptionServices, getMigrationHsmService } from "./utils/services";
|
||||||
|
|
||||||
const BATCH_SIZE = 500;
|
const BATCH_SIZE = 500;
|
||||||
export async function up(knex: Knex): Promise<void> {
|
export async function up(knex: Knex): Promise<void> {
|
||||||
@@ -30,8 +31,12 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initLogger();
|
initLogger();
|
||||||
|
|
||||||
|
const { hsmService } = await getMigrationHsmService({ envConfig: getMigrationHsmConfig() });
|
||||||
|
|
||||||
const superAdminDAL = superAdminDALFactory(knex);
|
const superAdminDAL = superAdminDALFactory(knex);
|
||||||
const envConfig = await getMigrationEnvConfig(superAdminDAL);
|
const kmsRootConfigDAL = kmsRootConfigDALFactory(knex);
|
||||||
|
const envConfig = await getMigrationEnvConfig(superAdminDAL, hsmService, kmsRootConfigDAL);
|
||||||
|
|
||||||
const keyStore = inMemoryKeyStore();
|
const keyStore = inMemoryKeyStore();
|
||||||
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
||||||
|
|||||||
@@ -4,13 +4,14 @@ import { inMemoryKeyStore } from "@app/keystore/memory";
|
|||||||
import { crypto } from "@app/lib/crypto/cryptography";
|
import { crypto } from "@app/lib/crypto/cryptography";
|
||||||
import { selectAllTableCols } from "@app/lib/knex";
|
import { selectAllTableCols } from "@app/lib/knex";
|
||||||
import { initLogger } from "@app/lib/logger";
|
import { initLogger } from "@app/lib/logger";
|
||||||
|
import { kmsRootConfigDALFactory } from "@app/services/kms/kms-root-config-dal";
|
||||||
import { KmsDataKey } from "@app/services/kms/kms-types";
|
import { KmsDataKey } from "@app/services/kms/kms-types";
|
||||||
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||||
|
|
||||||
import { SecretKeyEncoding, TableName } from "../schemas";
|
import { SecretKeyEncoding, TableName } from "../schemas";
|
||||||
import { getMigrationEnvConfig } from "./utils/env-config";
|
import { getMigrationEnvConfig, getMigrationHsmConfig } from "./utils/env-config";
|
||||||
import { createCircularCache } from "./utils/ring-buffer";
|
import { createCircularCache } from "./utils/ring-buffer";
|
||||||
import { getMigrationEncryptionServices } from "./utils/services";
|
import { getMigrationEncryptionServices, getMigrationHsmService } from "./utils/services";
|
||||||
|
|
||||||
const BATCH_SIZE = 500;
|
const BATCH_SIZE = 500;
|
||||||
export async function up(knex: Knex): Promise<void> {
|
export async function up(knex: Knex): Promise<void> {
|
||||||
@@ -24,8 +25,11 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initLogger();
|
initLogger();
|
||||||
|
const { hsmService } = await getMigrationHsmService({ envConfig: getMigrationHsmConfig() });
|
||||||
|
|
||||||
const superAdminDAL = superAdminDALFactory(knex);
|
const superAdminDAL = superAdminDALFactory(knex);
|
||||||
const envConfig = await getMigrationEnvConfig(superAdminDAL);
|
const kmsRootConfigDAL = kmsRootConfigDALFactory(knex);
|
||||||
|
const envConfig = await getMigrationEnvConfig(superAdminDAL, hsmService, kmsRootConfigDAL);
|
||||||
|
|
||||||
const keyStore = inMemoryKeyStore();
|
const keyStore = inMemoryKeyStore();
|
||||||
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
||||||
|
|||||||
@@ -4,13 +4,14 @@ import { inMemoryKeyStore } from "@app/keystore/memory";
|
|||||||
import { crypto, SymmetricKeySize } from "@app/lib/crypto/cryptography";
|
import { crypto, SymmetricKeySize } from "@app/lib/crypto/cryptography";
|
||||||
import { selectAllTableCols } from "@app/lib/knex";
|
import { selectAllTableCols } from "@app/lib/knex";
|
||||||
import { initLogger } from "@app/lib/logger";
|
import { initLogger } from "@app/lib/logger";
|
||||||
|
import { kmsRootConfigDALFactory } from "@app/services/kms/kms-root-config-dal";
|
||||||
import { KmsDataKey } from "@app/services/kms/kms-types";
|
import { KmsDataKey } from "@app/services/kms/kms-types";
|
||||||
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||||
|
|
||||||
import { SecretKeyEncoding, TableName, TOrgBots } from "../schemas";
|
import { SecretKeyEncoding, TableName, TOrgBots } from "../schemas";
|
||||||
import { getMigrationEnvConfig } from "./utils/env-config";
|
import { getMigrationEnvConfig, getMigrationHsmConfig } from "./utils/env-config";
|
||||||
import { createCircularCache } from "./utils/ring-buffer";
|
import { createCircularCache } from "./utils/ring-buffer";
|
||||||
import { getMigrationEncryptionServices } from "./utils/services";
|
import { getMigrationEncryptionServices, getMigrationHsmService } from "./utils/services";
|
||||||
|
|
||||||
const BATCH_SIZE = 500;
|
const BATCH_SIZE = 500;
|
||||||
const reencryptIdentityK8sAuth = async (knex: Knex) => {
|
const reencryptIdentityK8sAuth = async (knex: Knex) => {
|
||||||
@@ -55,9 +56,11 @@ const reencryptIdentityK8sAuth = async (knex: Knex) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initLogger();
|
initLogger();
|
||||||
const superAdminDAL = superAdminDALFactory(knex);
|
const { hsmService } = await getMigrationHsmService({ envConfig: getMigrationHsmConfig() });
|
||||||
const envConfig = await getMigrationEnvConfig(superAdminDAL);
|
|
||||||
|
|
||||||
|
const superAdminDAL = superAdminDALFactory(knex);
|
||||||
|
const kmsRootConfigDAL = kmsRootConfigDALFactory(knex);
|
||||||
|
const envConfig = await getMigrationEnvConfig(superAdminDAL, hsmService, kmsRootConfigDAL);
|
||||||
const keyStore = inMemoryKeyStore();
|
const keyStore = inMemoryKeyStore();
|
||||||
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
||||||
const orgEncryptionRingBuffer =
|
const orgEncryptionRingBuffer =
|
||||||
|
|||||||
@@ -4,13 +4,14 @@ import { inMemoryKeyStore } from "@app/keystore/memory";
|
|||||||
import { crypto, SymmetricKeySize } from "@app/lib/crypto/cryptography";
|
import { crypto, SymmetricKeySize } from "@app/lib/crypto/cryptography";
|
||||||
import { selectAllTableCols } from "@app/lib/knex";
|
import { selectAllTableCols } from "@app/lib/knex";
|
||||||
import { initLogger } from "@app/lib/logger";
|
import { initLogger } from "@app/lib/logger";
|
||||||
|
import { kmsRootConfigDALFactory } from "@app/services/kms/kms-root-config-dal";
|
||||||
import { KmsDataKey } from "@app/services/kms/kms-types";
|
import { KmsDataKey } from "@app/services/kms/kms-types";
|
||||||
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||||
|
|
||||||
import { SecretKeyEncoding, TableName, TOrgBots } from "../schemas";
|
import { SecretKeyEncoding, TableName, TOrgBots } from "../schemas";
|
||||||
import { getMigrationEnvConfig } from "./utils/env-config";
|
import { getMigrationEnvConfig, getMigrationHsmConfig } from "./utils/env-config";
|
||||||
import { createCircularCache } from "./utils/ring-buffer";
|
import { createCircularCache } from "./utils/ring-buffer";
|
||||||
import { getMigrationEncryptionServices } from "./utils/services";
|
import { getMigrationEncryptionServices, getMigrationHsmService } from "./utils/services";
|
||||||
|
|
||||||
const BATCH_SIZE = 500;
|
const BATCH_SIZE = 500;
|
||||||
const reencryptIdentityOidcAuth = async (knex: Knex) => {
|
const reencryptIdentityOidcAuth = async (knex: Knex) => {
|
||||||
@@ -35,8 +36,11 @@ const reencryptIdentityOidcAuth = async (knex: Knex) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initLogger();
|
initLogger();
|
||||||
|
const { hsmService } = await getMigrationHsmService({ envConfig: getMigrationHsmConfig() });
|
||||||
|
|
||||||
const superAdminDAL = superAdminDALFactory(knex);
|
const superAdminDAL = superAdminDALFactory(knex);
|
||||||
const envConfig = await getMigrationEnvConfig(superAdminDAL);
|
const kmsRootConfigDAL = kmsRootConfigDALFactory(knex);
|
||||||
|
const envConfig = await getMigrationEnvConfig(superAdminDAL, hsmService, kmsRootConfigDAL);
|
||||||
|
|
||||||
const keyStore = inMemoryKeyStore();
|
const keyStore = inMemoryKeyStore();
|
||||||
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
||||||
|
|||||||
@@ -4,16 +4,18 @@ import { inMemoryKeyStore } from "@app/keystore/memory";
|
|||||||
import { crypto, SymmetricKeySize } from "@app/lib/crypto/cryptography";
|
import { crypto, SymmetricKeySize } from "@app/lib/crypto/cryptography";
|
||||||
import { selectAllTableCols } from "@app/lib/knex";
|
import { selectAllTableCols } from "@app/lib/knex";
|
||||||
import { initLogger } from "@app/lib/logger";
|
import { initLogger } from "@app/lib/logger";
|
||||||
|
import { kmsRootConfigDALFactory } from "@app/services/kms/kms-root-config-dal";
|
||||||
|
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 { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||||
|
|
||||||
import { SecretKeyEncoding, TableName } from "../schemas";
|
import { SecretKeyEncoding, TableName } from "../schemas";
|
||||||
import { getMigrationEnvConfig } from "./utils/env-config";
|
import { getMigrationEnvConfig, getMigrationHsmConfig } from "./utils/env-config";
|
||||||
import { createCircularCache } from "./utils/ring-buffer";
|
import { createCircularCache } from "./utils/ring-buffer";
|
||||||
import { getMigrationEncryptionServices } from "./utils/services";
|
import { getMigrationEncryptionServices, getMigrationHsmService } from "./utils/services";
|
||||||
|
|
||||||
const BATCH_SIZE = 500;
|
const BATCH_SIZE = 500;
|
||||||
const reencryptSamlConfig = async (knex: Knex) => {
|
const reencryptSamlConfig = async (knex: Knex, kmsService: TKmsServiceFactory) => {
|
||||||
const hasEncryptedEntrypointColumn = await knex.schema.hasColumn(TableName.SamlConfig, "encryptedSamlEntryPoint");
|
const hasEncryptedEntrypointColumn = await knex.schema.hasColumn(TableName.SamlConfig, "encryptedSamlEntryPoint");
|
||||||
const hasEncryptedIssuerColumn = await knex.schema.hasColumn(TableName.SamlConfig, "encryptedSamlIssuer");
|
const hasEncryptedIssuerColumn = await knex.schema.hasColumn(TableName.SamlConfig, "encryptedSamlIssuer");
|
||||||
const hasEncryptedCertificateColumn = await knex.schema.hasColumn(TableName.SamlConfig, "encryptedSamlCertificate");
|
const hasEncryptedCertificateColumn = await knex.schema.hasColumn(TableName.SamlConfig, "encryptedSamlCertificate");
|
||||||
@@ -28,10 +30,6 @@ const reencryptSamlConfig = async (knex: Knex) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initLogger();
|
initLogger();
|
||||||
const superAdminDAL = superAdminDALFactory(knex);
|
|
||||||
const envConfig = await getMigrationEnvConfig(superAdminDAL);
|
|
||||||
const keyStore = inMemoryKeyStore();
|
|
||||||
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
|
||||||
const orgEncryptionRingBuffer =
|
const orgEncryptionRingBuffer =
|
||||||
createCircularCache<Awaited<ReturnType<(typeof kmsService)["createCipherPairWithDataKey"]>>>(25);
|
createCircularCache<Awaited<ReturnType<(typeof kmsService)["createCipherPairWithDataKey"]>>>(25);
|
||||||
|
|
||||||
@@ -159,7 +157,7 @@ const reencryptSamlConfig = async (knex: Knex) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const reencryptLdapConfig = async (knex: Knex) => {
|
const reencryptLdapConfig = async (knex: Knex, kmsService: TKmsServiceFactory) => {
|
||||||
const hasEncryptedLdapBindDNColum = await knex.schema.hasColumn(TableName.LdapConfig, "encryptedLdapBindDN");
|
const hasEncryptedLdapBindDNColum = await knex.schema.hasColumn(TableName.LdapConfig, "encryptedLdapBindDN");
|
||||||
const hasEncryptedLdapBindPassColumn = await knex.schema.hasColumn(TableName.LdapConfig, "encryptedLdapBindPass");
|
const hasEncryptedLdapBindPassColumn = await knex.schema.hasColumn(TableName.LdapConfig, "encryptedLdapBindPass");
|
||||||
const hasEncryptedCertificateColumn = await knex.schema.hasColumn(TableName.LdapConfig, "encryptedLdapCaCertificate");
|
const hasEncryptedCertificateColumn = await knex.schema.hasColumn(TableName.LdapConfig, "encryptedLdapCaCertificate");
|
||||||
@@ -194,10 +192,6 @@ const reencryptLdapConfig = async (knex: Knex) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initLogger();
|
initLogger();
|
||||||
const superAdminDAL = superAdminDALFactory(knex);
|
|
||||||
const envConfig = await getMigrationEnvConfig(superAdminDAL);
|
|
||||||
const keyStore = inMemoryKeyStore();
|
|
||||||
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
|
||||||
const orgEncryptionRingBuffer =
|
const orgEncryptionRingBuffer =
|
||||||
createCircularCache<Awaited<ReturnType<(typeof kmsService)["createCipherPairWithDataKey"]>>>(25);
|
createCircularCache<Awaited<ReturnType<(typeof kmsService)["createCipherPairWithDataKey"]>>>(25);
|
||||||
|
|
||||||
@@ -323,7 +317,7 @@ const reencryptLdapConfig = async (knex: Knex) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const reencryptOidcConfig = async (knex: Knex) => {
|
const reencryptOidcConfig = async (knex: Knex, kmsService: TKmsServiceFactory) => {
|
||||||
const hasEncryptedOidcClientIdColumn = await knex.schema.hasColumn(TableName.OidcConfig, "encryptedOidcClientId");
|
const hasEncryptedOidcClientIdColumn = await knex.schema.hasColumn(TableName.OidcConfig, "encryptedOidcClientId");
|
||||||
const hasEncryptedOidcClientSecretColumn = await knex.schema.hasColumn(
|
const hasEncryptedOidcClientSecretColumn = await knex.schema.hasColumn(
|
||||||
TableName.OidcConfig,
|
TableName.OidcConfig,
|
||||||
@@ -354,10 +348,6 @@ const reencryptOidcConfig = async (knex: Knex) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initLogger();
|
initLogger();
|
||||||
const superAdminDAL = superAdminDALFactory(knex);
|
|
||||||
const envConfig = await getMigrationEnvConfig(superAdminDAL);
|
|
||||||
const keyStore = inMemoryKeyStore();
|
|
||||||
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
|
||||||
const orgEncryptionRingBuffer =
|
const orgEncryptionRingBuffer =
|
||||||
createCircularCache<Awaited<ReturnType<(typeof kmsService)["createCipherPairWithDataKey"]>>>(25);
|
createCircularCache<Awaited<ReturnType<(typeof kmsService)["createCipherPairWithDataKey"]>>>(25);
|
||||||
|
|
||||||
@@ -462,9 +452,18 @@ const reencryptOidcConfig = async (knex: Knex) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export async function up(knex: Knex): Promise<void> {
|
export async function up(knex: Knex): Promise<void> {
|
||||||
await reencryptSamlConfig(knex);
|
initLogger();
|
||||||
await reencryptLdapConfig(knex);
|
|
||||||
await reencryptOidcConfig(knex);
|
const { hsmService } = await getMigrationHsmService({ envConfig: getMigrationHsmConfig() });
|
||||||
|
const superAdminDAL = superAdminDALFactory(knex);
|
||||||
|
const kmsRootConfigDAL = kmsRootConfigDALFactory(knex);
|
||||||
|
const envConfig = await getMigrationEnvConfig(superAdminDAL, hsmService, kmsRootConfigDAL);
|
||||||
|
const keyStore = inMemoryKeyStore();
|
||||||
|
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
||||||
|
|
||||||
|
await reencryptSamlConfig(knex, kmsService);
|
||||||
|
await reencryptLdapConfig(knex, kmsService);
|
||||||
|
await reencryptOidcConfig(knex, kmsService);
|
||||||
}
|
}
|
||||||
|
|
||||||
const dropSamlConfigColumns = async (knex: Knex) => {
|
const dropSamlConfigColumns = async (knex: Knex) => {
|
||||||
|
|||||||
@@ -3,12 +3,13 @@ import { Knex } from "knex";
|
|||||||
import { inMemoryKeyStore } from "@app/keystore/memory";
|
import { inMemoryKeyStore } from "@app/keystore/memory";
|
||||||
import { selectAllTableCols } from "@app/lib/knex";
|
import { selectAllTableCols } from "@app/lib/knex";
|
||||||
import { initLogger } from "@app/lib/logger";
|
import { initLogger } from "@app/lib/logger";
|
||||||
|
import { kmsRootConfigDALFactory } from "@app/services/kms/kms-root-config-dal";
|
||||||
import { KmsDataKey } from "@app/services/kms/kms-types";
|
import { KmsDataKey } from "@app/services/kms/kms-types";
|
||||||
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||||
|
|
||||||
import { TableName } from "../schemas";
|
import { TableName } from "../schemas";
|
||||||
import { getMigrationEnvConfig } from "./utils/env-config";
|
import { getMigrationEnvConfig, getMigrationHsmConfig } from "./utils/env-config";
|
||||||
import { getMigrationEncryptionServices } from "./utils/services";
|
import { getMigrationEncryptionServices, getMigrationHsmService } from "./utils/services";
|
||||||
|
|
||||||
// Note(daniel): We aren't dropping tables or columns in this migrations so we can easily rollback if needed.
|
// Note(daniel): We aren't dropping tables or columns in this migrations so we can easily rollback if needed.
|
||||||
// In the future we need to drop the projectGatewayId on the dynamic secrets table, and drop the project_gateways table entirely.
|
// In the future we need to drop the projectGatewayId on the dynamic secrets table, and drop the project_gateways table entirely.
|
||||||
@@ -40,8 +41,10 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
initLogger();
|
initLogger();
|
||||||
|
const { hsmService } = await getMigrationHsmService({ envConfig: getMigrationHsmConfig() });
|
||||||
const superAdminDAL = superAdminDALFactory(knex);
|
const superAdminDAL = superAdminDALFactory(knex);
|
||||||
const envConfig = await getMigrationEnvConfig(superAdminDAL);
|
const kmsRootConfigDAL = kmsRootConfigDALFactory(knex);
|
||||||
|
const envConfig = await getMigrationEnvConfig(superAdminDAL, hsmService, kmsRootConfigDAL);
|
||||||
const keyStore = inMemoryKeyStore();
|
const keyStore = inMemoryKeyStore();
|
||||||
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
||||||
|
|
||||||
|
|||||||
@@ -2,19 +2,23 @@ import { Knex } from "knex";
|
|||||||
|
|
||||||
import { inMemoryKeyStore } from "@app/keystore/memory";
|
import { inMemoryKeyStore } from "@app/keystore/memory";
|
||||||
import { selectAllTableCols } from "@app/lib/knex";
|
import { selectAllTableCols } from "@app/lib/knex";
|
||||||
|
import { kmsRootConfigDALFactory } from "@app/services/kms/kms-root-config-dal";
|
||||||
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||||
|
|
||||||
import { TableName } from "../schemas";
|
import { TableName } from "../schemas";
|
||||||
import { getMigrationEnvConfig } from "./utils/env-config";
|
import { getMigrationEnvConfig, getMigrationHsmConfig } from "./utils/env-config";
|
||||||
import { getMigrationEncryptionServices } from "./utils/services";
|
import { getMigrationEncryptionServices, getMigrationHsmService } from "./utils/services";
|
||||||
|
|
||||||
export async function up(knex: Knex) {
|
export async function up(knex: Knex) {
|
||||||
const existingSuperAdminsWithGithubConnection = await knex(TableName.SuperAdmin)
|
const existingSuperAdminsWithGithubConnection = await knex(TableName.SuperAdmin)
|
||||||
.select(selectAllTableCols(TableName.SuperAdmin))
|
.select(selectAllTableCols(TableName.SuperAdmin))
|
||||||
.whereNotNull(`${TableName.SuperAdmin}.encryptedGitHubAppConnectionClientId`);
|
.whereNotNull(`${TableName.SuperAdmin}.encryptedGitHubAppConnectionClientId`);
|
||||||
|
|
||||||
|
const { hsmService } = await getMigrationHsmService({ envConfig: getMigrationHsmConfig() });
|
||||||
|
|
||||||
const superAdminDAL = superAdminDALFactory(knex);
|
const superAdminDAL = superAdminDALFactory(knex);
|
||||||
const envConfig = await getMigrationEnvConfig(superAdminDAL);
|
const kmsRootConfigDAL = kmsRootConfigDALFactory(knex);
|
||||||
|
const envConfig = await getMigrationEnvConfig(superAdminDAL, hsmService, kmsRootConfigDAL);
|
||||||
const keyStore = inMemoryKeyStore();
|
const keyStore = inMemoryKeyStore();
|
||||||
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
||||||
|
|
||||||
|
|||||||
@@ -2,13 +2,14 @@ import { Knex } from "knex";
|
|||||||
|
|
||||||
import { inMemoryKeyStore } from "@app/keystore/memory";
|
import { inMemoryKeyStore } from "@app/keystore/memory";
|
||||||
import { crypto } from "@app/lib/crypto/cryptography";
|
import { crypto } from "@app/lib/crypto/cryptography";
|
||||||
|
import { kmsRootConfigDALFactory } from "@app/services/kms/kms-root-config-dal";
|
||||||
import { KmsDataKey } from "@app/services/kms/kms-types";
|
import { KmsDataKey } from "@app/services/kms/kms-types";
|
||||||
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||||
|
|
||||||
import { SecretKeyEncoding, TableName } from "../schemas";
|
import { SecretKeyEncoding, TableName } from "../schemas";
|
||||||
import { getMigrationEnvConfig } from "./utils/env-config";
|
import { getMigrationEnvConfig, getMigrationHsmConfig } from "./utils/env-config";
|
||||||
import { createCircularCache } from "./utils/ring-buffer";
|
import { createCircularCache } from "./utils/ring-buffer";
|
||||||
import { getMigrationEncryptionServices } from "./utils/services";
|
import { getMigrationEncryptionServices, getMigrationHsmService } from "./utils/services";
|
||||||
|
|
||||||
const BATCH_SIZE = 500;
|
const BATCH_SIZE = 500;
|
||||||
export async function up(knex: Knex): Promise<void> {
|
export async function up(knex: Knex): Promise<void> {
|
||||||
@@ -25,8 +26,10 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!hasEncryptedCredentials) {
|
if (!hasEncryptedCredentials) {
|
||||||
|
const { hsmService } = await getMigrationHsmService({ envConfig: getMigrationHsmConfig() });
|
||||||
const superAdminDAL = superAdminDALFactory(knex);
|
const superAdminDAL = superAdminDALFactory(knex);
|
||||||
const envConfig = await getMigrationEnvConfig(superAdminDAL);
|
const kmsRootConfigDAL = kmsRootConfigDALFactory(knex);
|
||||||
|
const envConfig = await getMigrationEnvConfig(superAdminDAL, hsmService, kmsRootConfigDAL);
|
||||||
const keyStore = inMemoryKeyStore();
|
const keyStore = inMemoryKeyStore();
|
||||||
|
|
||||||
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
||||||
@@ -131,8 +134,11 @@ export async function down(knex: Knex): Promise<void> {
|
|||||||
const hasEncryptedCredentials = await knex.schema.hasColumn(TableName.AuditLogStream, "encryptedCredentials");
|
const hasEncryptedCredentials = await knex.schema.hasColumn(TableName.AuditLogStream, "encryptedCredentials");
|
||||||
|
|
||||||
if (hasEncryptedCredentials) {
|
if (hasEncryptedCredentials) {
|
||||||
|
const { hsmService } = await getMigrationHsmService({ envConfig: getMigrationHsmConfig() });
|
||||||
|
|
||||||
const superAdminDAL = superAdminDALFactory(knex);
|
const superAdminDAL = superAdminDALFactory(knex);
|
||||||
const envConfig = await getMigrationEnvConfig(superAdminDAL);
|
const kmsRootConfigDAL = kmsRootConfigDALFactory(knex);
|
||||||
|
const envConfig = await getMigrationEnvConfig(superAdminDAL, hsmService, kmsRootConfigDAL);
|
||||||
const keyStore = inMemoryKeyStore();
|
const keyStore = inMemoryKeyStore();
|
||||||
|
|
||||||
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
const { kmsService } = await getMigrationEncryptionServices({ envConfig, keyStore, db: knex });
|
||||||
|
|||||||
@@ -0,0 +1,165 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
// PAM Folders
|
||||||
|
if (!(await knex.schema.hasTable(TableName.PamFolder))) {
|
||||||
|
await knex.schema.createTable(TableName.PamFolder, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
|
||||||
|
t.string("projectId").notNullable();
|
||||||
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
|
t.index("projectId");
|
||||||
|
|
||||||
|
t.uuid("parentId").nullable();
|
||||||
|
t.foreign("parentId").references("id").inTable(TableName.PamFolder).onDelete("CASCADE");
|
||||||
|
t.index("parentId");
|
||||||
|
|
||||||
|
t.string("name").notNullable();
|
||||||
|
t.index("name");
|
||||||
|
|
||||||
|
// Enforce uniqueness for sub-folders
|
||||||
|
t.unique(["projectId", "parentId", "name"], {
|
||||||
|
indexName: "uidx_pam_folder_children_name",
|
||||||
|
predicate: knex.whereNotNull("parentId")
|
||||||
|
});
|
||||||
|
|
||||||
|
// Enforce uniqueness for root-level folders
|
||||||
|
t.unique(["projectId", "name"], {
|
||||||
|
indexName: "uidx_pam_folder_root_name",
|
||||||
|
predicate: knex.whereNull("parentId")
|
||||||
|
});
|
||||||
|
|
||||||
|
t.text("description").nullable();
|
||||||
|
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// PAM Resources
|
||||||
|
if (!(await knex.schema.hasTable(TableName.PamResource))) {
|
||||||
|
await knex.schema.createTable(TableName.PamResource, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
|
||||||
|
t.string("projectId").notNullable();
|
||||||
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
|
t.index("projectId");
|
||||||
|
|
||||||
|
t.string("name").notNullable();
|
||||||
|
t.index("name");
|
||||||
|
|
||||||
|
t.uuid("gatewayId").notNullable();
|
||||||
|
t.foreign("gatewayId").references("id").inTable(TableName.GatewayV2);
|
||||||
|
t.index("gatewayId");
|
||||||
|
|
||||||
|
t.string("resourceType").notNullable();
|
||||||
|
t.index("resourceType");
|
||||||
|
|
||||||
|
t.binary("encryptedConnectionDetails").notNullable();
|
||||||
|
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// PAM Accounts
|
||||||
|
if (!(await knex.schema.hasTable(TableName.PamAccount))) {
|
||||||
|
await knex.schema.createTable(TableName.PamAccount, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
|
||||||
|
t.string("projectId").notNullable();
|
||||||
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
|
t.index("projectId");
|
||||||
|
|
||||||
|
t.uuid("folderId").nullable();
|
||||||
|
t.foreign("folderId").references("id").inTable(TableName.PamFolder).onDelete("CASCADE");
|
||||||
|
t.index("folderId");
|
||||||
|
|
||||||
|
t.uuid("resourceId").notNullable();
|
||||||
|
t.foreign("resourceId").references("id").inTable(TableName.PamResource);
|
||||||
|
t.index("resourceId");
|
||||||
|
|
||||||
|
t.string("name").notNullable();
|
||||||
|
t.index("name");
|
||||||
|
|
||||||
|
// Enforce uniqueness for folders
|
||||||
|
t.unique(["projectId", "folderId", "name"], {
|
||||||
|
indexName: "uidx_pam_account_children_name",
|
||||||
|
predicate: knex.whereNotNull("folderId")
|
||||||
|
});
|
||||||
|
|
||||||
|
// Enforce uniqueness for root-level
|
||||||
|
t.unique(["projectId", "name"], {
|
||||||
|
indexName: "uidx_pam_account_root_name",
|
||||||
|
predicate: knex.whereNull("folderId")
|
||||||
|
});
|
||||||
|
|
||||||
|
t.text("description").nullable();
|
||||||
|
t.binary("encryptedCredentials").notNullable();
|
||||||
|
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// PAM Sessions
|
||||||
|
if (!(await knex.schema.hasTable(TableName.PamSession))) {
|
||||||
|
await knex.schema.createTable(TableName.PamSession, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
|
||||||
|
t.string("projectId").notNullable();
|
||||||
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
|
t.index("projectId");
|
||||||
|
|
||||||
|
t.uuid("accountId").nullable();
|
||||||
|
t.foreign("accountId").references("id").inTable(TableName.PamAccount).onDelete("SET NULL");
|
||||||
|
t.index("accountId");
|
||||||
|
|
||||||
|
// To be used in the event of an account deletion
|
||||||
|
t.string("resourceType").notNullable();
|
||||||
|
t.string("resourceName").notNullable();
|
||||||
|
t.string("accountName").notNullable();
|
||||||
|
|
||||||
|
t.uuid("userId").nullable();
|
||||||
|
t.foreign("userId").references("id").inTable(TableName.Users).onDelete("SET NULL");
|
||||||
|
t.index("userId");
|
||||||
|
|
||||||
|
// To be used in the event of user deletion
|
||||||
|
t.string("actorName").notNullable();
|
||||||
|
t.string("actorEmail").notNullable();
|
||||||
|
|
||||||
|
t.string("actorIp").notNullable();
|
||||||
|
t.string("actorUserAgent").notNullable();
|
||||||
|
|
||||||
|
t.string("status").notNullable();
|
||||||
|
t.index("status");
|
||||||
|
|
||||||
|
t.binary("encryptedLogsBlob").nullable();
|
||||||
|
|
||||||
|
t.datetime("expiresAt").notNullable();
|
||||||
|
|
||||||
|
t.datetime("startedAt").nullable(); // Not when the row is created, but when the end-to-end connection between user and resource is established
|
||||||
|
t.datetime("endedAt").nullable();
|
||||||
|
t.index(["startedAt", "endedAt"]);
|
||||||
|
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await createOnUpdateTrigger(knex, TableName.PamFolder);
|
||||||
|
await createOnUpdateTrigger(knex, TableName.PamResource);
|
||||||
|
await createOnUpdateTrigger(knex, TableName.PamAccount);
|
||||||
|
await createOnUpdateTrigger(knex, TableName.PamSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.PamSession);
|
||||||
|
await knex.schema.dropTableIfExists(TableName.PamAccount);
|
||||||
|
await knex.schema.dropTableIfExists(TableName.PamResource);
|
||||||
|
await knex.schema.dropTableIfExists(TableName.PamFolder);
|
||||||
|
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.PamSession);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.PamAccount);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.PamResource);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.PamFolder);
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasColumn(TableName.GatewayV2, "encryptedPamSessionKey"))) {
|
||||||
|
await knex.schema.alterTable(TableName.GatewayV2, (t) => {
|
||||||
|
t.binary("encryptedPamSessionKey");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
if (await knex.schema.hasColumn(TableName.GatewayV2, "encryptedPamSessionKey")) {
|
||||||
|
await knex.schema.alterTable(TableName.GatewayV2, (t) => {
|
||||||
|
t.dropColumn("encryptedPamSessionKey");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,117 @@
|
|||||||
|
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.PkiCertificateTemplateV2))) {
|
||||||
|
await knex.schema.createTable(TableName.PkiCertificateTemplateV2, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("projectId").notNullable();
|
||||||
|
t.foreign("projectId").references("id").inTable(TableName.Project);
|
||||||
|
|
||||||
|
t.string("name").notNullable();
|
||||||
|
t.string("description");
|
||||||
|
|
||||||
|
t.jsonb("subject");
|
||||||
|
t.jsonb("sans");
|
||||||
|
t.jsonb("keyUsages");
|
||||||
|
t.jsonb("extendedKeyUsages");
|
||||||
|
t.jsonb("algorithms");
|
||||||
|
t.jsonb("validity");
|
||||||
|
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
|
||||||
|
t.unique(["name", "projectId"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
await createOnUpdateTrigger(knex, TableName.PkiCertificateTemplateV2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(await knex.schema.hasTable(TableName.PkiEstEnrollmentConfig))) {
|
||||||
|
await knex.schema.createTable(TableName.PkiEstEnrollmentConfig, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
|
||||||
|
t.boolean("disableBootstrapCaValidation").defaultTo(false);
|
||||||
|
t.text("hashedPassphrase").notNullable();
|
||||||
|
t.binary("encryptedCaChain");
|
||||||
|
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
await createOnUpdateTrigger(knex, TableName.PkiEstEnrollmentConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(await knex.schema.hasTable(TableName.PkiApiEnrollmentConfig))) {
|
||||||
|
await knex.schema.createTable(TableName.PkiApiEnrollmentConfig, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
|
||||||
|
t.boolean("autoRenew").defaultTo(false);
|
||||||
|
t.integer("autoRenewDays");
|
||||||
|
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
await createOnUpdateTrigger(knex, TableName.PkiApiEnrollmentConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(await knex.schema.hasTable(TableName.PkiCertificateProfile))) {
|
||||||
|
await knex.schema.createTable(TableName.PkiCertificateProfile, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("projectId").notNullable();
|
||||||
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
|
|
||||||
|
t.uuid("caId").notNullable();
|
||||||
|
t.foreign("caId").references("id").inTable(TableName.CertificateAuthority);
|
||||||
|
|
||||||
|
t.uuid("certificateTemplateId").notNullable();
|
||||||
|
t.foreign("certificateTemplateId").references("id").inTable(TableName.PkiCertificateTemplateV2);
|
||||||
|
|
||||||
|
t.string("slug").notNullable();
|
||||||
|
t.string("description");
|
||||||
|
t.string("enrollmentType").notNullable().checkIn(["api", "est"]);
|
||||||
|
|
||||||
|
t.uuid("estConfigId");
|
||||||
|
t.foreign("estConfigId").references("id").inTable(TableName.PkiEstEnrollmentConfig).onDelete("SET NULL");
|
||||||
|
|
||||||
|
t.uuid("apiConfigId");
|
||||||
|
t.foreign("apiConfigId").references("id").inTable(TableName.PkiApiEnrollmentConfig).onDelete("SET NULL");
|
||||||
|
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
|
||||||
|
t.unique(["slug", "projectId"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
await createOnUpdateTrigger(knex, TableName.PkiCertificateProfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(await knex.schema.hasColumn(TableName.Certificate, "profileId"))) {
|
||||||
|
await knex.schema.alterTable(TableName.Certificate, (t) => {
|
||||||
|
t.uuid("profileId");
|
||||||
|
t.foreign("profileId").references("id").inTable(TableName.PkiCertificateProfile).onDelete("SET NULL");
|
||||||
|
t.index("profileId");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
if (await knex.schema.hasColumn(TableName.Certificate, "profileId")) {
|
||||||
|
await knex.schema.alterTable(TableName.Certificate, (t) => {
|
||||||
|
t.dropForeign(["profileId"]);
|
||||||
|
t.dropIndex("profileId");
|
||||||
|
t.dropColumn("profileId");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await knex.schema.dropTableIfExists(TableName.PkiCertificateProfile);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.PkiCertificateProfile);
|
||||||
|
|
||||||
|
await knex.schema.dropTableIfExists(TableName.PkiApiEnrollmentConfig);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.PkiApiEnrollmentConfig);
|
||||||
|
|
||||||
|
await knex.schema.dropTableIfExists(TableName.PkiEstEnrollmentConfig);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.PkiEstEnrollmentConfig);
|
||||||
|
|
||||||
|
await knex.schema.dropTableIfExists(TableName.PkiCertificateTemplateV2);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.PkiCertificateTemplateV2);
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasColumn(TableName.Relay, "heartbeat"))) {
|
||||||
|
await knex.schema.alterTable(TableName.Relay, (t) => {
|
||||||
|
t.datetime("heartbeat");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
if (await knex.schema.hasColumn(TableName.Relay, "heartbeat")) {
|
||||||
|
await knex.schema.alterTable(TableName.Relay, (t) => {
|
||||||
|
t.dropColumn("heartbeat");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasColumn(TableName.Relay, "healthAlertedAt"))) {
|
||||||
|
await knex.schema.alterTable(TableName.Relay, (t) => {
|
||||||
|
t.datetime("healthAlertedAt");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!(await knex.schema.hasColumn(TableName.GatewayV2, "healthAlertedAt"))) {
|
||||||
|
await knex.schema.alterTable(TableName.GatewayV2, (t) => {
|
||||||
|
t.datetime("healthAlertedAt");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
if (await knex.schema.hasColumn(TableName.GatewayV2, "healthAlertedAt")) {
|
||||||
|
await knex.schema.alterTable(TableName.GatewayV2, (t) => {
|
||||||
|
t.dropColumn("healthAlertedAt");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (await knex.schema.hasColumn(TableName.Relay, "healthAlertedAt")) {
|
||||||
|
await knex.schema.alterTable(TableName.Relay, (t) => {
|
||||||
|
t.dropColumn("healthAlertedAt");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasColumn(TableName.KmsKey, "kmipMetadata"))) {
|
||||||
|
await knex.schema.alterTable(TableName.KmsKey, (t) => {
|
||||||
|
t.jsonb("kmipMetadata");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
if (await knex.schema.hasColumn(TableName.KmsKey, "kmipMetadata")) {
|
||||||
|
await knex.schema.alterTable(TableName.KmsKey, (t) => {
|
||||||
|
t.dropColumn("kmipMetadata");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
const hasScopeColumn = await knex.schema.hasColumn(TableName.Membership, "scope");
|
||||||
|
const hasActorIdentityColumn = await knex.schema.hasColumn(TableName.Membership, "actorIdentityId");
|
||||||
|
if (hasScopeColumn && hasActorIdentityColumn) {
|
||||||
|
await knex.schema.alterTable(TableName.Membership, (t) => {
|
||||||
|
t.index(["scope", "actorIdentityId"]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
const hasScopeColumn = await knex.schema.hasColumn(TableName.Membership, "scope");
|
||||||
|
const hasActorIdentityColumn = await knex.schema.hasColumn(TableName.Membership, "actorIdentityId");
|
||||||
|
if (hasScopeColumn && hasActorIdentityColumn) {
|
||||||
|
await knex.schema.alterTable(TableName.Membership, (t) => {
|
||||||
|
t.dropIndex(["scope", "actorIdentityId"]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
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.VaultExternalMigrationConfig))) {
|
||||||
|
await knex.schema.createTable(TableName.VaultExternalMigrationConfig, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.uuid("orgId").notNullable();
|
||||||
|
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||||
|
|
||||||
|
t.string("namespace").notNullable();
|
||||||
|
|
||||||
|
t.uuid("connectionId");
|
||||||
|
t.foreign("connectionId").references("id").inTable(TableName.AppConnection);
|
||||||
|
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.unique(["orgId", "namespace"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
await createOnUpdateTrigger(knex, TableName.VaultExternalMigrationConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.VaultExternalMigrationConfig);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.VaultExternalMigrationConfig);
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasColumn(TableName.PamAccount, "rotationEnabled"))) {
|
||||||
|
await knex.schema.alterTable(TableName.PamAccount, (t) => {
|
||||||
|
t.boolean("rotationEnabled").notNullable().defaultTo(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!(await knex.schema.hasColumn(TableName.PamAccount, "rotationIntervalSeconds"))) {
|
||||||
|
await knex.schema.alterTable(TableName.PamAccount, (t) => {
|
||||||
|
t.integer("rotationIntervalSeconds").nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!(await knex.schema.hasColumn(TableName.PamAccount, "lastRotatedAt"))) {
|
||||||
|
await knex.schema.alterTable(TableName.PamAccount, (t) => {
|
||||||
|
t.timestamp("lastRotatedAt").nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!(await knex.schema.hasColumn(TableName.PamResource, "encryptedRotationAccountCredentials"))) {
|
||||||
|
await knex.schema.alterTable(TableName.PamResource, (t) => {
|
||||||
|
t.binary("encryptedRotationAccountCredentials").nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
if (await knex.schema.hasColumn(TableName.PamResource, "encryptedRotationAccountCredentials")) {
|
||||||
|
await knex.schema.alterTable(TableName.PamResource, (t) => {
|
||||||
|
t.dropColumn("encryptedRotationAccountCredentials");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (await knex.schema.hasColumn(TableName.PamAccount, "rotationEnabled")) {
|
||||||
|
await knex.schema.alterTable(TableName.PamAccount, (t) => {
|
||||||
|
t.dropColumn("rotationEnabled");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (await knex.schema.hasColumn(TableName.PamAccount, "rotationIntervalSeconds")) {
|
||||||
|
await knex.schema.alterTable(TableName.PamAccount, (t) => {
|
||||||
|
t.dropColumn("rotationIntervalSeconds");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (await knex.schema.hasColumn(TableName.PamAccount, "lastRotatedAt")) {
|
||||||
|
await knex.schema.alterTable(TableName.PamAccount, (t) => {
|
||||||
|
t.dropColumn("lastRotatedAt");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { dropConstraintIfExists } from "@app/db/migrations/utils/dropConstraintIfExists";
|
||||||
|
|
||||||
|
import { AccessScope, TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
const hasParentOrgId = await knex.schema.hasColumn(TableName.Organization, "parentOrgId");
|
||||||
|
if (!hasParentOrgId) {
|
||||||
|
await knex.schema.alterTable(TableName.Organization, async (t) => {
|
||||||
|
// the one just above the chain
|
||||||
|
t.uuid("parentOrgId");
|
||||||
|
t.foreign("parentOrgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||||
|
// this would root organization containing various informations like billing etc
|
||||||
|
t.uuid("rootOrgId");
|
||||||
|
t.foreign("rootOrgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||||
|
|
||||||
|
await dropConstraintIfExists(TableName.Organization, "organizations_slug_unique", knex);
|
||||||
|
t.unique(["rootOrgId", "parentOrgId", "slug"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// had to switch to raw for null not distinct
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasIdentityOrgCol = await knex.schema.hasColumn(TableName.Identity, "orgId");
|
||||||
|
if (!hasIdentityOrgCol) {
|
||||||
|
await knex.schema.alterTable(TableName.Identity, (t) => {
|
||||||
|
t.uuid("orgId");
|
||||||
|
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
|
||||||
|
await knex.raw(
|
||||||
|
`
|
||||||
|
UPDATE ?? AS identity
|
||||||
|
SET "orgId" = membership."scopeOrgId"
|
||||||
|
FROM ?? AS membership
|
||||||
|
WHERE
|
||||||
|
membership."actorIdentityId" = identity."id"
|
||||||
|
AND membership."scope" = ?
|
||||||
|
`,
|
||||||
|
[TableName.Identity, TableName.Membership, AccessScope.Organization]
|
||||||
|
);
|
||||||
|
|
||||||
|
await knex.raw(`DELETE FROM ?? WHERE "orgId" IS NULL`, [TableName.Identity]);
|
||||||
|
|
||||||
|
await knex.schema.alterTable(TableName.Identity, (t) => {
|
||||||
|
t.uuid("orgId").notNullable().alter();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
const hasParentOrgId = await knex.schema.hasColumn(TableName.Organization, "parentOrgId");
|
||||||
|
const hasRootOrgId = await knex.schema.hasColumn(TableName.Organization, "rootOrgId");
|
||||||
|
if (hasParentOrgId || hasRootOrgId) {
|
||||||
|
await knex.schema.alterTable(TableName.Organization, (t) => {
|
||||||
|
if (hasParentOrgId) t.dropColumn("parentOrgId");
|
||||||
|
if (hasRootOrgId) t.dropColumn("rootOrgId");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasIdentityOrgCol = await knex.schema.hasColumn(TableName.Identity, "orgId");
|
||||||
|
if (hasIdentityOrgCol) {
|
||||||
|
await knex.schema.alterTable(TableName.Identity, (t) => {
|
||||||
|
t.dropColumn("orgId");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { AccessScope, TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
const hasGroupsTable = await knex.schema.hasTable(TableName.Groups);
|
||||||
|
const hasMembershipTable = await knex.schema.hasTable(TableName.Membership);
|
||||||
|
const hasMembershipRoleTable = await knex.schema.hasTable(TableName.MembershipRole);
|
||||||
|
|
||||||
|
if (!hasGroupsTable || !hasMembershipTable || !hasMembershipRoleTable) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const groupsWithoutMembership = await knex
|
||||||
|
.select(
|
||||||
|
`${TableName.Groups}.id`,
|
||||||
|
`${TableName.Groups}.orgId`,
|
||||||
|
`${TableName.Groups}.role`,
|
||||||
|
`${TableName.Groups}.roleId`
|
||||||
|
)
|
||||||
|
.from(TableName.Groups)
|
||||||
|
.leftJoin(TableName.Membership, `${TableName.Groups}.id`, `${TableName.Membership}.actorGroupId`)
|
||||||
|
.whereNull(`${TableName.Membership}.actorGroupId`);
|
||||||
|
|
||||||
|
if (groupsWithoutMembership.length > 0) {
|
||||||
|
const membershipInserts = groupsWithoutMembership.map((group) => ({
|
||||||
|
actorGroupId: group.id,
|
||||||
|
scope: AccessScope.Organization,
|
||||||
|
scopeOrgId: group.orgId,
|
||||||
|
isActive: true
|
||||||
|
}));
|
||||||
|
|
||||||
|
const insertedMemberships = await knex(TableName.Membership).insert(membershipInserts).returning("*");
|
||||||
|
|
||||||
|
const membershipRoleInserts = insertedMemberships.map((membership, index) => {
|
||||||
|
const group = groupsWithoutMembership[index];
|
||||||
|
return {
|
||||||
|
membershipId: membership.id,
|
||||||
|
role: group.role,
|
||||||
|
customRoleId: group.roleId
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
await knex(TableName.MembershipRole).insert(membershipRoleInserts);
|
||||||
|
}
|
||||||
|
|
||||||
|
await knex.schema.alterTable(TableName.Membership, (t) => {
|
||||||
|
t.check(
|
||||||
|
`("actorUserId" IS NOT NULL OR "actorIdentityId" IS NOT NULL OR "actorGroupId" IS NOT NULL)`,
|
||||||
|
undefined,
|
||||||
|
"at_least_one_actor"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.alterTable(TableName.Membership, (t) => {
|
||||||
|
t.dropChecks("at_least_one_actor");
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { THsmServiceFactory } from "@app/ee/services/hsm/hsm-service";
|
||||||
import { crypto } from "@app/lib/crypto/cryptography";
|
import { crypto } from "@app/lib/crypto/cryptography";
|
||||||
|
import { removeTrailingSlash } from "@app/lib/fn";
|
||||||
import { zpStr } from "@app/lib/zod";
|
import { zpStr } from "@app/lib/zod";
|
||||||
|
import { TKmsRootConfigDALFactory } from "@app/services/kms/kms-root-config-dal";
|
||||||
import { TSuperAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
import { TSuperAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||||
|
|
||||||
const envSchema = z
|
const envSchema = z
|
||||||
@@ -22,13 +25,17 @@ const envSchema = z
|
|||||||
HSM_LIB_PATH: zpStr(z.string().optional()),
|
HSM_LIB_PATH: zpStr(z.string().optional()),
|
||||||
HSM_PIN: zpStr(z.string().optional()),
|
HSM_PIN: zpStr(z.string().optional()),
|
||||||
HSM_KEY_LABEL: zpStr(z.string().optional()),
|
HSM_KEY_LABEL: zpStr(z.string().optional()),
|
||||||
HSM_SLOT: z.coerce.number().optional().default(0)
|
HSM_SLOT: z.coerce.number().optional().default(0),
|
||||||
|
|
||||||
|
LICENSE_SERVER_URL: zpStr(z.string().optional().default("https://portal.infisical.com")),
|
||||||
|
LICENSE_SERVER_KEY: zpStr(z.string().optional()),
|
||||||
|
LICENSE_KEY: zpStr(z.string().optional()),
|
||||||
|
LICENSE_KEY_OFFLINE: zpStr(z.string().optional()),
|
||||||
|
INTERNAL_REGION: zpStr(z.enum(["us", "eu"]).optional()),
|
||||||
|
|
||||||
|
SITE_URL: zpStr(z.string().transform((val) => (val ? removeTrailingSlash(val) : val))).optional()
|
||||||
})
|
})
|
||||||
// To ensure that basic encryption is always possible.
|
// To ensure that basic encryption is always possible.
|
||||||
.refine(
|
|
||||||
(data) => Boolean(data.ENCRYPTION_KEY) || Boolean(data.ROOT_ENCRYPTION_KEY),
|
|
||||||
"Either ENCRYPTION_KEY or ROOT_ENCRYPTION_KEY must be defined."
|
|
||||||
)
|
|
||||||
.transform((data) => ({
|
.transform((data) => ({
|
||||||
...data,
|
...data,
|
||||||
isHsmConfigured:
|
isHsmConfigured:
|
||||||
@@ -37,7 +44,27 @@ const envSchema = z
|
|||||||
|
|
||||||
export type TMigrationEnvConfig = z.infer<typeof envSchema>;
|
export type TMigrationEnvConfig = z.infer<typeof envSchema>;
|
||||||
|
|
||||||
export const getMigrationEnvConfig = async (superAdminDAL: TSuperAdminDALFactory) => {
|
export const getMigrationHsmConfig = () => {
|
||||||
|
const parsedEnv = envSchema.safeParse(process.env);
|
||||||
|
if (!parsedEnv.success) {
|
||||||
|
console.error("Invalid environment variables. Check the error below");
|
||||||
|
console.error(parsedEnv.error.issues);
|
||||||
|
process.exit(-1);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
isHsmConfigured: parsedEnv.data.isHsmConfigured,
|
||||||
|
HSM_PIN: parsedEnv.data.HSM_PIN,
|
||||||
|
HSM_SLOT: parsedEnv.data.HSM_SLOT,
|
||||||
|
HSM_LIB_PATH: parsedEnv.data.HSM_LIB_PATH,
|
||||||
|
HSM_KEY_LABEL: parsedEnv.data.HSM_KEY_LABEL
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getMigrationEnvConfig = async (
|
||||||
|
superAdminDAL: TSuperAdminDALFactory,
|
||||||
|
hsmService: THsmServiceFactory,
|
||||||
|
kmsRootConfigDAL: TKmsRootConfigDALFactory
|
||||||
|
) => {
|
||||||
const parsedEnv = envSchema.safeParse(process.env);
|
const parsedEnv = envSchema.safeParse(process.env);
|
||||||
if (!parsedEnv.success) {
|
if (!parsedEnv.success) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
@@ -53,7 +80,7 @@ export const getMigrationEnvConfig = async (superAdminDAL: TSuperAdminDALFactory
|
|||||||
|
|
||||||
let envCfg = Object.freeze(parsedEnv.data);
|
let envCfg = Object.freeze(parsedEnv.data);
|
||||||
|
|
||||||
const fipsEnabled = await crypto.initialize(superAdminDAL, envCfg);
|
const fipsEnabled = await crypto.initialize(superAdminDAL, hsmService, kmsRootConfigDAL, envCfg);
|
||||||
|
|
||||||
// Fix for 128-bit entropy encryption key expansion issue:
|
// Fix for 128-bit entropy encryption key expansion issue:
|
||||||
// In FIPS it is not ideal to expand a 128-bit key into 256-bit. We solved this issue in the past by creating the ROOT_ENCRYPTION_KEY.
|
// In FIPS it is not ideal to expand a 128-bit key into 256-bit. We solved this issue in the past by creating the ROOT_ENCRYPTION_KEY.
|
||||||
|
|||||||
@@ -1,28 +1,23 @@
|
|||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { initializeHsmModule } from "@app/ee/services/hsm/hsm-fns";
|
import { initializeHsmModule, isHsmActiveAndEnabled } from "@app/ee/services/hsm/hsm-fns";
|
||||||
import { hsmServiceFactory } from "@app/ee/services/hsm/hsm-service";
|
import { hsmServiceFactory } from "@app/ee/services/hsm/hsm-service";
|
||||||
|
import { licenseDALFactory } from "@app/ee/services/license/license-dal";
|
||||||
|
import { licenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
|
import { permissionDALFactory } from "@app/ee/services/permission/permission-dal";
|
||||||
|
import { permissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||||
import { TKeyStoreFactory } from "@app/keystore/keystore";
|
import { TKeyStoreFactory } from "@app/keystore/keystore";
|
||||||
import { folderCheckpointDALFactory } from "@app/services/folder-checkpoint/folder-checkpoint-dal";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
import { folderCheckpointResourcesDALFactory } from "@app/services/folder-checkpoint-resources/folder-checkpoint-resources-dal";
|
|
||||||
import { folderCommitDALFactory } from "@app/services/folder-commit/folder-commit-dal";
|
|
||||||
import { folderCommitServiceFactory } from "@app/services/folder-commit/folder-commit-service";
|
|
||||||
import { folderCommitChangesDALFactory } from "@app/services/folder-commit-changes/folder-commit-changes-dal";
|
|
||||||
import { folderTreeCheckpointDALFactory } from "@app/services/folder-tree-checkpoint/folder-tree-checkpoint-dal";
|
|
||||||
import { folderTreeCheckpointResourcesDALFactory } from "@app/services/folder-tree-checkpoint-resources/folder-tree-checkpoint-resources-dal";
|
|
||||||
import { identityDALFactory } from "@app/services/identity/identity-dal";
|
import { identityDALFactory } from "@app/services/identity/identity-dal";
|
||||||
import { internalKmsDALFactory } from "@app/services/kms/internal-kms-dal";
|
import { internalKmsDALFactory } from "@app/services/kms/internal-kms-dal";
|
||||||
import { kmskeyDALFactory } from "@app/services/kms/kms-key-dal";
|
import { kmskeyDALFactory } from "@app/services/kms/kms-key-dal";
|
||||||
import { kmsRootConfigDALFactory } from "@app/services/kms/kms-root-config-dal";
|
import { kmsRootConfigDALFactory } from "@app/services/kms/kms-root-config-dal";
|
||||||
import { kmsServiceFactory } from "@app/services/kms/kms-service";
|
import { kmsServiceFactory } from "@app/services/kms/kms-service";
|
||||||
|
import { RootKeyEncryptionStrategy } from "@app/services/kms/kms-types";
|
||||||
import { orgDALFactory } from "@app/services/org/org-dal";
|
import { orgDALFactory } from "@app/services/org/org-dal";
|
||||||
import { projectDALFactory } from "@app/services/project/project-dal";
|
import { projectDALFactory } from "@app/services/project/project-dal";
|
||||||
import { resourceMetadataDALFactory } from "@app/services/resource-metadata/resource-metadata-dal";
|
import { roleDALFactory } from "@app/services/role/role-dal";
|
||||||
import { secretFolderDALFactory } from "@app/services/secret-folder/secret-folder-dal";
|
import { serviceTokenDALFactory } from "@app/services/service-token/service-token-dal";
|
||||||
import { secretFolderVersionDALFactory } from "@app/services/secret-folder/secret-folder-version-dal";
|
|
||||||
import { secretTagDALFactory } from "@app/services/secret-tag/secret-tag-dal";
|
|
||||||
import { secretV2BridgeDALFactory } from "@app/services/secret-v2-bridge/secret-v2-bridge-dal";
|
|
||||||
import { secretVersionV2BridgeDALFactory } from "@app/services/secret-v2-bridge/secret-version-dal";
|
|
||||||
import { userDALFactory } from "@app/services/user/user-dal";
|
import { userDALFactory } from "@app/services/user/user-dal";
|
||||||
|
|
||||||
import { TMigrationEnvConfig } from "./env-config";
|
import { TMigrationEnvConfig } from "./env-config";
|
||||||
@@ -33,8 +28,11 @@ type TDependencies = {
|
|||||||
keyStore: TKeyStoreFactory;
|
keyStore: TKeyStoreFactory;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getMigrationEncryptionServices = async ({ envConfig, db, keyStore }: TDependencies) => {
|
type THsmServiceDependencies = {
|
||||||
// eslint-disable-next-line no-param-reassign
|
envConfig: Pick<TMigrationEnvConfig, "HSM_PIN" | "HSM_SLOT" | "HSM_LIB_PATH" | "HSM_KEY_LABEL" | "isHsmConfigured">;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getMigrationHsmService = async ({ envConfig }: THsmServiceDependencies) => {
|
||||||
const hsmModule = initializeHsmModule(envConfig);
|
const hsmModule = initializeHsmModule(envConfig);
|
||||||
hsmModule.initialize();
|
hsmModule.initialize();
|
||||||
|
|
||||||
@@ -43,67 +41,72 @@ export const getMigrationEncryptionServices = async ({ envConfig, db, keyStore }
|
|||||||
envConfig
|
envConfig
|
||||||
});
|
});
|
||||||
|
|
||||||
const orgDAL = orgDALFactory(db);
|
|
||||||
const kmsRootConfigDAL = kmsRootConfigDALFactory(db);
|
|
||||||
const kmsDAL = kmskeyDALFactory(db);
|
|
||||||
const internalKmsDAL = internalKmsDALFactory(db);
|
|
||||||
const projectDAL = projectDALFactory(db);
|
|
||||||
|
|
||||||
const kmsService = kmsServiceFactory({
|
|
||||||
kmsRootConfigDAL,
|
|
||||||
keyStore,
|
|
||||||
kmsDAL,
|
|
||||||
internalKmsDAL,
|
|
||||||
orgDAL,
|
|
||||||
projectDAL,
|
|
||||||
hsmService,
|
|
||||||
envConfig
|
|
||||||
});
|
|
||||||
|
|
||||||
await hsmService.startService();
|
await hsmService.startService();
|
||||||
await kmsService.startService();
|
|
||||||
|
|
||||||
return { kmsService };
|
return { hsmService };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getMigrationPITServices = async ({
|
export const getMigrationEncryptionServices = async ({ envConfig, db, keyStore }: TDependencies) => {
|
||||||
db,
|
// ----- DAL dependencies -----
|
||||||
keyStore,
|
const orgDAL = orgDALFactory(db);
|
||||||
envConfig
|
const licenseDAL = licenseDALFactory(db);
|
||||||
}: {
|
const permissionDAL = permissionDALFactory(db);
|
||||||
db: Knex;
|
|
||||||
keyStore: TKeyStoreFactory;
|
|
||||||
envConfig: TMigrationEnvConfig;
|
|
||||||
}) => {
|
|
||||||
const projectDAL = projectDALFactory(db);
|
const projectDAL = projectDALFactory(db);
|
||||||
const folderCommitDAL = folderCommitDALFactory(db);
|
const roleDAL = roleDALFactory(db);
|
||||||
const folderCommitChangesDAL = folderCommitChangesDALFactory(db);
|
|
||||||
const folderCheckpointDAL = folderCheckpointDALFactory(db);
|
|
||||||
const folderTreeCheckpointDAL = folderTreeCheckpointDALFactory(db);
|
|
||||||
const userDAL = userDALFactory(db);
|
const userDAL = userDALFactory(db);
|
||||||
const identityDAL = identityDALFactory(db);
|
const identityDAL = identityDALFactory(db);
|
||||||
const folderDAL = secretFolderDALFactory(db);
|
const serviceTokenDAL = serviceTokenDALFactory(db);
|
||||||
const folderVersionDAL = secretFolderVersionDALFactory(db);
|
|
||||||
const secretVersionV2BridgeDAL = secretVersionV2BridgeDALFactory(db);
|
|
||||||
const folderCheckpointResourcesDAL = folderCheckpointResourcesDALFactory(db);
|
|
||||||
const secretV2BridgeDAL = secretV2BridgeDALFactory({ db, keyStore });
|
|
||||||
const folderTreeCheckpointResourcesDAL = folderTreeCheckpointResourcesDALFactory(db);
|
|
||||||
const secretTagDAL = secretTagDALFactory(db);
|
|
||||||
|
|
||||||
const orgDAL = orgDALFactory(db);
|
|
||||||
const kmsRootConfigDAL = kmsRootConfigDALFactory(db);
|
const kmsRootConfigDAL = kmsRootConfigDALFactory(db);
|
||||||
const kmsDAL = kmskeyDALFactory(db);
|
const kmsDAL = kmskeyDALFactory(db);
|
||||||
const internalKmsDAL = internalKmsDALFactory(db);
|
const internalKmsDAL = internalKmsDALFactory(db);
|
||||||
const resourceMetadataDAL = resourceMetadataDALFactory(db);
|
|
||||||
|
|
||||||
const hsmModule = initializeHsmModule(envConfig);
|
// ----- Service dependencies -----
|
||||||
hsmModule.initialize();
|
const permissionService = permissionServiceFactory({
|
||||||
|
permissionDAL,
|
||||||
|
serviceTokenDAL,
|
||||||
|
projectDAL,
|
||||||
|
keyStore,
|
||||||
|
roleDAL,
|
||||||
|
userDAL,
|
||||||
|
identityDAL
|
||||||
|
});
|
||||||
|
|
||||||
const hsmService = hsmServiceFactory({
|
const licenseService = licenseServiceFactory({
|
||||||
hsmModule: hsmModule.getModule(),
|
permissionService,
|
||||||
|
orgDAL,
|
||||||
|
licenseDAL,
|
||||||
|
keyStore,
|
||||||
|
projectDAL,
|
||||||
envConfig
|
envConfig
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ----- HSM startup -----
|
||||||
|
|
||||||
|
const { hsmService } = await getMigrationHsmService({ envConfig });
|
||||||
|
|
||||||
|
const hsmStatus = await isHsmActiveAndEnabled({
|
||||||
|
hsmService,
|
||||||
|
kmsRootConfigDAL,
|
||||||
|
licenseService
|
||||||
|
});
|
||||||
|
|
||||||
|
// if the encryption strategy is software - user needs to provide an encryption key
|
||||||
|
// if the encryption strategy is null AND the hsm is not configured - user needs to provide an encryption key
|
||||||
|
const needsEncryptionKey =
|
||||||
|
hsmStatus.rootKmsConfigEncryptionStrategy === RootKeyEncryptionStrategy.Software ||
|
||||||
|
(hsmStatus.rootKmsConfigEncryptionStrategy === null && !hsmStatus.isHsmConfigured);
|
||||||
|
|
||||||
|
if (needsEncryptionKey) {
|
||||||
|
if (!envConfig.ROOT_ENCRYPTION_KEY && !envConfig.ENCRYPTION_KEY) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message:
|
||||||
|
"Root KMS encryption strategy is set to software. Please set the ENCRYPTION_KEY environment variable and restart your deployment.\nYou can enable HSM encryption in the Server Console."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- KMS startup -----
|
||||||
|
|
||||||
const kmsService = kmsServiceFactory({
|
const kmsService = kmsServiceFactory({
|
||||||
kmsRootConfigDAL,
|
kmsRootConfigDAL,
|
||||||
keyStore,
|
keyStore,
|
||||||
@@ -115,27 +118,7 @@ export const getMigrationPITServices = async ({
|
|||||||
envConfig
|
envConfig
|
||||||
});
|
});
|
||||||
|
|
||||||
await hsmService.startService();
|
await kmsService.startService(hsmStatus);
|
||||||
await kmsService.startService();
|
|
||||||
|
|
||||||
const folderCommitService = folderCommitServiceFactory({
|
return { kmsService, hsmService };
|
||||||
folderCommitDAL,
|
|
||||||
folderCommitChangesDAL,
|
|
||||||
folderCheckpointDAL,
|
|
||||||
folderTreeCheckpointDAL,
|
|
||||||
userDAL,
|
|
||||||
identityDAL,
|
|
||||||
folderDAL,
|
|
||||||
folderVersionDAL,
|
|
||||||
secretVersionV2BridgeDAL,
|
|
||||||
projectDAL,
|
|
||||||
folderCheckpointResourcesDAL,
|
|
||||||
secretV2BridgeDAL,
|
|
||||||
folderTreeCheckpointResourcesDAL,
|
|
||||||
kmsService,
|
|
||||||
secretTagDAL,
|
|
||||||
resourceMetadataDAL
|
|
||||||
});
|
|
||||||
|
|
||||||
return { folderCommitService };
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
// 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 AdditionalPrivilegesSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
name: z.string(),
|
||||||
|
isTemporary: z.boolean().default(false),
|
||||||
|
temporaryMode: z.string().nullable().optional(),
|
||||||
|
temporaryRange: z.string().nullable().optional(),
|
||||||
|
temporaryAccessStartTime: z.date().nullable().optional(),
|
||||||
|
temporaryAccessEndTime: z.date().nullable().optional(),
|
||||||
|
permissions: z.unknown(),
|
||||||
|
actorUserId: z.string().uuid().nullable().optional(),
|
||||||
|
actorIdentityId: z.string().uuid().nullable().optional(),
|
||||||
|
orgId: z.string().uuid().nullable().optional(),
|
||||||
|
projectId: z.string().nullable().optional(),
|
||||||
|
namespaceId: z.string().uuid().nullable().optional(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date()
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TAdditionalPrivileges = z.infer<typeof AdditionalPrivilegesSchema>;
|
||||||
|
export type TAdditionalPrivilegesInsert = Omit<z.input<typeof AdditionalPrivilegesSchema>, TImmutableDBKeys>;
|
||||||
|
export type TAdditionalPrivilegesUpdate = Partial<Omit<z.input<typeof AdditionalPrivilegesSchema>, TImmutableDBKeys>>;
|
||||||
@@ -26,7 +26,8 @@ export const CertificatesSchema = z.object({
|
|||||||
keyUsages: z.string().array().nullable().optional(),
|
keyUsages: z.string().array().nullable().optional(),
|
||||||
extendedKeyUsages: z.string().array().nullable().optional(),
|
extendedKeyUsages: z.string().array().nullable().optional(),
|
||||||
projectId: z.string(),
|
projectId: z.string(),
|
||||||
pkiSubscriberId: z.string().uuid().nullable().optional()
|
pkiSubscriberId: z.string().uuid().nullable().optional(),
|
||||||
|
profileId: z.string().uuid().nullable().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TCertificates = z.infer<typeof CertificatesSchema>;
|
export type TCertificates = z.infer<typeof CertificatesSchema>;
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { zodBuffer } from "@app/lib/zod";
|
||||||
|
|
||||||
import { TImmutableDBKeys } from "./models";
|
import { TImmutableDBKeys } from "./models";
|
||||||
|
|
||||||
export const GatewaysV2Schema = z.object({
|
export const GatewaysV2Schema = z.object({
|
||||||
@@ -15,7 +17,9 @@ export const GatewaysV2Schema = z.object({
|
|||||||
identityId: z.string().uuid(),
|
identityId: z.string().uuid(),
|
||||||
relayId: z.string().uuid().nullable().optional(),
|
relayId: z.string().uuid().nullable().optional(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
heartbeat: z.date().nullable().optional()
|
heartbeat: z.date().nullable().optional(),
|
||||||
|
encryptedPamSessionKey: zodBuffer.nullable().optional(),
|
||||||
|
healthAlertedAt: z.date().nullable().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TGatewaysV2 = z.infer<typeof GatewaysV2Schema>;
|
export type TGatewaysV2 = z.infer<typeof GatewaysV2Schema>;
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ export const IdentitiesSchema = z.object({
|
|||||||
authMethod: z.string().nullable().optional(),
|
authMethod: z.string().nullable().optional(),
|
||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
hasDeleteProtection: z.boolean().default(false)
|
hasDeleteProtection: z.boolean().default(false),
|
||||||
|
orgId: z.string().uuid()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TIdentities = z.infer<typeof IdentitiesSchema>;
|
export type TIdentities = z.infer<typeof IdentitiesSchema>;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ export * from "./access-approval-policies-approvers";
|
|||||||
export * from "./access-approval-policies-bypassers";
|
export * from "./access-approval-policies-bypassers";
|
||||||
export * from "./access-approval-requests";
|
export * from "./access-approval-requests";
|
||||||
export * from "./access-approval-requests-reviewers";
|
export * from "./access-approval-requests-reviewers";
|
||||||
|
export * from "./additional-privileges";
|
||||||
export * from "./api-keys";
|
export * from "./api-keys";
|
||||||
export * from "./app-connections";
|
export * from "./app-connections";
|
||||||
export * from "./audit-log-streams";
|
export * from "./audit-log-streams";
|
||||||
@@ -73,8 +74,11 @@ export * from "./kms-keys";
|
|||||||
export * from "./kms-root-config";
|
export * from "./kms-root-config";
|
||||||
export * from "./ldap-configs";
|
export * from "./ldap-configs";
|
||||||
export * from "./ldap-group-maps";
|
export * from "./ldap-group-maps";
|
||||||
|
export * from "./membership-roles";
|
||||||
|
export * from "./memberships";
|
||||||
export * from "./microsoft-teams-integrations";
|
export * from "./microsoft-teams-integrations";
|
||||||
export * from "./models";
|
export * from "./models";
|
||||||
|
export * from "./namespaces";
|
||||||
export * from "./oidc-configs";
|
export * from "./oidc-configs";
|
||||||
export * from "./org-bots";
|
export * from "./org-bots";
|
||||||
export * from "./org-gateway-config";
|
export * from "./org-gateway-config";
|
||||||
@@ -83,9 +87,17 @@ export * from "./org-memberships";
|
|||||||
export * from "./org-relay-config";
|
export * from "./org-relay-config";
|
||||||
export * from "./org-roles";
|
export * from "./org-roles";
|
||||||
export * from "./organizations";
|
export * from "./organizations";
|
||||||
|
export * from "./pam-accounts";
|
||||||
|
export * from "./pam-folders";
|
||||||
|
export * from "./pam-resources";
|
||||||
|
export * from "./pam-sessions";
|
||||||
export * from "./pki-alerts";
|
export * from "./pki-alerts";
|
||||||
|
export * from "./pki-api-enrollment-configs";
|
||||||
|
export * from "./pki-certificate-profiles";
|
||||||
|
export * from "./pki-certificate-templates-v2";
|
||||||
export * from "./pki-collection-items";
|
export * from "./pki-collection-items";
|
||||||
export * from "./pki-collections";
|
export * from "./pki-collections";
|
||||||
|
export * from "./pki-est-enrollment-configs";
|
||||||
export * from "./pki-subscribers";
|
export * from "./pki-subscribers";
|
||||||
export * from "./pki-syncs";
|
export * from "./pki-syncs";
|
||||||
export * from "./project-bots";
|
export * from "./project-bots";
|
||||||
@@ -104,6 +116,7 @@ export * from "./projects";
|
|||||||
export * from "./rate-limit";
|
export * from "./rate-limit";
|
||||||
export * from "./relays";
|
export * from "./relays";
|
||||||
export * from "./resource-metadata";
|
export * from "./resource-metadata";
|
||||||
|
export * from "./roles";
|
||||||
export * from "./saml-configs";
|
export * from "./saml-configs";
|
||||||
export * from "./scim-tokens";
|
export * from "./scim-tokens";
|
||||||
export * from "./secret-approval-policies";
|
export * from "./secret-approval-policies";
|
||||||
@@ -167,5 +180,6 @@ export * from "./user-aliases";
|
|||||||
export * from "./user-encryption-keys";
|
export * from "./user-encryption-keys";
|
||||||
export * from "./user-group-membership";
|
export * from "./user-group-membership";
|
||||||
export * from "./users";
|
export * from "./users";
|
||||||
|
export * from "./vault-external-migration-configs";
|
||||||
export * from "./webhooks";
|
export * from "./webhooks";
|
||||||
export * from "./workflow-integrations";
|
export * from "./workflow-integrations";
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ export const KmsKeysSchema = z.object({
|
|||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
projectId: z.string().nullable().optional(),
|
projectId: z.string().nullable().optional(),
|
||||||
keyUsage: z.string().default("encrypt-decrypt")
|
keyUsage: z.string().default("encrypt-decrypt"),
|
||||||
|
kmipMetadata: z.unknown().nullable().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TKmsKeys = z.infer<typeof KmsKeysSchema>;
|
export type TKmsKeys = z.infer<typeof KmsKeysSchema>;
|
||||||
|
|||||||
@@ -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 MembershipRolesSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
role: z.string(),
|
||||||
|
isTemporary: z.boolean().default(false),
|
||||||
|
temporaryMode: z.string().nullable().optional(),
|
||||||
|
temporaryRange: z.string().nullable().optional(),
|
||||||
|
temporaryAccessStartTime: z.date().nullable().optional(),
|
||||||
|
temporaryAccessEndTime: z.date().nullable().optional(),
|
||||||
|
customRoleId: z.string().uuid().nullable().optional(),
|
||||||
|
membershipId: z.string().uuid(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date()
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TMembershipRoles = z.infer<typeof MembershipRolesSchema>;
|
||||||
|
export type TMembershipRolesInsert = Omit<z.input<typeof MembershipRolesSchema>, TImmutableDBKeys>;
|
||||||
|
export type TMembershipRolesUpdate = Partial<Omit<z.input<typeof MembershipRolesSchema>, TImmutableDBKeys>>;
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
// 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 MembershipsSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
scope: z.string(),
|
||||||
|
actorUserId: z.string().uuid().nullable().optional(),
|
||||||
|
actorIdentityId: z.string().uuid().nullable().optional(),
|
||||||
|
actorGroupId: z.string().uuid().nullable().optional(),
|
||||||
|
scopeOrgId: z.string().uuid(),
|
||||||
|
scopeProjectId: z.string().nullable().optional(),
|
||||||
|
scopeNamespaceId: z.string().uuid().nullable().optional(),
|
||||||
|
isActive: z.boolean().default(true),
|
||||||
|
status: z.string().nullable().optional(),
|
||||||
|
inviteEmail: z.string().nullable().optional(),
|
||||||
|
lastInvitedAt: z.date().nullable().optional(),
|
||||||
|
lastLoginAuthMethod: z.string().nullable().optional(),
|
||||||
|
lastLoginTime: z.date().nullable().optional(),
|
||||||
|
projectFavorites: z.string().array().nullable().optional(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date()
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TMemberships = z.infer<typeof MembershipsSchema>;
|
||||||
|
export type TMembershipsInsert = Omit<z.input<typeof MembershipsSchema>, TImmutableDBKeys>;
|
||||||
|
export type TMembershipsUpdate = Partial<Omit<z.input<typeof MembershipsSchema>, TImmutableDBKeys>>;
|
||||||
@@ -23,6 +23,10 @@ export enum TableName {
|
|||||||
CertificateBody = "certificate_bodies",
|
CertificateBody = "certificate_bodies",
|
||||||
CertificateSecret = "certificate_secrets",
|
CertificateSecret = "certificate_secrets",
|
||||||
CertificateTemplate = "certificate_templates",
|
CertificateTemplate = "certificate_templates",
|
||||||
|
PkiCertificateTemplateV2 = "pki_certificate_templates_v2",
|
||||||
|
PkiCertificateProfile = "pki_certificate_profiles",
|
||||||
|
PkiEstEnrollmentConfig = "pki_est_enrollment_configs",
|
||||||
|
PkiApiEnrollmentConfig = "pki_api_enrollment_configs",
|
||||||
PkiSubscriber = "pki_subscribers",
|
PkiSubscriber = "pki_subscribers",
|
||||||
PkiAlert = "pki_alerts",
|
PkiAlert = "pki_alerts",
|
||||||
PkiCollection = "pki_collections",
|
PkiCollection = "pki_collections",
|
||||||
@@ -178,6 +182,14 @@ export enum TableName {
|
|||||||
SecretScanningScan = "secret_scanning_scans",
|
SecretScanningScan = "secret_scanning_scans",
|
||||||
SecretScanningFinding = "secret_scanning_findings",
|
SecretScanningFinding = "secret_scanning_findings",
|
||||||
SecretScanningConfig = "secret_scanning_configs",
|
SecretScanningConfig = "secret_scanning_configs",
|
||||||
|
|
||||||
|
Membership = "memberships",
|
||||||
|
MembershipRole = "membership_roles",
|
||||||
|
Role = "roles",
|
||||||
|
AdditionalPrivilege = "additional_privileges",
|
||||||
|
|
||||||
|
Namespace = "namespaces",
|
||||||
|
|
||||||
// reminders
|
// reminders
|
||||||
Reminder = "reminders",
|
Reminder = "reminders",
|
||||||
ReminderRecipient = "reminders_recipients",
|
ReminderRecipient = "reminders_recipients",
|
||||||
@@ -189,7 +201,15 @@ export enum TableName {
|
|||||||
Relay = "relays",
|
Relay = "relays",
|
||||||
GatewayV2 = "gateways_v2",
|
GatewayV2 = "gateways_v2",
|
||||||
|
|
||||||
KeyValueStore = "key_value_store"
|
KeyValueStore = "key_value_store",
|
||||||
|
|
||||||
|
// PAM
|
||||||
|
PamFolder = "pam_folders",
|
||||||
|
PamResource = "pam_resources",
|
||||||
|
PamAccount = "pam_accounts",
|
||||||
|
PamSession = "pam_sessions",
|
||||||
|
|
||||||
|
VaultExternalMigrationConfig = "vault_external_migration_configs"
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TImmutableDBKeys = "id" | "createdAt" | "updatedAt" | "commitId";
|
export type TImmutableDBKeys = "id" | "createdAt" | "updatedAt" | "commitId";
|
||||||
@@ -281,7 +301,8 @@ export enum ProjectType {
|
|||||||
CertificateManager = "cert-manager",
|
CertificateManager = "cert-manager",
|
||||||
KMS = "kms",
|
KMS = "kms",
|
||||||
SSH = "ssh",
|
SSH = "ssh",
|
||||||
SecretScanning = "secret-scanning"
|
SecretScanning = "secret-scanning",
|
||||||
|
PAM = "pam"
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ActionProjectType {
|
export enum ActionProjectType {
|
||||||
@@ -290,11 +311,50 @@ export enum ActionProjectType {
|
|||||||
KMS = ProjectType.KMS,
|
KMS = ProjectType.KMS,
|
||||||
SSH = ProjectType.SSH,
|
SSH = ProjectType.SSH,
|
||||||
SecretScanning = ProjectType.SecretScanning,
|
SecretScanning = ProjectType.SecretScanning,
|
||||||
|
PAM = ProjectType.PAM,
|
||||||
// project operations that happen on all types
|
// project operations that happen on all types
|
||||||
Any = "any"
|
Any = "any"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum OrganizationActionScope {
|
||||||
|
ChildOrganization = "child-organization-only",
|
||||||
|
ParentOrganization = "parent-organization-only",
|
||||||
|
Any = "any"
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum TemporaryPermissionMode {
|
||||||
|
Relative = "relative"
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum MembershipActors {
|
||||||
|
Group = "group",
|
||||||
|
User = "user",
|
||||||
|
Identity = "identity"
|
||||||
|
}
|
||||||
|
|
||||||
export enum SortDirection {
|
export enum SortDirection {
|
||||||
ASC = "asc",
|
ASC = "asc",
|
||||||
DESC = "desc"
|
DESC = "desc"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum AccessScope {
|
||||||
|
Organization = "organization",
|
||||||
|
Namespace = "namespace",
|
||||||
|
Project = "project"
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AccessScopeData =
|
||||||
|
| {
|
||||||
|
scope: AccessScope.Organization;
|
||||||
|
orgId: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
scope: AccessScope.Namespace;
|
||||||
|
orgId: string;
|
||||||
|
namespaceId: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
scope: AccessScope.Project;
|
||||||
|
orgId: string;
|
||||||
|
projectId: string;
|
||||||
|
};
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// 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 NamespacesSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
name: z.string(),
|
||||||
|
description: z.string().nullable().optional(),
|
||||||
|
orgId: z.string().uuid(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date()
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TNamespaces = z.infer<typeof NamespacesSchema>;
|
||||||
|
export type TNamespacesInsert = Omit<z.input<typeof NamespacesSchema>, TImmutableDBKeys>;
|
||||||
|
export type TNamespacesUpdate = Partial<Omit<z.input<typeof NamespacesSchema>, TImmutableDBKeys>>;
|
||||||
@@ -38,7 +38,9 @@ export const OrganizationsSchema = z.object({
|
|||||||
maxSharedSecretLifetime: z.number().default(2592000).nullable().optional(),
|
maxSharedSecretLifetime: z.number().default(2592000).nullable().optional(),
|
||||||
maxSharedSecretViewLimit: z.number().nullable().optional(),
|
maxSharedSecretViewLimit: z.number().nullable().optional(),
|
||||||
googleSsoAuthEnforced: z.boolean().default(false),
|
googleSsoAuthEnforced: z.boolean().default(false),
|
||||||
googleSsoAuthLastUsed: z.date().nullable().optional()
|
googleSsoAuthLastUsed: z.date().nullable().optional(),
|
||||||
|
parentOrgId: z.string().uuid().nullable().optional(),
|
||||||
|
rootOrgId: z.string().uuid().nullable().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TOrganizations = z.infer<typeof OrganizationsSchema>;
|
export type TOrganizations = z.infer<typeof OrganizationsSchema>;
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
// 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 PamAccountsSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
projectId: z.string(),
|
||||||
|
folderId: z.string().uuid().nullable().optional(),
|
||||||
|
resourceId: z.string().uuid(),
|
||||||
|
name: z.string(),
|
||||||
|
description: z.string().nullable().optional(),
|
||||||
|
encryptedCredentials: zodBuffer,
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date(),
|
||||||
|
rotationEnabled: z.boolean().default(false),
|
||||||
|
rotationIntervalSeconds: z.number().nullable().optional(),
|
||||||
|
lastRotatedAt: z.date().nullable().optional()
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TPamAccounts = z.infer<typeof PamAccountsSchema>;
|
||||||
|
export type TPamAccountsInsert = Omit<z.input<typeof PamAccountsSchema>, TImmutableDBKeys>;
|
||||||
|
export type TPamAccountsUpdate = Partial<Omit<z.input<typeof PamAccountsSchema>, TImmutableDBKeys>>;
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
// 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 PamFoldersSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
projectId: z.string(),
|
||||||
|
parentId: z.string().uuid().nullable().optional(),
|
||||||
|
name: z.string(),
|
||||||
|
description: z.string().nullable().optional(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date()
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TPamFolders = z.infer<typeof PamFoldersSchema>;
|
||||||
|
export type TPamFoldersInsert = Omit<z.input<typeof PamFoldersSchema>, TImmutableDBKeys>;
|
||||||
|
export type TPamFoldersUpdate = Partial<Omit<z.input<typeof PamFoldersSchema>, TImmutableDBKeys>>;
|
||||||
@@ -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 { zodBuffer } from "@app/lib/zod";
|
||||||
|
|
||||||
|
import { TImmutableDBKeys } from "./models";
|
||||||
|
|
||||||
|
export const PamResourcesSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
projectId: z.string(),
|
||||||
|
name: z.string(),
|
||||||
|
gatewayId: z.string().uuid(),
|
||||||
|
resourceType: z.string(),
|
||||||
|
encryptedConnectionDetails: zodBuffer,
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date(),
|
||||||
|
encryptedRotationAccountCredentials: zodBuffer.nullable().optional()
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TPamResources = z.infer<typeof PamResourcesSchema>;
|
||||||
|
export type TPamResourcesInsert = Omit<z.input<typeof PamResourcesSchema>, TImmutableDBKeys>;
|
||||||
|
export type TPamResourcesUpdate = Partial<Omit<z.input<typeof PamResourcesSchema>, TImmutableDBKeys>>;
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
// 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 PamSessionsSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
projectId: z.string(),
|
||||||
|
accountId: z.string().uuid().nullable().optional(),
|
||||||
|
resourceType: z.string(),
|
||||||
|
resourceName: z.string(),
|
||||||
|
accountName: z.string(),
|
||||||
|
userId: z.string().uuid().nullable().optional(),
|
||||||
|
actorName: z.string(),
|
||||||
|
actorEmail: z.string(),
|
||||||
|
actorIp: z.string(),
|
||||||
|
actorUserAgent: z.string(),
|
||||||
|
status: z.string(),
|
||||||
|
encryptedLogsBlob: zodBuffer.nullable().optional(),
|
||||||
|
expiresAt: z.date(),
|
||||||
|
startedAt: z.date().nullable().optional(),
|
||||||
|
endedAt: z.date().nullable().optional(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date()
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TPamSessions = z.infer<typeof PamSessionsSchema>;
|
||||||
|
export type TPamSessionsInsert = Omit<z.input<typeof PamSessionsSchema>, TImmutableDBKeys>;
|
||||||
|
export type TPamSessionsUpdate = Partial<Omit<z.input<typeof PamSessionsSchema>, TImmutableDBKeys>>;
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
// 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 PkiApiEnrollmentConfigsSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
autoRenew: z.boolean().default(false).nullable().optional(),
|
||||||
|
autoRenewDays: z.number().nullable().optional(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date()
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TPkiApiEnrollmentConfigs = z.infer<typeof PkiApiEnrollmentConfigsSchema>;
|
||||||
|
export type TPkiApiEnrollmentConfigsInsert = Omit<z.input<typeof PkiApiEnrollmentConfigsSchema>, TImmutableDBKeys>;
|
||||||
|
export type TPkiApiEnrollmentConfigsUpdate = Partial<
|
||||||
|
Omit<z.input<typeof PkiApiEnrollmentConfigsSchema>, TImmutableDBKeys>
|
||||||
|
>;
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// 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 PkiCertificateProfilesSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
projectId: z.string(),
|
||||||
|
caId: z.string().uuid(),
|
||||||
|
certificateTemplateId: z.string().uuid(),
|
||||||
|
slug: z.string(),
|
||||||
|
description: z.string().nullable().optional(),
|
||||||
|
enrollmentType: z.string(),
|
||||||
|
estConfigId: z.string().uuid().nullable().optional(),
|
||||||
|
apiConfigId: z.string().uuid().nullable().optional(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date()
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TPkiCertificateProfiles = z.infer<typeof PkiCertificateProfilesSchema>;
|
||||||
|
export type TPkiCertificateProfilesInsert = Omit<z.input<typeof PkiCertificateProfilesSchema>, TImmutableDBKeys>;
|
||||||
|
export type TPkiCertificateProfilesUpdate = Partial<
|
||||||
|
Omit<z.input<typeof PkiCertificateProfilesSchema>, TImmutableDBKeys>
|
||||||
|
>;
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
// 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 PkiCertificateTemplatesV2Schema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
projectId: z.string(),
|
||||||
|
name: z.string(),
|
||||||
|
description: z.string().nullable().optional(),
|
||||||
|
subject: z.unknown().nullable().optional(),
|
||||||
|
sans: z.unknown().nullable().optional(),
|
||||||
|
keyUsages: z.unknown().nullable().optional(),
|
||||||
|
extendedKeyUsages: z.unknown().nullable().optional(),
|
||||||
|
algorithms: z.unknown().nullable().optional(),
|
||||||
|
validity: z.unknown().nullable().optional(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date()
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TPkiCertificateTemplatesV2 = z.infer<typeof PkiCertificateTemplatesV2Schema>;
|
||||||
|
export type TPkiCertificateTemplatesV2Insert = Omit<z.input<typeof PkiCertificateTemplatesV2Schema>, TImmutableDBKeys>;
|
||||||
|
export type TPkiCertificateTemplatesV2Update = Partial<
|
||||||
|
Omit<z.input<typeof PkiCertificateTemplatesV2Schema>, TImmutableDBKeys>
|
||||||
|
>;
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
// 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 PkiEstEnrollmentConfigsSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
disableBootstrapCaValidation: z.boolean().default(false).nullable().optional(),
|
||||||
|
hashedPassphrase: z.string(),
|
||||||
|
encryptedCaChain: zodBuffer.nullable().optional(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date()
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TPkiEstEnrollmentConfigs = z.infer<typeof PkiEstEnrollmentConfigsSchema>;
|
||||||
|
export type TPkiEstEnrollmentConfigsInsert = Omit<z.input<typeof PkiEstEnrollmentConfigsSchema>, TImmutableDBKeys>;
|
||||||
|
export type TPkiEstEnrollmentConfigsUpdate = Partial<
|
||||||
|
Omit<z.input<typeof PkiEstEnrollmentConfigsSchema>, TImmutableDBKeys>
|
||||||
|
>;
|
||||||
@@ -14,7 +14,9 @@ export const RelaysSchema = z.object({
|
|||||||
orgId: z.string().uuid().nullable().optional(),
|
orgId: z.string().uuid().nullable().optional(),
|
||||||
identityId: z.string().uuid().nullable().optional(),
|
identityId: z.string().uuid().nullable().optional(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
host: z.string()
|
host: z.string(),
|
||||||
|
heartbeat: z.date().nullable().optional(),
|
||||||
|
healthAlertedAt: z.date().nullable().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TRelays = z.infer<typeof RelaysSchema>;
|
export type TRelays = z.infer<typeof RelaysSchema>;
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
// 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 RolesSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
name: z.string(),
|
||||||
|
description: z.string().nullable().optional(),
|
||||||
|
slug: z.string(),
|
||||||
|
permissions: z.unknown(),
|
||||||
|
orgId: z.string().uuid().nullable().optional(),
|
||||||
|
projectId: z.string().nullable().optional(),
|
||||||
|
namespaceId: z.string().uuid().nullable().optional(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date()
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TRoles = z.infer<typeof RolesSchema>;
|
||||||
|
export type TRolesInsert = Omit<z.input<typeof RolesSchema>, TImmutableDBKeys>;
|
||||||
|
export type TRolesUpdate = Partial<Omit<z.input<typeof RolesSchema>, TImmutableDBKeys>>;
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
// 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 UserNotificationsDefaultSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
userId: z.string().uuid(),
|
||||||
|
orgId: z.string().uuid().nullable().optional(),
|
||||||
|
type: z.string(),
|
||||||
|
title: z.string(),
|
||||||
|
body: z.string().nullable().optional(),
|
||||||
|
link: z.string().nullable().optional(),
|
||||||
|
isRead: z.boolean().default(false),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date()
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TUserNotificationsDefault = z.infer<typeof UserNotificationsDefaultSchema>;
|
||||||
|
export type TUserNotificationsDefaultInsert = Omit<z.input<typeof UserNotificationsDefaultSchema>, TImmutableDBKeys>;
|
||||||
|
export type TUserNotificationsDefaultUpdate = Partial<
|
||||||
|
Omit<z.input<typeof UserNotificationsDefaultSchema>, TImmutableDBKeys>
|
||||||
|
>;
|
||||||
@@ -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 VaultExternalMigrationConfigsSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
orgId: z.string().uuid(),
|
||||||
|
namespace: z.string(),
|
||||||
|
connectionId: z.string().uuid().nullable().optional(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date()
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TVaultExternalMigrationConfigs = z.infer<typeof VaultExternalMigrationConfigsSchema>;
|
||||||
|
export type TVaultExternalMigrationConfigsInsert = Omit<
|
||||||
|
z.input<typeof VaultExternalMigrationConfigsSchema>,
|
||||||
|
TImmutableDBKeys
|
||||||
|
>;
|
||||||
|
export type TVaultExternalMigrationConfigsUpdate = Partial<
|
||||||
|
Omit<z.input<typeof VaultExternalMigrationConfigsSchema>, TImmutableDBKeys>
|
||||||
|
>;
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { initEnvConfig } from "@app/lib/config/env";
|
import { initializeHsmModule } from "@app/ee/services/hsm/hsm-fns";
|
||||||
|
import { hsmServiceFactory } from "@app/ee/services/hsm/hsm-service";
|
||||||
|
import { getHsmConfig, initEnvConfig } from "@app/lib/config/env";
|
||||||
import { initLogger, logger } from "@app/lib/logger";
|
import { initLogger, logger } from "@app/lib/logger";
|
||||||
|
import { kmsRootConfigDALFactory } from "@app/services/kms/kms-root-config-dal";
|
||||||
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||||
|
|
||||||
import { AuthMethod } from "../../services/auth/auth-type";
|
import { AuthMethod } from "../../services/auth/auth-type";
|
||||||
@@ -17,7 +20,21 @@ export async function seed(knex: Knex): Promise<void> {
|
|||||||
initLogger();
|
initLogger();
|
||||||
|
|
||||||
const superAdminDAL = superAdminDALFactory(knex);
|
const superAdminDAL = superAdminDALFactory(knex);
|
||||||
await initEnvConfig(superAdminDAL, logger);
|
const kmsRootConfigDAL = kmsRootConfigDALFactory(knex);
|
||||||
|
|
||||||
|
const hsmConfig = getHsmConfig(logger);
|
||||||
|
|
||||||
|
const hsmModule = initializeHsmModule(hsmConfig);
|
||||||
|
hsmModule.initialize();
|
||||||
|
|
||||||
|
const hsmService = hsmServiceFactory({
|
||||||
|
hsmModule: hsmModule.getModule(),
|
||||||
|
envConfig: hsmConfig
|
||||||
|
});
|
||||||
|
|
||||||
|
await hsmService.startService();
|
||||||
|
|
||||||
|
await initEnvConfig(hsmService, kmsRootConfigDAL, superAdminDAL, logger);
|
||||||
|
|
||||||
await knex(TableName.SuperAdmin).insert([
|
await knex(TableName.SuperAdmin).insert([
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { OrgMembershipRole, OrgMembershipStatus, TableName } from "../schemas";
|
import { AccessScope, OrgMembershipRole, OrgMembershipStatus, TableName } from "../schemas";
|
||||||
import { seedData1 } from "../seed-data";
|
import { seedData1 } from "../seed-data";
|
||||||
|
|
||||||
export async function seed(knex: Knex): Promise<void> {
|
export async function seed(knex: Knex): Promise<void> {
|
||||||
@@ -24,13 +24,22 @@ export async function seed(knex: Knex): Promise<void> {
|
|||||||
])
|
])
|
||||||
.returning("*");
|
.returning("*");
|
||||||
|
|
||||||
await knex(TableName.OrgMembership).insert([
|
const [membership] = await knex(TableName.Membership)
|
||||||
|
.insert([
|
||||||
{
|
{
|
||||||
role: OrgMembershipRole.Admin,
|
scope: AccessScope.Organization,
|
||||||
orgId: org.id,
|
scopeOrgId: org.id,
|
||||||
status: OrgMembershipStatus.Accepted,
|
actorUserId: user.id,
|
||||||
userId: user.id,
|
isActive: true,
|
||||||
isActive: true
|
status: OrgMembershipStatus.Accepted
|
||||||
|
}
|
||||||
|
])
|
||||||
|
.returning("*");
|
||||||
|
|
||||||
|
await knex(TableName.MembershipRole).insert([
|
||||||
|
{
|
||||||
|
membershipId: membership.id,
|
||||||
|
role: OrgMembershipRole.Admin
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,23 @@
|
|||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { initEnvConfig } from "@app/lib/config/env";
|
import { initializeHsmModule } from "@app/ee/services/hsm/hsm-fns";
|
||||||
|
import { hsmServiceFactory } from "@app/ee/services/hsm/hsm-service";
|
||||||
|
import { getHsmConfig, initEnvConfig } from "@app/lib/config/env";
|
||||||
import { crypto, SymmetricKeySize } from "@app/lib/crypto/cryptography";
|
import { crypto, SymmetricKeySize } from "@app/lib/crypto/cryptography";
|
||||||
import { generateUserSrpKeys } from "@app/lib/crypto/srp";
|
import { generateUserSrpKeys } from "@app/lib/crypto/srp";
|
||||||
import { initLogger, logger } from "@app/lib/logger";
|
import { initLogger, logger } from "@app/lib/logger";
|
||||||
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
||||||
import { AuthMethod } from "@app/services/auth/auth-type";
|
import { AuthMethod } from "@app/services/auth/auth-type";
|
||||||
|
import { kmsRootConfigDALFactory } from "@app/services/kms/kms-root-config-dal";
|
||||||
|
import { membershipRoleDALFactory } from "@app/services/membership/membership-role-dal";
|
||||||
|
import { membershipUserDALFactory } from "@app/services/membership-user/membership-user-dal";
|
||||||
import { assignWorkspaceKeysToMembers, createProjectKey } from "@app/services/project/project-fns";
|
import { assignWorkspaceKeysToMembers, createProjectKey } from "@app/services/project/project-fns";
|
||||||
import { projectKeyDALFactory } from "@app/services/project-key/project-key-dal";
|
import { projectKeyDALFactory } from "@app/services/project-key/project-key-dal";
|
||||||
import { projectMembershipDALFactory } from "@app/services/project-membership/project-membership-dal";
|
|
||||||
import { projectUserMembershipRoleDALFactory } from "@app/services/project-membership/project-user-membership-role-dal";
|
|
||||||
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||||
import { userDALFactory } from "@app/services/user/user-dal";
|
import { userDALFactory } from "@app/services/user/user-dal";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
AccessScope,
|
||||||
OrgMembershipRole,
|
OrgMembershipRole,
|
||||||
OrgMembershipStatus,
|
OrgMembershipStatus,
|
||||||
ProjectMembershipRole,
|
ProjectMembershipRole,
|
||||||
@@ -39,8 +43,8 @@ const createUserWithGhostUser = async (
|
|||||||
) => {
|
) => {
|
||||||
const projectKeyDAL = projectKeyDALFactory(knex);
|
const projectKeyDAL = projectKeyDALFactory(knex);
|
||||||
const userDAL = userDALFactory(knex);
|
const userDAL = userDALFactory(knex);
|
||||||
const projectMembershipDAL = projectMembershipDALFactory(knex);
|
const membershipDAL = membershipUserDALFactory(knex);
|
||||||
const projectUserMembershipRoleDAL = projectUserMembershipRoleDALFactory(knex);
|
const membershipRoleDAL = membershipRoleDALFactory(knex);
|
||||||
|
|
||||||
const email = `sudo-${alphaNumericNanoId(16)}-${orgId}@infisical.com`; // We add a nanoid because the email is unique. And we have to create a new ghost user each time, so we can have access to the private key.
|
const email = `sudo-${alphaNumericNanoId(16)}-${orgId}@infisical.com`; // We add a nanoid because the email is unique. And we have to create a new ghost user each time, so we can have access to the private key.
|
||||||
|
|
||||||
@@ -63,25 +67,36 @@ const createUserWithGhostUser = async (
|
|||||||
.onConflict("userId")
|
.onConflict("userId")
|
||||||
.merge();
|
.merge();
|
||||||
|
|
||||||
await knex(TableName.OrgMembership)
|
const [orgMembership] = await knex(TableName.Membership)
|
||||||
.insert({
|
.insert({
|
||||||
orgId,
|
scope: AccessScope.Organization,
|
||||||
userId: ghostUser.id,
|
scopeOrgId: orgId,
|
||||||
role: OrgMembershipRole.Admin,
|
actorUserId: ghostUser.id,
|
||||||
status: OrgMembershipStatus.Accepted,
|
status: OrgMembershipStatus.Accepted,
|
||||||
isActive: true
|
isActive: true
|
||||||
})
|
})
|
||||||
.returning("*");
|
.returning("*");
|
||||||
|
|
||||||
const [projectMembership] = await knex(TableName.ProjectMembership)
|
await knex(TableName.MembershipRole).insert([
|
||||||
|
{
|
||||||
|
membershipId: orgMembership.id,
|
||||||
|
role: OrgMembershipRole.Admin
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
const [projectMembership] = await knex(TableName.Membership)
|
||||||
.insert({
|
.insert({
|
||||||
userId: ghostUser.id,
|
actorUserId: ghostUser.id,
|
||||||
projectId
|
scopeProjectId: projectId,
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
scopeOrgId: orgId,
|
||||||
|
status: OrgMembershipStatus.Accepted,
|
||||||
|
isActive: true
|
||||||
})
|
})
|
||||||
.returning("*");
|
.returning("*");
|
||||||
|
|
||||||
await knex(TableName.ProjectUserMembershipRole).insert({
|
await knex(TableName.MembershipRole).insert({
|
||||||
projectMembershipId: projectMembership.id,
|
membershipId: projectMembership.id,
|
||||||
role: ProjectMembershipRole.Admin
|
role: ProjectMembershipRole.Admin
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -142,17 +157,16 @@ const createUserWithGhostUser = async (
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Create a membership for the user
|
// Create a membership for the user
|
||||||
const userProjectMembership = await projectMembershipDAL.create(
|
const userProjectMembership = await membershipDAL.create(
|
||||||
{
|
{
|
||||||
projectId,
|
scopeProjectId: projectId,
|
||||||
userId: user.id
|
scope: AccessScope.Project,
|
||||||
|
actorUserId: user.id,
|
||||||
|
scopeOrgId: orgId
|
||||||
},
|
},
|
||||||
knex
|
knex
|
||||||
);
|
);
|
||||||
await projectUserMembershipRoleDAL.create(
|
await membershipRoleDAL.create({ membershipId: userProjectMembership.id, role: ProjectMembershipRole.Admin }, knex);
|
||||||
{ projectMembershipId: userProjectMembership.id, role: ProjectMembershipRole.Admin },
|
|
||||||
knex
|
|
||||||
);
|
|
||||||
|
|
||||||
// Create a project key for the user
|
// Create a project key for the user
|
||||||
await projectKeyDAL.create(
|
await projectKeyDAL.create(
|
||||||
@@ -181,7 +195,21 @@ export async function seed(knex: Knex): Promise<void> {
|
|||||||
initLogger();
|
initLogger();
|
||||||
|
|
||||||
const superAdminDAL = superAdminDALFactory(knex);
|
const superAdminDAL = superAdminDALFactory(knex);
|
||||||
await initEnvConfig(superAdminDAL, logger);
|
const kmsRootConfigDAL = kmsRootConfigDALFactory(knex);
|
||||||
|
|
||||||
|
const hsmConfig = getHsmConfig(logger);
|
||||||
|
|
||||||
|
const hsmModule = initializeHsmModule(hsmConfig);
|
||||||
|
hsmModule.initialize();
|
||||||
|
|
||||||
|
const hsmService = hsmServiceFactory({
|
||||||
|
hsmModule: hsmModule.getModule(),
|
||||||
|
envConfig: hsmConfig
|
||||||
|
});
|
||||||
|
|
||||||
|
await hsmService.startService();
|
||||||
|
|
||||||
|
await initEnvConfig(hsmService, kmsRootConfigDAL, superAdminDAL, logger);
|
||||||
|
|
||||||
const [project] = await knex(TableName.Project)
|
const [project] = await knex(TableName.Project)
|
||||||
.insert({
|
.insert({
|
||||||
@@ -195,10 +223,11 @@ export async function seed(knex: Knex): Promise<void> {
|
|||||||
})
|
})
|
||||||
.returning("*");
|
.returning("*");
|
||||||
|
|
||||||
const userOrgMembership = await knex(TableName.OrgMembership)
|
const userOrgMembership = await knex(TableName.Membership)
|
||||||
.where({
|
.where({
|
||||||
orgId: seedData1.organization.id,
|
scopeOrgId: seedData1.organization.id,
|
||||||
userId: seedData1.id
|
actorUserId: seedData1.id,
|
||||||
|
scope: AccessScope.Organization
|
||||||
})
|
})
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { ProjectMembershipRole, ProjectType, ProjectVersion, TableName } from "../schemas";
|
import { AccessScope, ProjectMembershipRole, ProjectType, ProjectVersion, TableName } from "../schemas";
|
||||||
import { seedData1 } from "../seed-data";
|
import { seedData1 } from "../seed-data";
|
||||||
|
|
||||||
export const DEFAULT_PROJECT_ENVS = [
|
export const DEFAULT_PROJECT_ENVS = [
|
||||||
@@ -23,15 +23,17 @@ export async function seed(knex: Knex): Promise<void> {
|
|||||||
})
|
})
|
||||||
.returning("*");
|
.returning("*");
|
||||||
|
|
||||||
const projectMembershipV3 = await knex(TableName.ProjectMembership)
|
const projectMembershipV3 = await knex(TableName.Membership)
|
||||||
.insert({
|
.insert({
|
||||||
projectId: projectV2.id,
|
scopeProjectId: projectV2.id,
|
||||||
userId: seedData1.id
|
actorUserId: seedData1.id,
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
scopeOrgId: seedData1.organization.id
|
||||||
})
|
})
|
||||||
.returning("*");
|
.returning("*");
|
||||||
await knex(TableName.ProjectUserMembershipRole).insert({
|
await knex(TableName.MembershipRole).insert({
|
||||||
role: ProjectMembershipRole.Admin,
|
role: ProjectMembershipRole.Admin,
|
||||||
projectMembershipId: projectMembershipV3[0].id
|
membershipId: projectMembershipV3[0].id
|
||||||
});
|
});
|
||||||
|
|
||||||
// create default environments and default folders
|
// create default environments and default folders
|
||||||
|
|||||||
@@ -1,22 +1,37 @@
|
|||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { initEnvConfig } from "@app/lib/config/env";
|
import { initializeHsmModule } from "@app/ee/services/hsm/hsm-fns";
|
||||||
|
import { hsmServiceFactory } from "@app/ee/services/hsm/hsm-service";
|
||||||
|
import { getHsmConfig, initEnvConfig } from "@app/lib/config/env";
|
||||||
import { crypto } from "@app/lib/crypto/cryptography";
|
import { crypto } from "@app/lib/crypto/cryptography";
|
||||||
import { initLogger, logger } from "@app/lib/logger";
|
import { initLogger, logger } from "@app/lib/logger";
|
||||||
|
import { kmsRootConfigDALFactory } from "@app/services/kms/kms-root-config-dal";
|
||||||
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||||
|
|
||||||
import { IdentityAuthMethod, OrgMembershipRole, ProjectMembershipRole, TableName } from "../schemas";
|
import { AccessScope, IdentityAuthMethod, OrgMembershipRole, ProjectMembershipRole, TableName } from "../schemas";
|
||||||
import { seedData1 } from "../seed-data";
|
import { seedData1 } from "../seed-data";
|
||||||
|
|
||||||
export async function seed(knex: Knex): Promise<void> {
|
export async function seed(knex: Knex): Promise<void> {
|
||||||
// Deletes ALL existing entries
|
// Deletes ALL existing entries
|
||||||
await knex(TableName.Identity).del();
|
await knex(TableName.Identity).del();
|
||||||
await knex(TableName.IdentityOrgMembership).del();
|
|
||||||
|
|
||||||
initLogger();
|
initLogger();
|
||||||
|
|
||||||
const superAdminDAL = superAdminDALFactory(knex);
|
const superAdminDAL = superAdminDALFactory(knex);
|
||||||
await initEnvConfig(superAdminDAL, logger);
|
const kmsRootConfigDAL = kmsRootConfigDALFactory(knex);
|
||||||
|
const hsmConfig = getHsmConfig(logger);
|
||||||
|
|
||||||
|
const hsmModule = initializeHsmModule(hsmConfig);
|
||||||
|
hsmModule.initialize();
|
||||||
|
|
||||||
|
const hsmService = hsmServiceFactory({
|
||||||
|
hsmModule: hsmModule.getModule(),
|
||||||
|
envConfig: hsmConfig
|
||||||
|
});
|
||||||
|
|
||||||
|
await hsmService.startService();
|
||||||
|
|
||||||
|
await initEnvConfig(hsmService, kmsRootConfigDAL, superAdminDAL, logger);
|
||||||
|
|
||||||
// Inserts seed entries
|
// Inserts seed entries
|
||||||
await knex(TableName.Identity).insert([
|
await knex(TableName.Identity).insert([
|
||||||
@@ -25,7 +40,8 @@ export async function seed(knex: Knex): Promise<void> {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
id: seedData1.machineIdentity.id,
|
id: seedData1.machineIdentity.id,
|
||||||
name: seedData1.machineIdentity.name,
|
name: seedData1.machineIdentity.name,
|
||||||
authMethod: IdentityAuthMethod.UNIVERSAL_AUTH
|
authMethod: IdentityAuthMethod.UNIVERSAL_AUTH,
|
||||||
|
orgId: seedData1.organization.id
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
const identityUa = await knex(TableName.IdentityUniversalAuth)
|
const identityUa = await knex(TableName.IdentityUniversalAuth)
|
||||||
@@ -78,34 +94,47 @@ export async function seed(knex: Knex): Promise<void> {
|
|||||||
isClientSecretRevoked: false
|
isClientSecretRevoked: false
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
await knex(TableName.IdentityOrgMembership).insert([
|
const [orgMembership] = await knex(TableName.Membership)
|
||||||
|
.insert([
|
||||||
{
|
{
|
||||||
identityId: seedData1.machineIdentity.id,
|
actorIdentityId: seedData1.machineIdentity.id,
|
||||||
orgId: seedData1.organization.id,
|
scopeOrgId: seedData1.organization.id,
|
||||||
|
scope: AccessScope.Organization
|
||||||
|
}
|
||||||
|
])
|
||||||
|
.returning("*");
|
||||||
|
await knex(TableName.MembershipRole).insert([
|
||||||
|
{
|
||||||
|
membershipId: orgMembership.id,
|
||||||
role: OrgMembershipRole.Admin
|
role: OrgMembershipRole.Admin
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const identityProjectMembership = await knex(TableName.IdentityProjectMembership)
|
const identityProjectMembership = await knex(TableName.Membership)
|
||||||
.insert({
|
.insert({
|
||||||
identityId: seedData1.machineIdentity.id,
|
actorIdentityId: seedData1.machineIdentity.id,
|
||||||
projectId: seedData1.project.id
|
scopeOrgId: seedData1.organization.id,
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
scopeProjectId: seedData1.project.id
|
||||||
})
|
})
|
||||||
.returning("*");
|
.returning("*");
|
||||||
|
|
||||||
await knex(TableName.IdentityProjectMembershipRole).insert({
|
await knex(TableName.MembershipRole).insert({
|
||||||
role: ProjectMembershipRole.Admin,
|
role: ProjectMembershipRole.Admin,
|
||||||
projectMembershipId: identityProjectMembership[0].id
|
membershipId: identityProjectMembership[0].id
|
||||||
});
|
});
|
||||||
const identityProjectMembershipV3 = await knex(TableName.IdentityProjectMembership)
|
|
||||||
|
const identityProjectMembershipV3 = await knex(TableName.Membership)
|
||||||
.insert({
|
.insert({
|
||||||
identityId: seedData1.machineIdentity.id,
|
actorIdentityId: seedData1.machineIdentity.id,
|
||||||
projectId: seedData1.projectV3.id
|
scopeOrgId: seedData1.organization.id,
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
scopeProjectId: seedData1.projectV3.id
|
||||||
})
|
})
|
||||||
.returning("*");
|
.returning("*");
|
||||||
|
|
||||||
await knex(TableName.IdentityProjectMembershipRole).insert({
|
await knex(TableName.MembershipRole).insert({
|
||||||
role: ProjectMembershipRole.Admin,
|
role: ProjectMembershipRole.Admin,
|
||||||
projectMembershipId: identityProjectMembershipV3[0].id
|
membershipId: identityProjectMembershipV3[0].id
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,35 @@ import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
|||||||
export const registerCertificateEstRouter = async (server: FastifyZodProvider) => {
|
export const registerCertificateEstRouter = async (server: FastifyZodProvider) => {
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
|
|
||||||
|
const getIdentifierType = async (identifier: string): Promise<"template" | "profile" | null> => {
|
||||||
|
try {
|
||||||
|
// Try to find as profile first using internal access
|
||||||
|
await server.services.certificateProfile.getEstConfigurationByProfile({
|
||||||
|
profileId: identifier,
|
||||||
|
isInternal: true
|
||||||
|
});
|
||||||
|
return "profile";
|
||||||
|
} catch (profileError) {
|
||||||
|
try {
|
||||||
|
await server.services.certificateTemplate.getEstConfiguration({
|
||||||
|
isInternal: true,
|
||||||
|
certificateTemplateId: identifier
|
||||||
|
});
|
||||||
|
return "template";
|
||||||
|
} catch (templateError) {
|
||||||
|
server.log.debug(
|
||||||
|
{
|
||||||
|
identifier,
|
||||||
|
profileError: profileError instanceof Error ? profileError.message : "Unknown error",
|
||||||
|
templateError: templateError instanceof Error ? templateError.message : "Unknown error"
|
||||||
|
},
|
||||||
|
"EST identifier not found as profile or template"
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// add support for CSR bodies
|
// add support for CSR bodies
|
||||||
server.addContentTypeParser("application/pkcs10", { parseAs: "string" }, (_, body, done) => {
|
server.addContentTypeParser("application/pkcs10", { parseAs: "string" }, (_, body, done) => {
|
||||||
try {
|
try {
|
||||||
@@ -59,11 +88,29 @@ export const registerCertificateEstRouter = async (server: FastifyZodProvider) =
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const certificateTemplateId = urlFragments.slice(-2)[0];
|
const identifier = urlFragments.slice(-2)[0];
|
||||||
const estConfig = await server.services.certificateTemplate.getEstConfiguration({
|
|
||||||
isInternal: true,
|
const identifierType = await getIdentifierType(identifier);
|
||||||
certificateTemplateId
|
if (!identifierType) {
|
||||||
|
res.raw.statusCode = 404;
|
||||||
|
res.raw.setHeader("Content-Type", "text/plain");
|
||||||
|
res.raw.write("Certificate template or profile not found");
|
||||||
|
res.raw.flushHeaders();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let estConfig;
|
||||||
|
if (identifierType === "profile") {
|
||||||
|
estConfig = await server.services.certificateProfile.getEstConfigurationByProfile({
|
||||||
|
profileId: identifier,
|
||||||
|
isInternal: true
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
estConfig = await server.services.certificateTemplate.getEstConfiguration({
|
||||||
|
isInternal: true,
|
||||||
|
certificateTemplateId: identifier
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!estConfig.isEnabled) {
|
if (!estConfig.isEnabled) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -95,14 +142,14 @@ export const registerCertificateEstRouter = async (server: FastifyZodProvider) =
|
|||||||
|
|
||||||
server.route({
|
server.route({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
url: "/:certificateTemplateId/simpleenroll",
|
url: "/:identifier/simpleenroll",
|
||||||
config: {
|
config: {
|
||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
body: z.string().min(1),
|
body: z.string().min(1),
|
||||||
params: z.object({
|
params: z.object({
|
||||||
certificateTemplateId: z.string().min(1)
|
identifier: z.string().min(1)
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.string()
|
200: z.string()
|
||||||
@@ -112,9 +159,23 @@ export const registerCertificateEstRouter = async (server: FastifyZodProvider) =
|
|||||||
void res.header("Content-Type", "application/pkcs7-mime; smime-type=certs-only");
|
void res.header("Content-Type", "application/pkcs7-mime; smime-type=certs-only");
|
||||||
void res.header("Content-Transfer-Encoding", "base64");
|
void res.header("Content-Transfer-Encoding", "base64");
|
||||||
|
|
||||||
|
const { identifier } = req.params;
|
||||||
|
const identifierType = await getIdentifierType(identifier);
|
||||||
|
|
||||||
|
if (!identifierType) {
|
||||||
|
throw new BadRequestError({ message: "Certificate template or profile not found" });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (identifierType === "profile") {
|
||||||
|
return server.services.certificateEstV3.simpleEnrollByProfile({
|
||||||
|
csr: req.body,
|
||||||
|
profileId: identifier,
|
||||||
|
sslClientCert: req.headers[appCfg.SSL_CLIENT_CERTIFICATE_HEADER_KEY] as string
|
||||||
|
});
|
||||||
|
}
|
||||||
return server.services.certificateEst.simpleEnroll({
|
return server.services.certificateEst.simpleEnroll({
|
||||||
csr: req.body,
|
csr: req.body,
|
||||||
certificateTemplateId: req.params.certificateTemplateId,
|
certificateTemplateId: identifier,
|
||||||
sslClientCert: req.headers[appCfg.SSL_CLIENT_CERTIFICATE_HEADER_KEY] as string
|
sslClientCert: req.headers[appCfg.SSL_CLIENT_CERTIFICATE_HEADER_KEY] as string
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -122,14 +183,14 @@ export const registerCertificateEstRouter = async (server: FastifyZodProvider) =
|
|||||||
|
|
||||||
server.route({
|
server.route({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
url: "/:certificateTemplateId/simplereenroll",
|
url: "/:identifier/simplereenroll",
|
||||||
config: {
|
config: {
|
||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
body: z.string().min(1),
|
body: z.string().min(1),
|
||||||
params: z.object({
|
params: z.object({
|
||||||
certificateTemplateId: z.string().min(1)
|
identifier: z.string().min(1)
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.string()
|
200: z.string()
|
||||||
@@ -139,9 +200,23 @@ export const registerCertificateEstRouter = async (server: FastifyZodProvider) =
|
|||||||
void res.header("Content-Type", "application/pkcs7-mime; smime-type=certs-only");
|
void res.header("Content-Type", "application/pkcs7-mime; smime-type=certs-only");
|
||||||
void res.header("Content-Transfer-Encoding", "base64");
|
void res.header("Content-Transfer-Encoding", "base64");
|
||||||
|
|
||||||
|
const { identifier } = req.params;
|
||||||
|
const identifierType = await getIdentifierType(identifier);
|
||||||
|
|
||||||
|
if (!identifierType) {
|
||||||
|
throw new BadRequestError({ message: "Certificate template or profile not found" });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (identifierType === "profile") {
|
||||||
|
return server.services.certificateEstV3.simpleReenrollByProfile({
|
||||||
|
csr: req.body,
|
||||||
|
profileId: identifier,
|
||||||
|
sslClientCert: req.headers[appCfg.SSL_CLIENT_CERTIFICATE_HEADER_KEY] as string
|
||||||
|
});
|
||||||
|
}
|
||||||
return server.services.certificateEst.simpleReenroll({
|
return server.services.certificateEst.simpleReenroll({
|
||||||
csr: req.body,
|
csr: req.body,
|
||||||
certificateTemplateId: req.params.certificateTemplateId,
|
certificateTemplateId: identifier,
|
||||||
sslClientCert: req.headers[appCfg.SSL_CLIENT_CERTIFICATE_HEADER_KEY] as string
|
sslClientCert: req.headers[appCfg.SSL_CLIENT_CERTIFICATE_HEADER_KEY] as string
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -149,13 +224,13 @@ export const registerCertificateEstRouter = async (server: FastifyZodProvider) =
|
|||||||
|
|
||||||
server.route({
|
server.route({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
url: "/:certificateTemplateId/cacerts",
|
url: "/:identifier/cacerts",
|
||||||
config: {
|
config: {
|
||||||
rateLimit: readLimit
|
rateLimit: readLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
params: z.object({
|
params: z.object({
|
||||||
certificateTemplateId: z.string().min(1)
|
identifier: z.string().min(1)
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.string()
|
200: z.string()
|
||||||
@@ -165,8 +240,20 @@ export const registerCertificateEstRouter = async (server: FastifyZodProvider) =
|
|||||||
void res.header("Content-Type", "application/pkcs7-mime; smime-type=certs-only");
|
void res.header("Content-Type", "application/pkcs7-mime; smime-type=certs-only");
|
||||||
void res.header("Content-Transfer-Encoding", "base64");
|
void res.header("Content-Transfer-Encoding", "base64");
|
||||||
|
|
||||||
|
const { identifier } = req.params;
|
||||||
|
const identifierType = await getIdentifierType(identifier);
|
||||||
|
|
||||||
|
if (!identifierType) {
|
||||||
|
throw new BadRequestError({ message: "Certificate template or profile not found" });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (identifierType === "profile") {
|
||||||
|
return server.services.certificateEstV3.getCaCertsByProfile({
|
||||||
|
profileId: identifier
|
||||||
|
});
|
||||||
|
}
|
||||||
return server.services.certificateEst.getCaCerts({
|
return server.services.certificateEst.getCaCerts({
|
||||||
certificateTemplateId: req.params.certificateTemplateId
|
certificateTemplateId: identifier
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { packRules } from "@casl/ability/extra";
|
import { packRules } from "@casl/ability/extra";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { ProjectMembershipRole, ProjectRolesSchema } from "@app/db/schemas";
|
import { AccessScope, ProjectMembershipRole, ProjectRolesSchema } 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 {
|
import {
|
||||||
backfillPermissionV1SchemaToV2Schema,
|
backfillPermissionV1SchemaToV2Schema,
|
||||||
@@ -13,7 +13,6 @@ import { slugSchema } from "@app/server/lib/schemas";
|
|||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { SanitizedRoleSchemaV1 } from "@app/server/routes/sanitizedSchemas";
|
import { SanitizedRoleSchemaV1 } from "@app/server/routes/sanitizedSchemas";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
import { ProjectRoleServiceIdentifierType } from "@app/services/project-role/project-role-types";
|
|
||||||
|
|
||||||
export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProvider) => {
|
export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProvider) => {
|
||||||
server.route({
|
server.route({
|
||||||
@@ -55,14 +54,16 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv
|
|||||||
packRules(backfillPermissionV1SchemaToV2Schema(req.body.permissions, true))
|
packRules(backfillPermissionV1SchemaToV2Schema(req.body.permissions, true))
|
||||||
);
|
);
|
||||||
|
|
||||||
const role = await server.services.projectRole.createRole({
|
const { id: projectId } = await server.services.convertor.projectSlugToId({
|
||||||
actorAuthMethod: req.permission.authMethod,
|
slug: req.params.projectSlug,
|
||||||
actorId: req.permission.id,
|
orgId: req.permission.orgId
|
||||||
actorOrgId: req.permission.orgId,
|
});
|
||||||
actor: req.permission.type,
|
const role = await server.services.role.createRole({
|
||||||
filter: {
|
permission: req.permission,
|
||||||
type: ProjectRoleServiceIdentifierType.SLUG,
|
scopeData: {
|
||||||
projectSlug: req.params.projectSlug
|
scope: AccessScope.Project,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
projectId
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
...req.body,
|
...req.body,
|
||||||
@@ -73,7 +74,7 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv
|
|||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: req.permission.orgId,
|
orgId: req.permission.orgId,
|
||||||
projectId: role.projectId,
|
projectId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.CREATE_PROJECT_ROLE,
|
type: EventType.CREATE_PROJECT_ROLE,
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -86,7 +87,7 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return { role };
|
return { role: { ...role, projectId: role.projectId as string } };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -131,12 +132,21 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv
|
|||||||
? JSON.stringify(packRules(backfillPermissionV1SchemaToV2Schema(req.body.permissions, true)))
|
? JSON.stringify(packRules(backfillPermissionV1SchemaToV2Schema(req.body.permissions, true)))
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const role = await server.services.projectRole.updateRole({
|
const { id: projectId } = await server.services.convertor.projectSlugToId({
|
||||||
actorAuthMethod: req.permission.authMethod,
|
slug: req.params.projectSlug,
|
||||||
actorId: req.permission.id,
|
orgId: req.permission.orgId
|
||||||
actorOrgId: req.permission.orgId,
|
});
|
||||||
actor: req.permission.type,
|
|
||||||
roleId: req.params.roleId,
|
const role = await server.services.role.updateRole({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
projectId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
id: req.params.roleId
|
||||||
|
},
|
||||||
data: {
|
data: {
|
||||||
...req.body,
|
...req.body,
|
||||||
permissions: stringifiedPermissions
|
permissions: stringifiedPermissions
|
||||||
@@ -146,7 +156,7 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv
|
|||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: req.permission.orgId,
|
orgId: req.permission.orgId,
|
||||||
projectId: role.projectId,
|
projectId: role.projectId as string,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.UPDATE_PROJECT_ROLE,
|
type: EventType.UPDATE_PROJECT_ROLE,
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -159,7 +169,7 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return { role };
|
return { role: { ...role, projectId: role.projectId as string } };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -188,18 +198,27 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const role = await server.services.projectRole.deleteRole({
|
const { id: projectId } = await server.services.convertor.projectSlugToId({
|
||||||
actorAuthMethod: req.permission.authMethod,
|
slug: req.params.projectSlug,
|
||||||
actorId: req.permission.id,
|
orgId: req.permission.orgId
|
||||||
actorOrgId: req.permission.orgId,
|
});
|
||||||
actor: req.permission.type,
|
|
||||||
roleId: req.params.roleId
|
const role = await server.services.role.deleteRole({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
projectId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
id: req.params.roleId
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: req.permission.orgId,
|
orgId: req.permission.orgId,
|
||||||
projectId: role.projectId,
|
projectId: role.projectId as string,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.DELETE_PROJECT_ROLE,
|
type: EventType.DELETE_PROJECT_ROLE,
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -210,7 +229,7 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return { role };
|
return { role: { ...role, projectId: role.projectId as string } };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -238,17 +257,21 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const roles = await server.services.projectRole.listRoles({
|
const { id: projectId } = await server.services.convertor.projectSlugToId({
|
||||||
actorAuthMethod: req.permission.authMethod,
|
slug: req.params.projectSlug,
|
||||||
actorId: req.permission.id,
|
orgId: req.permission.orgId
|
||||||
actorOrgId: req.permission.orgId,
|
|
||||||
actor: req.permission.type,
|
|
||||||
filter: {
|
|
||||||
type: ProjectRoleServiceIdentifierType.SLUG,
|
|
||||||
projectSlug: req.params.projectSlug
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return { roles };
|
|
||||||
|
const { roles } = await server.services.role.listRoles({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
projectId
|
||||||
|
},
|
||||||
|
data: {}
|
||||||
|
});
|
||||||
|
return { roles: roles.map((el) => ({ ...el, projectId: el.projectId as string })) };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -265,78 +288,30 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv
|
|||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
role: SanitizedRoleSchemaV1.omit({ version: true })
|
role: SanitizedRoleSchemaV1
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const role = await server.services.projectRole.getRoleBySlug({
|
const { id: projectId } = await server.services.convertor.projectSlugToId({
|
||||||
actorAuthMethod: req.permission.authMethod,
|
slug: req.params.projectSlug,
|
||||||
actorId: req.permission.id,
|
orgId: req.permission.orgId
|
||||||
actorOrgId: req.permission.orgId,
|
|
||||||
actor: req.permission.type,
|
|
||||||
filter: {
|
|
||||||
type: ProjectRoleServiceIdentifierType.SLUG,
|
|
||||||
projectSlug: req.params.projectSlug
|
|
||||||
},
|
|
||||||
roleSlug: req.params.slug
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return { role };
|
const role = await server.services.role.getRoleBySlug({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
projectId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
slug: req.params.slug
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
server.route({
|
return { role: { ...role, projectId: role.projectId as string } };
|
||||||
method: "GET",
|
|
||||||
url: "/:projectId/permissions",
|
|
||||||
config: {
|
|
||||||
rateLimit: readLimit
|
|
||||||
},
|
|
||||||
schema: {
|
|
||||||
params: z.object({
|
|
||||||
projectId: z.string().trim()
|
|
||||||
}),
|
|
||||||
response: {
|
|
||||||
200: z.object({
|
|
||||||
data: z.object({
|
|
||||||
membership: z.object({
|
|
||||||
id: z.string(),
|
|
||||||
roles: z
|
|
||||||
.object({
|
|
||||||
role: z.string()
|
|
||||||
})
|
|
||||||
.array()
|
|
||||||
}),
|
|
||||||
assumedPrivilegeDetails: z
|
|
||||||
.object({
|
|
||||||
actorId: z.string(),
|
|
||||||
actorType: z.string(),
|
|
||||||
actorName: z.string(),
|
|
||||||
actorEmail: z.string().optional()
|
|
||||||
})
|
|
||||||
.optional(),
|
|
||||||
permissions: z.any().array()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
|
||||||
handler: async (req) => {
|
|
||||||
const { permissions, membership, assumedPrivilegeDetails } = await server.services.projectRole.getUserPermission(
|
|
||||||
req.permission.id,
|
|
||||||
req.params.projectId,
|
|
||||||
req.permission.authMethod,
|
|
||||||
req.permission.orgId
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
data: {
|
|
||||||
permissions,
|
|
||||||
membership,
|
|
||||||
assumedPrivilegeDetails
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import slugify from "@sindresorhus/slugify";
|
import slugify from "@sindresorhus/slugify";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { IdentityProjectAdditionalPrivilegeTemporaryMode } from "@app/ee/services/identity-project-additional-privilege/identity-project-additional-privilege-types";
|
import { AccessScope, TemporaryPermissionMode } from "@app/db/schemas";
|
||||||
import { backfillPermissionV1SchemaToV2Schema } from "@app/ee/services/permission/project-permission";
|
import { backfillPermissionV1SchemaToV2Schema } from "@app/ee/services/permission/project-permission";
|
||||||
import { ApiDocsTags, IDENTITY_ADDITIONAL_PRIVILEGE } from "@app/lib/api-docs";
|
import { ApiDocsTags, IDENTITY_ADDITIONAL_PRIVILEGE } from "@app/lib/api-docs";
|
||||||
import { UnauthorizedError } from "@app/lib/errors";
|
import { UnauthorizedError } from "@app/lib/errors";
|
||||||
@@ -15,7 +15,7 @@ import {
|
|||||||
ProjectSpecificPrivilegePermissionSchema,
|
ProjectSpecificPrivilegePermissionSchema,
|
||||||
SanitizedIdentityPrivilegeSchema
|
SanitizedIdentityPrivilegeSchema
|
||||||
} from "@app/server/routes/sanitizedSchemas";
|
} from "@app/server/routes/sanitizedSchemas";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { ActorType, AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: FastifyZodProvider) => {
|
export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: FastifyZodProvider) => {
|
||||||
server.route({
|
server.route({
|
||||||
@@ -56,6 +56,10 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
if (!permissions && !privilegePermission) {
|
if (!permissions && !privilegePermission) {
|
||||||
throw new UnauthorizedError({ message: "Permission or privilegePermission must be provided" });
|
throw new UnauthorizedError({ message: "Permission or privilegePermission must be provided" });
|
||||||
}
|
}
|
||||||
|
const { id: projectId } = await server.services.convertor.projectSlugToId({
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
slug: req.body.projectSlug
|
||||||
|
});
|
||||||
|
|
||||||
const permission = privilegePermission
|
const permission = privilegePermission
|
||||||
? privilegePermission.actions.map((action) => ({
|
? privilegePermission.actions.map((action) => ({
|
||||||
@@ -64,19 +68,35 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
conditions: privilegePermission.conditions
|
conditions: privilegePermission.conditions
|
||||||
}))
|
}))
|
||||||
: permissions!;
|
: permissions!;
|
||||||
const privilege = await server.services.identityProjectAdditionalPrivilege.create({
|
|
||||||
actorId: req.permission.id,
|
const { additionalPrivilege: privilege } = await server.services.additionalPrivilege.createAdditionalPrivilege({
|
||||||
actor: req.permission.type,
|
permission: req.permission,
|
||||||
actorOrgId: req.permission.orgId,
|
scopeData: {
|
||||||
actorAuthMethod: req.permission.authMethod,
|
scope: AccessScope.Project,
|
||||||
|
projectId,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
actorId: req.body.identityId,
|
||||||
|
actorType: ActorType.IDENTITY,
|
||||||
...req.body,
|
...req.body,
|
||||||
slug: req.body.slug ?? slugify(alphaNumericNanoId(12)),
|
|
||||||
isTemporary: false,
|
isTemporary: false,
|
||||||
|
name: req.body.slug || slugify(alphaNumericNanoId(8)),
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore-error this is valid ts
|
// @ts-ignore-error this is valid ts
|
||||||
permissions: backfillPermissionV1SchemaToV2Schema(permission)
|
permissions: backfillPermissionV1SchemaToV2Schema(permission)
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return { privilege };
|
|
||||||
|
return {
|
||||||
|
privilege: {
|
||||||
|
...privilege,
|
||||||
|
identityId: req.body.identityId,
|
||||||
|
projectMembershipId: projectId,
|
||||||
|
projectId,
|
||||||
|
slug: privilege.name
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -106,7 +126,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
IDENTITY_ADDITIONAL_PRIVILEGE.CREATE.privilegePermission
|
IDENTITY_ADDITIONAL_PRIVILEGE.CREATE.privilegePermission
|
||||||
).optional(),
|
).optional(),
|
||||||
temporaryMode: z
|
temporaryMode: z
|
||||||
.nativeEnum(IdentityProjectAdditionalPrivilegeTemporaryMode)
|
.nativeEnum(TemporaryPermissionMode)
|
||||||
.describe(IDENTITY_ADDITIONAL_PRIVILEGE.CREATE.temporaryMode),
|
.describe(IDENTITY_ADDITIONAL_PRIVILEGE.CREATE.temporaryMode),
|
||||||
temporaryRange: z
|
temporaryRange: z
|
||||||
.string()
|
.string()
|
||||||
@@ -138,19 +158,39 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
}))
|
}))
|
||||||
: permissions!;
|
: permissions!;
|
||||||
|
|
||||||
const privilege = await server.services.identityProjectAdditionalPrivilege.create({
|
const { id: projectId } = await server.services.convertor.projectSlugToId({
|
||||||
actorId: req.permission.id,
|
orgId: req.permission.orgId,
|
||||||
actor: req.permission.type,
|
slug: req.body.projectSlug
|
||||||
actorOrgId: req.permission.orgId,
|
});
|
||||||
actorAuthMethod: req.permission.authMethod,
|
|
||||||
|
const { additionalPrivilege: privilege } = await server.services.additionalPrivilege.createAdditionalPrivilege({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
projectId,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
actorId: req.body.identityId,
|
||||||
|
actorType: ActorType.IDENTITY,
|
||||||
...req.body,
|
...req.body,
|
||||||
slug: req.body.slug ?? slugify(alphaNumericNanoId(12)),
|
|
||||||
isTemporary: true,
|
isTemporary: true,
|
||||||
|
name: req.body.slug || slugify(alphaNumericNanoId(8)),
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore-error this is valid ts
|
// @ts-ignore-error this is valid ts
|
||||||
permissions: backfillPermissionV1SchemaToV2Schema(permission)
|
permissions: backfillPermissionV1SchemaToV2Schema(permission)
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return { privilege };
|
|
||||||
|
return {
|
||||||
|
privilege: {
|
||||||
|
...privilege,
|
||||||
|
identityId: req.body.identityId,
|
||||||
|
projectMembershipId: projectId,
|
||||||
|
projectId,
|
||||||
|
slug: privilege.name
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -183,7 +223,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
).optional(),
|
).optional(),
|
||||||
isTemporary: z.boolean().describe(IDENTITY_ADDITIONAL_PRIVILEGE.UPDATE.isTemporary),
|
isTemporary: z.boolean().describe(IDENTITY_ADDITIONAL_PRIVILEGE.UPDATE.isTemporary),
|
||||||
temporaryMode: z
|
temporaryMode: z
|
||||||
.nativeEnum(IdentityProjectAdditionalPrivilegeTemporaryMode)
|
.nativeEnum(TemporaryPermissionMode)
|
||||||
.describe(IDENTITY_ADDITIONAL_PRIVILEGE.UPDATE.temporaryMode),
|
.describe(IDENTITY_ADDITIONAL_PRIVILEGE.UPDATE.temporaryMode),
|
||||||
temporaryRange: z
|
temporaryRange: z
|
||||||
.string()
|
.string()
|
||||||
@@ -216,18 +256,36 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
conditions: privilegePermission.conditions
|
conditions: privilegePermission.conditions
|
||||||
}))
|
}))
|
||||||
: permissions!;
|
: permissions!;
|
||||||
const privilege = await server.services.identityProjectAdditionalPrivilege.updateBySlug({
|
|
||||||
actorId: req.permission.id,
|
const { id: projectId } = await server.services.convertor.projectSlugToId({
|
||||||
actor: req.permission.type,
|
orgId: req.permission.orgId,
|
||||||
actorOrgId: req.permission.orgId,
|
slug: req.body.projectSlug
|
||||||
actorAuthMethod: req.permission.authMethod,
|
});
|
||||||
slug: req.body.privilegeSlug,
|
|
||||||
identityId: req.body.identityId,
|
const { privilege: privilegeDoc } = await server.services.convertor.additionalPrivilegeNameToDoc(
|
||||||
projectSlug: req.body.projectSlug,
|
req.body.privilegeSlug,
|
||||||
|
projectId
|
||||||
|
);
|
||||||
|
|
||||||
|
const { additionalPrivilege: privilege } = await server.services.additionalPrivilege.updateAdditionalPrivilege({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
projectId,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
actorId: req.body.identityId,
|
||||||
|
actorType: ActorType.IDENTITY,
|
||||||
|
id: privilegeDoc.id
|
||||||
|
},
|
||||||
data: {
|
data: {
|
||||||
|
...req.body,
|
||||||
...updatedInfo,
|
...updatedInfo,
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore-error this is valid ts
|
// @ts-ignore-error this is valid ts
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore-error this is valid ts
|
||||||
permissions: permission
|
permissions: permission
|
||||||
? // eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
? // eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore-error this is valid ts
|
// @ts-ignore-error this is valid ts
|
||||||
@@ -235,7 +293,16 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return { privilege };
|
|
||||||
|
return {
|
||||||
|
privilege: {
|
||||||
|
...privilege,
|
||||||
|
identityId: req.body.identityId,
|
||||||
|
projectMembershipId: projectId,
|
||||||
|
projectId,
|
||||||
|
slug: privilege.name
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -267,16 +334,39 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const privilege = await server.services.identityProjectAdditionalPrivilege.deleteBySlug({
|
const { id: projectId } = await server.services.convertor.projectSlugToId({
|
||||||
actorId: req.permission.id,
|
orgId: req.permission.orgId,
|
||||||
actor: req.permission.type,
|
slug: req.body.projectSlug
|
||||||
actorAuthMethod: req.permission.authMethod,
|
|
||||||
actorOrgId: req.permission.orgId,
|
|
||||||
slug: req.body.privilegeSlug,
|
|
||||||
identityId: req.body.identityId,
|
|
||||||
projectSlug: req.body.projectSlug
|
|
||||||
});
|
});
|
||||||
return { privilege };
|
|
||||||
|
const { privilegeId } = await server.services.convertor.additionalPrivilegeNameToDoc(
|
||||||
|
req.body.privilegeSlug,
|
||||||
|
projectId
|
||||||
|
);
|
||||||
|
|
||||||
|
const { additionalPrivilege: privilege } = await server.services.additionalPrivilege.deleteAdditionalPrivilege({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
projectId,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
actorId: req.body.identityId,
|
||||||
|
actorType: ActorType.IDENTITY,
|
||||||
|
id: privilegeId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
privilege: {
|
||||||
|
...privilege,
|
||||||
|
identityId: req.body.identityId,
|
||||||
|
projectMembershipId: projectId,
|
||||||
|
projectId,
|
||||||
|
slug: privilege.name
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -310,15 +400,39 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const privilege = await server.services.identityProjectAdditionalPrivilege.getPrivilegeDetailsBySlug({
|
const { id: projectId } = await server.services.convertor.projectSlugToId({
|
||||||
actorId: req.permission.id,
|
orgId: req.permission.orgId,
|
||||||
actorAuthMethod: req.permission.authMethod,
|
slug: req.query.projectSlug
|
||||||
actor: req.permission.type,
|
|
||||||
actorOrgId: req.permission.orgId,
|
|
||||||
slug: req.params.privilegeSlug,
|
|
||||||
...req.query
|
|
||||||
});
|
});
|
||||||
return { privilege };
|
|
||||||
|
const { privilegeId } = await server.services.convertor.additionalPrivilegeNameToDoc(
|
||||||
|
req.params.privilegeSlug,
|
||||||
|
projectId
|
||||||
|
);
|
||||||
|
|
||||||
|
const { additionalPrivilege: privilege } = await server.services.additionalPrivilege.getAdditionalPrivilegeById({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
projectId,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
actorId: req.query.identityId,
|
||||||
|
actorType: ActorType.IDENTITY,
|
||||||
|
id: privilegeId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
privilege: {
|
||||||
|
...privilege,
|
||||||
|
identityId: req.query.identityId,
|
||||||
|
projectMembershipId: projectId,
|
||||||
|
projectId,
|
||||||
|
slug: privilege.name
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -349,15 +463,32 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const privileges = await server.services.identityProjectAdditionalPrivilege.listIdentityProjectPrivileges({
|
const { id: projectId } = await server.services.convertor.projectSlugToId({
|
||||||
actorId: req.permission.id,
|
orgId: req.permission.orgId,
|
||||||
actor: req.permission.type,
|
slug: req.query.projectSlug
|
||||||
actorAuthMethod: req.permission.authMethod,
|
|
||||||
actorOrgId: req.permission.orgId,
|
|
||||||
...req.query
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { additionalPrivileges: privileges } = await server.services.additionalPrivilege.listAdditionalPrivileges({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
projectId,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
actorId: req.query.identityId,
|
||||||
|
actorType: ActorType.IDENTITY
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
privileges
|
privileges: privileges.map((privilege) => ({
|
||||||
|
...privilege,
|
||||||
|
identityId: req.query.identityId,
|
||||||
|
projectMembershipId: projectId,
|
||||||
|
projectId,
|
||||||
|
slug: privilege.name
|
||||||
|
}))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -23,6 +23,12 @@ import { registerLdapRouter } from "./ldap-router";
|
|||||||
import { registerLicenseRouter } from "./license-router";
|
import { registerLicenseRouter } from "./license-router";
|
||||||
import { registerOidcRouter } from "./oidc-router";
|
import { registerOidcRouter } from "./oidc-router";
|
||||||
import { registerOrgRoleRouter } from "./org-role-router";
|
import { registerOrgRoleRouter } from "./org-role-router";
|
||||||
|
import { PAM_ACCOUNT_REGISTER_ROUTER_MAP } from "./pam-account-routers";
|
||||||
|
import { registerPamAccountRouter } from "./pam-account-routers/pam-account-router";
|
||||||
|
import { registerPamFolderRouter } from "./pam-folder-router";
|
||||||
|
import { PAM_RESOURCE_REGISTER_ROUTER_MAP } from "./pam-resource-routers";
|
||||||
|
import { registerPamResourceRouter } from "./pam-resource-routers/pam-resource-router";
|
||||||
|
import { registerPamSessionRouter } from "./pam-session-router";
|
||||||
import { registerPITRouter } from "./pit-router";
|
import { registerPITRouter } from "./pit-router";
|
||||||
import { registerProjectRoleRouter } from "./project-role-router";
|
import { registerProjectRoleRouter } from "./project-role-router";
|
||||||
import { registerProjectRouter } from "./project-router";
|
import { registerProjectRouter } from "./project-router";
|
||||||
@@ -42,12 +48,14 @@ import { registerSshCertRouter } from "./ssh-certificate-router";
|
|||||||
import { registerSshCertificateTemplateRouter } from "./ssh-certificate-template-router";
|
import { registerSshCertificateTemplateRouter } from "./ssh-certificate-template-router";
|
||||||
import { registerSshHostGroupRouter } from "./ssh-host-group-router";
|
import { registerSshHostGroupRouter } from "./ssh-host-group-router";
|
||||||
import { registerSshHostRouter } from "./ssh-host-router";
|
import { registerSshHostRouter } from "./ssh-host-router";
|
||||||
|
import { registerSubOrgRouter } from "./sub-org-router";
|
||||||
import { registerTrustedIpRouter } from "./trusted-ip-router";
|
import { registerTrustedIpRouter } from "./trusted-ip-router";
|
||||||
import { registerUserAdditionalPrivilegeRouter } from "./user-additional-privilege-router";
|
import { registerUserAdditionalPrivilegeRouter } from "./user-additional-privilege-router";
|
||||||
|
|
||||||
export const registerV1EERoutes = async (server: FastifyZodProvider) => {
|
export const registerV1EERoutes = async (server: FastifyZodProvider) => {
|
||||||
// org role starts with organization
|
// org role starts with organization
|
||||||
await server.register(registerOrgRoleRouter, { prefix: "/organization" });
|
await server.register(registerOrgRoleRouter, { prefix: "/organization" });
|
||||||
|
await server.register(registerSubOrgRouter, { prefix: "/sub-organizations" });
|
||||||
await server.register(registerLicenseRouter, { prefix: "/organizations" });
|
await server.register(registerLicenseRouter, { prefix: "/organizations" });
|
||||||
|
|
||||||
// depreciated in favour of infisical workspace
|
// depreciated in favour of infisical workspace
|
||||||
@@ -166,4 +174,40 @@ export const registerV1EERoutes = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
{ prefix: "/kmip" }
|
{ prefix: "/kmip" }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await server.register(
|
||||||
|
async (pamRouter) => {
|
||||||
|
await pamRouter.register(registerPamFolderRouter, { prefix: "/folders" });
|
||||||
|
await pamRouter.register(registerPamSessionRouter, { prefix: "/sessions" });
|
||||||
|
|
||||||
|
await pamRouter.register(
|
||||||
|
async (pamAccountRouter) => {
|
||||||
|
await pamAccountRouter.register(registerPamAccountRouter);
|
||||||
|
|
||||||
|
// Provider-specific endpoints
|
||||||
|
await Promise.all(
|
||||||
|
Object.entries(PAM_ACCOUNT_REGISTER_ROUTER_MAP).map(([provider, router]) =>
|
||||||
|
pamAccountRouter.register(router, { prefix: `/${provider}` })
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
{ prefix: "/accounts" }
|
||||||
|
);
|
||||||
|
|
||||||
|
await pamRouter.register(
|
||||||
|
async (pamResourceRouter) => {
|
||||||
|
await pamResourceRouter.register(registerPamResourceRouter);
|
||||||
|
|
||||||
|
// Provider-specific endpoints
|
||||||
|
await Promise.all(
|
||||||
|
Object.entries(PAM_RESOURCE_REGISTER_ROUTER_MAP).map(([provider, router]) =>
|
||||||
|
pamResourceRouter.register(router, { prefix: `/${provider}` })
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
{ prefix: "/resources" }
|
||||||
|
);
|
||||||
|
},
|
||||||
|
{ prefix: "/pam" }
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -128,7 +128,8 @@ export const registerKmipSpecRouter = async (server: FastifyZodProvider) => {
|
|||||||
200: z.object({
|
200: z.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
value: z.string(),
|
value: z.string(),
|
||||||
algorithm: z.string()
|
algorithm: z.string(),
|
||||||
|
kmipMetadata: z.record(z.any()).nullish()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -433,7 +434,8 @@ export const registerKmipSpecRouter = async (server: FastifyZodProvider) => {
|
|||||||
body: z.object({
|
body: z.object({
|
||||||
key: z.string(),
|
key: z.string(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
algorithm: z.nativeEnum(SymmetricKeyAlgorithm)
|
algorithm: z.nativeEnum(SymmetricKeyAlgorithm),
|
||||||
|
kmipMetadata: z.record(z.any()).nullish()
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
|
|||||||
const plan = await server.services.license.getOrgPlan({
|
const plan = await server.services.license.getOrgPlan({
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
actor: req.permission.type,
|
actor: req.permission.type,
|
||||||
actorOrgId: req.permission.orgId,
|
actorOrgId: req.permission.rootOrgId,
|
||||||
actorAuthMethod: req.permission.authMethod,
|
actorAuthMethod: req.permission.authMethod,
|
||||||
orgId: req.params.organizationId,
|
orgId: req.params.organizationId,
|
||||||
refreshCache: req.query.refreshCache
|
refreshCache: req.query.refreshCache
|
||||||
|
|||||||
@@ -1,12 +1,37 @@
|
|||||||
|
import { packRules } from "@casl/ability/extra";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { OrgMembershipRole, OrgMembershipsSchema, OrgRolesSchema } from "@app/db/schemas";
|
import { AccessScope, OrgMembershipRole, OrgRolesSchema } 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 { OrgPermissionSchema, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
import { slugSchema } from "@app/server/lib/schemas";
|
import { slugSchema } from "@app/server/lib/schemas";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
|
const INVALID_SUBORG_PERMISSIONS = [
|
||||||
|
OrgPermissionSubjects.Sso,
|
||||||
|
OrgPermissionSubjects.Ldap,
|
||||||
|
OrgPermissionSubjects.Scim,
|
||||||
|
OrgPermissionSubjects.GithubOrgSync,
|
||||||
|
OrgPermissionSubjects.GithubOrgSyncManual,
|
||||||
|
OrgPermissionSubjects.Billing,
|
||||||
|
OrgPermissionSubjects.SubOrganization
|
||||||
|
];
|
||||||
|
|
||||||
|
const validateSubOrganizationSubjects = (permissions: unknown) => {
|
||||||
|
const invalidPermissionSubjects = (permissions as { subject: OrgPermissionSubjects }[])
|
||||||
|
.filter((el) => INVALID_SUBORG_PERMISSIONS.includes(el.subject))
|
||||||
|
.map((el) => el.subject);
|
||||||
|
if (invalidPermissionSubjects.length) {
|
||||||
|
const deduplication = Array.from(new Set(invalidPermissionSubjects));
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: `Suborganization contains invalid permission subjects: ${deduplication.join(",")}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
|
export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
|
||||||
server.route({
|
server.route({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
@@ -25,8 +50,7 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
),
|
),
|
||||||
name: z.string().trim(),
|
name: z.string().trim(),
|
||||||
description: z.string().trim().nullish(),
|
description: z.string().trim().nullish(),
|
||||||
// TODO(scott): once UI refactored permissions: OrgPermissionSchema.array()
|
permissions: OrgPermissionSchema.array()
|
||||||
permissions: z.any().array()
|
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
@@ -36,13 +60,23 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const role = await server.services.orgRole.createRole(
|
const isSubOrganization = req.permission.rootOrgId !== req.permission.orgId;
|
||||||
req.permission.id,
|
if (isSubOrganization) {
|
||||||
req.params.organizationId,
|
validateSubOrganizationSubjects(req.body.permissions);
|
||||||
req.body,
|
}
|
||||||
req.permission.authMethod,
|
|
||||||
req.permission.orgId
|
const stringifiedPermissions = JSON.stringify(packRules(req.body.permissions));
|
||||||
);
|
const role = await server.services.role.createRole({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Organization,
|
||||||
|
orgId: req.params.organizationId
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
...req.body,
|
||||||
|
permissions: stringifiedPermissions
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
@@ -59,7 +93,7 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return { role };
|
return { role: { ...role, orgId: role.orgId as string } };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -82,14 +116,17 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const role = await server.services.orgRole.getRole(
|
const role = await server.services.role.getRoleById({
|
||||||
req.permission.id,
|
permission: req.permission,
|
||||||
req.params.organizationId,
|
scopeData: {
|
||||||
req.params.roleId,
|
scope: AccessScope.Organization,
|
||||||
req.permission.authMethod,
|
orgId: req.params.organizationId
|
||||||
req.permission.orgId
|
},
|
||||||
);
|
selector: {
|
||||||
return { role };
|
id: req.params.roleId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return { role: { ...role, orgId: role.orgId as string } };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -114,8 +151,7 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
.optional(),
|
.optional(),
|
||||||
name: z.string().trim().optional(),
|
name: z.string().trim().optional(),
|
||||||
description: z.string().trim().nullish(),
|
description: z.string().trim().nullish(),
|
||||||
// TODO(scott): once UI refactored permissions: OrgPermissionSchema.array().optional()
|
permissions: OrgPermissionSchema.array().optional()
|
||||||
permissions: z.any().array().optional()
|
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
@@ -125,14 +161,26 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const role = await server.services.orgRole.updateRole(
|
const isSubOrganization = req.permission.rootOrgId !== req.permission.orgId;
|
||||||
req.permission.id,
|
if (isSubOrganization && req.body.permissions) {
|
||||||
req.params.organizationId,
|
validateSubOrganizationSubjects(req.body.permissions);
|
||||||
req.params.roleId,
|
}
|
||||||
req.body,
|
|
||||||
req.permission.authMethod,
|
const stringifiedPermissions = req.body.permissions ? JSON.stringify(packRules(req.body.permissions)) : undefined;
|
||||||
req.permission.orgId
|
const role = await server.services.role.updateRole({
|
||||||
);
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Organization,
|
||||||
|
orgId: req.params.organizationId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
id: req.params.roleId
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
...req.body,
|
||||||
|
permissions: stringifiedPermissions
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
@@ -149,7 +197,7 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return { role };
|
return { role: { ...role, orgId: role.orgId as string } };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -172,13 +220,16 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const role = await server.services.orgRole.deleteRole(
|
const role = await server.services.role.deleteRole({
|
||||||
req.permission.id,
|
permission: req.permission,
|
||||||
req.params.organizationId,
|
scopeData: {
|
||||||
req.params.roleId,
|
scope: AccessScope.Organization,
|
||||||
req.permission.authMethod,
|
orgId: req.params.organizationId
|
||||||
req.permission.orgId
|
},
|
||||||
);
|
selector: {
|
||||||
|
id: req.params.roleId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
@@ -189,7 +240,7 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return { role };
|
return { role: { ...role, orgId: role.orgId as string } };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -206,22 +257,26 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
data: z.object({
|
data: z.object({
|
||||||
roles: OrgRolesSchema.omit({ permissions: true })
|
roles: OrgRolesSchema.omit({ permissions: true }).array()
|
||||||
.merge(z.object({ permissions: z.unknown() }))
|
|
||||||
.array()
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const roles = await server.services.orgRole.listRoles(
|
const { roles } = await server.services.role.listRoles({
|
||||||
req.permission.id,
|
permission: req.permission,
|
||||||
req.params.organizationId,
|
scopeData: {
|
||||||
req.permission.authMethod,
|
scope: AccessScope.Organization,
|
||||||
req.permission.orgId
|
orgId: req.permission.orgId
|
||||||
);
|
},
|
||||||
return { data: { roles } };
|
data: {}
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
data: {
|
||||||
|
roles: roles.map((el) => ({ ...el, orgId: el.orgId as string }))
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -237,20 +292,33 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
membership: OrgMembershipsSchema,
|
memberships: z
|
||||||
|
.object({
|
||||||
|
id: z.string(),
|
||||||
|
roles: z
|
||||||
|
.object({
|
||||||
|
role: z.string()
|
||||||
|
})
|
||||||
|
.array()
|
||||||
|
})
|
||||||
|
.array(),
|
||||||
permissions: z.any().array()
|
permissions: z.any().array()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { permissions, membership } = await server.services.orgRole.getUserPermission(
|
const { permissions, memberships } = await server.services.role.getUserPermission({
|
||||||
req.permission.id,
|
permission: req.permission,
|
||||||
req.params.organizationId,
|
scopeData: {
|
||||||
req.permission.authMethod,
|
scope: AccessScope.Organization,
|
||||||
req.permission.orgId
|
orgId: req.permission.orgId
|
||||||
);
|
}
|
||||||
return { permissions, membership };
|
});
|
||||||
|
return {
|
||||||
|
permissions,
|
||||||
|
memberships
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import {
|
||||||
|
CreateMySQLAccountSchema,
|
||||||
|
SanitizedMySQLAccountWithResourceSchema,
|
||||||
|
UpdateMySQLAccountSchema
|
||||||
|
} from "@app/ee/services/pam-resource/mysql/mysql-resource-schemas";
|
||||||
|
import { PamResource } from "@app/ee/services/pam-resource/pam-resource-enums";
|
||||||
|
import {
|
||||||
|
CreatePostgresAccountSchema,
|
||||||
|
SanitizedPostgresAccountWithResourceSchema,
|
||||||
|
UpdatePostgresAccountSchema
|
||||||
|
} from "@app/ee/services/pam-resource/postgres/postgres-resource-schemas";
|
||||||
|
|
||||||
|
import { registerPamResourceEndpoints } from "./pam-account-endpoints";
|
||||||
|
|
||||||
|
export const PAM_ACCOUNT_REGISTER_ROUTER_MAP: Record<PamResource, (server: FastifyZodProvider) => Promise<void>> = {
|
||||||
|
[PamResource.Postgres]: async (server: FastifyZodProvider) => {
|
||||||
|
registerPamResourceEndpoints({
|
||||||
|
server,
|
||||||
|
resourceType: PamResource.Postgres,
|
||||||
|
accountResponseSchema: SanitizedPostgresAccountWithResourceSchema,
|
||||||
|
createAccountSchema: CreatePostgresAccountSchema,
|
||||||
|
updateAccountSchema: UpdatePostgresAccountSchema
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[PamResource.MySQL]: async (server: FastifyZodProvider) => {
|
||||||
|
registerPamResourceEndpoints({
|
||||||
|
server,
|
||||||
|
resourceType: PamResource.MySQL,
|
||||||
|
accountResponseSchema: SanitizedMySQLAccountWithResourceSchema,
|
||||||
|
createAccountSchema: CreateMySQLAccountSchema,
|
||||||
|
updateAccountSchema: UpdateMySQLAccountSchema
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
|
import { PamResource } from "@app/ee/services/pam-resource/pam-resource-enums";
|
||||||
|
import { TPamAccount } from "@app/ee/services/pam-resource/pam-resource-types";
|
||||||
|
import { writeLimit } from "@app/server/config/rateLimiter";
|
||||||
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
|
export const registerPamResourceEndpoints = <C extends TPamAccount>({
|
||||||
|
server,
|
||||||
|
resourceType,
|
||||||
|
createAccountSchema,
|
||||||
|
updateAccountSchema,
|
||||||
|
accountResponseSchema
|
||||||
|
}: {
|
||||||
|
server: FastifyZodProvider;
|
||||||
|
resourceType: PamResource;
|
||||||
|
createAccountSchema: z.ZodType<{
|
||||||
|
credentials: C["credentials"];
|
||||||
|
resourceId: C["resourceId"];
|
||||||
|
folderId?: C["folderId"];
|
||||||
|
name: C["name"];
|
||||||
|
description?: C["description"];
|
||||||
|
rotationEnabled: C["rotationEnabled"];
|
||||||
|
rotationIntervalSeconds?: C["rotationIntervalSeconds"];
|
||||||
|
}>;
|
||||||
|
updateAccountSchema: z.ZodType<{
|
||||||
|
credentials?: C["credentials"];
|
||||||
|
name?: C["name"];
|
||||||
|
description?: C["description"];
|
||||||
|
rotationEnabled?: C["rotationEnabled"];
|
||||||
|
rotationIntervalSeconds?: C["rotationIntervalSeconds"];
|
||||||
|
}>;
|
||||||
|
accountResponseSchema: z.ZodTypeAny;
|
||||||
|
}) => {
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "Create PAM account",
|
||||||
|
body: createAccountSchema,
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
account: accountResponseSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const account = await server.services.pamAccount.create(req.body, req.permission);
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
projectId: account.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.PAM_ACCOUNT_CREATE,
|
||||||
|
metadata: {
|
||||||
|
resourceId: req.body.resourceId,
|
||||||
|
resourceType,
|
||||||
|
folderId: req.body.folderId,
|
||||||
|
name: req.body.name,
|
||||||
|
description: req.body.description,
|
||||||
|
rotationEnabled: req.body.rotationEnabled,
|
||||||
|
rotationIntervalSeconds: req.body.rotationIntervalSeconds
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { account };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "PATCH",
|
||||||
|
url: "/:accountId",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "Update PAM account",
|
||||||
|
params: z.object({
|
||||||
|
accountId: z.string().uuid()
|
||||||
|
}),
|
||||||
|
body: updateAccountSchema,
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
account: accountResponseSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const account = await server.services.pamAccount.updateById(
|
||||||
|
{
|
||||||
|
...req.body,
|
||||||
|
accountId: req.params.accountId
|
||||||
|
},
|
||||||
|
req.permission
|
||||||
|
);
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
projectId: account.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.PAM_ACCOUNT_UPDATE,
|
||||||
|
metadata: {
|
||||||
|
accountId: req.params.accountId,
|
||||||
|
resourceId: account.resourceId,
|
||||||
|
resourceType,
|
||||||
|
name: req.body.name,
|
||||||
|
description: req.body.description,
|
||||||
|
rotationEnabled: req.body.rotationEnabled,
|
||||||
|
rotationIntervalSeconds: req.body.rotationIntervalSeconds
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { account };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "DELETE",
|
||||||
|
url: "/:accountId",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "Delete PAM account",
|
||||||
|
params: z.object({
|
||||||
|
accountId: z.string().uuid()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
account: accountResponseSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const account = await server.services.pamAccount.deleteById(req.params.accountId, req.permission);
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
projectId: account.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.PAM_ACCOUNT_DELETE,
|
||||||
|
metadata: {
|
||||||
|
accountId: req.params.accountId,
|
||||||
|
accountName: account.name,
|
||||||
|
resourceId: account.resourceId,
|
||||||
|
resourceType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { account };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { PamFoldersSchema } from "@app/db/schemas";
|
||||||
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
|
import { SanitizedMySQLAccountWithResourceSchema } from "@app/ee/services/pam-resource/mysql/mysql-resource-schemas";
|
||||||
|
import { PamResource } from "@app/ee/services/pam-resource/pam-resource-enums";
|
||||||
|
import { SanitizedPostgresAccountWithResourceSchema } from "@app/ee/services/pam-resource/postgres/postgres-resource-schemas";
|
||||||
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
|
import { ms } from "@app/lib/ms";
|
||||||
|
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";
|
||||||
|
|
||||||
|
const SanitizedAccountSchema = z.union([
|
||||||
|
SanitizedPostgresAccountWithResourceSchema,
|
||||||
|
SanitizedMySQLAccountWithResourceSchema
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const registerPamAccountRouter = async (server: FastifyZodProvider) => {
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/",
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "List PAM accounts",
|
||||||
|
querystring: z.object({
|
||||||
|
projectId: z.string().uuid()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
accounts: SanitizedAccountSchema.array(),
|
||||||
|
folders: PamFoldersSchema.array()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const response = await server.services.pamAccount.list(req.query.projectId, req.permission);
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
projectId: req.query.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.PAM_ACCOUNT_LIST,
|
||||||
|
metadata: {
|
||||||
|
accountCount: response.accounts.length,
|
||||||
|
folderCount: response.folders.length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/access",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "Access PAM account",
|
||||||
|
body: z.object({
|
||||||
|
accountId: z.string().uuid(),
|
||||||
|
duration: z
|
||||||
|
.string()
|
||||||
|
.min(1)
|
||||||
|
.transform((val, ctx) => {
|
||||||
|
const parsedMs = ms(val);
|
||||||
|
|
||||||
|
if (typeof parsedMs !== "number" || parsedMs <= 0) {
|
||||||
|
ctx.addIssue({
|
||||||
|
code: z.ZodIssueCode.custom,
|
||||||
|
message: "Invalid duration format. Must be a positive duration (e.g., '1h', '30m', '2d')."
|
||||||
|
});
|
||||||
|
return z.NEVER;
|
||||||
|
}
|
||||||
|
return parsedMs;
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
sessionId: z.string(),
|
||||||
|
resourceType: z.nativeEnum(PamResource),
|
||||||
|
relayClientCertificate: z.string(),
|
||||||
|
relayClientPrivateKey: z.string(),
|
||||||
|
relayServerCertificateChain: z.string(),
|
||||||
|
gatewayClientCertificate: z.string(),
|
||||||
|
gatewayClientPrivateKey: z.string(),
|
||||||
|
gatewayServerCertificateChain: z.string(),
|
||||||
|
relayHost: z.string()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
// To prevent type errors when accessing req.auth
|
||||||
|
if (req.auth.authMode !== AuthMode.JWT) {
|
||||||
|
throw new BadRequestError({ message: "You can only access PAM accounts using JWT auth tokens." });
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await server.services.pamAccount.access(
|
||||||
|
{
|
||||||
|
actorEmail: req.auth.user.email ?? "",
|
||||||
|
actorIp: req.realIp,
|
||||||
|
actorName: `${req.auth.user.firstName ?? ""} ${req.auth.user.lastName ?? ""}`.trim(),
|
||||||
|
actorUserAgent: req.auditLogInfo.userAgent ?? "",
|
||||||
|
...req.body
|
||||||
|
},
|
||||||
|
req.permission
|
||||||
|
);
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
projectId: response.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.PAM_ACCOUNT_ACCESS,
|
||||||
|
metadata: {
|
||||||
|
accountId: req.body.accountId,
|
||||||
|
accountName: response.account.name,
|
||||||
|
duration: req.body.duration ? new Date(req.body.duration).toISOString() : undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { PamFoldersSchema } from "@app/db/schemas";
|
||||||
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
|
import { isValidFolderName } from "@app/lib/validator";
|
||||||
|
import { writeLimit } from "@app/server/config/rateLimiter";
|
||||||
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
|
export const registerPamFolderRouter = async (server: FastifyZodProvider) => {
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "Create PAM folder",
|
||||||
|
body: z.object({
|
||||||
|
projectId: z.string().uuid(),
|
||||||
|
parentId: z.string().uuid().nullable().optional(),
|
||||||
|
name: z
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.refine((name) => isValidFolderName(name), {
|
||||||
|
message: "Folder name can only contain alphanumeric characters, dashes, and underscores."
|
||||||
|
}),
|
||||||
|
description: z.string().trim().max(512).nullable().optional()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
folder: PamFoldersSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const folder = await server.services.pamFolder.createFolder(req.body, req.permission);
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
projectId: req.body.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.PAM_FOLDER_CREATE,
|
||||||
|
metadata: {
|
||||||
|
name: req.body.name,
|
||||||
|
description: req.body.description,
|
||||||
|
parentId: req.body.parentId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { folder };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "PATCH",
|
||||||
|
url: "/:folderId",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "Update PAM folder",
|
||||||
|
params: z.object({
|
||||||
|
folderId: z.string().uuid()
|
||||||
|
}),
|
||||||
|
body: z.object({
|
||||||
|
name: z
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.optional()
|
||||||
|
.refine((name) => (name ? isValidFolderName(name) : true), {
|
||||||
|
message: "Folder name can only contain alphanumeric characters, dashes, and underscores."
|
||||||
|
}),
|
||||||
|
description: z.string().trim().max(512).nullable().optional()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
folder: PamFoldersSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const folder = await server.services.pamFolder.updateFolder(
|
||||||
|
{
|
||||||
|
...req.body,
|
||||||
|
id: req.params.folderId
|
||||||
|
},
|
||||||
|
req.permission
|
||||||
|
);
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
projectId: folder.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.PAM_FOLDER_UPDATE,
|
||||||
|
metadata: {
|
||||||
|
folderId: req.params.folderId,
|
||||||
|
name: req.body.name,
|
||||||
|
description: req.body.description
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { folder };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "DELETE",
|
||||||
|
url: "/:folderId",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "Delete PAM folder",
|
||||||
|
params: z.object({
|
||||||
|
folderId: z.string().uuid()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
folder: PamFoldersSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const folder = await server.services.pamFolder.deleteFolder(req.params.folderId, req.permission);
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
projectId: folder.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.PAM_FOLDER_DELETE,
|
||||||
|
metadata: {
|
||||||
|
folderName: folder.name,
|
||||||
|
folderId: req.params.folderId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { folder };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import { PamResource } from "@app/ee/services/pam-resource/pam-resource-enums";
|
||||||
|
import {
|
||||||
|
CreatePostgresResourceSchema,
|
||||||
|
SanitizedPostgresResourceSchema,
|
||||||
|
UpdatePostgresResourceSchema
|
||||||
|
} from "@app/ee/services/pam-resource/postgres/postgres-resource-schemas";
|
||||||
|
import {
|
||||||
|
CreateMySQLResourceSchema,
|
||||||
|
MySQLResourceSchema,
|
||||||
|
UpdateMySQLResourceSchema
|
||||||
|
} from "@app/ee/services/pam-resource/mysql/mysql-resource-schemas";
|
||||||
|
|
||||||
|
import { registerPamResourceEndpoints } from "./pam-resource-endpoints";
|
||||||
|
|
||||||
|
export const PAM_RESOURCE_REGISTER_ROUTER_MAP: Record<PamResource, (server: FastifyZodProvider) => Promise<void>> = {
|
||||||
|
[PamResource.Postgres]: async (server: FastifyZodProvider) => {
|
||||||
|
registerPamResourceEndpoints({
|
||||||
|
server,
|
||||||
|
resourceType: PamResource.Postgres,
|
||||||
|
resourceResponseSchema: SanitizedPostgresResourceSchema,
|
||||||
|
createResourceSchema: CreatePostgresResourceSchema,
|
||||||
|
updateResourceSchema: UpdatePostgresResourceSchema
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[PamResource.MySQL]: async (server: FastifyZodProvider) => {
|
||||||
|
registerPamResourceEndpoints({
|
||||||
|
server,
|
||||||
|
resourceType: PamResource.MySQL,
|
||||||
|
resourceResponseSchema: MySQLResourceSchema,
|
||||||
|
createResourceSchema: CreateMySQLResourceSchema,
|
||||||
|
updateResourceSchema: UpdateMySQLResourceSchema
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,200 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
|
import { PamResource } from "@app/ee/services/pam-resource/pam-resource-enums";
|
||||||
|
import { TPamResource } from "@app/ee/services/pam-resource/pam-resource-types";
|
||||||
|
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";
|
||||||
|
|
||||||
|
export const registerPamResourceEndpoints = <T extends TPamResource>({
|
||||||
|
server,
|
||||||
|
resourceType,
|
||||||
|
createResourceSchema,
|
||||||
|
updateResourceSchema,
|
||||||
|
resourceResponseSchema
|
||||||
|
}: {
|
||||||
|
server: FastifyZodProvider;
|
||||||
|
resourceType: PamResource;
|
||||||
|
createResourceSchema: z.ZodType<{
|
||||||
|
projectId: T["projectId"];
|
||||||
|
connectionDetails: T["connectionDetails"];
|
||||||
|
gatewayId: T["gatewayId"];
|
||||||
|
name: T["name"];
|
||||||
|
rotationAccountCredentials?: T["rotationAccountCredentials"];
|
||||||
|
}>;
|
||||||
|
updateResourceSchema: z.ZodType<{
|
||||||
|
connectionDetails?: T["connectionDetails"];
|
||||||
|
gatewayId?: T["gatewayId"];
|
||||||
|
name?: T["name"];
|
||||||
|
rotationAccountCredentials?: T["rotationAccountCredentials"];
|
||||||
|
}>;
|
||||||
|
resourceResponseSchema: z.ZodTypeAny;
|
||||||
|
}) => {
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/:resourceId",
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "Get PAM resource",
|
||||||
|
params: z.object({
|
||||||
|
resourceId: z.string().uuid()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
resource: resourceResponseSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const resource = await server.services.pamResource.getById(req.params.resourceId, resourceType, req.permission);
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
projectId: resource.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.PAM_RESOURCE_GET,
|
||||||
|
metadata: {
|
||||||
|
resourceId: resource.id,
|
||||||
|
resourceType: resource.resourceType,
|
||||||
|
name: resource.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { resource };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "Create PAM resource",
|
||||||
|
body: createResourceSchema,
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
resource: resourceResponseSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const resource = await server.services.pamResource.create(
|
||||||
|
{
|
||||||
|
...req.body,
|
||||||
|
resourceType
|
||||||
|
},
|
||||||
|
req.permission
|
||||||
|
);
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
projectId: req.body.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.PAM_RESOURCE_CREATE,
|
||||||
|
metadata: {
|
||||||
|
resourceType,
|
||||||
|
gatewayId: req.body.gatewayId,
|
||||||
|
name: req.body.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { resource };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "PATCH",
|
||||||
|
url: "/:resourceId",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "Update PAM resource",
|
||||||
|
params: z.object({
|
||||||
|
resourceId: z.string().uuid()
|
||||||
|
}),
|
||||||
|
body: updateResourceSchema,
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
resource: resourceResponseSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const resource = await server.services.pamResource.updateById(
|
||||||
|
{
|
||||||
|
...req.body,
|
||||||
|
resourceId: req.params.resourceId
|
||||||
|
},
|
||||||
|
req.permission
|
||||||
|
);
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
projectId: resource.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.PAM_RESOURCE_UPDATE,
|
||||||
|
metadata: {
|
||||||
|
resourceId: req.params.resourceId,
|
||||||
|
resourceType,
|
||||||
|
gatewayId: req.body.gatewayId,
|
||||||
|
name: req.body.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { resource };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "DELETE",
|
||||||
|
url: "/:resourceId",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "Delete PAM resource",
|
||||||
|
params: z.object({
|
||||||
|
resourceId: z.string().uuid()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
resource: resourceResponseSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const resource = await server.services.pamResource.deleteById(req.params.resourceId, req.permission);
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
projectId: resource.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.PAM_RESOURCE_DELETE,
|
||||||
|
metadata: {
|
||||||
|
resourceId: req.params.resourceId,
|
||||||
|
resourceType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { resource };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
|
import {
|
||||||
|
MySQLResourceListItemSchema,
|
||||||
|
SanitizedMySQLResourceSchema
|
||||||
|
} from "@app/ee/services/pam-resource/mysql/mysql-resource-schemas";
|
||||||
|
import {
|
||||||
|
PostgresResourceListItemSchema,
|
||||||
|
SanitizedPostgresResourceSchema
|
||||||
|
} from "@app/ee/services/pam-resource/postgres/postgres-resource-schemas";
|
||||||
|
import { readLimit } from "@app/server/config/rateLimiter";
|
||||||
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
|
const SanitizedResourceSchema = z.union([SanitizedPostgresResourceSchema, SanitizedMySQLResourceSchema]);
|
||||||
|
|
||||||
|
const ResourceOptionsSchema = z.discriminatedUnion("resource", [
|
||||||
|
PostgresResourceListItemSchema,
|
||||||
|
MySQLResourceListItemSchema
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const registerPamResourceRouter = async (server: FastifyZodProvider) => {
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/options",
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "List PAM resource types",
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
resourceOptions: ResourceOptionsSchema.array()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: () => {
|
||||||
|
const resourceOptions = server.services.pamResource.listResourceOptions();
|
||||||
|
|
||||||
|
return { resourceOptions };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/",
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "List PAM resources",
|
||||||
|
querystring: z.object({
|
||||||
|
projectId: z.string().uuid()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
resources: SanitizedResourceSchema.array()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const response = await server.services.pamResource.list(req.query.projectId, req.permission);
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
projectId: req.query.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.PAM_RESOURCE_LIST,
|
||||||
|
metadata: {
|
||||||
|
count: response.resources.length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -0,0 +1,224 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { PamSessionsSchema } from "@app/db/schemas";
|
||||||
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
|
import { MySQLSessionCredentialsSchema } from "@app/ee/services/pam-resource/mysql/mysql-resource-schemas";
|
||||||
|
import { PostgresSessionCredentialsSchema } from "@app/ee/services/pam-resource/postgres/postgres-resource-schemas";
|
||||||
|
import { PamSessionCommandLogSchema, SanitizedSessionSchema } from "@app/ee/services/pam-session/pam-session-schemas";
|
||||||
|
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";
|
||||||
|
|
||||||
|
const SessionCredentialsSchema = z.union([PostgresSessionCredentialsSchema, MySQLSessionCredentialsSchema]);
|
||||||
|
|
||||||
|
export const registerPamSessionRouter = async (server: FastifyZodProvider) => {
|
||||||
|
// Meant to be hit solely by gateway identities
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/:sessionId/credentials",
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "Get PAM session credentials and start session",
|
||||||
|
params: z.object({
|
||||||
|
sessionId: z.string().uuid()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
credentials: SessionCredentialsSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const { credentials, projectId, account } = await server.services.pamAccount.getSessionCredentials(
|
||||||
|
req.params.sessionId,
|
||||||
|
req.permission
|
||||||
|
);
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.PAM_SESSION_START,
|
||||||
|
metadata: {
|
||||||
|
sessionId: req.params.sessionId,
|
||||||
|
accountName: account.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { credentials };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Meant to be hit solely by gateway identities
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/:sessionId/logs",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "Update PAM session logs",
|
||||||
|
params: z.object({
|
||||||
|
sessionId: z.string().uuid()
|
||||||
|
}),
|
||||||
|
body: z.object({
|
||||||
|
logs: PamSessionCommandLogSchema.array()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
session: PamSessionsSchema.omit({
|
||||||
|
encryptedLogsBlob: true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const { session, projectId } = await server.services.pamSession.updateLogsById(
|
||||||
|
{
|
||||||
|
sessionId: req.params.sessionId,
|
||||||
|
logs: req.body.logs
|
||||||
|
},
|
||||||
|
req.permission
|
||||||
|
);
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.PAM_SESSION_LOGS_UPDATE,
|
||||||
|
metadata: {
|
||||||
|
sessionId: req.params.sessionId,
|
||||||
|
accountName: session.accountName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { session };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Meant to be hit solely by gateway identities
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/:sessionId/end",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "End PAM session",
|
||||||
|
params: z.object({
|
||||||
|
sessionId: z.string().uuid()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
session: PamSessionsSchema.omit({
|
||||||
|
encryptedLogsBlob: true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const { session, projectId } = await server.services.pamSession.endSessionById(
|
||||||
|
req.params.sessionId,
|
||||||
|
req.permission
|
||||||
|
);
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.PAM_SESSION_END,
|
||||||
|
metadata: {
|
||||||
|
sessionId: req.params.sessionId,
|
||||||
|
accountName: session.accountName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { session };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/:sessionId",
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "Get PAM session",
|
||||||
|
params: z.object({
|
||||||
|
sessionId: z.string().uuid()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
session: SanitizedSessionSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const response = await server.services.pamSession.getById(req.params.sessionId, req.permission);
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
projectId: response.session.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.PAM_SESSION_GET,
|
||||||
|
metadata: {
|
||||||
|
sessionId: req.params.sessionId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/",
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "List PAM sessions",
|
||||||
|
querystring: z.object({
|
||||||
|
projectId: z.string().uuid()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
sessions: SanitizedSessionSchema.array()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const response = await server.services.pamSession.list(req.query.projectId, req.permission);
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
projectId: req.query.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.PAM_SESSION_LIST,
|
||||||
|
metadata: {
|
||||||
|
count: response.sessions.length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { packRules } from "@casl/ability/extra";
|
import { packRules } from "@casl/ability/extra";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { ProjectMembershipRole, ProjectRolesSchema } from "@app/db/schemas";
|
import { AccessScope, ProjectMembershipRole, ProjectRolesSchema } 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 { checkForInvalidPermissionCombination } from "@app/ee/services/permission/permission-fns";
|
import { checkForInvalidPermissionCombination } from "@app/ee/services/permission/permission-fns";
|
||||||
import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
|
import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
|
||||||
@@ -11,7 +11,6 @@ import { slugSchema } from "@app/server/lib/schemas";
|
|||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { SanitizedRoleSchema } from "@app/server/routes/sanitizedSchemas";
|
import { SanitizedRoleSchema } from "@app/server/routes/sanitizedSchemas";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
import { ProjectRoleServiceIdentifierType } from "@app/services/project-role/project-role-types";
|
|
||||||
|
|
||||||
export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
|
export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
|
||||||
server.route({
|
server.route({
|
||||||
@@ -55,13 +54,11 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const stringifiedPermissions = JSON.stringify(packRules(req.body.permissions));
|
const stringifiedPermissions = JSON.stringify(packRules(req.body.permissions));
|
||||||
|
|
||||||
const role = await server.services.projectRole.createRole({
|
const role = await server.services.role.createRole({
|
||||||
actorAuthMethod: req.permission.authMethod,
|
permission: req.permission,
|
||||||
actorId: req.permission.id,
|
scopeData: {
|
||||||
actorOrgId: req.permission.orgId,
|
scope: AccessScope.Project,
|
||||||
actor: req.permission.type,
|
orgId: req.permission.orgId,
|
||||||
filter: {
|
|
||||||
type: ProjectRoleServiceIdentifierType.ID,
|
|
||||||
projectId: req.params.projectId
|
projectId: req.params.projectId
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
@@ -73,7 +70,7 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: req.permission.orgId,
|
orgId: req.permission.orgId,
|
||||||
projectId: role.projectId,
|
projectId: role.projectId as string,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.CREATE_PROJECT_ROLE,
|
type: EventType.CREATE_PROJECT_ROLE,
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -86,7 +83,7 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return { role };
|
return { role: { ...role, projectId: role.projectId as string } };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -133,12 +130,16 @@ export const registerProjectRoleRouter = 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 stringifiedPermissions = req.body.permissions ? JSON.stringify(packRules(req.body.permissions)) : undefined;
|
const stringifiedPermissions = req.body.permissions ? JSON.stringify(packRules(req.body.permissions)) : undefined;
|
||||||
const role = await server.services.projectRole.updateRole({
|
const role = await server.services.role.updateRole({
|
||||||
actorAuthMethod: req.permission.authMethod,
|
permission: req.permission,
|
||||||
actorId: req.permission.id,
|
scopeData: {
|
||||||
actorOrgId: req.permission.orgId,
|
scope: AccessScope.Project,
|
||||||
actor: req.permission.type,
|
orgId: req.permission.orgId,
|
||||||
roleId: req.params.roleId,
|
projectId: req.params.projectId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
id: req.params.roleId
|
||||||
|
},
|
||||||
data: {
|
data: {
|
||||||
...req.body,
|
...req.body,
|
||||||
permissions: stringifiedPermissions
|
permissions: stringifiedPermissions
|
||||||
@@ -148,7 +149,7 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: req.permission.orgId,
|
orgId: req.permission.orgId,
|
||||||
projectId: role.projectId,
|
projectId: role.projectId as string,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.UPDATE_PROJECT_ROLE,
|
type: EventType.UPDATE_PROJECT_ROLE,
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -161,7 +162,7 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return { role };
|
return { role: { ...role, projectId: role.projectId as string } };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -192,18 +193,22 @@ export const registerProjectRoleRouter = 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 role = await server.services.projectRole.deleteRole({
|
const role = await server.services.role.deleteRole({
|
||||||
actorAuthMethod: req.permission.authMethod,
|
permission: req.permission,
|
||||||
actorId: req.permission.id,
|
scopeData: {
|
||||||
actorOrgId: req.permission.orgId,
|
scope: AccessScope.Project,
|
||||||
actor: req.permission.type,
|
orgId: req.permission.orgId,
|
||||||
roleId: req.params.roleId
|
projectId: req.params.projectId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
id: req.params.roleId
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: req.permission.orgId,
|
orgId: req.permission.orgId,
|
||||||
projectId: role.projectId,
|
projectId: role.projectId as string,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.DELETE_PROJECT_ROLE,
|
type: EventType.DELETE_PROJECT_ROLE,
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -214,7 +219,7 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return { role };
|
return { role: { ...role, projectId: role.projectId as string } };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -244,17 +249,16 @@ export const registerProjectRoleRouter = 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 roles = await server.services.projectRole.listRoles({
|
const { roles } = await server.services.role.listRoles({
|
||||||
actorAuthMethod: req.permission.authMethod,
|
permission: req.permission,
|
||||||
actorId: req.permission.id,
|
scopeData: {
|
||||||
actorOrgId: req.permission.orgId,
|
scope: AccessScope.Project,
|
||||||
actor: req.permission.type,
|
orgId: req.permission.orgId,
|
||||||
filter: {
|
|
||||||
type: ProjectRoleServiceIdentifierType.ID,
|
|
||||||
projectId: req.params.projectId
|
projectId: req.params.projectId
|
||||||
}
|
},
|
||||||
|
data: {}
|
||||||
});
|
});
|
||||||
return { roles };
|
return { roles: roles.map((el) => ({ ...el, projectId: el.projectId as string })) };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -273,24 +277,25 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
role: SanitizedRoleSchema.omit({ version: true })
|
role: SanitizedRoleSchema
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const role = await server.services.projectRole.getRoleBySlug({
|
const role = await server.services.role.getRoleBySlug({
|
||||||
actorAuthMethod: req.permission.authMethod,
|
permission: req.permission,
|
||||||
actorId: req.permission.id,
|
scopeData: {
|
||||||
actorOrgId: req.permission.orgId,
|
scope: AccessScope.Project,
|
||||||
actor: req.permission.type,
|
orgId: req.permission.orgId,
|
||||||
filter: {
|
|
||||||
type: ProjectRoleServiceIdentifierType.ID,
|
|
||||||
projectId: req.params.projectId
|
projectId: req.params.projectId
|
||||||
},
|
},
|
||||||
roleSlug: req.params.roleSlug
|
selector: {
|
||||||
|
slug: req.params.roleSlug
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return { role };
|
|
||||||
|
return { role: { ...role, projectId: role.projectId as string } };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -307,14 +312,16 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
data: z.object({
|
data: z.object({
|
||||||
membership: z.object({
|
memberships: z
|
||||||
|
.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
roles: z
|
roles: z
|
||||||
.object({
|
.object({
|
||||||
role: z.string()
|
role: z.string()
|
||||||
})
|
})
|
||||||
.array()
|
.array()
|
||||||
}),
|
})
|
||||||
|
.array(),
|
||||||
assumedPrivilegeDetails: z
|
assumedPrivilegeDetails: z
|
||||||
.object({
|
.object({
|
||||||
actorId: z.string(),
|
actorId: z.string(),
|
||||||
@@ -330,17 +337,19 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { permissions, membership, assumedPrivilegeDetails } = await server.services.projectRole.getUserPermission(
|
const { permissions, memberships, assumedPrivilegeDetails } = await server.services.role.getUserPermission({
|
||||||
req.permission.id,
|
permission: req.permission,
|
||||||
req.params.projectId,
|
scopeData: {
|
||||||
req.permission.authMethod,
|
scope: AccessScope.Project,
|
||||||
req.permission.orgId
|
projectId: req.params.projectId,
|
||||||
);
|
orgId: req.permission.orgId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data: {
|
data: {
|
||||||
permissions,
|
permissions,
|
||||||
membership,
|
memberships,
|
||||||
assumedPrivilegeDetails
|
assumedPrivilegeDetails
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -146,4 +146,85 @@ export const registerRelayRouter = async (server: FastifyZodProvider) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/heartbeat-instance-relay",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
body: z.object({
|
||||||
|
name: slugSchema({ min: 1, max: 32, field: "name" })
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
message: z.string()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: (req, _, next) => {
|
||||||
|
const authHeader = req.headers.authorization;
|
||||||
|
|
||||||
|
if (!appCfg.RELAY_AUTH_SECRET) {
|
||||||
|
throw new UnauthorizedError({
|
||||||
|
message: "Relay authentication not configured"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!authHeader) {
|
||||||
|
throw new UnauthorizedError({
|
||||||
|
message: "Missing authorization header"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const expectedHeader = `Bearer ${appCfg.RELAY_AUTH_SECRET}`;
|
||||||
|
if (
|
||||||
|
authHeader.length === expectedHeader.length &&
|
||||||
|
crypto.nativeCrypto.timingSafeEqual(Buffer.from(authHeader), Buffer.from(expectedHeader))
|
||||||
|
) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new UnauthorizedError({
|
||||||
|
message: "Invalid relay auth secret"
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handler: async (req) => {
|
||||||
|
await server.services.relay.heartbeat({
|
||||||
|
name: req.body.name
|
||||||
|
});
|
||||||
|
|
||||||
|
return { message: "Successfully triggered heartbeat" };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/heartbeat-org-relay",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
body: z.object({
|
||||||
|
name: slugSchema({ min: 1, max: 32, field: "name" })
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
message: z.string()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
await server.services.relay.heartbeat({
|
||||||
|
name: req.body.name,
|
||||||
|
identityId: req.permission.id,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
actorAuthMethod: req.permission.authMethod
|
||||||
|
});
|
||||||
|
|
||||||
|
return { message: "Successfully triggered heartbeat" };
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ const AccessListEntrySchema = z
|
|||||||
.object({
|
.object({
|
||||||
allowedActions: z.nativeEnum(ProjectPermissionSecretActions).array(),
|
allowedActions: z.nativeEnum(ProjectPermissionSecretActions).array(),
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
membershipId: z.string(),
|
|
||||||
name: z.string()
|
name: z.string()
|
||||||
})
|
})
|
||||||
.array();
|
.array();
|
||||||
|
|||||||
@@ -0,0 +1,163 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { OrganizationsSchema } from "@app/db/schemas";
|
||||||
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
|
import { ApiDocsTags, SUB_ORGANIZATIONS } from "@app/lib/api-docs";
|
||||||
|
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
|
import { slugSchema } from "@app/server/lib/schemas";
|
||||||
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
|
const sanitizedSubOrganizationSchema = OrganizationsSchema.pick({
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
slug: true,
|
||||||
|
createdAt: true,
|
||||||
|
updatedAt: true,
|
||||||
|
parentOrgId: true
|
||||||
|
});
|
||||||
|
|
||||||
|
export const registerSubOrgRouter = async (server: FastifyZodProvider) => {
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SubOrganizations],
|
||||||
|
description: "Create a sub organization",
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
body: z.object({
|
||||||
|
name: slugSchema().describe(SUB_ORGANIZATIONS.CREATE.name)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
organization: sanitizedSubOrganizationSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const { organization } = await server.services.subOrganization.createSubOrg({
|
||||||
|
name: req.body.name,
|
||||||
|
permissionActor: req.permission
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
event: {
|
||||||
|
type: EventType.CREATE_SUB_ORGANIZATION,
|
||||||
|
metadata: {
|
||||||
|
name: req.body.name,
|
||||||
|
organizationId: organization.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { organization };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/",
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SubOrganizations],
|
||||||
|
description: "List of sub organizations",
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
querystring: z.object({
|
||||||
|
limit: z.coerce.number().min(1).max(1000).default(25).describe(SUB_ORGANIZATIONS.LIST.limit),
|
||||||
|
offset: z.coerce.number().min(0).default(0).describe(SUB_ORGANIZATIONS.LIST.offset),
|
||||||
|
isAccessible: z
|
||||||
|
.enum(["true", "false"])
|
||||||
|
.optional()
|
||||||
|
.transform((value) => value === "true")
|
||||||
|
.describe(SUB_ORGANIZATIONS.LIST.isAccessible)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
organizations: sanitizedSubOrganizationSchema.array()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const { organizations } = await server.services.subOrganization.listSubOrgs({
|
||||||
|
permissionActor: req.permission,
|
||||||
|
data: {
|
||||||
|
limit: req.query.limit,
|
||||||
|
offset: req.query.offset,
|
||||||
|
isAccessible: req.query.isAccessible
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { organizations };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "PATCH",
|
||||||
|
url: "/:subOrgId",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SubOrganizations],
|
||||||
|
description: "Update a sub organization",
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
params: z.object({
|
||||||
|
subOrgId: z.string().trim().describe(SUB_ORGANIZATIONS.UPDATE.subOrgId)
|
||||||
|
}),
|
||||||
|
body: z.object({
|
||||||
|
name: slugSchema().describe(SUB_ORGANIZATIONS.UPDATE.name)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
organization: sanitizedSubOrganizationSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const { organization } = await server.services.subOrganization.updateSubOrg({
|
||||||
|
subOrgId: req.params.subOrgId,
|
||||||
|
name: req.body.name,
|
||||||
|
permissionActor: req.permission
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
event: {
|
||||||
|
type: EventType.UPDATE_SUB_ORGANIZATION,
|
||||||
|
metadata: {
|
||||||
|
name: req.body.name,
|
||||||
|
organizationId: organization.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { organization };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -1,17 +1,18 @@
|
|||||||
import slugify from "@sindresorhus/slugify";
|
import slugify from "@sindresorhus/slugify";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { AccessScope, TemporaryPermissionMode } from "@app/db/schemas";
|
||||||
import { checkForInvalidPermissionCombination } from "@app/ee/services/permission/permission-fns";
|
import { checkForInvalidPermissionCombination } from "@app/ee/services/permission/permission-fns";
|
||||||
import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
|
import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
|
||||||
import { ProjectUserAdditionalPrivilegeTemporaryMode } from "@app/ee/services/project-user-additional-privilege/project-user-additional-privilege-types";
|
|
||||||
import { PROJECT_USER_ADDITIONAL_PRIVILEGE } from "@app/lib/api-docs";
|
import { PROJECT_USER_ADDITIONAL_PRIVILEGE } from "@app/lib/api-docs";
|
||||||
|
import { NotFoundError } from "@app/lib/errors";
|
||||||
import { ms } from "@app/lib/ms";
|
import { ms } from "@app/lib/ms";
|
||||||
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
||||||
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
import { slugSchema } from "@app/server/lib/schemas";
|
import { slugSchema } from "@app/server/lib/schemas";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { SanitizedUserProjectAdditionalPrivilegeSchema } from "@app/server/routes/sanitizedSchema/user-additional-privilege";
|
import { SanitizedUserProjectAdditionalPrivilegeSchema } from "@app/server/routes/sanitizedSchema/user-additional-privilege";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { ActorType, AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
export const registerUserAdditionalPrivilegeRouter = async (server: FastifyZodProvider) => {
|
export const registerUserAdditionalPrivilegeRouter = async (server: FastifyZodProvider) => {
|
||||||
server.route({
|
server.route({
|
||||||
@@ -34,7 +35,7 @@ export const registerUserAdditionalPrivilegeRouter = async (server: FastifyZodPr
|
|||||||
z.object({
|
z.object({
|
||||||
isTemporary: z.literal(true),
|
isTemporary: z.literal(true),
|
||||||
temporaryMode: z
|
temporaryMode: z
|
||||||
.nativeEnum(ProjectUserAdditionalPrivilegeTemporaryMode)
|
.nativeEnum(TemporaryPermissionMode)
|
||||||
.describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.CREATE.temporaryMode),
|
.describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.CREATE.temporaryMode),
|
||||||
temporaryRange: z
|
temporaryRange: z
|
||||||
.string()
|
.string()
|
||||||
@@ -55,17 +56,31 @@ export const registerUserAdditionalPrivilegeRouter = async (server: FastifyZodPr
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const privilege = await server.services.projectUserAdditionalPrivilege.create({
|
const { userId, membership } = await server.services.convertor.userMembershipIdToUserId(
|
||||||
actorId: req.permission.id,
|
req.body.projectMembershipId,
|
||||||
actor: req.permission.type,
|
AccessScope.Project,
|
||||||
actorOrgId: req.permission.orgId,
|
req.permission.orgId
|
||||||
actorAuthMethod: req.permission.authMethod,
|
);
|
||||||
projectMembershipId: req.body.projectMembershipId,
|
|
||||||
|
const { additionalPrivilege: privilege } = await server.services.additionalPrivilege.createAdditionalPrivilege({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
projectId: membership.scopeProjectId as string,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
actorId: userId,
|
||||||
|
actorType: ActorType.USER,
|
||||||
...req.body.type,
|
...req.body.type,
|
||||||
slug: req.body.slug || slugify(alphaNumericNanoId(8)),
|
name: req.body.slug || slugify(alphaNumericNanoId(8)),
|
||||||
permissions: req.body.permissions
|
permissions: req.body.permissions
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return { privilege };
|
|
||||||
|
return {
|
||||||
|
privilege: { ...privilege, userId, projectId: membership.scopeProjectId as string, slug: privilege.name }
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -91,7 +106,7 @@ export const registerUserAdditionalPrivilegeRouter = async (server: FastifyZodPr
|
|||||||
z.object({
|
z.object({
|
||||||
isTemporary: z.literal(true).describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.UPDATE.isTemporary),
|
isTemporary: z.literal(true).describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.UPDATE.isTemporary),
|
||||||
temporaryMode: z
|
temporaryMode: z
|
||||||
.nativeEnum(ProjectUserAdditionalPrivilegeTemporaryMode)
|
.nativeEnum(TemporaryPermissionMode)
|
||||||
.describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.UPDATE.temporaryMode),
|
.describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.UPDATE.temporaryMode),
|
||||||
temporaryRange: z
|
temporaryRange: z
|
||||||
.string()
|
.string()
|
||||||
@@ -113,21 +128,41 @@ export const registerUserAdditionalPrivilegeRouter = async (server: FastifyZodPr
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const privilege = await server.services.projectUserAdditionalPrivilege.updateById({
|
const data = await server.services.convertor.additionalPrivilegeIdToDoc(req.params.privilegeId);
|
||||||
actorId: req.permission.id,
|
if (!data.privilege.actorUserId)
|
||||||
actor: req.permission.type,
|
throw new NotFoundError({ message: `Privilege with id ${req.params.privilegeId} not found` });
|
||||||
actorOrgId: req.permission.orgId,
|
|
||||||
actorAuthMethod: req.permission.authMethod,
|
const { additionalPrivilege: privilege } = await server.services.additionalPrivilege.updateAdditionalPrivilege({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
projectId: data.privilege.projectId as string,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
data: {
|
||||||
...req.body,
|
...req.body,
|
||||||
...req.body.type,
|
...req.body.type,
|
||||||
permissions: req.body.permissions
|
permissions: req.body.permissions
|
||||||
? // eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
? // eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore-error this is valid ts
|
// @ts-ignore-error this is valid ts
|
||||||
req.body.permissions
|
req.body.permissions
|
||||||
: undefined,
|
: undefined
|
||||||
privilegeId: req.params.privilegeId
|
},
|
||||||
|
selector: {
|
||||||
|
id: req.params.privilegeId,
|
||||||
|
actorId: data.privilege.actorUserId,
|
||||||
|
actorType: ActorType.USER
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return { privilege };
|
|
||||||
|
return {
|
||||||
|
privilege: {
|
||||||
|
...privilege,
|
||||||
|
userId: data.privilege.actorUserId,
|
||||||
|
projectId: data.privilege.projectId as string,
|
||||||
|
slug: privilege.name
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -149,14 +184,32 @@ export const registerUserAdditionalPrivilegeRouter = async (server: FastifyZodPr
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const privilege = await server.services.projectUserAdditionalPrivilege.deleteById({
|
const data = await server.services.convertor.additionalPrivilegeIdToDoc(req.params.privilegeId);
|
||||||
actorId: req.permission.id,
|
if (!data.privilege.actorUserId)
|
||||||
actor: req.permission.type,
|
throw new NotFoundError({ message: `Privilege with id ${req.params.privilegeId} not found` });
|
||||||
actorOrgId: req.permission.orgId,
|
|
||||||
actorAuthMethod: req.permission.authMethod,
|
const { additionalPrivilege: privilege } = await server.services.additionalPrivilege.deleteAdditionalPrivilege({
|
||||||
privilegeId: req.params.privilegeId
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
projectId: data.privilege.projectId as string,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
id: req.params.privilegeId,
|
||||||
|
actorId: data.privilege.actorUserId,
|
||||||
|
actorType: ActorType.USER
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return { privilege };
|
|
||||||
|
return {
|
||||||
|
privilege: {
|
||||||
|
...privilege,
|
||||||
|
userId: data.privilege.actorUserId,
|
||||||
|
projectId: data.privilege.projectId as string,
|
||||||
|
slug: privilege.name
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -178,14 +231,33 @@ export const registerUserAdditionalPrivilegeRouter = async (server: FastifyZodPr
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const privileges = await server.services.projectUserAdditionalPrivilege.listPrivileges({
|
const { userId, membership } = await server.services.convertor.userMembershipIdToUserId(
|
||||||
actorId: req.permission.id,
|
req.query.projectMembershipId,
|
||||||
actor: req.permission.type,
|
AccessScope.Project,
|
||||||
actorOrgId: req.permission.orgId,
|
req.permission.orgId
|
||||||
actorAuthMethod: req.permission.authMethod,
|
);
|
||||||
projectMembershipId: req.query.projectMembershipId
|
|
||||||
|
const { additionalPrivileges: privileges } = await server.services.additionalPrivilege.listAdditionalPrivileges({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
projectId: membership.scopeProjectId as string,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
actorId: userId,
|
||||||
|
actorType: ActorType.USER
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return { privileges };
|
|
||||||
|
return {
|
||||||
|
privileges: privileges.map((privilege) => ({
|
||||||
|
...privilege,
|
||||||
|
userId: membership.actorUserId as string,
|
||||||
|
projectId: membership.scopeProjectId as string,
|
||||||
|
slug: privilege.name
|
||||||
|
}))
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -207,14 +279,32 @@ export const registerUserAdditionalPrivilegeRouter = async (server: FastifyZodPr
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const privilege = await server.services.projectUserAdditionalPrivilege.getPrivilegeDetailsById({
|
const data = await server.services.convertor.additionalPrivilegeIdToDoc(req.params.privilegeId);
|
||||||
actorId: req.permission.id,
|
if (!data.privilege.actorUserId)
|
||||||
actor: req.permission.type,
|
throw new NotFoundError({ message: `Privilege with id ${req.params.privilegeId} not found` });
|
||||||
actorOrgId: req.permission.orgId,
|
|
||||||
actorAuthMethod: req.permission.authMethod,
|
const { additionalPrivilege: privilege } = await server.services.additionalPrivilege.getAdditionalPrivilegeById({
|
||||||
privilegeId: req.params.privilegeId
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
projectId: data.privilege.projectId as string,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
id: req.params.privilegeId,
|
||||||
|
actorId: data.privilege.actorUserId,
|
||||||
|
actorType: ActorType.USER
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return { privilege };
|
|
||||||
|
return {
|
||||||
|
privilege: {
|
||||||
|
...privilege,
|
||||||
|
userId: data.privilege.actorUserId,
|
||||||
|
projectId: data.privilege.projectId as string,
|
||||||
|
slug: privilege.name
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { packRules } from "@casl/ability/extra";
|
import { packRules } from "@casl/ability/extra";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { ProjectMembershipRole, ProjectRolesSchema } from "@app/db/schemas";
|
import { AccessScope, ProjectMembershipRole, ProjectRolesSchema } 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 { checkForInvalidPermissionCombination } from "@app/ee/services/permission/permission-fns";
|
import { checkForInvalidPermissionCombination } from "@app/ee/services/permission/permission-fns";
|
||||||
import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
|
import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
|
||||||
@@ -11,7 +11,6 @@ import { slugSchema } from "@app/server/lib/schemas";
|
|||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { SanitizedRoleSchema } from "@app/server/routes/sanitizedSchemas";
|
import { SanitizedRoleSchema } from "@app/server/routes/sanitizedSchemas";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
import { ProjectRoleServiceIdentifierType } from "@app/services/project-role/project-role-types";
|
|
||||||
|
|
||||||
export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProvider) => {
|
export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProvider) => {
|
||||||
server.route({
|
server.route({
|
||||||
@@ -55,13 +54,11 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv
|
|||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const stringifiedPermissions = JSON.stringify(packRules(req.body.permissions));
|
const stringifiedPermissions = JSON.stringify(packRules(req.body.permissions));
|
||||||
|
|
||||||
const role = await server.services.projectRole.createRole({
|
const role = await server.services.role.createRole({
|
||||||
actorAuthMethod: req.permission.authMethod,
|
permission: req.permission,
|
||||||
actorId: req.permission.id,
|
scopeData: {
|
||||||
actorOrgId: req.permission.orgId,
|
scope: AccessScope.Project,
|
||||||
actor: req.permission.type,
|
orgId: req.permission.orgId,
|
||||||
filter: {
|
|
||||||
type: ProjectRoleServiceIdentifierType.ID,
|
|
||||||
projectId: req.params.projectId
|
projectId: req.params.projectId
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
@@ -73,7 +70,7 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv
|
|||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: req.permission.orgId,
|
orgId: req.permission.orgId,
|
||||||
projectId: role.projectId,
|
projectId: req.params.projectId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.CREATE_PROJECT_ROLE,
|
type: EventType.CREATE_PROJECT_ROLE,
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -86,7 +83,7 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return { role };
|
return { role: { ...role, projectId: role.projectId as string } };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -133,12 +130,16 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv
|
|||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const stringifiedPermissions = req.body.permissions ? JSON.stringify(packRules(req.body.permissions)) : undefined;
|
const stringifiedPermissions = req.body.permissions ? JSON.stringify(packRules(req.body.permissions)) : undefined;
|
||||||
const role = await server.services.projectRole.updateRole({
|
const role = await server.services.role.updateRole({
|
||||||
actorAuthMethod: req.permission.authMethod,
|
permission: req.permission,
|
||||||
actorId: req.permission.id,
|
scopeData: {
|
||||||
actorOrgId: req.permission.orgId,
|
scope: AccessScope.Project,
|
||||||
actor: req.permission.type,
|
orgId: req.permission.orgId,
|
||||||
roleId: req.params.roleId,
|
projectId: req.params.projectId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
id: req.params.roleId
|
||||||
|
},
|
||||||
data: {
|
data: {
|
||||||
...req.body,
|
...req.body,
|
||||||
permissions: stringifiedPermissions
|
permissions: stringifiedPermissions
|
||||||
@@ -148,7 +149,7 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv
|
|||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: req.permission.orgId,
|
orgId: req.permission.orgId,
|
||||||
projectId: role.projectId,
|
projectId: role.projectId as string,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.UPDATE_PROJECT_ROLE,
|
type: EventType.UPDATE_PROJECT_ROLE,
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -161,7 +162,7 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return { role };
|
return { role: { ...role, projectId: role.projectId as string } };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -192,18 +193,22 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const role = await server.services.projectRole.deleteRole({
|
const role = await server.services.role.deleteRole({
|
||||||
actorAuthMethod: req.permission.authMethod,
|
permission: req.permission,
|
||||||
actorId: req.permission.id,
|
scopeData: {
|
||||||
actorOrgId: req.permission.orgId,
|
scope: AccessScope.Project,
|
||||||
actor: req.permission.type,
|
orgId: req.permission.orgId,
|
||||||
roleId: req.params.roleId
|
projectId: req.params.projectId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
id: req.params.roleId
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: req.permission.orgId,
|
orgId: req.permission.orgId,
|
||||||
projectId: role.projectId,
|
projectId: role.projectId as string,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.DELETE_PROJECT_ROLE,
|
type: EventType.DELETE_PROJECT_ROLE,
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -214,7 +219,7 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return { role };
|
return { role: { ...role, projectId: role.projectId as string } };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -244,17 +249,16 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const roles = await server.services.projectRole.listRoles({
|
const { roles } = await server.services.role.listRoles({
|
||||||
actorAuthMethod: req.permission.authMethod,
|
permission: req.permission,
|
||||||
actorId: req.permission.id,
|
scopeData: {
|
||||||
actorOrgId: req.permission.orgId,
|
scope: AccessScope.Project,
|
||||||
actor: req.permission.type,
|
orgId: req.permission.orgId,
|
||||||
filter: {
|
|
||||||
type: ProjectRoleServiceIdentifierType.ID,
|
|
||||||
projectId: req.params.projectId
|
projectId: req.params.projectId
|
||||||
}
|
},
|
||||||
|
data: {}
|
||||||
});
|
});
|
||||||
return { roles };
|
return { roles: roles.map((el) => ({ ...el, projectId: el.projectId as string })) };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -273,24 +277,25 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv
|
|||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
role: SanitizedRoleSchema.omit({ version: true })
|
role: SanitizedRoleSchema
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const role = await server.services.projectRole.getRoleBySlug({
|
const role = await server.services.role.getRoleBySlug({
|
||||||
actorAuthMethod: req.permission.authMethod,
|
permission: req.permission,
|
||||||
actorId: req.permission.id,
|
scopeData: {
|
||||||
actorOrgId: req.permission.orgId,
|
scope: AccessScope.Project,
|
||||||
actor: req.permission.type,
|
orgId: req.permission.orgId,
|
||||||
filter: {
|
|
||||||
type: ProjectRoleServiceIdentifierType.ID,
|
|
||||||
projectId: req.params.projectId
|
projectId: req.params.projectId
|
||||||
},
|
},
|
||||||
roleSlug: req.params.roleSlug
|
selector: {
|
||||||
|
slug: req.params.roleSlug
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return { role };
|
|
||||||
|
return { role: { ...role, projectId: role.projectId as string } };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import z from "zod";
|
import z from "zod";
|
||||||
|
|
||||||
import { GatewaysV2Schema } from "@app/db/schemas";
|
import { GatewaysV2Schema } from "@app/db/schemas";
|
||||||
|
import { zodBuffer } from "@app/lib/zod";
|
||||||
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
import { slugSchema } from "@app/server/lib/schemas";
|
import { slugSchema } from "@app/server/lib/schemas";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
@@ -130,4 +131,25 @@ export const registerGatewayV2Router = async (server: FastifyZodProvider) => {
|
|||||||
return gateway;
|
return gateway;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/pam-session-key",
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
response: {
|
||||||
|
200: zodBuffer
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const pamSessionKey = await server.services.gatewayV2.getPamSessionKey({
|
||||||
|
orgPermission: req.permission
|
||||||
|
});
|
||||||
|
|
||||||
|
return pamSessionKey;
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import slugify from "@sindresorhus/slugify";
|
import slugify from "@sindresorhus/slugify";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { IdentityProjectAdditionalPrivilegeTemporaryMode } from "@app/ee/services/identity-project-additional-privilege-v2/identity-project-additional-privilege-v2-types";
|
import { AccessScope, TemporaryPermissionMode } from "@app/db/schemas";
|
||||||
import { checkForInvalidPermissionCombination } from "@app/ee/services/permission/permission-fns";
|
import { checkForInvalidPermissionCombination } from "@app/ee/services/permission/permission-fns";
|
||||||
import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
|
import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
|
||||||
import { ApiDocsTags, IDENTITY_ADDITIONAL_PRIVILEGE_V2 } from "@app/lib/api-docs";
|
import { ApiDocsTags, IDENTITY_ADDITIONAL_PRIVILEGE_V2 } from "@app/lib/api-docs";
|
||||||
@@ -11,7 +11,7 @@ import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
|||||||
import { slugSchema } from "@app/server/lib/schemas";
|
import { slugSchema } from "@app/server/lib/schemas";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { SanitizedIdentityPrivilegeSchema } from "@app/server/routes/sanitizedSchema/identitiy-additional-privilege";
|
import { SanitizedIdentityPrivilegeSchema } from "@app/server/routes/sanitizedSchema/identitiy-additional-privilege";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { ActorType, AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: FastifyZodProvider) => {
|
export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: FastifyZodProvider) => {
|
||||||
server.route({
|
server.route({
|
||||||
@@ -43,7 +43,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
z.object({
|
z.object({
|
||||||
isTemporary: z.literal(true),
|
isTemporary: z.literal(true),
|
||||||
temporaryMode: z
|
temporaryMode: z
|
||||||
.nativeEnum(IdentityProjectAdditionalPrivilegeTemporaryMode)
|
.nativeEnum(TemporaryPermissionMode)
|
||||||
.describe(IDENTITY_ADDITIONAL_PRIVILEGE_V2.CREATE.temporaryMode),
|
.describe(IDENTITY_ADDITIONAL_PRIVILEGE_V2.CREATE.temporaryMode),
|
||||||
temporaryRange: z
|
temporaryRange: z
|
||||||
.string()
|
.string()
|
||||||
@@ -64,18 +64,31 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const privilege = await server.services.identityProjectAdditionalPrivilegeV2.create({
|
const { additionalPrivilege: privilege } = await server.services.additionalPrivilege.createAdditionalPrivilege({
|
||||||
actorAuthMethod: req.permission.authMethod,
|
permission: req.permission,
|
||||||
actorId: req.permission.id,
|
scopeData: {
|
||||||
actorOrgId: req.permission.orgId,
|
scope: AccessScope.Project,
|
||||||
actor: req.permission.type,
|
|
||||||
projectId: req.body.projectId,
|
projectId: req.body.projectId,
|
||||||
identityId: req.body.identityId,
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
actorId: req.body.identityId,
|
||||||
|
actorType: ActorType.IDENTITY,
|
||||||
...req.body.type,
|
...req.body.type,
|
||||||
slug: req.body.slug || slugify(alphaNumericNanoId(8)),
|
name: req.body.slug || slugify(alphaNumericNanoId(8)),
|
||||||
permissions: req.body.permissions
|
permissions: req.body.permissions
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return { privilege };
|
|
||||||
|
return {
|
||||||
|
privilege: {
|
||||||
|
...privilege,
|
||||||
|
identityId: req.body.identityId,
|
||||||
|
projectMembershipId: req.body.projectId,
|
||||||
|
projectId: req.body.projectId,
|
||||||
|
slug: privilege.name
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -108,7 +121,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
z.object({
|
z.object({
|
||||||
isTemporary: z.literal(true).describe(IDENTITY_ADDITIONAL_PRIVILEGE_V2.UPDATE.isTemporary),
|
isTemporary: z.literal(true).describe(IDENTITY_ADDITIONAL_PRIVILEGE_V2.UPDATE.isTemporary),
|
||||||
temporaryMode: z
|
temporaryMode: z
|
||||||
.nativeEnum(IdentityProjectAdditionalPrivilegeTemporaryMode)
|
.nativeEnum(TemporaryPermissionMode)
|
||||||
.describe(IDENTITY_ADDITIONAL_PRIVILEGE_V2.UPDATE.temporaryMode),
|
.describe(IDENTITY_ADDITIONAL_PRIVILEGE_V2.UPDATE.temporaryMode),
|
||||||
temporaryRange: z
|
temporaryRange: z
|
||||||
.string()
|
.string()
|
||||||
@@ -129,19 +142,36 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const privilege = await server.services.identityProjectAdditionalPrivilegeV2.updateById({
|
const { privilege: privilegeDoc } = await server.services.convertor.additionalPrivilegeIdToDoc(req.params.id);
|
||||||
actorId: req.permission.id,
|
|
||||||
actor: req.permission.type,
|
const { additionalPrivilege: privilege } = await server.services.additionalPrivilege.updateAdditionalPrivilege({
|
||||||
actorOrgId: req.permission.orgId,
|
permission: req.permission,
|
||||||
actorAuthMethod: req.permission.authMethod,
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
projectId: privilegeDoc.projectId as string,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
id: req.params.id,
|
id: req.params.id,
|
||||||
|
actorId: privilegeDoc.actorIdentityId as string,
|
||||||
|
actorType: ActorType.IDENTITY
|
||||||
|
},
|
||||||
data: {
|
data: {
|
||||||
...req.body,
|
...req.body,
|
||||||
...req.body.type,
|
...req.body.type,
|
||||||
permissions: req.body.permissions || undefined
|
permissions: req.body.permissions || undefined
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return { privilege };
|
|
||||||
|
return {
|
||||||
|
privilege: {
|
||||||
|
...privilege,
|
||||||
|
identityId: privilegeDoc.actorIdentityId as string,
|
||||||
|
projectMembershipId: privilegeDoc.projectId as string,
|
||||||
|
projectId: privilegeDoc.projectId as string,
|
||||||
|
slug: privilege.name
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -171,14 +201,31 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const privilege = await server.services.identityProjectAdditionalPrivilegeV2.deleteById({
|
const { privilege: privilegeDoc } = await server.services.convertor.additionalPrivilegeIdToDoc(req.params.id);
|
||||||
actorId: req.permission.id,
|
|
||||||
actor: req.permission.type,
|
const { additionalPrivilege: privilege } = await server.services.additionalPrivilege.deleteAdditionalPrivilege({
|
||||||
actorAuthMethod: req.permission.authMethod,
|
permission: req.permission,
|
||||||
actorOrgId: req.permission.orgId,
|
scopeData: {
|
||||||
id: req.params.id
|
scope: AccessScope.Project,
|
||||||
|
projectId: privilegeDoc.projectId as string,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
id: req.params.id,
|
||||||
|
actorId: privilegeDoc.actorIdentityId as string,
|
||||||
|
actorType: ActorType.IDENTITY
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return { privilege };
|
|
||||||
|
return {
|
||||||
|
privilege: {
|
||||||
|
...privilege,
|
||||||
|
identityId: privilegeDoc.actorIdentityId as string,
|
||||||
|
projectMembershipId: privilegeDoc.projectId as string,
|
||||||
|
projectId: privilegeDoc.projectId as string,
|
||||||
|
slug: privilege.name
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -208,14 +255,31 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const privilege = await server.services.identityProjectAdditionalPrivilegeV2.getPrivilegeDetailsById({
|
const { privilege: privilegeDoc } = await server.services.convertor.additionalPrivilegeIdToDoc(req.params.id);
|
||||||
actorId: req.permission.id,
|
|
||||||
actorAuthMethod: req.permission.authMethod,
|
const { additionalPrivilege: privilege } = await server.services.additionalPrivilege.getAdditionalPrivilegeById({
|
||||||
actor: req.permission.type,
|
permission: req.permission,
|
||||||
actorOrgId: req.permission.orgId,
|
scopeData: {
|
||||||
id: req.params.id
|
scope: AccessScope.Project,
|
||||||
|
projectId: privilegeDoc.projectId as string,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
id: req.params.id,
|
||||||
|
actorId: privilegeDoc.actorIdentityId as string,
|
||||||
|
actorType: ActorType.IDENTITY
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return { privilege };
|
|
||||||
|
return {
|
||||||
|
privilege: {
|
||||||
|
...privilege,
|
||||||
|
identityId: privilegeDoc.actorIdentityId as string,
|
||||||
|
projectMembershipId: privilegeDoc.projectId as string,
|
||||||
|
projectId: privilegeDoc.projectId as string,
|
||||||
|
slug: privilege.name
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -249,15 +313,36 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const privilege = await server.services.identityProjectAdditionalPrivilegeV2.getPrivilegeDetailsBySlug({
|
const { id: projectId } = await server.services.convertor.projectSlugToId({
|
||||||
actorId: req.permission.id,
|
slug: req.query.projectSlug,
|
||||||
actorAuthMethod: req.permission.authMethod,
|
orgId: req.permission.orgId
|
||||||
actor: req.permission.type,
|
|
||||||
actorOrgId: req.permission.orgId,
|
|
||||||
slug: req.params.privilegeSlug,
|
|
||||||
...req.query
|
|
||||||
});
|
});
|
||||||
return { privilege };
|
|
||||||
|
const { additionalPrivilege: privilege } = await server.services.additionalPrivilege.getAdditionalPrivilegeByName(
|
||||||
|
{
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
projectId,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
name: req.params.privilegeSlug,
|
||||||
|
actorId: req.query.identityId,
|
||||||
|
actorType: ActorType.IDENTITY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
privilege: {
|
||||||
|
...privilege,
|
||||||
|
identityId: req.query.identityId,
|
||||||
|
projectMembershipId: privilege.projectId as string,
|
||||||
|
projectId,
|
||||||
|
slug: privilege.name
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -288,15 +373,27 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const privileges = await server.services.identityProjectAdditionalPrivilegeV2.listIdentityProjectPrivileges({
|
const { additionalPrivileges: privileges } = await server.services.additionalPrivilege.listAdditionalPrivileges({
|
||||||
actorId: req.permission.id,
|
permission: req.permission,
|
||||||
actor: req.permission.type,
|
scopeData: {
|
||||||
actorAuthMethod: req.permission.authMethod,
|
scope: AccessScope.Project,
|
||||||
actorOrgId: req.permission.orgId,
|
projectId: req.query.projectId,
|
||||||
...req.query
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
actorId: req.query.identityId,
|
||||||
|
actorType: ActorType.IDENTITY
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
privileges
|
privileges: privileges.map((privilege) => ({
|
||||||
|
...privilege,
|
||||||
|
identityId: req.query.identityId,
|
||||||
|
projectMembershipId: privilege.projectId as string,
|
||||||
|
projectId: req.query.projectId,
|
||||||
|
slug: privilege.name
|
||||||
|
}))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,8 +3,9 @@ import { ForbiddenError } from "@casl/ability";
|
|||||||
import { ActionProjectType } from "@app/db/schemas";
|
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, NotFoundError } from "@app/lib/errors";
|
||||||
import { groupBy } from "@app/lib/fn";
|
import { groupBy } from "@app/lib/fn";
|
||||||
|
import { TAdditionalPrivilegeDALFactory } from "@app/services/additional-privilege/additional-privilege-dal";
|
||||||
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||||
import { TProjectEnvDALFactory } from "@app/services/project-env/project-env-dal";
|
import { TProjectEnvDALFactory } from "@app/services/project-env/project-env-dal";
|
||||||
import { TProjectMembershipDALFactory } from "@app/services/project-membership/project-membership-dal";
|
import { TProjectMembershipDALFactory } from "@app/services/project-membership/project-membership-dal";
|
||||||
@@ -14,7 +15,6 @@ import { TAccessApprovalRequestDALFactory } from "../access-approval-request/acc
|
|||||||
import { TAccessApprovalRequestReviewerDALFactory } from "../access-approval-request/access-approval-request-reviewer-dal";
|
import { TAccessApprovalRequestReviewerDALFactory } from "../access-approval-request/access-approval-request-reviewer-dal";
|
||||||
import { ApprovalStatus } from "../access-approval-request/access-approval-request-types";
|
import { ApprovalStatus } from "../access-approval-request/access-approval-request-types";
|
||||||
import { TGroupDALFactory } from "../group/group-dal";
|
import { TGroupDALFactory } from "../group/group-dal";
|
||||||
import { TProjectUserAdditionalPrivilegeDALFactory } from "../project-user-additional-privilege/project-user-additional-privilege-dal";
|
|
||||||
import {
|
import {
|
||||||
TAccessApprovalPolicyApproverDALFactory,
|
TAccessApprovalPolicyApproverDALFactory,
|
||||||
TAccessApprovalPolicyBypasserDALFactory
|
TAccessApprovalPolicyBypasserDALFactory
|
||||||
@@ -38,11 +38,11 @@ type TAccessApprovalPolicyServiceFactoryDep = {
|
|||||||
projectEnvDAL: Pick<TProjectEnvDALFactory, "find" | "findOne">;
|
projectEnvDAL: Pick<TProjectEnvDALFactory, "find" | "findOne">;
|
||||||
accessApprovalPolicyApproverDAL: TAccessApprovalPolicyApproverDALFactory;
|
accessApprovalPolicyApproverDAL: TAccessApprovalPolicyApproverDALFactory;
|
||||||
accessApprovalPolicyBypasserDAL: TAccessApprovalPolicyBypasserDALFactory;
|
accessApprovalPolicyBypasserDAL: TAccessApprovalPolicyBypasserDALFactory;
|
||||||
projectMembershipDAL: Pick<TProjectMembershipDALFactory, "find">;
|
projectMembershipDAL: Pick<TProjectMembershipDALFactory, "findProjectMembershipsByUserIds">;
|
||||||
groupDAL: TGroupDALFactory;
|
groupDAL: TGroupDALFactory;
|
||||||
userDAL: Pick<TUserDALFactory, "find">;
|
userDAL: Pick<TUserDALFactory, "find">;
|
||||||
accessApprovalRequestDAL: Pick<TAccessApprovalRequestDALFactory, "update" | "find" | "resetReviewByPolicyId">;
|
accessApprovalRequestDAL: Pick<TAccessApprovalRequestDALFactory, "update" | "find" | "resetReviewByPolicyId">;
|
||||||
additionalPrivilegeDAL: Pick<TProjectUserAdditionalPrivilegeDALFactory, "delete">;
|
additionalPrivilegeDAL: Pick<TAdditionalPrivilegeDALFactory, "delete">;
|
||||||
accessApprovalRequestReviewerDAL: Pick<TAccessApprovalRequestReviewerDALFactory, "update" | "delete">;
|
accessApprovalRequestReviewerDAL: Pick<TAccessApprovalRequestReviewerDALFactory, "update" | "delete">;
|
||||||
accessApprovalPolicyEnvironmentDAL: TAccessApprovalPolicyEnvironmentDALFactory;
|
accessApprovalPolicyEnvironmentDAL: TAccessApprovalPolicyEnvironmentDALFactory;
|
||||||
};
|
};
|
||||||
@@ -83,12 +83,11 @@ export const accessApprovalPolicyServiceFactory = ({
|
|||||||
return policyId ? policy && policy.id !== policyId : Boolean(policy);
|
return policyId ? policy && policy.id !== policyId : Boolean(policy);
|
||||||
};
|
};
|
||||||
|
|
||||||
const verifyProjectUserMembership = async (userIds: string[], projectId: string) => {
|
const verifyProjectUserMembership = async (userIds: string[], orgId: string, projectId: string) => {
|
||||||
if (userIds.length === 0) return;
|
if (userIds.length === 0) return;
|
||||||
const projectMemberships = await projectMembershipDAL.find({
|
const projectMemberships = (await projectMembershipDAL.findProjectMembershipsByUserIds(orgId, userIds)).filter(
|
||||||
$in: { userId: userIds },
|
(v) => v.projectId === projectId
|
||||||
projectId
|
);
|
||||||
});
|
|
||||||
|
|
||||||
if (projectMemberships.length !== userIds.length) {
|
if (projectMemberships.length !== userIds.length) {
|
||||||
const projectMemberUserIds = new Set(projectMemberships.map((member) => member.userId));
|
const projectMemberUserIds = new Set(projectMemberships.map((member) => member.userId));
|
||||||
@@ -191,6 +190,7 @@ export const accessApprovalPolicyServiceFactory = ({
|
|||||||
if (approverUserIds.length > 0) {
|
if (approverUserIds.length > 0) {
|
||||||
await verifyProjectUserMembership(
|
await verifyProjectUserMembership(
|
||||||
approverUserIds.map((au) => au.id),
|
approverUserIds.map((au) => au.id),
|
||||||
|
project.orgId,
|
||||||
project.id
|
project.id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -445,7 +445,7 @@ export const accessApprovalPolicyServiceFactory = ({
|
|||||||
|
|
||||||
// Validate user bypassers
|
// Validate user bypassers
|
||||||
if (bypasserUserIds.length > 0) {
|
if (bypasserUserIds.length > 0) {
|
||||||
await verifyProjectUserMembership(bypasserUserIds, accessApprovalPolicy.projectId);
|
await verifyProjectUserMembership(bypasserUserIds, actorOrgId, accessApprovalPolicy.projectId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate group bypassers
|
// Validate group bypassers
|
||||||
@@ -513,6 +513,7 @@ export const accessApprovalPolicyServiceFactory = ({
|
|||||||
if (approverUserIds.length > 0) {
|
if (approverUserIds.length > 0) {
|
||||||
await verifyProjectUserMembership(
|
await verifyProjectUserMembership(
|
||||||
approverUserIds.map((au) => au.id),
|
approverUserIds.map((au) => au.id),
|
||||||
|
actorOrgId,
|
||||||
accessApprovalPolicy.projectId
|
accessApprovalPolicy.projectId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -650,7 +651,7 @@ export const accessApprovalPolicyServiceFactory = ({
|
|||||||
|
|
||||||
if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` });
|
if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` });
|
||||||
|
|
||||||
const { membership } = await permissionService.getProjectPermission({
|
await permissionService.getProjectPermission({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
projectId: project.id,
|
projectId: project.id,
|
||||||
@@ -658,9 +659,6 @@ export const accessApprovalPolicyServiceFactory = ({
|
|||||||
actorOrgId,
|
actorOrgId,
|
||||||
actionProjectType: ActionProjectType.SecretManager
|
actionProjectType: ActionProjectType.SecretManager
|
||||||
});
|
});
|
||||||
if (!membership) {
|
|
||||||
throw new ForbiddenRequestError({ message: "You are not a member of this project" });
|
|
||||||
}
|
|
||||||
|
|
||||||
const environment = await projectEnvDAL.findOne({ projectId: project.id, slug: envSlug });
|
const environment = await projectEnvDAL.findOne({ projectId: project.id, slug: envSlug });
|
||||||
if (!environment) throw new NotFoundError({ message: `Environment with slug '${envSlug}' not found` });
|
if (!environment) throw new NotFoundError({ message: `Environment with slug '${envSlug}' not found` });
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user