mirror of
https://github.com/Infisical/infisical.git
synced 2025-07-31 10:38:12 +00:00
Compare commits
435 Commits
daniel/vie
...
feat/add-u
Author | SHA1 | Date | |
---|---|---|---|
|
178acc412d | ||
|
b0288c49c0 | ||
|
4e10f51e50 | ||
|
26c14119be | ||
|
b4e831d3e2 | ||
|
8818d5c94b | ||
|
8bfbac153c | ||
|
d7af9e84be | ||
|
f2a984e6b6 | ||
|
2cff90913b | ||
|
c783fa32e9 | ||
|
109971916b | ||
|
f7d35e61f7 | ||
|
6107adcc15 | ||
|
a4eb2e77c2 | ||
|
40d119b462 | ||
|
6f738d7ed0 | ||
|
7f4d4b931b | ||
|
ac2ee6884c | ||
|
608e9a644c | ||
|
c15a1c6ed3 | ||
|
35f0e8f49a | ||
|
efb8b69777 | ||
|
b4226e7e1b | ||
|
ca1f7d3448 | ||
|
4d569d70d6 | ||
|
5fccc62213 | ||
|
eba12912f8 | ||
|
80edccc953 | ||
|
f1b1d6f480 | ||
|
07d6616f3c | ||
|
7364717f60 | ||
|
28d056cf7a | ||
|
f5d7809515 | ||
|
233740e029 | ||
|
767fdc645f | ||
|
c477703dda | ||
|
923d639c40 | ||
|
7655dc7f3c | ||
|
6c6c4db92c | ||
|
8cf125ed32 | ||
|
886cc9a113 | ||
|
e1016f0a8b | ||
|
9c0a5f0bd4 | ||
|
7facd0e89e | ||
|
3afe2552d5 | ||
|
1fdb695240 | ||
|
d9bd1ac878 | ||
|
ee185cbe47 | ||
|
abc2f3808e | ||
|
733440a7b5 | ||
|
1ef3525917 | ||
|
6664add428 | ||
|
242e8fd2c6 | ||
|
1137247e69 | ||
|
32b951f6e9 | ||
|
6f5fe053cd | ||
|
875ec6a24e | ||
|
17233e6a6f | ||
|
0dd06c1d66 | ||
|
fc2e5d18b7 | ||
|
ae1ee25687 | ||
|
5d0bbce12d | ||
|
8c87c40467 | ||
|
a9dab557d9 | ||
|
76c3f1c152 | ||
|
965084cc0c | ||
|
4650ba9fdd | ||
|
73dea6a0be | ||
|
e7742afcd3 | ||
|
7d3dd765ad | ||
|
927eb0407d | ||
|
17ddb79def | ||
|
5ef5a5a107 | ||
|
9ae0880f50 | ||
|
3814c65f38 | ||
|
3fa98e2a8d | ||
|
c6b21491db | ||
|
357381b0d6 | ||
|
82af77c480 | ||
|
b2fae5c439 | ||
|
f16e96759f | ||
|
5eb9a1a667 | ||
|
03ad6f822a | ||
|
23a5a7a624 | ||
|
98447e9402 | ||
|
0f7e8585dc | ||
|
8568d1f6fe | ||
|
27198869d8 | ||
|
dd0880825b | ||
|
f27050a1c3 | ||
|
785173747f | ||
|
5b20c1feba | ||
|
ac73800acb | ||
|
d33b06dd8a | ||
|
9a6e27d4be | ||
|
d0db5c00e8 | ||
|
dd323eccd4 | ||
|
9475c1671e | ||
|
0f710b1ccc | ||
|
71c55d5a53 | ||
|
32bca651df | ||
|
82533f49ca | ||
|
1d8c513da1 | ||
|
ae8a78b883 | ||
|
b08b53b77d | ||
|
862ed4f4e7 | ||
|
7b9254d09a | ||
|
c6305045e3 | ||
|
24bf9f7a2a | ||
|
86d7fca8fb | ||
|
cac4f30ca8 | ||
|
101c056f43 | ||
|
8d4fa0bdb9 | ||
|
2642f7501d | ||
|
68ba807b43 | ||
|
80352acc8a | ||
|
499ff3635b | ||
|
78fc8a693d | ||
|
78687984b7 | ||
|
25d3fb6a8c | ||
|
31a4bcafbe | ||
|
ac8b3aca60 | ||
|
4ea0cc62e3 | ||
|
bdab16f64b | ||
|
9d0020fa4e | ||
|
3c07204532 | ||
|
c0926bec69 | ||
|
b9d74e0aed | ||
|
f3078040fc | ||
|
f2fead7a51 | ||
|
3483ed85ff | ||
|
3c58bf890d | ||
|
dc219b8e9f | ||
|
85627eb825 | ||
|
f1e30fd06b | ||
|
fcc6f812d5 | ||
|
7c38932878 | ||
|
e339b81bf1 | ||
|
b9bfe19b64 | ||
|
966ca1a3c6 | ||
|
fa030417ef | ||
|
8bfbae1037 | ||
|
d00b34663e | ||
|
cdc364d44c | ||
|
34a6ec1b64 | ||
|
32641cfc3a | ||
|
fe58508136 | ||
|
65f78c556f | ||
|
dd52f4d7e0 | ||
|
aa7ad9a8c8 | ||
|
85a716628b | ||
|
581e4b35f9 | ||
|
4b0e5fa05b | ||
|
4a9e24884d | ||
|
9565ef29d0 | ||
|
7107a1b225 | ||
|
8676421a10 | ||
|
5f6db870a6 | ||
|
5bc8e4729f | ||
|
27fdf68e42 | ||
|
9a5bc33517 | ||
|
0fecbad43c | ||
|
511a81a464 | ||
|
f33a777fae | ||
|
8a870131e9 | ||
|
041fac7f42 | ||
|
70f5f21e7f | ||
|
d97057b43b | ||
|
5ce738bba0 | ||
|
19b0cd9735 | ||
|
7dcd3d24aa | ||
|
3c5c6aeca8 | ||
|
b5b0d42dd5 | ||
|
1ec87fae75 | ||
|
d888d990d0 | ||
|
1cbab41609 | ||
|
49b5b488ef | ||
|
bb59e04c28 | ||
|
46b08dccd1 | ||
|
53ca8d7161 | ||
|
aec131543f | ||
|
e19c3630d9 | ||
|
071dab723a | ||
|
aeaa5babab | ||
|
1ce155e2fd | ||
|
2ed05c26e8 | ||
|
9e0fdb10b1 | ||
|
5c40347c52 | ||
|
edf375ca48 | ||
|
264177638f | ||
|
230b44fca1 | ||
|
3d02feaad9 | ||
|
77dd768a38 | ||
|
eb11efcafa | ||
|
8522420e7f | ||
|
81331ec4d1 | ||
|
f15491d102 | ||
|
4d4547015e | ||
|
06cd496ab3 | ||
|
4119478704 | ||
|
07898414a3 | ||
|
f15b30ff85 | ||
|
700efc9b6d | ||
|
894633143d | ||
|
b76ee9cc49 | ||
|
c498178923 | ||
|
8bb68f9889 | ||
|
1c121ec30d | ||
|
8ee2b54182 | ||
|
956d97eda2 | ||
|
e877a4c9e9 | ||
|
ee9a7cd5a1 | ||
|
a84dddaf6f | ||
|
8cbfeffe4c | ||
|
2084539f61 | ||
|
9baab63b29 | ||
|
34cf47a5eb | ||
|
b90c6cf3fc | ||
|
68374a17f0 | ||
|
993eb4d239 | ||
|
2382937385 | ||
|
ac0f4aa8bd | ||
|
05af70161a | ||
|
b121ec891f | ||
|
ab566bcbe4 | ||
|
2940300164 | ||
|
9356ab7cbc | ||
|
bbc94da522 | ||
|
8a241771ec | ||
|
ed5c18b5ac | ||
|
1f23515aac | ||
|
d01cb282f9 | ||
|
8fa8117fa1 | ||
|
6dc085b970 | ||
|
63dc9ec35d | ||
|
1d083befe4 | ||
|
c01e29b932 | ||
|
3aed79071b | ||
|
140fa49871 | ||
|
03a3e80082 | ||
|
5a114586dc | ||
|
20ebfcefaa | ||
|
bfcfffbabf | ||
|
210bd220e5 | ||
|
7be2a10631 | ||
|
5753eb7d77 | ||
|
cb86aa40fa | ||
|
1131143a71 | ||
|
041d585f19 | ||
|
728c3f56a7 | ||
|
939b77b050 | ||
|
a50b8120fd | ||
|
f1ee53d417 | ||
|
229ad79f49 | ||
|
d7dbd01ecf | ||
|
026fd21fd4 | ||
|
9b9c1a52b3 | ||
|
98aa424e2e | ||
|
2cd5df1ab3 | ||
|
e0d863e06e | ||
|
d991af557b | ||
|
ae54d04357 | ||
|
fa590ba697 | ||
|
9899864133 | ||
|
06715b1b58 | ||
|
038f43b769 | ||
|
35d7881613 | ||
|
b444908022 | ||
|
3f9a793578 | ||
|
479d6445a7 | ||
|
bf5e8d8c8b | ||
|
99aa567a6f | ||
|
1da2896bb0 | ||
|
423a2f38ea | ||
|
db0a72f7b4 | ||
|
4a202d180a | ||
|
33103f1e95 | ||
|
ce8a4bc50e | ||
|
141a821091 | ||
|
b3dd5410d7 | ||
|
74574c6c29 | ||
|
4f32756951 | ||
|
961fe09a6e | ||
|
eb4816fd29 | ||
|
5ab853d3e6 | ||
|
0e073cc9fc | ||
|
715bb447e6 | ||
|
c2f2a038ad | ||
|
433b1a49f0 | ||
|
5671cd5cef | ||
|
b8f04d6738 | ||
|
b0b255461d | ||
|
c2f2dc1e72 | ||
|
0ee1b425df | ||
|
46e72e9fba | ||
|
06fc4e955d | ||
|
18c8fc66ee | ||
|
ece294c483 | ||
|
2e40ee76d0 | ||
|
9a712b5c85 | ||
|
1ec427053b | ||
|
6c636415bb | ||
|
9b083a5dfb | ||
|
224b167000 | ||
|
e323cb4630 | ||
|
e87a1bd402 | ||
|
3b09173bb1 | ||
|
d957419b94 | ||
|
ec9897d561 | ||
|
4d41513abf | ||
|
2a8e159f51 | ||
|
83206aad93 | ||
|
9fc9f69fc9 | ||
|
cd333a7923 | ||
|
e11fdf8f3a | ||
|
4725108319 | ||
|
715441908b | ||
|
e1a11c37e3 | ||
|
cd83efb060 | ||
|
53b5497271 | ||
|
3f190426fe | ||
|
15130a433c | ||
|
954e94cd87 | ||
|
a0bf03b2ae | ||
|
9dd2379fb3 | ||
|
6bf9ab5937 | ||
|
ee536717c0 | ||
|
a0cb4889ca | ||
|
271a8de4c0 | ||
|
b18f7b957d | ||
|
c7416c825c | ||
|
e6349474aa | ||
|
419dd37d03 | ||
|
f00a54ed54 | ||
|
a25c25434c | ||
|
4f72d09458 | ||
|
08baf02ef0 | ||
|
fe172e39bf | ||
|
fda77fe464 | ||
|
c4c065ea9e | ||
|
c6ca668db9 | ||
|
4d8598a019 | ||
|
a9da2d6241 | ||
|
4420985669 | ||
|
d6da108e32 | ||
|
577c81be65 | ||
|
93baf9728b | ||
|
064322936b | ||
|
7634fc94a6 | ||
|
ecd39abdc1 | ||
|
d8313a161e | ||
|
d82b06c72b | ||
|
b8e79f20dc | ||
|
0088217fa9 | ||
|
13485cecbb | ||
|
85e9952a4c | ||
|
3d072c2f48 | ||
|
ebcf4761b6 | ||
|
82b828c10e | ||
|
5e7ad5614d | ||
|
f825a62af2 | ||
|
bf20556b17 | ||
|
dcde10a401 | ||
|
e0373cf416 | ||
|
ea038f26df | ||
|
f95c446651 | ||
|
90bf8f800b | ||
|
59ab4de24a | ||
|
d2295c47f5 | ||
|
47dc4f0c47 | ||
|
4b0e0d4de5 | ||
|
6128301622 | ||
|
766c1242fd | ||
|
8c318f51e4 | ||
|
be51e358fc | ||
|
e8dd8a908d | ||
|
fd20cb1e38 | ||
|
a07f168c36 | ||
|
530045aaf2 | ||
|
cd4f2cccf8 | ||
|
ff4ff0588f | ||
|
993024662a | ||
|
a03c152abf | ||
|
45d2cc05b3 | ||
|
74200bf860 | ||
|
c59cecdb45 | ||
|
dbabb4f964 | ||
|
483f26d863 | ||
|
da094383b8 | ||
|
fce772bc20 | ||
|
5e1a7cfb6e | ||
|
323d5d2d27 | ||
|
dd79d0385a | ||
|
0a28ac4a7d | ||
|
196c616986 | ||
|
bf6060d353 | ||
|
438e2dfa07 | ||
|
3ad50a4386 | ||
|
ed94e7a8e7 | ||
|
09ad1cce96 | ||
|
d7f9cff43e | ||
|
5d8d75ac93 | ||
|
db5a85d3ca | ||
|
a1a931d3dd | ||
|
e639f5ee49 | ||
|
a2c9c4529b | ||
|
0a338ee539 | ||
|
2a7679005e | ||
|
838d132898 | ||
|
b0cacc5a4a | ||
|
68d07f0136 | ||
|
10a3c7015e | ||
|
03b0334fa0 | ||
|
10a3658328 | ||
|
e8ece6be3f | ||
|
c765c20539 | ||
|
2f4c42482d | ||
|
75ca093b24 | ||
|
6c0889f117 | ||
|
5b11232325 | ||
|
042a472f59 | ||
|
53c015988d | ||
|
fb0b6b00dd | ||
|
a5f198a3d5 | ||
|
2f060407ab | ||
|
c516ce8196 | ||
|
95ccd35f61 | ||
|
d5741b4a72 | ||
|
4654a17e5f | ||
|
dd2fee3eca | ||
|
802cf79af5 | ||
|
4b9f409ea5 | ||
|
cefcd872ee | ||
|
4955e2064d |
259
.github/workflows/release_build_infisical_cli.yml
vendored
259
.github/workflows/release_build_infisical_cli.yml
vendored
@@ -1,132 +1,153 @@
|
|||||||
name: Build and release CLI
|
name: Build and release CLI
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
push:
|
push:
|
||||||
# run only against tags
|
# run only against tags
|
||||||
tags:
|
tags:
|
||||||
- "infisical-cli/v*.*.*"
|
- "infisical-cli/v*.*.*"
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
cli-integration-tests:
|
cli-integration-tests:
|
||||||
name: Run tests before deployment
|
name: Run tests before deployment
|
||||||
uses: ./.github/workflows/run-cli-tests.yml
|
uses: ./.github/workflows/run-cli-tests.yml
|
||||||
secrets:
|
secrets:
|
||||||
CLI_TESTS_UA_CLIENT_ID: ${{ secrets.CLI_TESTS_UA_CLIENT_ID }}
|
CLI_TESTS_UA_CLIENT_ID: ${{ secrets.CLI_TESTS_UA_CLIENT_ID }}
|
||||||
CLI_TESTS_UA_CLIENT_SECRET: ${{ secrets.CLI_TESTS_UA_CLIENT_SECRET }}
|
CLI_TESTS_UA_CLIENT_SECRET: ${{ secrets.CLI_TESTS_UA_CLIENT_SECRET }}
|
||||||
CLI_TESTS_SERVICE_TOKEN: ${{ secrets.CLI_TESTS_SERVICE_TOKEN }}
|
CLI_TESTS_SERVICE_TOKEN: ${{ secrets.CLI_TESTS_SERVICE_TOKEN }}
|
||||||
CLI_TESTS_PROJECT_ID: ${{ secrets.CLI_TESTS_PROJECT_ID }}
|
CLI_TESTS_PROJECT_ID: ${{ secrets.CLI_TESTS_PROJECT_ID }}
|
||||||
CLI_TESTS_ENV_SLUG: ${{ secrets.CLI_TESTS_ENV_SLUG }}
|
CLI_TESTS_ENV_SLUG: ${{ secrets.CLI_TESTS_ENV_SLUG }}
|
||||||
CLI_TESTS_USER_EMAIL: ${{ secrets.CLI_TESTS_USER_EMAIL }}
|
CLI_TESTS_USER_EMAIL: ${{ secrets.CLI_TESTS_USER_EMAIL }}
|
||||||
CLI_TESTS_USER_PASSWORD: ${{ secrets.CLI_TESTS_USER_PASSWORD }}
|
CLI_TESTS_USER_PASSWORD: ${{ secrets.CLI_TESTS_USER_PASSWORD }}
|
||||||
CLI_TESTS_INFISICAL_VAULT_FILE_PASSPHRASE: ${{ secrets.CLI_TESTS_INFISICAL_VAULT_FILE_PASSPHRASE }}
|
CLI_TESTS_INFISICAL_VAULT_FILE_PASSPHRASE: ${{ secrets.CLI_TESTS_INFISICAL_VAULT_FILE_PASSPHRASE }}
|
||||||
|
|
||||||
npm-release:
|
npm-release:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
working-directory: ./npm
|
||||||
|
needs:
|
||||||
|
- cli-integration-tests
|
||||||
|
- goreleaser
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Extract version
|
||||||
|
run: |
|
||||||
|
VERSION=$(echo ${{ github.ref_name }} | sed 's/infisical-cli\/v//')
|
||||||
|
echo "Version extracted: $VERSION"
|
||||||
|
echo "CLI_VERSION=$VERSION" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Print version
|
||||||
|
run: echo ${{ env.CLI_VERSION }}
|
||||||
|
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
cache: "npm"
|
||||||
|
cache-dependency-path: ./npm/package-lock.json
|
||||||
|
- name: Install dependencies
|
||||||
|
working-directory: ${{ env.working-directory }}
|
||||||
|
run: npm install --ignore-scripts
|
||||||
|
|
||||||
|
- name: Set NPM version
|
||||||
|
working-directory: ${{ env.working-directory }}
|
||||||
|
run: npm version ${{ env.CLI_VERSION }} --allow-same-version --no-git-tag-version
|
||||||
|
|
||||||
|
- name: Setup NPM
|
||||||
|
working-directory: ${{ env.working-directory }}
|
||||||
|
run: |
|
||||||
|
echo 'registry="https://registry.npmjs.org/"' > ./.npmrc
|
||||||
|
echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ./.npmrc
|
||||||
|
|
||||||
|
echo 'registry="https://registry.npmjs.org/"' > ~/.npmrc
|
||||||
|
echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc
|
||||||
env:
|
env:
|
||||||
working-directory: ./npm
|
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
needs:
|
|
||||||
- cli-integration-tests
|
|
||||||
- goreleaser
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Extract version
|
- name: Pack NPM
|
||||||
run: |
|
working-directory: ${{ env.working-directory }}
|
||||||
VERSION=$(echo ${{ github.ref_name }} | sed 's/infisical-cli\/v//')
|
run: npm pack
|
||||||
echo "Version extracted: $VERSION"
|
|
||||||
echo "CLI_VERSION=$VERSION" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Print version
|
- name: Publish NPM
|
||||||
run: echo ${{ env.CLI_VERSION }}
|
working-directory: ${{ env.working-directory }}
|
||||||
|
run: npm publish --tarball=./infisical-sdk-${{github.ref_name}} --access public --registry=https://registry.npmjs.org/
|
||||||
|
env:
|
||||||
|
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
|
|
||||||
- name: Setup Node
|
goreleaser:
|
||||||
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
|
runs-on: ubuntu-latest
|
||||||
with:
|
needs: [cli-integration-tests]
|
||||||
node-version: 20
|
steps:
|
||||||
cache: "npm"
|
- uses: actions/checkout@v3
|
||||||
cache-dependency-path: ./npm/package-lock.json
|
with:
|
||||||
- name: Install dependencies
|
fetch-depth: 0
|
||||||
working-directory: ${{ env.working-directory }}
|
- name: 🐋 Login to Docker Hub
|
||||||
run: npm install --ignore-scripts
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
- name: Set NPM version
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
working-directory: ${{ env.working-directory }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
run: npm version ${{ env.CLI_VERSION }} --allow-same-version --no-git-tag-version
|
- name: 🔧 Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
- name: Setup NPM
|
- run: git fetch --force --tags
|
||||||
working-directory: ${{ env.working-directory }}
|
- run: echo "Ref name ${{github.ref_name}}"
|
||||||
run: |
|
- uses: actions/setup-go@v3
|
||||||
echo 'registry="https://registry.npmjs.org/"' > ./.npmrc
|
with:
|
||||||
echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ./.npmrc
|
go-version: ">=1.19.3"
|
||||||
|
cache: true
|
||||||
echo 'registry="https://registry.npmjs.org/"' > ~/.npmrc
|
cache-dependency-path: cli/go.sum
|
||||||
echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc
|
- name: Setup for libssl1.0-dev
|
||||||
env:
|
run: |
|
||||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
echo 'deb http://security.ubuntu.com/ubuntu bionic-security main' | sudo tee -a /etc/apt/sources.list
|
||||||
|
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3B4FE6ACC0B21F32
|
||||||
- name: Pack NPM
|
sudo apt update
|
||||||
working-directory: ${{ env.working-directory }}
|
sudo apt-get install -y libssl1.0-dev
|
||||||
run: npm pack
|
- name: OSXCross for CGO Support
|
||||||
|
run: |
|
||||||
- name: Publish NPM
|
mkdir ../../osxcross
|
||||||
working-directory: ${{ env.working-directory }}
|
git clone https://github.com/plentico/osxcross-target.git ../../osxcross/target
|
||||||
run: npm publish --tarball=./infisical-sdk-${{github.ref_name}} --access public --registry=https://registry.npmjs.org/
|
- uses: goreleaser/goreleaser-action@v4
|
||||||
env:
|
with:
|
||||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
distribution: goreleaser-pro
|
||||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
version: v1.26.2-pro
|
||||||
|
args: release --clean
|
||||||
goreleaser:
|
env:
|
||||||
runs-on: ubuntu-latest
|
GITHUB_TOKEN: ${{ secrets.GO_RELEASER_GITHUB_TOKEN }}
|
||||||
needs: [cli-integration-tests]
|
POSTHOG_API_KEY_FOR_CLI: ${{ secrets.POSTHOG_API_KEY_FOR_CLI }}
|
||||||
steps:
|
FURY_TOKEN: ${{ secrets.FURYPUSHTOKEN }}
|
||||||
- uses: actions/checkout@v3
|
AUR_KEY: ${{ secrets.AUR_KEY }}
|
||||||
with:
|
GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
|
||||||
fetch-depth: 0
|
- uses: actions/setup-python@v4
|
||||||
- name: 🐋 Login to Docker Hub
|
- run: pip install --upgrade cloudsmith-cli
|
||||||
uses: docker/login-action@v2
|
- uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
ruby-version: "3.3" # Not needed with a .ruby-version, .tool-versions or mise.toml
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
||||||
- name: 🔧 Set up Docker Buildx
|
- name: Install deb-s3
|
||||||
uses: docker/setup-buildx-action@v2
|
run: gem install deb-s3
|
||||||
- run: git fetch --force --tags
|
- name: Configure GPG Key
|
||||||
- run: echo "Ref name ${{github.ref_name}}"
|
run: echo -n "$GPG_SIGNING_KEY" | base64 --decode | gpg --batch --import
|
||||||
- uses: actions/setup-go@v3
|
env:
|
||||||
with:
|
GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }}
|
||||||
go-version: ">=1.19.3"
|
GPG_SIGNING_KEY_PASSPHRASE: ${{ secrets.GPG_SIGNING_KEY_PASSPHRASE }}
|
||||||
cache: true
|
- name: Publish to CloudSmith
|
||||||
cache-dependency-path: cli/go.sum
|
run: sh cli/upload_to_cloudsmith.sh
|
||||||
- name: Setup for libssl1.0-dev
|
env:
|
||||||
run: |
|
CLOUDSMITH_API_KEY: ${{ secrets.CLOUDSMITH_API_KEY }}
|
||||||
echo 'deb http://security.ubuntu.com/ubuntu bionic-security main' | sudo tee -a /etc/apt/sources.list
|
INFISICAL_CLI_S3_BUCKET: ${{ secrets.INFISICAL_CLI_S3_BUCKET }}
|
||||||
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3B4FE6ACC0B21F32
|
INFISICAL_CLI_REPO_SIGNING_KEY_ID: ${{ secrets.INFISICAL_CLI_REPO_SIGNING_KEY_ID }}
|
||||||
sudo apt update
|
AWS_ACCESS_KEY_ID: ${{ secrets.INFISICAL_CLI_REPO_AWS_ACCESS_KEY_ID }}
|
||||||
sudo apt-get install -y libssl1.0-dev
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.INFISICAL_CLI_REPO_AWS_SECRET_ACCESS_KEY }}
|
||||||
- name: OSXCross for CGO Support
|
- name: Invalidate Cloudfront cache
|
||||||
run: |
|
run: aws cloudfront create-invalidation --distribution-id $CLOUDFRONT_DISTRIBUTION_ID --paths '/deb/dists/stable/*'
|
||||||
mkdir ../../osxcross
|
env:
|
||||||
git clone https://github.com/plentico/osxcross-target.git ../../osxcross/target
|
AWS_ACCESS_KEY_ID: ${{ secrets.INFISICAL_CLI_REPO_AWS_ACCESS_KEY_ID }}
|
||||||
- uses: goreleaser/goreleaser-action@v4
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.INFISICAL_CLI_REPO_AWS_SECRET_ACCESS_KEY }}
|
||||||
with:
|
CLOUDFRONT_DISTRIBUTION_ID: ${{ secrets.INFISICAL_CLI_REPO_CLOUDFRONT_DISTRIBUTION_ID }}
|
||||||
distribution: goreleaser-pro
|
|
||||||
version: v1.26.2-pro
|
|
||||||
args: release --clean
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GO_RELEASER_GITHUB_TOKEN }}
|
|
||||||
POSTHOG_API_KEY_FOR_CLI: ${{ secrets.POSTHOG_API_KEY_FOR_CLI }}
|
|
||||||
FURY_TOKEN: ${{ secrets.FURYPUSHTOKEN }}
|
|
||||||
AUR_KEY: ${{ secrets.AUR_KEY }}
|
|
||||||
GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
|
|
||||||
- uses: actions/setup-python@v4
|
|
||||||
- run: pip install --upgrade cloudsmith-cli
|
|
||||||
- name: Publish to CloudSmith
|
|
||||||
run: sh cli/upload_to_cloudsmith.sh
|
|
||||||
env:
|
|
||||||
CLOUDSMITH_API_KEY: ${{ secrets.CLOUDSMITH_API_KEY }}
|
|
||||||
|
@@ -4,6 +4,10 @@ on:
|
|||||||
tags:
|
tags:
|
||||||
- "infisical-k8-operator/v*.*.*"
|
- "infisical-k8-operator/v*.*.*"
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release-image:
|
release-image:
|
||||||
name: Generate Helm Chart PR
|
name: Generate Helm Chart PR
|
||||||
|
@@ -162,6 +162,24 @@ scoop:
|
|||||||
description: "The official Infisical CLI"
|
description: "The official Infisical CLI"
|
||||||
license: MIT
|
license: MIT
|
||||||
|
|
||||||
|
winget:
|
||||||
|
- name: infisical
|
||||||
|
publisher: infisical
|
||||||
|
license: MIT
|
||||||
|
homepage: https://infisical.com
|
||||||
|
short_description: "The official Infisical CLI"
|
||||||
|
repository:
|
||||||
|
owner: infisical
|
||||||
|
name: winget-pkgs
|
||||||
|
branch: "infisical-{{.Version}}"
|
||||||
|
pull_request:
|
||||||
|
enabled: true
|
||||||
|
draft: false
|
||||||
|
base:
|
||||||
|
owner: microsoft
|
||||||
|
name: winget-pkgs
|
||||||
|
branch: master
|
||||||
|
|
||||||
aurs:
|
aurs:
|
||||||
- name: infisical-bin
|
- name: infisical-bin
|
||||||
homepage: "https://infisical.com"
|
homepage: "https://infisical.com"
|
||||||
|
@@ -12,3 +12,15 @@ docs/cli/commands/bootstrap.mdx:jwt:86
|
|||||||
docs/documentation/platform/audit-log-streams/audit-log-streams.mdx:generic-api-key:102
|
docs/documentation/platform/audit-log-streams/audit-log-streams.mdx:generic-api-key:102
|
||||||
docs/self-hosting/guides/automated-bootstrapping.mdx:jwt:74
|
docs/self-hosting/guides/automated-bootstrapping.mdx:jwt:74
|
||||||
frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretDetailSidebar.tsx:generic-api-key:72
|
frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretDetailSidebar.tsx:generic-api-key:72
|
||||||
|
k8-operator/config/samples/crd/pushsecret/source-secret-with-templating.yaml:private-key:11
|
||||||
|
k8-operator/config/samples/crd/pushsecret/push-secret-with-template.yaml:private-key:52
|
||||||
|
backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-types.ts:generic-api-key:125
|
||||||
|
frontend/src/components/permissions/AccessTree/nodes/RoleNode.tsx:generic-api-key:67
|
||||||
|
frontend/src/components/secret-rotations-v2/RotateSecretRotationV2Modal.tsx:generic-api-key:14
|
||||||
|
frontend/src/components/secret-rotations-v2/SecretRotationV2StatusBadge.tsx:generic-api-key:11
|
||||||
|
frontend/src/components/secret-rotations-v2/ViewSecretRotationV2GeneratedCredentials/ViewSecretRotationV2GeneratedCredentials.tsx:generic-api-key:23
|
||||||
|
frontend/src/hooks/api/secretRotationsV2/types/index.ts:generic-api-key:28
|
||||||
|
frontend/src/hooks/api/secretRotationsV2/types/index.ts:generic-api-key:65
|
||||||
|
frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretRotationListView/SecretRotationItem.tsx:generic-api-key:26
|
||||||
|
docs/documentation/platform/kms/overview.mdx:generic-api-key:281
|
||||||
|
docs/documentation/platform/kms/overview.mdx:generic-api-key:344
|
||||||
|
@@ -50,7 +50,7 @@ We're on a mission to make security tooling more accessible to everyone, not jus
|
|||||||
- **[Dashboard](https://infisical.com/docs/documentation/platform/project)**: Manage secrets across projects and environments (e.g. development, production, etc.) through a user-friendly interface.
|
- **[Dashboard](https://infisical.com/docs/documentation/platform/project)**: Manage secrets across projects and environments (e.g. development, production, etc.) through a user-friendly interface.
|
||||||
- **[Native Integrations](https://infisical.com/docs/integrations/overview)**: Sync secrets to platforms like [GitHub](https://infisical.com/docs/integrations/cicd/githubactions), [Vercel](https://infisical.com/docs/integrations/cloud/vercel), [AWS](https://infisical.com/docs/integrations/cloud/aws-secret-manager), and use tools like [Terraform](https://infisical.com/docs/integrations/frameworks/terraform), [Ansible](https://infisical.com/docs/integrations/platforms/ansible), and more.
|
- **[Native Integrations](https://infisical.com/docs/integrations/overview)**: Sync secrets to platforms like [GitHub](https://infisical.com/docs/integrations/cicd/githubactions), [Vercel](https://infisical.com/docs/integrations/cloud/vercel), [AWS](https://infisical.com/docs/integrations/cloud/aws-secret-manager), and use tools like [Terraform](https://infisical.com/docs/integrations/frameworks/terraform), [Ansible](https://infisical.com/docs/integrations/platforms/ansible), and more.
|
||||||
- **[Secret versioning](https://infisical.com/docs/documentation/platform/secret-versioning)** and **[Point-in-Time Recovery](https://infisical.com/docs/documentation/platform/pit-recovery)**: Keep track of every secret and project state; roll back when needed.
|
- **[Secret versioning](https://infisical.com/docs/documentation/platform/secret-versioning)** and **[Point-in-Time Recovery](https://infisical.com/docs/documentation/platform/pit-recovery)**: Keep track of every secret and project state; roll back when needed.
|
||||||
- **[Secret Rotation](https://infisical.com/docs/documentation/platform/secret-rotation/overview)**: Rotate secrets at regular intervals for services like [PostgreSQL](https://infisical.com/docs/documentation/platform/secret-rotation/postgres), [MySQL](https://infisical.com/docs/documentation/platform/secret-rotation/mysql), [AWS IAM](https://infisical.com/docs/documentation/platform/secret-rotation/aws-iam), and more.
|
- **[Secret Rotation](https://infisical.com/docs/documentation/platform/secret-rotation/overview)**: Rotate secrets at regular intervals for services like [PostgreSQL](https://infisical.com/docs/documentation/platform/secret-rotation/postgres-credentials), [MySQL](https://infisical.com/docs/documentation/platform/secret-rotation/mysql), [AWS IAM](https://infisical.com/docs/documentation/platform/secret-rotation/aws-iam), and more.
|
||||||
- **[Dynamic Secrets](https://infisical.com/docs/documentation/platform/dynamic-secrets/overview)**: Generate ephemeral secrets on-demand for services like [PostgreSQL](https://infisical.com/docs/documentation/platform/dynamic-secrets/postgresql), [MySQL](https://infisical.com/docs/documentation/platform/dynamic-secrets/mysql), [RabbitMQ](https://infisical.com/docs/documentation/platform/dynamic-secrets/rabbit-mq), and more.
|
- **[Dynamic Secrets](https://infisical.com/docs/documentation/platform/dynamic-secrets/overview)**: Generate ephemeral secrets on-demand for services like [PostgreSQL](https://infisical.com/docs/documentation/platform/dynamic-secrets/postgresql), [MySQL](https://infisical.com/docs/documentation/platform/dynamic-secrets/mysql), [RabbitMQ](https://infisical.com/docs/documentation/platform/dynamic-secrets/rabbit-mq), and more.
|
||||||
- **[Secret Scanning and Leak Prevention](https://infisical.com/docs/cli/scanning-overview)**: Prevent secrets from leaking to git.
|
- **[Secret Scanning and Leak Prevention](https://infisical.com/docs/cli/scanning-overview)**: Prevent secrets from leaking to git.
|
||||||
- **[Infisical Kubernetes Operator](https://infisical.com/docs/documentation/getting-started/kubernetes)**: Deliver secrets to your Kubernetes workloads and automatically reload deployments.
|
- **[Infisical Kubernetes Operator](https://infisical.com/docs/documentation/getting-started/kubernetes)**: Deliver secrets to your Kubernetes workloads and automatically reload deployments.
|
||||||
|
@@ -8,7 +8,8 @@ RUN apt-get update && apt-get install -y \
|
|||||||
python3 \
|
python3 \
|
||||||
make \
|
make \
|
||||||
g++ \
|
g++ \
|
||||||
openssh-client
|
openssh-client \
|
||||||
|
openssl
|
||||||
|
|
||||||
# Install dependencies for TDS driver (required for SAP ASE dynamic secrets)
|
# Install dependencies for TDS driver (required for SAP ASE dynamic secrets)
|
||||||
RUN apt-get install -y \
|
RUN apt-get install -y \
|
||||||
|
@@ -19,6 +19,7 @@ RUN apt-get update && apt-get install -y \
|
|||||||
make \
|
make \
|
||||||
g++ \
|
g++ \
|
||||||
openssh-client \
|
openssh-client \
|
||||||
|
openssl \
|
||||||
curl \
|
curl \
|
||||||
pkg-config
|
pkg-config
|
||||||
|
|
||||||
|
85
backend/Dockerfile.dev.fips
Normal file
85
backend/Dockerfile.dev.fips
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
FROM node:20-slim
|
||||||
|
|
||||||
|
# ? Setup a test SoftHSM module. In production a real HSM is used.
|
||||||
|
|
||||||
|
ARG SOFTHSM2_VERSION=2.5.0
|
||||||
|
|
||||||
|
ENV SOFTHSM2_VERSION=${SOFTHSM2_VERSION} \
|
||||||
|
SOFTHSM2_SOURCES=/tmp/softhsm2
|
||||||
|
|
||||||
|
# Install build dependencies including python3 (required for pkcs11js and partially TDS driver)
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
build-essential \
|
||||||
|
autoconf \
|
||||||
|
automake \
|
||||||
|
git \
|
||||||
|
libtool \
|
||||||
|
libssl-dev \
|
||||||
|
python3 \
|
||||||
|
make \
|
||||||
|
g++ \
|
||||||
|
openssh-client \
|
||||||
|
curl \
|
||||||
|
pkg-config \
|
||||||
|
perl \
|
||||||
|
wget
|
||||||
|
|
||||||
|
# Install dependencies for TDS driver (required for SAP ASE dynamic secrets)
|
||||||
|
RUN apt-get install -y \
|
||||||
|
unixodbc \
|
||||||
|
unixodbc-dev \
|
||||||
|
freetds-dev \
|
||||||
|
freetds-bin \
|
||||||
|
tdsodbc
|
||||||
|
|
||||||
|
RUN printf "[FreeTDS]\nDescription = FreeTDS Driver\nDriver = /usr/lib/x86_64-linux-gnu/odbc/libtdsodbc.so\nSetup = /usr/lib/x86_64-linux-gnu/odbc/libtdsodbc.so\nFileUsage = 1\n" > /etc/odbcinst.ini
|
||||||
|
|
||||||
|
# Build and install SoftHSM2
|
||||||
|
RUN git clone https://github.com/opendnssec/SoftHSMv2.git ${SOFTHSM2_SOURCES}
|
||||||
|
WORKDIR ${SOFTHSM2_SOURCES}
|
||||||
|
|
||||||
|
RUN git checkout ${SOFTHSM2_VERSION} -b ${SOFTHSM2_VERSION} \
|
||||||
|
&& sh autogen.sh \
|
||||||
|
&& ./configure --prefix=/usr/local --disable-gost \
|
||||||
|
&& make \
|
||||||
|
&& make install
|
||||||
|
|
||||||
|
WORKDIR /root
|
||||||
|
RUN rm -fr ${SOFTHSM2_SOURCES}
|
||||||
|
|
||||||
|
# Install pkcs11-tool
|
||||||
|
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
|
||||||
|
RUN wget https://www.openssl.org/source/openssl-3.1.2.tar.gz \
|
||||||
|
&& tar -xf openssl-3.1.2.tar.gz \
|
||||||
|
&& cd openssl-3.1.2 \
|
||||||
|
&& ./Configure enable-fips \
|
||||||
|
&& make \
|
||||||
|
&& make install_fips
|
||||||
|
|
||||||
|
# ? App setup
|
||||||
|
|
||||||
|
# Install Infisical CLI
|
||||||
|
RUN curl -1sLf 'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.deb.sh' | bash && \
|
||||||
|
apt-get update && \
|
||||||
|
apt-get install -y infisical=0.8.1
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package.json package.json
|
||||||
|
COPY package-lock.json package-lock.json
|
||||||
|
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
ENV HOST=0.0.0.0
|
||||||
|
ENV OPENSSL_CONF=/app/nodejs.cnf
|
||||||
|
ENV OPENSSL_MODULES=/usr/local/lib/ossl-modules
|
||||||
|
ENV NODE_OPTIONS=--force-fips
|
||||||
|
|
||||||
|
CMD ["npm", "run", "dev:docker"]
|
@@ -9,6 +9,7 @@ export const mockKeyStore = (): TKeyStoreFactory => {
|
|||||||
store[key] = value;
|
store[key] = value;
|
||||||
return "OK";
|
return "OK";
|
||||||
},
|
},
|
||||||
|
setExpiry: async () => 0,
|
||||||
setItemWithExpiry: async (key, value) => {
|
setItemWithExpiry: async (key, value) => {
|
||||||
store[key] = value;
|
store[key] = value;
|
||||||
return "OK";
|
return "OK";
|
||||||
|
@@ -11,6 +11,7 @@ export const mockQueue = (): TQueueServiceFactory => {
|
|||||||
job[name] = jobData;
|
job[name] = jobData;
|
||||||
},
|
},
|
||||||
queuePg: async () => {},
|
queuePg: async () => {},
|
||||||
|
schedulePg: async () => {},
|
||||||
initialize: async () => {},
|
initialize: async () => {},
|
||||||
shutdown: async () => undefined,
|
shutdown: async () => undefined,
|
||||||
stopRepeatableJob: async () => true,
|
stopRepeatableJob: async () => true,
|
||||||
|
16
backend/nodejs.cnf
Normal file
16
backend/nodejs.cnf
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
nodejs_conf = nodejs_init
|
||||||
|
|
||||||
|
.include /usr/local/ssl/fipsmodule.cnf
|
||||||
|
|
||||||
|
[nodejs_init]
|
||||||
|
providers = provider_sect
|
||||||
|
|
||||||
|
[provider_sect]
|
||||||
|
default = default_sect
|
||||||
|
fips = fips_sect
|
||||||
|
|
||||||
|
[default_sect]
|
||||||
|
activate = 1
|
||||||
|
|
||||||
|
[algorithm_sect]
|
||||||
|
default_properties = fips=yes
|
736
backend/package-lock.json
generated
736
backend/package-lock.json
generated
@@ -104,6 +104,7 @@
|
|||||||
"pkijs": "^3.2.4",
|
"pkijs": "^3.2.4",
|
||||||
"posthog-node": "^3.6.2",
|
"posthog-node": "^3.6.2",
|
||||||
"probot": "^13.3.8",
|
"probot": "^13.3.8",
|
||||||
|
"re2": "^1.21.4",
|
||||||
"safe-regex": "^2.1.1",
|
"safe-regex": "^2.1.1",
|
||||||
"scim-patch": "^0.8.3",
|
"scim-patch": "^0.8.3",
|
||||||
"scim2-parse-filter": "^0.2.10",
|
"scim2-parse-filter": "^0.2.10",
|
||||||
@@ -132,7 +133,7 @@
|
|||||||
"@types/jsrp": "^0.2.6",
|
"@types/jsrp": "^0.2.6",
|
||||||
"@types/libsodium-wrappers": "^0.7.13",
|
"@types/libsodium-wrappers": "^0.7.13",
|
||||||
"@types/lodash.isequal": "^4.5.8",
|
"@types/lodash.isequal": "^4.5.8",
|
||||||
"@types/node": "^20.9.5",
|
"@types/node": "^20.17.30",
|
||||||
"@types/nodemailer": "^6.4.14",
|
"@types/nodemailer": "^6.4.14",
|
||||||
"@types/passport-github": "^1.1.12",
|
"@types/passport-github": "^1.1.12",
|
||||||
"@types/passport-google-oauth20": "^2.0.14",
|
"@types/passport-google-oauth20": "^2.0.14",
|
||||||
@@ -6860,6 +6861,79 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@npmcli/agent": {
|
||||||
|
"version": "2.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz",
|
||||||
|
"integrity": "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"agent-base": "^7.1.0",
|
||||||
|
"http-proxy-agent": "^7.0.0",
|
||||||
|
"https-proxy-agent": "^7.0.1",
|
||||||
|
"lru-cache": "^10.0.1",
|
||||||
|
"socks-proxy-agent": "^8.0.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.14.0 || >=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@npmcli/agent/node_modules/agent-base": {
|
||||||
|
"version": "7.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz",
|
||||||
|
"integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@npmcli/agent/node_modules/debug": {
|
||||||
|
"version": "4.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
||||||
|
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "^2.1.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"supports-color": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@npmcli/agent/node_modules/https-proxy-agent": {
|
||||||
|
"version": "7.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
|
||||||
|
"integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"agent-base": "^7.1.2",
|
||||||
|
"debug": "4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@npmcli/agent/node_modules/lru-cache": {
|
||||||
|
"version": "10.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
|
||||||
|
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/@npmcli/fs": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"semver": "^7.3.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@octokit/auth-app": {
|
"node_modules/@octokit/auth-app": {
|
||||||
"version": "7.1.1",
|
"version": "7.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/auth-app/-/auth-app-7.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@octokit/auth-app/-/auth-app-7.1.1.tgz",
|
||||||
@@ -9753,11 +9827,12 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "20.9.5",
|
"version": "20.17.30",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.30.tgz",
|
||||||
"integrity": "sha512-Uq2xbNq0chGg+/WQEU0LJTSs/1nKxz6u1iemLcGomkSnKokbW1fbLqc3HOqCf2JP7KjlL4QkS7oZZTrOQHQYgQ==",
|
"integrity": "sha512-7zf4YyHA+jvBNfVrk2Gtvs6x7E8V+YDW05bNfG2XkWDJfYRXrTiP/DsB2zSYTaHX0bGIujTBQdMVAhb+j7mwpg==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~5.26.4"
|
"undici-types": "~6.19.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/node-fetch": {
|
"node_modules/@types/node-fetch": {
|
||||||
@@ -11862,6 +11937,115 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cacache": {
|
||||||
|
"version": "18.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.4.tgz",
|
||||||
|
"integrity": "sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@npmcli/fs": "^3.1.0",
|
||||||
|
"fs-minipass": "^3.0.0",
|
||||||
|
"glob": "^10.2.2",
|
||||||
|
"lru-cache": "^10.0.1",
|
||||||
|
"minipass": "^7.0.3",
|
||||||
|
"minipass-collect": "^2.0.1",
|
||||||
|
"minipass-flush": "^1.0.5",
|
||||||
|
"minipass-pipeline": "^1.2.4",
|
||||||
|
"p-map": "^4.0.0",
|
||||||
|
"ssri": "^10.0.0",
|
||||||
|
"tar": "^6.1.11",
|
||||||
|
"unique-filename": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.14.0 || >=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cacache/node_modules/brace-expansion": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"balanced-match": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cacache/node_modules/fs-minipass": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"minipass": "^7.0.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cacache/node_modules/glob": {
|
||||||
|
"version": "10.4.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
|
||||||
|
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"foreground-child": "^3.1.0",
|
||||||
|
"jackspeak": "^3.1.2",
|
||||||
|
"minimatch": "^9.0.4",
|
||||||
|
"minipass": "^7.1.2",
|
||||||
|
"package-json-from-dist": "^1.0.0",
|
||||||
|
"path-scurry": "^1.11.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"glob": "dist/esm/bin.mjs"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cacache/node_modules/jackspeak": {
|
||||||
|
"version": "3.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
|
||||||
|
"integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
|
||||||
|
"license": "BlueOak-1.0.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@isaacs/cliui": "^8.0.2"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@pkgjs/parseargs": "^0.11.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cacache/node_modules/lru-cache": {
|
||||||
|
"version": "10.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
|
||||||
|
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/cacache/node_modules/minimatch": {
|
||||||
|
"version": "9.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
||||||
|
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"brace-expansion": "^2.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16 || 14 >=14.17"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cacache/node_modules/minipass": {
|
||||||
|
"version": "7.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
|
||||||
|
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16 || 14 >=14.17"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/call-bind": {
|
"node_modules/call-bind": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
|
||||||
@@ -12841,6 +13025,16 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/encoding": {
|
||||||
|
"version": "0.1.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
|
||||||
|
"integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"iconv-lite": "^0.6.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/end-of-stream": {
|
"node_modules/end-of-stream": {
|
||||||
"version": "1.4.4",
|
"version": "1.4.4",
|
||||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
|
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
|
||||||
@@ -12873,6 +13067,21 @@
|
|||||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/env-paths": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
|
||||||
|
"integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/err-code": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/error-ex": {
|
"node_modules/error-ex": {
|
||||||
"version": "1.3.2",
|
"version": "1.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
|
||||||
@@ -13643,6 +13852,12 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/exponential-backoff": {
|
||||||
|
"version": "3.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.2.tgz",
|
||||||
|
"integrity": "sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==",
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
"node_modules/express": {
|
"node_modules/express": {
|
||||||
"version": "4.21.2",
|
"version": "4.21.2",
|
||||||
"resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
|
"resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
|
||||||
@@ -15220,6 +15435,12 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/http-cache-semantics": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
|
||||||
|
"integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==",
|
||||||
|
"license": "BSD-2-Clause"
|
||||||
|
},
|
||||||
"node_modules/http-errors": {
|
"node_modules/http-errors": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
|
||||||
@@ -15402,7 +15623,6 @@
|
|||||||
"version": "0.1.4",
|
"version": "0.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
|
||||||
"integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
|
"integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.19"
|
"node": ">=0.8.19"
|
||||||
}
|
}
|
||||||
@@ -15435,6 +15655,16 @@
|
|||||||
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
|
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/install-artifact-from-github": {
|
||||||
|
"version": "1.3.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/install-artifact-from-github/-/install-artifact-from-github-1.3.5.tgz",
|
||||||
|
"integrity": "sha512-gZHC7f/cJgXz7MXlHFBxPVMsvIbev1OQN1uKQYKVJDydGNm9oYf9JstbU4Atnh/eSvk41WtEovoRm+8IF686xg==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"bin": {
|
||||||
|
"install-from-cache": "bin/install-from-cache.js",
|
||||||
|
"save-to-github-cache": "bin/save-to-github-cache.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/internal-slot": {
|
"node_modules/internal-slot": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz",
|
||||||
@@ -15517,6 +15747,19 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||||
},
|
},
|
||||||
|
"node_modules/ip-address": {
|
||||||
|
"version": "9.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
|
||||||
|
"integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"jsbn": "1.1.0",
|
||||||
|
"sprintf-js": "^1.1.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ip-num": {
|
"node_modules/ip-num": {
|
||||||
"version": "1.5.1",
|
"version": "1.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/ip-num/-/ip-num-1.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/ip-num/-/ip-num-1.5.1.tgz",
|
||||||
@@ -15716,6 +15959,12 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-lambda": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/is-negative-zero": {
|
"node_modules/is-negative-zero": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
|
||||||
@@ -16859,6 +17108,38 @@
|
|||||||
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
|
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/make-fetch-happen": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@npmcli/agent": "^2.0.0",
|
||||||
|
"cacache": "^18.0.0",
|
||||||
|
"http-cache-semantics": "^4.1.1",
|
||||||
|
"is-lambda": "^1.0.1",
|
||||||
|
"minipass": "^7.0.2",
|
||||||
|
"minipass-fetch": "^3.0.0",
|
||||||
|
"minipass-flush": "^1.0.5",
|
||||||
|
"minipass-pipeline": "^1.2.4",
|
||||||
|
"negotiator": "^0.6.3",
|
||||||
|
"proc-log": "^4.2.0",
|
||||||
|
"promise-retry": "^2.0.1",
|
||||||
|
"ssri": "^10.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.14.0 || >=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/make-fetch-happen/node_modules/minipass": {
|
||||||
|
"version": "7.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
|
||||||
|
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16 || 14 >=14.17"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/math-intrinsics": {
|
"node_modules/math-intrinsics": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||||
@@ -17032,6 +17313,125 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/minipass-collect": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"minipass": "^7.0.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16 || 14 >=14.17"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/minipass-collect/node_modules/minipass": {
|
||||||
|
"version": "7.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
|
||||||
|
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16 || 14 >=14.17"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/minipass-fetch": {
|
||||||
|
"version": "3.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz",
|
||||||
|
"integrity": "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"minipass": "^7.0.3",
|
||||||
|
"minipass-sized": "^1.0.3",
|
||||||
|
"minizlib": "^2.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"encoding": "^0.1.13"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/minipass-fetch/node_modules/minipass": {
|
||||||
|
"version": "7.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
|
||||||
|
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16 || 14 >=14.17"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/minipass-flush": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"minipass": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/minipass-flush/node_modules/minipass": {
|
||||||
|
"version": "3.3.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
|
||||||
|
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"yallist": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/minipass-pipeline": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"minipass": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/minipass-pipeline/node_modules/minipass": {
|
||||||
|
"version": "3.3.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
|
||||||
|
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"yallist": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/minipass-sized": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"minipass": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/minipass-sized/node_modules/minipass": {
|
||||||
|
"version": "3.3.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
|
||||||
|
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"yallist": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/minizlib": {
|
"node_modules/minizlib": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
|
||||||
@@ -17353,6 +17753,12 @@
|
|||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/nan": {
|
||||||
|
"version": "2.22.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/nan/-/nan-2.22.2.tgz",
|
||||||
|
"integrity": "sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/nanoid": {
|
"node_modules/nanoid": {
|
||||||
"version": "3.3.8",
|
"version": "3.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
|
||||||
@@ -17443,6 +17849,30 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/node-gyp": {
|
||||||
|
"version": "10.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.3.1.tgz",
|
||||||
|
"integrity": "sha512-Pp3nFHBThHzVtNY7U6JfPjvT/DTE8+o/4xKsLQtBoU+j2HLsGlhcfzflAoUreaJbNmYnX+LlLi0qjV8kpyO6xQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"env-paths": "^2.2.0",
|
||||||
|
"exponential-backoff": "^3.1.1",
|
||||||
|
"glob": "^10.3.10",
|
||||||
|
"graceful-fs": "^4.2.6",
|
||||||
|
"make-fetch-happen": "^13.0.0",
|
||||||
|
"nopt": "^7.0.0",
|
||||||
|
"proc-log": "^4.1.0",
|
||||||
|
"semver": "^7.3.5",
|
||||||
|
"tar": "^6.2.1",
|
||||||
|
"which": "^4.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"node-gyp": "bin/node-gyp.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.14.0 || >=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/node-gyp-build": {
|
"node_modules/node-gyp-build": {
|
||||||
"version": "3.9.0",
|
"version": "3.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-3.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-3.9.0.tgz",
|
||||||
@@ -17464,6 +17894,122 @@
|
|||||||
"node-gyp-build-optional-packages-test": "build-test.js"
|
"node-gyp-build-optional-packages-test": "build-test.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/node-gyp/node_modules/abbrev": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/node-gyp/node_modules/brace-expansion": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"balanced-match": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/node-gyp/node_modules/glob": {
|
||||||
|
"version": "10.4.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
|
||||||
|
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"foreground-child": "^3.1.0",
|
||||||
|
"jackspeak": "^3.1.2",
|
||||||
|
"minimatch": "^9.0.4",
|
||||||
|
"minipass": "^7.1.2",
|
||||||
|
"package-json-from-dist": "^1.0.0",
|
||||||
|
"path-scurry": "^1.11.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"glob": "dist/esm/bin.mjs"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/node-gyp/node_modules/isexe": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/node-gyp/node_modules/jackspeak": {
|
||||||
|
"version": "3.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
|
||||||
|
"integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
|
||||||
|
"license": "BlueOak-1.0.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@isaacs/cliui": "^8.0.2"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@pkgjs/parseargs": "^0.11.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/node-gyp/node_modules/minimatch": {
|
||||||
|
"version": "9.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
||||||
|
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"brace-expansion": "^2.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16 || 14 >=14.17"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/node-gyp/node_modules/minipass": {
|
||||||
|
"version": "7.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
|
||||||
|
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16 || 14 >=14.17"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/node-gyp/node_modules/nopt": {
|
||||||
|
"version": "7.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz",
|
||||||
|
"integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"abbrev": "^2.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"nopt": "bin/nopt.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/node-gyp/node_modules/which": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"isexe": "^3.1.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"node-which": "bin/which.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.13.0 || >=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/node-releases": {
|
"node_modules/node-releases": {
|
||||||
"version": "2.0.14",
|
"version": "2.0.14",
|
||||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
|
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
|
||||||
@@ -18124,6 +18670,21 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/p-map": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"aggregate-error": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/p-queue": {
|
"node_modules/p-queue": {
|
||||||
"version": "6.6.2",
|
"version": "6.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz",
|
||||||
@@ -19201,6 +19762,15 @@
|
|||||||
"real-require": "^0.2.0"
|
"real-require": "^0.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/proc-log": {
|
||||||
|
"version": "4.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz",
|
||||||
|
"integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/process": {
|
"node_modules/process": {
|
||||||
"version": "0.11.10",
|
"version": "0.11.10",
|
||||||
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
|
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
|
||||||
@@ -19229,6 +19799,28 @@
|
|||||||
"node": ">=0.4.0"
|
"node": ">=0.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/promise-retry": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"err-code": "^2.0.2",
|
||||||
|
"retry": "^0.12.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/promise-retry/node_modules/retry": {
|
||||||
|
"version": "0.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
|
||||||
|
"integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/prompt-sync": {
|
"node_modules/prompt-sync": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/prompt-sync/-/prompt-sync-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/prompt-sync/-/prompt-sync-4.2.0.tgz",
|
||||||
@@ -19500,6 +20092,18 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/re2": {
|
||||||
|
"version": "1.21.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/re2/-/re2-1.21.4.tgz",
|
||||||
|
"integrity": "sha512-MVIfXWJmsP28mRsSt8HeL750ifb8H5+oF2UDIxGaiJCr8fkMqhLZ7kcX9ADRk2dC8qeGKedB7UVYRfBVpEiLfA==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"install-artifact-from-github": "^1.3.5",
|
||||||
|
"nan": "^2.20.0",
|
||||||
|
"node-gyp": "^10.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-is": {
|
"node_modules/react-is": {
|
||||||
"version": "18.2.0",
|
"version": "18.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
|
||||||
@@ -20081,11 +20685,6 @@
|
|||||||
"undici-types": "~6.19.2"
|
"undici-types": "~6.19.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/scim-patch/node_modules/undici-types": {
|
|
||||||
"version": "6.19.8",
|
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
|
|
||||||
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="
|
|
||||||
},
|
|
||||||
"node_modules/scim2-parse-filter": {
|
"node_modules/scim2-parse-filter": {
|
||||||
"version": "0.2.10",
|
"version": "0.2.10",
|
||||||
"resolved": "https://registry.npmjs.org/scim2-parse-filter/-/scim2-parse-filter-0.2.10.tgz",
|
"resolved": "https://registry.npmjs.org/scim2-parse-filter/-/scim2-parse-filter-0.2.10.tgz",
|
||||||
@@ -20426,6 +21025,16 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/smart-buffer": {
|
||||||
|
"version": "4.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
|
||||||
|
"integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6.0.0",
|
||||||
|
"npm": ">= 3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/smee-client": {
|
"node_modules/smee-client": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/smee-client/-/smee-client-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/smee-client/-/smee-client-2.0.0.tgz",
|
||||||
@@ -20629,6 +21238,60 @@
|
|||||||
"uuid": "dist/bin/uuid"
|
"uuid": "dist/bin/uuid"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/socks": {
|
||||||
|
"version": "2.8.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/socks/-/socks-2.8.4.tgz",
|
||||||
|
"integrity": "sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ip-address": "^9.0.5",
|
||||||
|
"smart-buffer": "^4.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0",
|
||||||
|
"npm": ">= 3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/socks-proxy-agent": {
|
||||||
|
"version": "8.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz",
|
||||||
|
"integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"agent-base": "^7.1.2",
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"socks": "^2.8.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/socks-proxy-agent/node_modules/agent-base": {
|
||||||
|
"version": "7.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz",
|
||||||
|
"integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/socks-proxy-agent/node_modules/debug": {
|
||||||
|
"version": "4.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
||||||
|
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "^2.1.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"supports-color": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/sonic-boom": {
|
"node_modules/sonic-boom": {
|
||||||
"version": "3.7.0",
|
"version": "3.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.7.0.tgz",
|
||||||
@@ -20684,6 +21347,27 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ssri": {
|
||||||
|
"version": "10.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz",
|
||||||
|
"integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"minipass": "^7.0.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ssri/node_modules/minipass": {
|
||||||
|
"version": "7.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
|
||||||
|
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16 || 14 >=14.17"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/stack-trace": {
|
"node_modules/stack-trace": {
|
||||||
"version": "0.0.10",
|
"version": "0.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
|
||||||
@@ -22442,9 +23126,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/undici-types": {
|
"node_modules/undici-types": {
|
||||||
"version": "5.26.5",
|
"version": "6.19.8",
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
|
||||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
|
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="
|
||||||
},
|
},
|
||||||
"node_modules/unicode-canonical-property-names-ecmascript": {
|
"node_modules/unicode-canonical-property-names-ecmascript": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
@@ -22486,6 +23170,30 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/unique-filename": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"unique-slug": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/unique-slug": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"imurmurhash": "^0.1.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/universal-github-app-jwt": {
|
"node_modules/universal-github-app-jwt": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/universal-github-app-jwt/-/universal-github-app-jwt-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/universal-github-app-jwt/-/universal-github-app-jwt-2.2.0.tgz",
|
||||||
|
@@ -89,7 +89,7 @@
|
|||||||
"@types/jsrp": "^0.2.6",
|
"@types/jsrp": "^0.2.6",
|
||||||
"@types/libsodium-wrappers": "^0.7.13",
|
"@types/libsodium-wrappers": "^0.7.13",
|
||||||
"@types/lodash.isequal": "^4.5.8",
|
"@types/lodash.isequal": "^4.5.8",
|
||||||
"@types/node": "^20.9.5",
|
"@types/node": "^20.17.30",
|
||||||
"@types/nodemailer": "^6.4.14",
|
"@types/nodemailer": "^6.4.14",
|
||||||
"@types/passport-github": "^1.1.12",
|
"@types/passport-github": "^1.1.12",
|
||||||
"@types/passport-google-oauth20": "^2.0.14",
|
"@types/passport-google-oauth20": "^2.0.14",
|
||||||
@@ -221,6 +221,7 @@
|
|||||||
"pkijs": "^3.2.4",
|
"pkijs": "^3.2.4",
|
||||||
"posthog-node": "^3.6.2",
|
"posthog-node": "^3.6.2",
|
||||||
"probot": "^13.3.8",
|
"probot": "^13.3.8",
|
||||||
|
"re2": "^1.21.4",
|
||||||
"safe-regex": "^2.1.1",
|
"safe-regex": "^2.1.1",
|
||||||
"scim-patch": "^0.8.3",
|
"scim-patch": "^0.8.3",
|
||||||
"scim2-parse-filter": "^0.2.10",
|
"scim2-parse-filter": "^0.2.10",
|
||||||
|
6
backend/src/@types/fastify.d.ts
vendored
6
backend/src/@types/fastify.d.ts
vendored
@@ -33,10 +33,12 @@ import { TScimServiceFactory } from "@app/ee/services/scim/scim-service";
|
|||||||
import { TSecretApprovalPolicyServiceFactory } from "@app/ee/services/secret-approval-policy/secret-approval-policy-service";
|
import { TSecretApprovalPolicyServiceFactory } from "@app/ee/services/secret-approval-policy/secret-approval-policy-service";
|
||||||
import { TSecretApprovalRequestServiceFactory } from "@app/ee/services/secret-approval-request/secret-approval-request-service";
|
import { TSecretApprovalRequestServiceFactory } from "@app/ee/services/secret-approval-request/secret-approval-request-service";
|
||||||
import { TSecretRotationServiceFactory } from "@app/ee/services/secret-rotation/secret-rotation-service";
|
import { TSecretRotationServiceFactory } from "@app/ee/services/secret-rotation/secret-rotation-service";
|
||||||
|
import { TSecretRotationV2ServiceFactory } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-service";
|
||||||
import { TSecretScanningServiceFactory } from "@app/ee/services/secret-scanning/secret-scanning-service";
|
import { TSecretScanningServiceFactory } from "@app/ee/services/secret-scanning/secret-scanning-service";
|
||||||
import { TSecretSnapshotServiceFactory } from "@app/ee/services/secret-snapshot/secret-snapshot-service";
|
import { TSecretSnapshotServiceFactory } from "@app/ee/services/secret-snapshot/secret-snapshot-service";
|
||||||
import { TSshCertificateAuthorityServiceFactory } from "@app/ee/services/ssh/ssh-certificate-authority-service";
|
import { TSshCertificateAuthorityServiceFactory } from "@app/ee/services/ssh/ssh-certificate-authority-service";
|
||||||
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 { TTrustedIpServiceFactory } from "@app/ee/services/trusted-ip/trusted-ip-service";
|
import { TTrustedIpServiceFactory } from "@app/ee/services/trusted-ip/trusted-ip-service";
|
||||||
import { TAuthMode } from "@app/server/plugins/auth/inject-identity";
|
import { TAuthMode } from "@app/server/plugins/auth/inject-identity";
|
||||||
import { TApiKeyServiceFactory } from "@app/services/api-key/api-key-service";
|
import { TApiKeyServiceFactory } from "@app/services/api-key/api-key-service";
|
||||||
@@ -134,7 +136,7 @@ declare module "fastify" {
|
|||||||
rateLimits: RateLimitConfiguration;
|
rateLimits: RateLimitConfiguration;
|
||||||
// passport data
|
// passport data
|
||||||
passportUser: {
|
passportUser: {
|
||||||
isUserCompleted: string;
|
isUserCompleted: boolean;
|
||||||
providerAuthToken: string;
|
providerAuthToken: string;
|
||||||
};
|
};
|
||||||
kmipUser: {
|
kmipUser: {
|
||||||
@@ -205,6 +207,7 @@ declare module "fastify" {
|
|||||||
certificateTemplate: TCertificateTemplateServiceFactory;
|
certificateTemplate: TCertificateTemplateServiceFactory;
|
||||||
sshCertificateAuthority: TSshCertificateAuthorityServiceFactory;
|
sshCertificateAuthority: TSshCertificateAuthorityServiceFactory;
|
||||||
sshCertificateTemplate: TSshCertificateTemplateServiceFactory;
|
sshCertificateTemplate: TSshCertificateTemplateServiceFactory;
|
||||||
|
sshHost: TSshHostServiceFactory;
|
||||||
certificateAuthority: TCertificateAuthorityServiceFactory;
|
certificateAuthority: TCertificateAuthorityServiceFactory;
|
||||||
certificateAuthorityCrl: TCertificateAuthorityCrlServiceFactory;
|
certificateAuthorityCrl: TCertificateAuthorityCrlServiceFactory;
|
||||||
certificateEst: TCertificateEstServiceFactory;
|
certificateEst: TCertificateEstServiceFactory;
|
||||||
@@ -237,6 +240,7 @@ declare module "fastify" {
|
|||||||
kmip: TKmipServiceFactory;
|
kmip: TKmipServiceFactory;
|
||||||
kmipOperation: TKmipOperationServiceFactory;
|
kmipOperation: TKmipOperationServiceFactory;
|
||||||
gateway: TGatewayServiceFactory;
|
gateway: TGatewayServiceFactory;
|
||||||
|
secretRotationV2: TSecretRotationV2ServiceFactory;
|
||||||
};
|
};
|
||||||
// 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
|
||||||
|
80
backend/src/@types/knex.d.ts
vendored
80
backend/src/@types/knex.d.ts
vendored
@@ -17,6 +17,9 @@ import {
|
|||||||
TApiKeys,
|
TApiKeys,
|
||||||
TApiKeysInsert,
|
TApiKeysInsert,
|
||||||
TApiKeysUpdate,
|
TApiKeysUpdate,
|
||||||
|
TAppConnections,
|
||||||
|
TAppConnectionsInsert,
|
||||||
|
TAppConnectionsUpdate,
|
||||||
TAuditLogs,
|
TAuditLogs,
|
||||||
TAuditLogsInsert,
|
TAuditLogsInsert,
|
||||||
TAuditLogStreams,
|
TAuditLogStreams,
|
||||||
@@ -65,6 +68,9 @@ import {
|
|||||||
TDynamicSecrets,
|
TDynamicSecrets,
|
||||||
TDynamicSecretsInsert,
|
TDynamicSecretsInsert,
|
||||||
TDynamicSecretsUpdate,
|
TDynamicSecretsUpdate,
|
||||||
|
TExternalGroupOrgRoleMappings,
|
||||||
|
TExternalGroupOrgRoleMappingsInsert,
|
||||||
|
TExternalGroupOrgRoleMappingsUpdate,
|
||||||
TExternalKms,
|
TExternalKms,
|
||||||
TExternalKmsInsert,
|
TExternalKmsInsert,
|
||||||
TExternalKmsUpdate,
|
TExternalKmsUpdate,
|
||||||
@@ -226,6 +232,9 @@ import {
|
|||||||
TProjectSplitBackfillIds,
|
TProjectSplitBackfillIds,
|
||||||
TProjectSplitBackfillIdsInsert,
|
TProjectSplitBackfillIdsInsert,
|
||||||
TProjectSplitBackfillIdsUpdate,
|
TProjectSplitBackfillIdsUpdate,
|
||||||
|
TProjectSshConfigs,
|
||||||
|
TProjectSshConfigsInsert,
|
||||||
|
TProjectSshConfigsUpdate,
|
||||||
TProjectsUpdate,
|
TProjectsUpdate,
|
||||||
TProjectTemplates,
|
TProjectTemplates,
|
||||||
TProjectTemplatesInsert,
|
TProjectTemplatesInsert,
|
||||||
@@ -299,6 +308,12 @@ import {
|
|||||||
TSecretRotations,
|
TSecretRotations,
|
||||||
TSecretRotationsInsert,
|
TSecretRotationsInsert,
|
||||||
TSecretRotationsUpdate,
|
TSecretRotationsUpdate,
|
||||||
|
TSecretRotationsV2,
|
||||||
|
TSecretRotationsV2Insert,
|
||||||
|
TSecretRotationsV2Update,
|
||||||
|
TSecretRotationV2SecretMappings,
|
||||||
|
TSecretRotationV2SecretMappingsInsert,
|
||||||
|
TSecretRotationV2SecretMappingsUpdate,
|
||||||
TSecrets,
|
TSecrets,
|
||||||
TSecretScanningGitRisks,
|
TSecretScanningGitRisks,
|
||||||
TSecretScanningGitRisksInsert,
|
TSecretScanningGitRisksInsert,
|
||||||
@@ -320,15 +335,27 @@ import {
|
|||||||
TSecretSnapshotsInsert,
|
TSecretSnapshotsInsert,
|
||||||
TSecretSnapshotsUpdate,
|
TSecretSnapshotsUpdate,
|
||||||
TSecretsUpdate,
|
TSecretsUpdate,
|
||||||
|
TSecretsV2,
|
||||||
|
TSecretsV2Insert,
|
||||||
|
TSecretsV2Update,
|
||||||
|
TSecretSyncs,
|
||||||
|
TSecretSyncsInsert,
|
||||||
|
TSecretSyncsUpdate,
|
||||||
TSecretTagJunction,
|
TSecretTagJunction,
|
||||||
TSecretTagJunctionInsert,
|
TSecretTagJunctionInsert,
|
||||||
TSecretTagJunctionUpdate,
|
TSecretTagJunctionUpdate,
|
||||||
TSecretTags,
|
TSecretTags,
|
||||||
TSecretTagsInsert,
|
TSecretTagsInsert,
|
||||||
TSecretTagsUpdate,
|
TSecretTagsUpdate,
|
||||||
|
TSecretV2TagJunction,
|
||||||
|
TSecretV2TagJunctionInsert,
|
||||||
|
TSecretV2TagJunctionUpdate,
|
||||||
TSecretVersions,
|
TSecretVersions,
|
||||||
TSecretVersionsInsert,
|
TSecretVersionsInsert,
|
||||||
TSecretVersionsUpdate,
|
TSecretVersionsUpdate,
|
||||||
|
TSecretVersionsV2,
|
||||||
|
TSecretVersionsV2Insert,
|
||||||
|
TSecretVersionsV2Update,
|
||||||
TSecretVersionTagJunction,
|
TSecretVersionTagJunction,
|
||||||
TSecretVersionTagJunctionInsert,
|
TSecretVersionTagJunctionInsert,
|
||||||
TSecretVersionTagJunctionUpdate,
|
TSecretVersionTagJunctionUpdate,
|
||||||
@@ -356,6 +383,15 @@ import {
|
|||||||
TSshCertificateTemplates,
|
TSshCertificateTemplates,
|
||||||
TSshCertificateTemplatesInsert,
|
TSshCertificateTemplatesInsert,
|
||||||
TSshCertificateTemplatesUpdate,
|
TSshCertificateTemplatesUpdate,
|
||||||
|
TSshHostLoginUserMappings,
|
||||||
|
TSshHostLoginUserMappingsInsert,
|
||||||
|
TSshHostLoginUserMappingsUpdate,
|
||||||
|
TSshHostLoginUsers,
|
||||||
|
TSshHostLoginUsersInsert,
|
||||||
|
TSshHostLoginUsersUpdate,
|
||||||
|
TSshHosts,
|
||||||
|
TSshHostsInsert,
|
||||||
|
TSshHostsUpdate,
|
||||||
TSuperAdmin,
|
TSuperAdmin,
|
||||||
TSuperAdminInsert,
|
TSuperAdminInsert,
|
||||||
TSuperAdminUpdate,
|
TSuperAdminUpdate,
|
||||||
@@ -387,24 +423,6 @@ import {
|
|||||||
TWorkflowIntegrationsInsert,
|
TWorkflowIntegrationsInsert,
|
||||||
TWorkflowIntegrationsUpdate
|
TWorkflowIntegrationsUpdate
|
||||||
} from "@app/db/schemas";
|
} from "@app/db/schemas";
|
||||||
import { TAppConnections, TAppConnectionsInsert, TAppConnectionsUpdate } from "@app/db/schemas/app-connections";
|
|
||||||
import {
|
|
||||||
TExternalGroupOrgRoleMappings,
|
|
||||||
TExternalGroupOrgRoleMappingsInsert,
|
|
||||||
TExternalGroupOrgRoleMappingsUpdate
|
|
||||||
} from "@app/db/schemas/external-group-org-role-mappings";
|
|
||||||
import { TSecretSyncs, TSecretSyncsInsert, TSecretSyncsUpdate } from "@app/db/schemas/secret-syncs";
|
|
||||||
import {
|
|
||||||
TSecretV2TagJunction,
|
|
||||||
TSecretV2TagJunctionInsert,
|
|
||||||
TSecretV2TagJunctionUpdate
|
|
||||||
} from "@app/db/schemas/secret-v2-tag-junction";
|
|
||||||
import {
|
|
||||||
TSecretVersionsV2,
|
|
||||||
TSecretVersionsV2Insert,
|
|
||||||
TSecretVersionsV2Update
|
|
||||||
} from "@app/db/schemas/secret-versions-v2";
|
|
||||||
import { TSecretsV2, TSecretsV2Insert, TSecretsV2Update } from "@app/db/schemas/secrets-v2";
|
|
||||||
|
|
||||||
declare module "knex" {
|
declare module "knex" {
|
||||||
namespace Knex {
|
namespace Knex {
|
||||||
@@ -419,6 +437,7 @@ declare module "knex/types/tables" {
|
|||||||
interface Tables {
|
interface Tables {
|
||||||
[TableName.Users]: KnexOriginal.CompositeTableType<TUsers, TUsersInsert, TUsersUpdate>;
|
[TableName.Users]: KnexOriginal.CompositeTableType<TUsers, TUsersInsert, TUsersUpdate>;
|
||||||
[TableName.Groups]: KnexOriginal.CompositeTableType<TGroups, TGroupsInsert, TGroupsUpdate>;
|
[TableName.Groups]: KnexOriginal.CompositeTableType<TGroups, TGroupsInsert, TGroupsUpdate>;
|
||||||
|
[TableName.SshHost]: KnexOriginal.CompositeTableType<TSshHosts, TSshHostsInsert, TSshHostsUpdate>;
|
||||||
[TableName.SshCertificateAuthority]: KnexOriginal.CompositeTableType<
|
[TableName.SshCertificateAuthority]: KnexOriginal.CompositeTableType<
|
||||||
TSshCertificateAuthorities,
|
TSshCertificateAuthorities,
|
||||||
TSshCertificateAuthoritiesInsert,
|
TSshCertificateAuthoritiesInsert,
|
||||||
@@ -444,6 +463,16 @@ declare module "knex/types/tables" {
|
|||||||
TSshCertificateBodiesInsert,
|
TSshCertificateBodiesInsert,
|
||||||
TSshCertificateBodiesUpdate
|
TSshCertificateBodiesUpdate
|
||||||
>;
|
>;
|
||||||
|
[TableName.SshHostLoginUser]: KnexOriginal.CompositeTableType<
|
||||||
|
TSshHostLoginUsers,
|
||||||
|
TSshHostLoginUsersInsert,
|
||||||
|
TSshHostLoginUsersUpdate
|
||||||
|
>;
|
||||||
|
[TableName.SshHostLoginUserMapping]: KnexOriginal.CompositeTableType<
|
||||||
|
TSshHostLoginUserMappings,
|
||||||
|
TSshHostLoginUserMappingsInsert,
|
||||||
|
TSshHostLoginUserMappingsUpdate
|
||||||
|
>;
|
||||||
[TableName.CertificateAuthority]: KnexOriginal.CompositeTableType<
|
[TableName.CertificateAuthority]: KnexOriginal.CompositeTableType<
|
||||||
TCertificateAuthorities,
|
TCertificateAuthorities,
|
||||||
TCertificateAuthoritiesInsert,
|
TCertificateAuthoritiesInsert,
|
||||||
@@ -548,6 +577,11 @@ declare module "knex/types/tables" {
|
|||||||
[TableName.SuperAdmin]: KnexOriginal.CompositeTableType<TSuperAdmin, TSuperAdminInsert, TSuperAdminUpdate>;
|
[TableName.SuperAdmin]: KnexOriginal.CompositeTableType<TSuperAdmin, TSuperAdminInsert, TSuperAdminUpdate>;
|
||||||
[TableName.ApiKey]: KnexOriginal.CompositeTableType<TApiKeys, TApiKeysInsert, TApiKeysUpdate>;
|
[TableName.ApiKey]: KnexOriginal.CompositeTableType<TApiKeys, TApiKeysInsert, TApiKeysUpdate>;
|
||||||
[TableName.Project]: KnexOriginal.CompositeTableType<TProjects, TProjectsInsert, TProjectsUpdate>;
|
[TableName.Project]: KnexOriginal.CompositeTableType<TProjects, TProjectsInsert, TProjectsUpdate>;
|
||||||
|
[TableName.ProjectSshConfig]: KnexOriginal.CompositeTableType<
|
||||||
|
TProjectSshConfigs,
|
||||||
|
TProjectSshConfigsInsert,
|
||||||
|
TProjectSshConfigsUpdate
|
||||||
|
>;
|
||||||
[TableName.ProjectMembership]: KnexOriginal.CompositeTableType<
|
[TableName.ProjectMembership]: KnexOriginal.CompositeTableType<
|
||||||
TProjectMemberships,
|
TProjectMemberships,
|
||||||
TProjectMembershipsInsert,
|
TProjectMembershipsInsert,
|
||||||
@@ -950,5 +984,15 @@ declare module "knex/types/tables" {
|
|||||||
TOrgGatewayConfigInsert,
|
TOrgGatewayConfigInsert,
|
||||||
TOrgGatewayConfigUpdate
|
TOrgGatewayConfigUpdate
|
||||||
>;
|
>;
|
||||||
|
[TableName.SecretRotationV2]: KnexOriginal.CompositeTableType<
|
||||||
|
TSecretRotationsV2,
|
||||||
|
TSecretRotationsV2Insert,
|
||||||
|
TSecretRotationsV2Update
|
||||||
|
>;
|
||||||
|
[TableName.SecretRotationV2SecretMapping]: KnexOriginal.CompositeTableType<
|
||||||
|
TSecretRotationV2SecretMappings,
|
||||||
|
TSecretRotationV2SecretMappingsInsert,
|
||||||
|
TSecretRotationV2SecretMappingsUpdate
|
||||||
|
>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { TableName } from "../schemas";
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
export async function up(knex: Knex): Promise<void> {
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
@@ -0,0 +1,19 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "@app/db/schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasColumn(TableName.AppConnection, "isPlatformManagedCredentials"))) {
|
||||||
|
await knex.schema.alterTable(TableName.AppConnection, (t) => {
|
||||||
|
t.boolean("isPlatformManagedCredentials").defaultTo(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
if (await knex.schema.hasColumn(TableName.AppConnection, "isPlatformManagedCredentials")) {
|
||||||
|
await knex.schema.alterTable(TableName.AppConnection, (t) => {
|
||||||
|
t.dropColumn("isPlatformManagedCredentials");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,58 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "@app/db/schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "@app/db/utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.SecretRotationV2))) {
|
||||||
|
await knex.schema.createTable(TableName.SecretRotationV2, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.string("name", 32).notNullable();
|
||||||
|
t.string("description");
|
||||||
|
t.string("type").notNullable();
|
||||||
|
t.jsonb("parameters").notNullable();
|
||||||
|
t.jsonb("secretsMapping").notNullable();
|
||||||
|
t.binary("encryptedGeneratedCredentials").notNullable();
|
||||||
|
t.boolean("isAutoRotationEnabled").notNullable().defaultTo(true);
|
||||||
|
t.integer("activeIndex").notNullable().defaultTo(0);
|
||||||
|
t.uuid("folderId").notNullable();
|
||||||
|
t.foreign("folderId").references("id").inTable(TableName.SecretFolder).onDelete("CASCADE");
|
||||||
|
t.uuid("connectionId").notNullable();
|
||||||
|
t.foreign("connectionId").references("id").inTable(TableName.AppConnection);
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.integer("rotationInterval").notNullable();
|
||||||
|
t.jsonb("rotateAtUtc").notNullable(); // { hours: number; minutes: number }
|
||||||
|
t.string("rotationStatus").notNullable();
|
||||||
|
t.datetime("lastRotationAttemptedAt").notNullable();
|
||||||
|
t.datetime("lastRotatedAt").notNullable();
|
||||||
|
t.binary("encryptedLastRotationMessage"); // we encrypt this because it may contain sensitive info (SQL errors showing credentials)
|
||||||
|
t.string("lastRotationJobId");
|
||||||
|
t.datetime("nextRotationAt");
|
||||||
|
t.boolean("isLastRotationManual").notNullable().defaultTo(true); // creation is considered a "manual" rotation
|
||||||
|
});
|
||||||
|
|
||||||
|
await createOnUpdateTrigger(knex, TableName.SecretRotationV2);
|
||||||
|
|
||||||
|
await knex.schema.alterTable(TableName.SecretRotationV2, (t) => {
|
||||||
|
t.unique(["folderId", "name"]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(await knex.schema.hasTable(TableName.SecretRotationV2SecretMapping))) {
|
||||||
|
await knex.schema.createTable(TableName.SecretRotationV2SecretMapping, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.uuid("secretId").notNullable();
|
||||||
|
// scott: this is deferred to block secret deletion but not prevent folder/environment/project deletion
|
||||||
|
// ie, if rotation is being deleted as well we permit it, otherwise throw
|
||||||
|
t.foreign("secretId").references("id").inTable(TableName.SecretV2).deferrable("deferred");
|
||||||
|
t.uuid("rotationId").notNullable();
|
||||||
|
t.foreign("rotationId").references("id").inTable(TableName.SecretRotationV2).onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.SecretRotationV2SecretMapping);
|
||||||
|
await knex.schema.dropTableIfExists(TableName.SecretRotationV2);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.SecretRotationV2);
|
||||||
|
}
|
@@ -0,0 +1,21 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
const hasCol = await knex.schema.hasColumn(TableName.SecretFolder, "lastSecretModified");
|
||||||
|
if (!hasCol) {
|
||||||
|
await knex.schema.alterTable(TableName.SecretFolder, (t) => {
|
||||||
|
t.datetime("lastSecretModified");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
const hasCol = await knex.schema.hasColumn(TableName.SecretFolder, "lastSecretModified");
|
||||||
|
if (hasCol) {
|
||||||
|
await knex.schema.alterTable(TableName.SecretFolder, (t) => {
|
||||||
|
t.dropColumn("lastSecretModified");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,25 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { KmsKeyUsage } from "@app/services/kms/kms-types";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
const hasKeyUsageColumn = await knex.schema.hasColumn(TableName.KmsKey, "keyUsage");
|
||||||
|
|
||||||
|
if (!hasKeyUsageColumn) {
|
||||||
|
await knex.schema.alterTable(TableName.KmsKey, (t) => {
|
||||||
|
t.string("keyUsage").notNullable().defaultTo(KmsKeyUsage.ENCRYPT_DECRYPT);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
const hasKeyUsageColumn = await knex.schema.hasColumn(TableName.KmsKey, "keyUsage");
|
||||||
|
|
||||||
|
if (hasKeyUsageColumn) {
|
||||||
|
await knex.schema.alterTable(TableName.KmsKey, (t) => {
|
||||||
|
t.dropColumn("keyUsage");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,32 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasColumn(TableName.SshCertificateAuthority, "keySource"))) {
|
||||||
|
await knex.schema.alterTable(TableName.SshCertificateAuthority, (t) => {
|
||||||
|
t.string("keySource");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Backfilling the keySource to internal
|
||||||
|
await knex(TableName.SshCertificateAuthority).update({ keySource: "internal" });
|
||||||
|
|
||||||
|
await knex.schema.alterTable(TableName.SshCertificateAuthority, (t) => {
|
||||||
|
t.string("keySource").notNullable().alter();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (await knex.schema.hasColumn(TableName.SshCertificate, "sshCaId")) {
|
||||||
|
await knex.schema.alterTable(TableName.SshCertificate, (t) => {
|
||||||
|
t.uuid("sshCaId").nullable().alter();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
if (await knex.schema.hasColumn(TableName.SshCertificateAuthority, "keySource")) {
|
||||||
|
await knex.schema.alterTable(TableName.SshCertificateAuthority, (t) => {
|
||||||
|
t.dropColumn("keySource");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
93
backend/src/db/migrations/20250405185753_ssh-mgmt-v2.ts
Normal file
93
backend/src/db/migrations/20250405185753_ssh-mgmt-v2.ts
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
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.SshHost))) {
|
||||||
|
await knex.schema.createTable(TableName.SshHost, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.string("projectId").notNullable();
|
||||||
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
|
t.string("hostname").notNullable();
|
||||||
|
t.string("userCertTtl").notNullable();
|
||||||
|
t.string("hostCertTtl").notNullable();
|
||||||
|
t.uuid("userSshCaId").notNullable();
|
||||||
|
t.foreign("userSshCaId").references("id").inTable(TableName.SshCertificateAuthority).onDelete("CASCADE");
|
||||||
|
t.uuid("hostSshCaId").notNullable();
|
||||||
|
t.foreign("hostSshCaId").references("id").inTable(TableName.SshCertificateAuthority).onDelete("CASCADE");
|
||||||
|
t.unique(["projectId", "hostname"]);
|
||||||
|
});
|
||||||
|
await createOnUpdateTrigger(knex, TableName.SshHost);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(await knex.schema.hasTable(TableName.SshHostLoginUser))) {
|
||||||
|
await knex.schema.createTable(TableName.SshHostLoginUser, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.uuid("sshHostId").notNullable();
|
||||||
|
t.foreign("sshHostId").references("id").inTable(TableName.SshHost).onDelete("CASCADE");
|
||||||
|
t.string("loginUser").notNullable(); // e.g. ubuntu, root, ec2-user, ...
|
||||||
|
t.unique(["sshHostId", "loginUser"]);
|
||||||
|
});
|
||||||
|
await createOnUpdateTrigger(knex, TableName.SshHostLoginUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(await knex.schema.hasTable(TableName.SshHostLoginUserMapping))) {
|
||||||
|
await knex.schema.createTable(TableName.SshHostLoginUserMapping, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.uuid("sshHostLoginUserId").notNullable();
|
||||||
|
t.foreign("sshHostLoginUserId").references("id").inTable(TableName.SshHostLoginUser).onDelete("CASCADE");
|
||||||
|
t.uuid("userId").nullable();
|
||||||
|
t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE");
|
||||||
|
t.unique(["sshHostLoginUserId", "userId"]);
|
||||||
|
});
|
||||||
|
await createOnUpdateTrigger(knex, TableName.SshHostLoginUserMapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(await knex.schema.hasTable(TableName.ProjectSshConfig))) {
|
||||||
|
// new table to store configuration for projects of type SSH (i.e. Infisical SSH)
|
||||||
|
await knex.schema.createTable(TableName.ProjectSshConfig, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.string("projectId").notNullable();
|
||||||
|
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||||
|
t.uuid("defaultUserSshCaId");
|
||||||
|
t.foreign("defaultUserSshCaId").references("id").inTable(TableName.SshCertificateAuthority).onDelete("CASCADE");
|
||||||
|
t.uuid("defaultHostSshCaId");
|
||||||
|
t.foreign("defaultHostSshCaId").references("id").inTable(TableName.SshCertificateAuthority).onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
await createOnUpdateTrigger(knex, TableName.ProjectSshConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasColumn = await knex.schema.hasColumn(TableName.SshCertificate, "sshHostId");
|
||||||
|
if (!hasColumn) {
|
||||||
|
await knex.schema.alterTable(TableName.SshCertificate, (t) => {
|
||||||
|
t.uuid("sshHostId").nullable();
|
||||||
|
t.foreign("sshHostId").references("id").inTable(TableName.SshHost).onDelete("SET NULL");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.ProjectSshConfig);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.ProjectSshConfig);
|
||||||
|
|
||||||
|
await knex.schema.dropTableIfExists(TableName.SshHostLoginUserMapping);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.SshHostLoginUserMapping);
|
||||||
|
|
||||||
|
await knex.schema.dropTableIfExists(TableName.SshHostLoginUser);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.SshHostLoginUser);
|
||||||
|
|
||||||
|
const hasColumn = await knex.schema.hasColumn(TableName.SshCertificate, "sshHostId");
|
||||||
|
if (hasColumn) {
|
||||||
|
await knex.schema.alterTable(TableName.SshCertificate, (t) => {
|
||||||
|
t.dropColumn("sshHostId");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await knex.schema.dropTableIfExists(TableName.SshHost);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.SshHost);
|
||||||
|
}
|
@@ -0,0 +1,20 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasColumn(TableName.ResourceMetadata, "dynamicSecretId"))) {
|
||||||
|
await knex.schema.alterTable(TableName.ResourceMetadata, (tb) => {
|
||||||
|
tb.uuid("dynamicSecretId");
|
||||||
|
tb.foreign("dynamicSecretId").references("id").inTable(TableName.DynamicSecret).onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
if (await knex.schema.hasColumn(TableName.ResourceMetadata, "dynamicSecretId")) {
|
||||||
|
await knex.schema.alterTable(TableName.ResourceMetadata, (tb) => {
|
||||||
|
tb.dropColumn("dynamicSecretId");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,21 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
const hasCol = await knex.schema.hasColumn(TableName.AccessApprovalRequest, "note");
|
||||||
|
if (!hasCol) {
|
||||||
|
await knex.schema.alterTable(TableName.AccessApprovalRequest, (t) => {
|
||||||
|
t.string("note").nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
const hasCol = await knex.schema.hasColumn(TableName.AccessApprovalRequest, "note");
|
||||||
|
if (hasCol) {
|
||||||
|
await knex.schema.alterTable(TableName.AccessApprovalRequest, (t) => {
|
||||||
|
t.dropColumn("note");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,27 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
const hasCol = await knex.schema.hasColumn(TableName.ServiceToken, "expiryNotificationSent");
|
||||||
|
if (!hasCol) {
|
||||||
|
await knex.schema.alterTable(TableName.ServiceToken, (t) => {
|
||||||
|
t.boolean("expiryNotificationSent").defaultTo(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update only tokens where expiresAt is before current time
|
||||||
|
await knex(TableName.ServiceToken)
|
||||||
|
.whereRaw(`${TableName.ServiceToken}."expiresAt" < NOW()`)
|
||||||
|
.whereNotNull("expiresAt")
|
||||||
|
.update({ expiryNotificationSent: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
const hasCol = await knex.schema.hasColumn(TableName.ServiceToken, "expiryNotificationSent");
|
||||||
|
if (hasCol) {
|
||||||
|
await knex.schema.alterTable(TableName.ServiceToken, (t) => {
|
||||||
|
t.dropColumn("expiryNotificationSent");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,21 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
const hasCol = await knex.schema.hasColumn(TableName.Project, "hasDeleteProtection");
|
||||||
|
if (!hasCol) {
|
||||||
|
await knex.schema.alterTable(TableName.Project, (t) => {
|
||||||
|
t.boolean("hasDeleteProtection").defaultTo(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
const hasCol = await knex.schema.hasColumn(TableName.Project, "hasDeleteProtection");
|
||||||
|
if (hasCol) {
|
||||||
|
await knex.schema.alterTable(TableName.Project, (t) => {
|
||||||
|
t.dropColumn("hasDeleteProtection");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,15 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.alterTable(TableName.Certificate, (t) => {
|
||||||
|
t.string("altNames", 4096).alter();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.alterTable(TableName.Certificate, (t) => {
|
||||||
|
t.string("altNames").alter(); // Defaults to varchar(255)
|
||||||
|
});
|
||||||
|
}
|
@@ -0,0 +1,15 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.alterTable(TableName.KmipOrgServerCertificates, (t) => {
|
||||||
|
t.string("altNames", 4096).alter();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.alterTable(TableName.KmipOrgServerCertificates, (t) => {
|
||||||
|
t.string("altNames").alter(); // Defaults to varchar(255)
|
||||||
|
});
|
||||||
|
}
|
@@ -0,0 +1,21 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { OIDCJWTSignatureAlgorithm } from "@app/ee/services/oidc/oidc-config-types";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasColumn(TableName.OidcConfig, "jwtSignatureAlgorithm"))) {
|
||||||
|
await knex.schema.alterTable(TableName.OidcConfig, (t) => {
|
||||||
|
t.string("jwtSignatureAlgorithm").defaultTo(OIDCJWTSignatureAlgorithm.RS256).notNullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
if (await knex.schema.hasColumn(TableName.OidcConfig, "jwtSignatureAlgorithm")) {
|
||||||
|
await knex.schema.alterTable(TableName.OidcConfig, (t) => {
|
||||||
|
t.dropColumn("jwtSignatureAlgorithm");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -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.Organization, "bypassOrgAuthEnabled"))) {
|
||||||
|
await knex.schema.alterTable(TableName.Organization, (t) => {
|
||||||
|
t.boolean("bypassOrgAuthEnabled").defaultTo(false).notNullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
if (await knex.schema.hasColumn(TableName.Organization, "bypassOrgAuthEnabled")) {
|
||||||
|
await knex.schema.alterTable(TableName.Organization, (t) => {
|
||||||
|
t.dropColumn("bypassOrgAuthEnabled");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,29 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "@app/db/schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.alterTable(TableName.SecretVersionV2, (table) => {
|
||||||
|
table.dropForeign(["userActorId"]);
|
||||||
|
table.dropForeign(["identityActorId"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
await knex.schema.alterTable(TableName.SecretVersionV2, (table) => {
|
||||||
|
table.foreign("userActorId").references("id").inTable(TableName.Users).onDelete("SET NULL");
|
||||||
|
|
||||||
|
table.foreign("identityActorId").references("id").inTable(TableName.Identity).onDelete("SET NULL");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.alterTable(TableName.SecretVersionV2, (table) => {
|
||||||
|
table.dropForeign(["userActorId"]);
|
||||||
|
table.dropForeign(["identityActorId"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
await knex.schema.alterTable(TableName.SecretVersionV2, (table) => {
|
||||||
|
table.foreign("userActorId").references("id").inTable(TableName.Users);
|
||||||
|
|
||||||
|
table.foreign("identityActorId").references("id").inTable(TableName.Identity);
|
||||||
|
});
|
||||||
|
}
|
@@ -17,7 +17,8 @@ export const AccessApprovalRequestsSchema = z.object({
|
|||||||
permissions: z.unknown(),
|
permissions: z.unknown(),
|
||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
requestedByUserId: z.string().uuid()
|
requestedByUserId: z.string().uuid(),
|
||||||
|
note: z.string().nullable().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TAccessApprovalRequests = z.infer<typeof AccessApprovalRequestsSchema>;
|
export type TAccessApprovalRequests = z.infer<typeof AccessApprovalRequestsSchema>;
|
||||||
|
@@ -19,7 +19,8 @@ export const AppConnectionsSchema = z.object({
|
|||||||
version: z.number().default(1),
|
version: z.number().default(1),
|
||||||
orgId: z.string().uuid(),
|
orgId: z.string().uuid(),
|
||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date()
|
updatedAt: z.date(),
|
||||||
|
isPlatformManagedCredentials: z.boolean().default(false).nullable().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TAppConnections = z.infer<typeof AppConnectionsSchema>;
|
export type TAppConnections = z.infer<typeof AppConnectionsSchema>;
|
||||||
|
@@ -3,6 +3,7 @@ export * from "./access-approval-policies-approvers";
|
|||||||
export * from "./access-approval-requests";
|
export * from "./access-approval-requests";
|
||||||
export * from "./access-approval-requests-reviewers";
|
export * from "./access-approval-requests-reviewers";
|
||||||
export * from "./api-keys";
|
export * from "./api-keys";
|
||||||
|
export * from "./app-connections";
|
||||||
export * from "./audit-log-streams";
|
export * from "./audit-log-streams";
|
||||||
export * from "./audit-logs";
|
export * from "./audit-logs";
|
||||||
export * from "./auth-token-sessions";
|
export * from "./auth-token-sessions";
|
||||||
@@ -19,6 +20,7 @@ export * from "./certificate-templates";
|
|||||||
export * from "./certificates";
|
export * from "./certificates";
|
||||||
export * from "./dynamic-secret-leases";
|
export * from "./dynamic-secret-leases";
|
||||||
export * from "./dynamic-secrets";
|
export * from "./dynamic-secrets";
|
||||||
|
export * from "./external-group-org-role-mappings";
|
||||||
export * from "./external-kms";
|
export * from "./external-kms";
|
||||||
export * from "./gateways";
|
export * from "./gateways";
|
||||||
export * from "./git-app-install-sessions";
|
export * from "./git-app-install-sessions";
|
||||||
@@ -73,6 +75,7 @@ export * from "./project-memberships";
|
|||||||
export * from "./project-roles";
|
export * from "./project-roles";
|
||||||
export * from "./project-slack-configs";
|
export * from "./project-slack-configs";
|
||||||
export * from "./project-split-backfill-ids";
|
export * from "./project-split-backfill-ids";
|
||||||
|
export * from "./project-ssh-configs";
|
||||||
export * from "./project-templates";
|
export * from "./project-templates";
|
||||||
export * from "./project-user-additional-privilege";
|
export * from "./project-user-additional-privilege";
|
||||||
export * from "./project-user-membership-roles";
|
export * from "./project-user-membership-roles";
|
||||||
@@ -97,13 +100,16 @@ export * from "./secret-references";
|
|||||||
export * from "./secret-references-v2";
|
export * from "./secret-references-v2";
|
||||||
export * from "./secret-rotation-output-v2";
|
export * from "./secret-rotation-output-v2";
|
||||||
export * from "./secret-rotation-outputs";
|
export * from "./secret-rotation-outputs";
|
||||||
|
export * from "./secret-rotation-v2-secret-mappings";
|
||||||
export * from "./secret-rotations";
|
export * from "./secret-rotations";
|
||||||
|
export * from "./secret-rotations-v2";
|
||||||
export * from "./secret-scanning-git-risks";
|
export * from "./secret-scanning-git-risks";
|
||||||
export * from "./secret-sharing";
|
export * from "./secret-sharing";
|
||||||
export * from "./secret-snapshot-folders";
|
export * from "./secret-snapshot-folders";
|
||||||
export * from "./secret-snapshot-secrets";
|
export * from "./secret-snapshot-secrets";
|
||||||
export * from "./secret-snapshot-secrets-v2";
|
export * from "./secret-snapshot-secrets-v2";
|
||||||
export * from "./secret-snapshots";
|
export * from "./secret-snapshots";
|
||||||
|
export * from "./secret-syncs";
|
||||||
export * from "./secret-tag-junction";
|
export * from "./secret-tag-junction";
|
||||||
export * from "./secret-tags";
|
export * from "./secret-tags";
|
||||||
export * from "./secret-v2-tag-junction";
|
export * from "./secret-v2-tag-junction";
|
||||||
@@ -120,6 +126,9 @@ export * from "./ssh-certificate-authority-secrets";
|
|||||||
export * from "./ssh-certificate-bodies";
|
export * from "./ssh-certificate-bodies";
|
||||||
export * from "./ssh-certificate-templates";
|
export * from "./ssh-certificate-templates";
|
||||||
export * from "./ssh-certificates";
|
export * from "./ssh-certificates";
|
||||||
|
export * from "./ssh-host-login-user-mappings";
|
||||||
|
export * from "./ssh-host-login-users";
|
||||||
|
export * from "./ssh-hosts";
|
||||||
export * from "./super-admin";
|
export * from "./super-admin";
|
||||||
export * from "./totp-configs";
|
export * from "./totp-configs";
|
||||||
export * from "./trusted-ips";
|
export * from "./trusted-ips";
|
||||||
|
@@ -16,7 +16,8 @@ export const KmsKeysSchema = z.object({
|
|||||||
name: z.string(),
|
name: z.string(),
|
||||||
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")
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TKmsKeys = z.infer<typeof KmsKeysSchema>;
|
export type TKmsKeys = z.infer<typeof KmsKeysSchema>;
|
||||||
|
@@ -2,6 +2,9 @@ import { z } from "zod";
|
|||||||
|
|
||||||
export enum TableName {
|
export enum TableName {
|
||||||
Users = "users",
|
Users = "users",
|
||||||
|
SshHost = "ssh_hosts",
|
||||||
|
SshHostLoginUser = "ssh_host_login_users",
|
||||||
|
SshHostLoginUserMapping = "ssh_host_login_user_mappings",
|
||||||
SshCertificateAuthority = "ssh_certificate_authorities",
|
SshCertificateAuthority = "ssh_certificate_authorities",
|
||||||
SshCertificateAuthoritySecret = "ssh_certificate_authority_secrets",
|
SshCertificateAuthoritySecret = "ssh_certificate_authority_secrets",
|
||||||
SshCertificateTemplate = "ssh_certificate_templates",
|
SshCertificateTemplate = "ssh_certificate_templates",
|
||||||
@@ -38,6 +41,7 @@ export enum TableName {
|
|||||||
SuperAdmin = "super_admin",
|
SuperAdmin = "super_admin",
|
||||||
RateLimit = "rate_limit",
|
RateLimit = "rate_limit",
|
||||||
ApiKey = "api_keys",
|
ApiKey = "api_keys",
|
||||||
|
ProjectSshConfig = "project_ssh_configs",
|
||||||
Project = "projects",
|
Project = "projects",
|
||||||
ProjectBot = "project_bots",
|
ProjectBot = "project_bots",
|
||||||
Environment = "project_environments",
|
Environment = "project_environments",
|
||||||
@@ -140,7 +144,9 @@ export enum TableName {
|
|||||||
KmipClient = "kmip_clients",
|
KmipClient = "kmip_clients",
|
||||||
KmipOrgConfig = "kmip_org_configs",
|
KmipOrgConfig = "kmip_org_configs",
|
||||||
KmipOrgServerCertificates = "kmip_org_server_certificates",
|
KmipOrgServerCertificates = "kmip_org_server_certificates",
|
||||||
KmipClientCertificates = "kmip_client_certificates"
|
KmipClientCertificates = "kmip_client_certificates",
|
||||||
|
SecretRotationV2 = "secret_rotations_v2",
|
||||||
|
SecretRotationV2SecretMapping = "secret_rotation_v2_secret_mappings"
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TImmutableDBKeys = "id" | "createdAt" | "updatedAt";
|
export type TImmutableDBKeys = "id" | "createdAt" | "updatedAt";
|
||||||
@@ -233,3 +239,8 @@ export enum ActionProjectType {
|
|||||||
// project operations that happen on all types
|
// project operations that happen on all types
|
||||||
Any = "any"
|
Any = "any"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum SortDirection {
|
||||||
|
ASC = "asc",
|
||||||
|
DESC = "desc"
|
||||||
|
}
|
||||||
|
@@ -30,9 +30,10 @@ export const OidcConfigsSchema = z.object({
|
|||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
orgId: z.string().uuid(),
|
orgId: z.string().uuid(),
|
||||||
lastUsed: z.date().nullable().optional(),
|
lastUsed: z.date().nullable().optional(),
|
||||||
manageGroupMemberships: z.boolean().default(false),
|
|
||||||
encryptedOidcClientId: zodBuffer,
|
encryptedOidcClientId: zodBuffer,
|
||||||
encryptedOidcClientSecret: zodBuffer
|
encryptedOidcClientSecret: zodBuffer,
|
||||||
|
manageGroupMemberships: z.boolean().default(false),
|
||||||
|
jwtSignatureAlgorithm: z.string().default("RS256")
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TOidcConfigs = z.infer<typeof OidcConfigsSchema>;
|
export type TOidcConfigs = z.infer<typeof OidcConfigsSchema>;
|
||||||
|
@@ -23,10 +23,11 @@ export const OrganizationsSchema = z.object({
|
|||||||
defaultMembershipRole: z.string().default("member"),
|
defaultMembershipRole: z.string().default("member"),
|
||||||
enforceMfa: z.boolean().default(false),
|
enforceMfa: z.boolean().default(false),
|
||||||
selectedMfaMethod: z.string().nullable().optional(),
|
selectedMfaMethod: z.string().nullable().optional(),
|
||||||
|
allowSecretSharingOutsideOrganization: z.boolean().default(true).nullable().optional(),
|
||||||
shouldUseNewPrivilegeSystem: z.boolean().default(true),
|
shouldUseNewPrivilegeSystem: z.boolean().default(true),
|
||||||
privilegeUpgradeInitiatedByUsername: z.string().nullable().optional(),
|
privilegeUpgradeInitiatedByUsername: z.string().nullable().optional(),
|
||||||
privilegeUpgradeInitiatedAt: z.date().nullable().optional(),
|
privilegeUpgradeInitiatedAt: z.date().nullable().optional(),
|
||||||
allowSecretSharingOutsideOrganization: z.boolean().default(true).nullable().optional()
|
bypassOrgAuthEnabled: z.boolean().default(false)
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TOrganizations = z.infer<typeof OrganizationsSchema>;
|
export type TOrganizations = z.infer<typeof OrganizationsSchema>;
|
||||||
|
21
backend/src/db/schemas/project-ssh-configs.ts
Normal file
21
backend/src/db/schemas/project-ssh-configs.ts
Normal file
@@ -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 ProjectSshConfigsSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date(),
|
||||||
|
projectId: z.string(),
|
||||||
|
defaultUserSshCaId: z.string().uuid().nullable().optional(),
|
||||||
|
defaultHostSshCaId: z.string().uuid().nullable().optional()
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TProjectSshConfigs = z.infer<typeof ProjectSshConfigsSchema>;
|
||||||
|
export type TProjectSshConfigsInsert = Omit<z.input<typeof ProjectSshConfigsSchema>, TImmutableDBKeys>;
|
||||||
|
export type TProjectSshConfigsUpdate = Partial<Omit<z.input<typeof ProjectSshConfigsSchema>, TImmutableDBKeys>>;
|
@@ -26,7 +26,8 @@ export const ProjectsSchema = z.object({
|
|||||||
kmsSecretManagerEncryptedDataKey: zodBuffer.nullable().optional(),
|
kmsSecretManagerEncryptedDataKey: zodBuffer.nullable().optional(),
|
||||||
description: z.string().nullable().optional(),
|
description: z.string().nullable().optional(),
|
||||||
type: z.string(),
|
type: z.string(),
|
||||||
enforceCapitalization: z.boolean().default(false)
|
enforceCapitalization: z.boolean().default(false),
|
||||||
|
hasDeleteProtection: z.boolean().default(true).nullable().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TProjects = z.infer<typeof ProjectsSchema>;
|
export type TProjects = z.infer<typeof ProjectsSchema>;
|
||||||
|
@@ -16,7 +16,8 @@ export const ResourceMetadataSchema = z.object({
|
|||||||
identityId: z.string().uuid().nullable().optional(),
|
identityId: z.string().uuid().nullable().optional(),
|
||||||
secretId: z.string().uuid().nullable().optional(),
|
secretId: z.string().uuid().nullable().optional(),
|
||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date()
|
updatedAt: z.date(),
|
||||||
|
dynamicSecretId: z.string().uuid().nullable().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TResourceMetadata = z.infer<typeof ResourceMetadataSchema>;
|
export type TResourceMetadata = z.infer<typeof ResourceMetadataSchema>;
|
||||||
|
@@ -16,7 +16,8 @@ export const SecretFoldersSchema = z.object({
|
|||||||
envId: z.string().uuid(),
|
envId: z.string().uuid(),
|
||||||
parentId: z.string().uuid().nullable().optional(),
|
parentId: z.string().uuid().nullable().optional(),
|
||||||
isReserved: z.boolean().default(false).nullable().optional(),
|
isReserved: z.boolean().default(false).nullable().optional(),
|
||||||
description: z.string().nullable().optional()
|
description: z.string().nullable().optional(),
|
||||||
|
lastSecretModified: z.date().nullable().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TSecretFolders = z.infer<typeof SecretFoldersSchema>;
|
export type TSecretFolders = z.infer<typeof SecretFoldersSchema>;
|
||||||
|
23
backend/src/db/schemas/secret-rotation-v2-secret-mappings.ts
Normal file
23
backend/src/db/schemas/secret-rotation-v2-secret-mappings.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// 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 SecretRotationV2SecretMappingsSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
secretId: z.string().uuid(),
|
||||||
|
rotationId: z.string().uuid()
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TSecretRotationV2SecretMappings = z.infer<typeof SecretRotationV2SecretMappingsSchema>;
|
||||||
|
export type TSecretRotationV2SecretMappingsInsert = Omit<
|
||||||
|
z.input<typeof SecretRotationV2SecretMappingsSchema>,
|
||||||
|
TImmutableDBKeys
|
||||||
|
>;
|
||||||
|
export type TSecretRotationV2SecretMappingsUpdate = Partial<
|
||||||
|
Omit<z.input<typeof SecretRotationV2SecretMappingsSchema>, TImmutableDBKeys>
|
||||||
|
>;
|
39
backend/src/db/schemas/secret-rotations-v2.ts
Normal file
39
backend/src/db/schemas/secret-rotations-v2.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
// 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 SecretRotationsV2Schema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
name: z.string(),
|
||||||
|
description: z.string().nullable().optional(),
|
||||||
|
type: z.string(),
|
||||||
|
parameters: z.unknown(),
|
||||||
|
secretsMapping: z.unknown(),
|
||||||
|
encryptedGeneratedCredentials: zodBuffer,
|
||||||
|
isAutoRotationEnabled: z.boolean().default(true),
|
||||||
|
activeIndex: z.number().default(0),
|
||||||
|
folderId: z.string().uuid(),
|
||||||
|
connectionId: z.string().uuid(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date(),
|
||||||
|
rotationInterval: z.number(),
|
||||||
|
rotateAtUtc: z.unknown(),
|
||||||
|
rotationStatus: z.string(),
|
||||||
|
lastRotationAttemptedAt: z.date(),
|
||||||
|
lastRotatedAt: z.date(),
|
||||||
|
encryptedLastRotationMessage: zodBuffer.nullable().optional(),
|
||||||
|
lastRotationJobId: z.string().nullable().optional(),
|
||||||
|
nextRotationAt: z.date().nullable().optional(),
|
||||||
|
isLastRotationManual: z.boolean().default(true)
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TSecretRotationsV2 = z.infer<typeof SecretRotationsV2Schema>;
|
||||||
|
export type TSecretRotationsV2Insert = Omit<z.input<typeof SecretRotationsV2Schema>, TImmutableDBKeys>;
|
||||||
|
export type TSecretRotationsV2Update = Partial<Omit<z.input<typeof SecretRotationsV2Schema>, TImmutableDBKeys>>;
|
@@ -21,7 +21,8 @@ export const ServiceTokensSchema = z.object({
|
|||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
createdBy: z.string(),
|
createdBy: z.string(),
|
||||||
projectId: z.string()
|
projectId: z.string(),
|
||||||
|
expiryNotificationSent: z.boolean().default(false).nullable().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TServiceTokens = z.infer<typeof ServiceTokensSchema>;
|
export type TServiceTokens = z.infer<typeof ServiceTokensSchema>;
|
||||||
|
@@ -14,7 +14,8 @@ export const SshCertificateAuthoritiesSchema = z.object({
|
|||||||
projectId: z.string(),
|
projectId: z.string(),
|
||||||
status: z.string(),
|
status: z.string(),
|
||||||
friendlyName: z.string(),
|
friendlyName: z.string(),
|
||||||
keyAlgorithm: z.string()
|
keyAlgorithm: z.string(),
|
||||||
|
keySource: z.string()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TSshCertificateAuthorities = z.infer<typeof SshCertificateAuthoritiesSchema>;
|
export type TSshCertificateAuthorities = z.infer<typeof SshCertificateAuthoritiesSchema>;
|
||||||
|
@@ -11,14 +11,15 @@ export const SshCertificatesSchema = z.object({
|
|||||||
id: z.string().uuid(),
|
id: z.string().uuid(),
|
||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
sshCaId: z.string().uuid(),
|
sshCaId: z.string().uuid().nullable().optional(),
|
||||||
sshCertificateTemplateId: z.string().uuid().nullable().optional(),
|
sshCertificateTemplateId: z.string().uuid().nullable().optional(),
|
||||||
serialNumber: z.string(),
|
serialNumber: z.string(),
|
||||||
certType: z.string(),
|
certType: z.string(),
|
||||||
principals: z.string().array(),
|
principals: z.string().array(),
|
||||||
keyId: z.string(),
|
keyId: z.string(),
|
||||||
notBefore: z.date(),
|
notBefore: z.date(),
|
||||||
notAfter: z.date()
|
notAfter: z.date(),
|
||||||
|
sshHostId: z.string().uuid().nullable().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TSshCertificates = z.infer<typeof SshCertificatesSchema>;
|
export type TSshCertificates = z.infer<typeof SshCertificatesSchema>;
|
||||||
|
22
backend/src/db/schemas/ssh-host-login-user-mappings.ts
Normal file
22
backend/src/db/schemas/ssh-host-login-user-mappings.ts
Normal file
@@ -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 SshHostLoginUserMappingsSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date(),
|
||||||
|
sshHostLoginUserId: z.string().uuid(),
|
||||||
|
userId: z.string().uuid().nullable().optional()
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TSshHostLoginUserMappings = z.infer<typeof SshHostLoginUserMappingsSchema>;
|
||||||
|
export type TSshHostLoginUserMappingsInsert = Omit<z.input<typeof SshHostLoginUserMappingsSchema>, TImmutableDBKeys>;
|
||||||
|
export type TSshHostLoginUserMappingsUpdate = Partial<
|
||||||
|
Omit<z.input<typeof SshHostLoginUserMappingsSchema>, TImmutableDBKeys>
|
||||||
|
>;
|
20
backend/src/db/schemas/ssh-host-login-users.ts
Normal file
20
backend/src/db/schemas/ssh-host-login-users.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// 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 SshHostLoginUsersSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date(),
|
||||||
|
sshHostId: z.string().uuid(),
|
||||||
|
loginUser: z.string()
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TSshHostLoginUsers = z.infer<typeof SshHostLoginUsersSchema>;
|
||||||
|
export type TSshHostLoginUsersInsert = Omit<z.input<typeof SshHostLoginUsersSchema>, TImmutableDBKeys>;
|
||||||
|
export type TSshHostLoginUsersUpdate = Partial<Omit<z.input<typeof SshHostLoginUsersSchema>, TImmutableDBKeys>>;
|
24
backend/src/db/schemas/ssh-hosts.ts
Normal file
24
backend/src/db/schemas/ssh-hosts.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// 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 SshHostsSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date(),
|
||||||
|
projectId: z.string(),
|
||||||
|
hostname: z.string(),
|
||||||
|
userCertTtl: z.string(),
|
||||||
|
hostCertTtl: z.string(),
|
||||||
|
userSshCaId: z.string().uuid(),
|
||||||
|
hostSshCaId: z.string().uuid()
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TSshHosts = z.infer<typeof SshHostsSchema>;
|
||||||
|
export type TSshHostsInsert = Omit<z.input<typeof SshHostsSchema>, TImmutableDBKeys>;
|
||||||
|
export type TSshHostsUpdate = Partial<Omit<z.input<typeof SshHostsSchema>, TImmutableDBKeys>>;
|
@@ -22,7 +22,8 @@ export const registerAccessApprovalRequestRouter = async (server: FastifyZodProv
|
|||||||
body: z.object({
|
body: z.object({
|
||||||
permissions: z.any().array(),
|
permissions: z.any().array(),
|
||||||
isTemporary: z.boolean(),
|
isTemporary: z.boolean(),
|
||||||
temporaryRange: z.string().optional()
|
temporaryRange: z.string().optional(),
|
||||||
|
note: z.string().max(255).optional()
|
||||||
}),
|
}),
|
||||||
querystring: z.object({
|
querystring: z.object({
|
||||||
projectSlug: z.string().trim()
|
projectSlug: z.string().trim()
|
||||||
@@ -43,7 +44,8 @@ export const registerAccessApprovalRequestRouter = async (server: FastifyZodProv
|
|||||||
actorOrgId: req.permission.orgId,
|
actorOrgId: req.permission.orgId,
|
||||||
projectSlug: req.query.projectSlug,
|
projectSlug: req.query.projectSlug,
|
||||||
temporaryRange: req.body.temporaryRange,
|
temporaryRange: req.body.temporaryRange,
|
||||||
isTemporary: req.body.isTemporary
|
isTemporary: req.body.isTemporary,
|
||||||
|
note: req.body.note
|
||||||
});
|
});
|
||||||
return { approval: request };
|
return { approval: request };
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { DynamicSecretLeasesSchema } from "@app/db/schemas";
|
import { DynamicSecretLeasesSchema } from "@app/db/schemas";
|
||||||
import { DYNAMIC_SECRET_LEASES } from "@app/lib/api-docs";
|
import { ApiDocsTags, DYNAMIC_SECRET_LEASES } from "@app/lib/api-docs";
|
||||||
import { daysToMillisecond } from "@app/lib/dates";
|
import { daysToMillisecond } from "@app/lib/dates";
|
||||||
import { removeTrailingSlash } from "@app/lib/fn";
|
import { removeTrailingSlash } from "@app/lib/fn";
|
||||||
import { ms } from "@app/lib/ms";
|
import { ms } from "@app/lib/ms";
|
||||||
@@ -18,6 +18,8 @@ export const registerDynamicSecretLeaseRouter = async (server: FastifyZodProvide
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.DynamicSecrets],
|
||||||
body: z.object({
|
body: z.object({
|
||||||
dynamicSecretName: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.CREATE.dynamicSecretName).toLowerCase(),
|
dynamicSecretName: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.CREATE.dynamicSecretName).toLowerCase(),
|
||||||
projectSlug: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.CREATE.projectSlug),
|
projectSlug: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.CREATE.projectSlug),
|
||||||
@@ -65,6 +67,8 @@ export const registerDynamicSecretLeaseRouter = async (server: FastifyZodProvide
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.DynamicSecrets],
|
||||||
params: z.object({
|
params: z.object({
|
||||||
leaseId: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.DELETE.leaseId)
|
leaseId: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.DELETE.leaseId)
|
||||||
}),
|
}),
|
||||||
@@ -107,6 +111,8 @@ export const registerDynamicSecretLeaseRouter = async (server: FastifyZodProvide
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.DynamicSecrets],
|
||||||
params: z.object({
|
params: z.object({
|
||||||
leaseId: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.RENEW.leaseId)
|
leaseId: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.RENEW.leaseId)
|
||||||
}),
|
}),
|
||||||
@@ -160,6 +166,8 @@ export const registerDynamicSecretLeaseRouter = async (server: FastifyZodProvide
|
|||||||
rateLimit: readLimit
|
rateLimit: readLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.DynamicSecrets],
|
||||||
params: z.object({
|
params: z.object({
|
||||||
leaseId: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.GET_BY_LEASEID.leaseId)
|
leaseId: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.GET_BY_LEASEID.leaseId)
|
||||||
}),
|
}),
|
||||||
|
@@ -2,7 +2,7 @@ import { z } from "zod";
|
|||||||
|
|
||||||
import { DynamicSecretLeasesSchema } from "@app/db/schemas";
|
import { DynamicSecretLeasesSchema } from "@app/db/schemas";
|
||||||
import { DynamicSecretProviderSchema } from "@app/ee/services/dynamic-secret/providers/models";
|
import { DynamicSecretProviderSchema } from "@app/ee/services/dynamic-secret/providers/models";
|
||||||
import { DYNAMIC_SECRETS } from "@app/lib/api-docs";
|
import { ApiDocsTags, DYNAMIC_SECRETS } from "@app/lib/api-docs";
|
||||||
import { daysToMillisecond } from "@app/lib/dates";
|
import { daysToMillisecond } from "@app/lib/dates";
|
||||||
import { removeTrailingSlash } from "@app/lib/fn";
|
import { removeTrailingSlash } from "@app/lib/fn";
|
||||||
import { ms } from "@app/lib/ms";
|
import { ms } from "@app/lib/ms";
|
||||||
@@ -11,6 +11,7 @@ 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 { SanitizedDynamicSecretSchema } from "@app/server/routes/sanitizedSchemas";
|
import { SanitizedDynamicSecretSchema } from "@app/server/routes/sanitizedSchemas";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
import { ResourceMetadataSchema } from "@app/services/resource-metadata/resource-metadata-schema";
|
||||||
|
|
||||||
export const registerDynamicSecretRouter = async (server: FastifyZodProvider) => {
|
export const registerDynamicSecretRouter = async (server: FastifyZodProvider) => {
|
||||||
server.route({
|
server.route({
|
||||||
@@ -20,6 +21,8 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.DynamicSecrets],
|
||||||
body: z.object({
|
body: z.object({
|
||||||
projectSlug: z.string().min(1).describe(DYNAMIC_SECRETS.CREATE.projectSlug),
|
projectSlug: z.string().min(1).describe(DYNAMIC_SECRETS.CREATE.projectSlug),
|
||||||
provider: DynamicSecretProviderSchema.describe(DYNAMIC_SECRETS.CREATE.provider),
|
provider: DynamicSecretProviderSchema.describe(DYNAMIC_SECRETS.CREATE.provider),
|
||||||
@@ -48,7 +51,8 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
|
|||||||
.nullable(),
|
.nullable(),
|
||||||
path: z.string().describe(DYNAMIC_SECRETS.CREATE.path).trim().default("/").transform(removeTrailingSlash),
|
path: z.string().describe(DYNAMIC_SECRETS.CREATE.path).trim().default("/").transform(removeTrailingSlash),
|
||||||
environmentSlug: z.string().describe(DYNAMIC_SECRETS.CREATE.environmentSlug).min(1),
|
environmentSlug: z.string().describe(DYNAMIC_SECRETS.CREATE.environmentSlug).min(1),
|
||||||
name: slugSchema({ min: 1, max: 64, field: "Name" }).describe(DYNAMIC_SECRETS.CREATE.name)
|
name: slugSchema({ min: 1, max: 64, field: "Name" }).describe(DYNAMIC_SECRETS.CREATE.name),
|
||||||
|
metadata: ResourceMetadataSchema.optional()
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
@@ -109,6 +113,8 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.DynamicSecrets],
|
||||||
params: z.object({
|
params: z.object({
|
||||||
name: z.string().toLowerCase().describe(DYNAMIC_SECRETS.UPDATE.name)
|
name: z.string().toLowerCase().describe(DYNAMIC_SECRETS.UPDATE.name)
|
||||||
}),
|
}),
|
||||||
@@ -143,7 +149,8 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
|
|||||||
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
|
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
|
||||||
})
|
})
|
||||||
.nullable(),
|
.nullable(),
|
||||||
newName: z.string().describe(DYNAMIC_SECRETS.UPDATE.newName).optional()
|
newName: z.string().describe(DYNAMIC_SECRETS.UPDATE.newName).optional(),
|
||||||
|
metadata: ResourceMetadataSchema.optional()
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
@@ -176,6 +183,8 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.DynamicSecrets],
|
||||||
params: z.object({
|
params: z.object({
|
||||||
name: z.string().toLowerCase().describe(DYNAMIC_SECRETS.DELETE.name)
|
name: z.string().toLowerCase().describe(DYNAMIC_SECRETS.DELETE.name)
|
||||||
}),
|
}),
|
||||||
@@ -212,6 +221,8 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
|
|||||||
rateLimit: readLimit
|
rateLimit: readLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.DynamicSecrets],
|
||||||
params: z.object({
|
params: z.object({
|
||||||
name: z.string().min(1).describe(DYNAMIC_SECRETS.GET_BY_NAME.name)
|
name: z.string().min(1).describe(DYNAMIC_SECRETS.GET_BY_NAME.name)
|
||||||
}),
|
}),
|
||||||
@@ -238,6 +249,7 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
|
|||||||
name: req.params.name,
|
name: req.params.name,
|
||||||
...req.query
|
...req.query
|
||||||
});
|
});
|
||||||
|
|
||||||
return { dynamicSecret: dynamicSecretCfg };
|
return { dynamicSecret: dynamicSecretCfg };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -249,6 +261,8 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
|
|||||||
rateLimit: readLimit
|
rateLimit: readLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.DynamicSecrets],
|
||||||
querystring: z.object({
|
querystring: z.object({
|
||||||
projectSlug: z.string().min(1).describe(DYNAMIC_SECRETS.LIST.projectSlug),
|
projectSlug: z.string().min(1).describe(DYNAMIC_SECRETS.LIST.projectSlug),
|
||||||
path: z.string().trim().default("/").transform(removeTrailingSlash).describe(DYNAMIC_SECRETS.LIST.path),
|
path: z.string().trim().default("/").transform(removeTrailingSlash).describe(DYNAMIC_SECRETS.LIST.path),
|
||||||
@@ -280,18 +294,20 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
|
|||||||
rateLimit: readLimit
|
rateLimit: readLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.DynamicSecrets],
|
||||||
params: z.object({
|
params: z.object({
|
||||||
name: z.string().min(1).describe(DYNAMIC_SECRETS.LIST_LEAES_BY_NAME.name)
|
name: z.string().min(1).describe(DYNAMIC_SECRETS.LIST_LEASES_BY_NAME.name)
|
||||||
}),
|
}),
|
||||||
querystring: z.object({
|
querystring: z.object({
|
||||||
projectSlug: z.string().min(1).describe(DYNAMIC_SECRETS.LIST_LEAES_BY_NAME.projectSlug),
|
projectSlug: z.string().min(1).describe(DYNAMIC_SECRETS.LIST_LEASES_BY_NAME.projectSlug),
|
||||||
path: z
|
path: z
|
||||||
.string()
|
.string()
|
||||||
.trim()
|
.trim()
|
||||||
.default("/")
|
.default("/")
|
||||||
.transform(removeTrailingSlash)
|
.transform(removeTrailingSlash)
|
||||||
.describe(DYNAMIC_SECRETS.LIST_LEAES_BY_NAME.path),
|
.describe(DYNAMIC_SECRETS.LIST_LEASES_BY_NAME.path),
|
||||||
environmentSlug: z.string().min(1).describe(DYNAMIC_SECRETS.LIST_LEAES_BY_NAME.environmentSlug)
|
environmentSlug: z.string().min(1).describe(DYNAMIC_SECRETS.LIST_LEASES_BY_NAME.environmentSlug)
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
|
@@ -2,7 +2,7 @@ import { z } from "zod";
|
|||||||
|
|
||||||
import { GroupsSchema, OrgMembershipRole, UsersSchema } from "@app/db/schemas";
|
import { GroupsSchema, OrgMembershipRole, UsersSchema } from "@app/db/schemas";
|
||||||
import { EFilterReturnedUsers } from "@app/ee/services/group/group-types";
|
import { EFilterReturnedUsers } from "@app/ee/services/group/group-types";
|
||||||
import { GROUPS } from "@app/lib/api-docs";
|
import { ApiDocsTags, GROUPS } from "@app/lib/api-docs";
|
||||||
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";
|
||||||
@@ -13,6 +13,8 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => {
|
|||||||
method: "POST",
|
method: "POST",
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.Groups],
|
||||||
body: z.object({
|
body: z.object({
|
||||||
name: z.string().trim().min(1).max(50).describe(GROUPS.CREATE.name),
|
name: z.string().trim().min(1).max(50).describe(GROUPS.CREATE.name),
|
||||||
slug: slugSchema({ min: 5, max: 36 }).optional().describe(GROUPS.CREATE.slug),
|
slug: slugSchema({ min: 5, max: 36 }).optional().describe(GROUPS.CREATE.slug),
|
||||||
@@ -40,6 +42,8 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => {
|
|||||||
method: "GET",
|
method: "GET",
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.Groups],
|
||||||
params: z.object({
|
params: z.object({
|
||||||
id: z.string().trim().describe(GROUPS.GET_BY_ID.id)
|
id: z.string().trim().describe(GROUPS.GET_BY_ID.id)
|
||||||
}),
|
}),
|
||||||
@@ -65,6 +69,8 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => {
|
|||||||
method: "GET",
|
method: "GET",
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.Groups],
|
||||||
response: {
|
response: {
|
||||||
200: GroupsSchema.array()
|
200: GroupsSchema.array()
|
||||||
}
|
}
|
||||||
@@ -87,6 +93,8 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => {
|
|||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.Groups],
|
||||||
params: z.object({
|
params: z.object({
|
||||||
id: z.string().trim().describe(GROUPS.UPDATE.id)
|
id: z.string().trim().describe(GROUPS.UPDATE.id)
|
||||||
}),
|
}),
|
||||||
@@ -120,6 +128,8 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => {
|
|||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.Groups],
|
||||||
params: z.object({
|
params: z.object({
|
||||||
id: z.string().trim().describe(GROUPS.DELETE.id)
|
id: z.string().trim().describe(GROUPS.DELETE.id)
|
||||||
}),
|
}),
|
||||||
@@ -145,6 +155,8 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => {
|
|||||||
url: "/:id/users",
|
url: "/:id/users",
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.Groups],
|
||||||
params: z.object({
|
params: z.object({
|
||||||
id: z.string().trim().describe(GROUPS.LIST_USERS.id)
|
id: z.string().trim().describe(GROUPS.LIST_USERS.id)
|
||||||
}),
|
}),
|
||||||
@@ -194,6 +206,8 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => {
|
|||||||
url: "/:id/users/:username",
|
url: "/:id/users/:username",
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.Groups],
|
||||||
params: z.object({
|
params: z.object({
|
||||||
id: z.string().trim().describe(GROUPS.ADD_USER.id),
|
id: z.string().trim().describe(GROUPS.ADD_USER.id),
|
||||||
username: z.string().trim().describe(GROUPS.ADD_USER.username)
|
username: z.string().trim().describe(GROUPS.ADD_USER.username)
|
||||||
@@ -227,6 +241,8 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => {
|
|||||||
url: "/:id/users/:username",
|
url: "/:id/users/:username",
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.Groups],
|
||||||
params: z.object({
|
params: z.object({
|
||||||
id: z.string().trim().describe(GROUPS.DELETE_USER.id),
|
id: z.string().trim().describe(GROUPS.DELETE_USER.id),
|
||||||
username: z.string().trim().describe(GROUPS.DELETE_USER.username)
|
username: z.string().trim().describe(GROUPS.DELETE_USER.username)
|
||||||
|
@@ -3,7 +3,7 @@ import { z } from "zod";
|
|||||||
|
|
||||||
import { IdentityProjectAdditionalPrivilegeTemporaryMode } from "@app/ee/services/identity-project-additional-privilege/identity-project-additional-privilege-types";
|
import { IdentityProjectAdditionalPrivilegeTemporaryMode } from "@app/ee/services/identity-project-additional-privilege/identity-project-additional-privilege-types";
|
||||||
import { backfillPermissionV1SchemaToV2Schema } from "@app/ee/services/permission/project-permission";
|
import { backfillPermissionV1SchemaToV2Schema } from "@app/ee/services/permission/project-permission";
|
||||||
import { 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";
|
||||||
import { ms } from "@app/lib/ms";
|
import { ms } from "@app/lib/ms";
|
||||||
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
||||||
@@ -25,6 +25,8 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.IdentitySpecificPrivilegesV1],
|
||||||
description: "Create a permanent or a non expiry specific privilege for identity.",
|
description: "Create a permanent or a non expiry specific privilege for identity.",
|
||||||
security: [
|
security: [
|
||||||
{
|
{
|
||||||
@@ -85,6 +87,8 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.IdentitySpecificPrivilegesV1],
|
||||||
description: "Create a temporary or a expiring specific privilege for identity.",
|
description: "Create a temporary or a expiring specific privilege for identity.",
|
||||||
security: [
|
security: [
|
||||||
{
|
{
|
||||||
@@ -157,6 +161,8 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.IdentitySpecificPrivilegesV1],
|
||||||
description: "Update a specific privilege of an identity.",
|
description: "Update a specific privilege of an identity.",
|
||||||
security: [
|
security: [
|
||||||
{
|
{
|
||||||
@@ -240,6 +246,8 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.IdentitySpecificPrivilegesV1],
|
||||||
description: "Delete a specific privilege of an identity.",
|
description: "Delete a specific privilege of an identity.",
|
||||||
security: [
|
security: [
|
||||||
{
|
{
|
||||||
@@ -279,6 +287,8 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
rateLimit: readLimit
|
rateLimit: readLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.IdentitySpecificPrivilegesV1],
|
||||||
description: "Retrieve details of a specific privilege by privilege slug.",
|
description: "Retrieve details of a specific privilege by privilege slug.",
|
||||||
security: [
|
security: [
|
||||||
{
|
{
|
||||||
@@ -319,6 +329,8 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
rateLimit: readLimit
|
rateLimit: readLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.IdentitySpecificPrivilegesV1],
|
||||||
description: "List of a specific privilege of an identity in a project.",
|
description: "List of a specific privilege of an identity in a project.",
|
||||||
security: [
|
security: [
|
||||||
{
|
{
|
||||||
|
@@ -32,6 +32,7 @@ import { registerSnapshotRouter } from "./snapshot-router";
|
|||||||
import { registerSshCaRouter } from "./ssh-certificate-authority-router";
|
import { registerSshCaRouter } from "./ssh-certificate-authority-router";
|
||||||
import { registerSshCertRouter } from "./ssh-certificate-router";
|
import { registerSshCertRouter } from "./ssh-certificate-router";
|
||||||
import { registerSshCertificateTemplateRouter } from "./ssh-certificate-template-router";
|
import { registerSshCertificateTemplateRouter } from "./ssh-certificate-template-router";
|
||||||
|
import { registerSshHostRouter } from "./ssh-host-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";
|
||||||
|
|
||||||
@@ -82,6 +83,7 @@ export const registerV1EERoutes = async (server: FastifyZodProvider) => {
|
|||||||
await sshRouter.register(registerSshCaRouter, { prefix: "/ca" });
|
await sshRouter.register(registerSshCaRouter, { prefix: "/ca" });
|
||||||
await sshRouter.register(registerSshCertRouter, { prefix: "/certificates" });
|
await sshRouter.register(registerSshCertRouter, { prefix: "/certificates" });
|
||||||
await sshRouter.register(registerSshCertificateTemplateRouter, { prefix: "/certificate-templates" });
|
await sshRouter.register(registerSshCertificateTemplateRouter, { prefix: "/certificate-templates" });
|
||||||
|
await sshRouter.register(registerSshHostRouter, { prefix: "/hosts" });
|
||||||
},
|
},
|
||||||
{ prefix: "/ssh" }
|
{ prefix: "/ssh" }
|
||||||
);
|
);
|
||||||
|
@@ -2,7 +2,7 @@ import z from "zod";
|
|||||||
|
|
||||||
import { KmsKeysSchema } from "@app/db/schemas";
|
import { KmsKeysSchema } 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 { SymmetricEncryption } from "@app/lib/crypto/cipher";
|
import { SymmetricKeyAlgorithm } from "@app/lib/crypto/cipher";
|
||||||
import { ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
import { ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
import { writeLimit } from "@app/server/config/rateLimiter";
|
import { writeLimit } from "@app/server/config/rateLimiter";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
@@ -74,7 +74,7 @@ export const registerKmipSpecRouter = async (server: FastifyZodProvider) => {
|
|||||||
schema: {
|
schema: {
|
||||||
description: "KMIP endpoint for creating managed objects",
|
description: "KMIP endpoint for creating managed objects",
|
||||||
body: z.object({
|
body: z.object({
|
||||||
algorithm: z.nativeEnum(SymmetricEncryption)
|
algorithm: z.nativeEnum(SymmetricKeyAlgorithm)
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: KmsKeysSchema
|
200: KmsKeysSchema
|
||||||
@@ -433,7 +433,7 @@ 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(SymmetricEncryption)
|
algorithm: z.nativeEnum(SymmetricKeyAlgorithm)
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
|
@@ -12,7 +12,7 @@ import RedisStore from "connect-redis";
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { OidcConfigsSchema } from "@app/db/schemas";
|
import { OidcConfigsSchema } from "@app/db/schemas";
|
||||||
import { OIDCConfigurationType } from "@app/ee/services/oidc/oidc-config-types";
|
import { OIDCConfigurationType, OIDCJWTSignatureAlgorithm } from "@app/ee/services/oidc/oidc-config-types";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { authRateLimit, readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
import { authRateLimit, readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
@@ -30,7 +30,8 @@ const SanitizedOidcConfigSchema = OidcConfigsSchema.pick({
|
|||||||
orgId: true,
|
orgId: true,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
allowedEmailDomains: true,
|
allowedEmailDomains: true,
|
||||||
manageGroupMemberships: true
|
manageGroupMemberships: true,
|
||||||
|
jwtSignatureAlgorithm: true
|
||||||
});
|
});
|
||||||
|
|
||||||
export const registerOidcRouter = async (server: FastifyZodProvider) => {
|
export const registerOidcRouter = async (server: FastifyZodProvider) => {
|
||||||
@@ -136,11 +137,12 @@ export const registerOidcRouter = async (server: FastifyZodProvider) => {
|
|||||||
url: "/login/error",
|
url: "/login/error",
|
||||||
method: "GET",
|
method: "GET",
|
||||||
handler: async (req, res) => {
|
handler: async (req, res) => {
|
||||||
|
const failureMessage = req.session.get<any>("messages");
|
||||||
await req.session.destroy();
|
await req.session.destroy();
|
||||||
|
|
||||||
return res.status(500).send({
|
return res.status(500).send({
|
||||||
error: "Authentication error",
|
error: "Authentication error",
|
||||||
details: req.query
|
details: failureMessage ?? req.query
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -169,7 +171,8 @@ export const registerOidcRouter = async (server: FastifyZodProvider) => {
|
|||||||
isActive: true,
|
isActive: true,
|
||||||
orgId: true,
|
orgId: true,
|
||||||
allowedEmailDomains: true,
|
allowedEmailDomains: true,
|
||||||
manageGroupMemberships: true
|
manageGroupMemberships: true,
|
||||||
|
jwtSignatureAlgorithm: true
|
||||||
}).extend({
|
}).extend({
|
||||||
clientId: z.string(),
|
clientId: z.string(),
|
||||||
clientSecret: z.string()
|
clientSecret: z.string()
|
||||||
@@ -224,7 +227,8 @@ export const registerOidcRouter = async (server: FastifyZodProvider) => {
|
|||||||
clientId: z.string().trim(),
|
clientId: z.string().trim(),
|
||||||
clientSecret: z.string().trim(),
|
clientSecret: z.string().trim(),
|
||||||
isActive: z.boolean(),
|
isActive: z.boolean(),
|
||||||
manageGroupMemberships: z.boolean().optional()
|
manageGroupMemberships: z.boolean().optional(),
|
||||||
|
jwtSignatureAlgorithm: z.nativeEnum(OIDCJWTSignatureAlgorithm).optional()
|
||||||
})
|
})
|
||||||
.partial()
|
.partial()
|
||||||
.merge(z.object({ orgSlug: z.string() })),
|
.merge(z.object({ orgSlug: z.string() })),
|
||||||
@@ -291,7 +295,11 @@ export const registerOidcRouter = async (server: FastifyZodProvider) => {
|
|||||||
clientSecret: z.string().trim(),
|
clientSecret: z.string().trim(),
|
||||||
isActive: z.boolean(),
|
isActive: z.boolean(),
|
||||||
orgSlug: z.string().trim(),
|
orgSlug: z.string().trim(),
|
||||||
manageGroupMemberships: z.boolean().optional().default(false)
|
manageGroupMemberships: z.boolean().optional().default(false),
|
||||||
|
jwtSignatureAlgorithm: z
|
||||||
|
.nativeEnum(OIDCJWTSignatureAlgorithm)
|
||||||
|
.optional()
|
||||||
|
.default(OIDCJWTSignatureAlgorithm.RS256)
|
||||||
})
|
})
|
||||||
.superRefine((data, ctx) => {
|
.superRefine((data, ctx) => {
|
||||||
if (data.configurationType === OIDCConfigurationType.CUSTOM) {
|
if (data.configurationType === OIDCConfigurationType.CUSTOM) {
|
||||||
|
@@ -2,7 +2,7 @@ import { z } from "zod";
|
|||||||
|
|
||||||
import { AuditLogsSchema, SecretSnapshotsSchema } from "@app/db/schemas";
|
import { AuditLogsSchema, SecretSnapshotsSchema } from "@app/db/schemas";
|
||||||
import { EventType, UserAgentType } from "@app/ee/services/audit-log/audit-log-types";
|
import { EventType, UserAgentType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { AUDIT_LOGS, PROJECTS } from "@app/lib/api-docs";
|
import { ApiDocsTags, AUDIT_LOGS, PROJECTS } from "@app/lib/api-docs";
|
||||||
import { getLastMidnightDateISO, removeTrailingSlash } from "@app/lib/fn";
|
import { getLastMidnightDateISO, removeTrailingSlash } from "@app/lib/fn";
|
||||||
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
@@ -17,6 +17,8 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
|||||||
rateLimit: readLimit
|
rateLimit: readLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.Projects],
|
||||||
description: "Return project secret snapshots ids",
|
description: "Return project secret snapshots ids",
|
||||||
security: [
|
security: [
|
||||||
{
|
{
|
||||||
|
@@ -5,7 +5,7 @@ import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
|||||||
import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
|
import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
|
||||||
import { ProjectTemplateDefaultEnvironments } from "@app/ee/services/project-template/project-template-constants";
|
import { ProjectTemplateDefaultEnvironments } from "@app/ee/services/project-template/project-template-constants";
|
||||||
import { isInfisicalProjectTemplate } from "@app/ee/services/project-template/project-template-fns";
|
import { isInfisicalProjectTemplate } from "@app/ee/services/project-template/project-template-fns";
|
||||||
import { ProjectTemplates } from "@app/lib/api-docs";
|
import { ApiDocsTags, ProjectTemplates } from "@app/lib/api-docs";
|
||||||
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";
|
||||||
@@ -101,6 +101,8 @@ export const registerProjectTemplateRouter = async (server: FastifyZodProvider)
|
|||||||
rateLimit: readLimit
|
rateLimit: readLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.ProjectTemplates],
|
||||||
description: "List project templates for the current organization.",
|
description: "List project templates for the current organization.",
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
@@ -137,6 +139,8 @@ export const registerProjectTemplateRouter = async (server: FastifyZodProvider)
|
|||||||
rateLimit: readLimit
|
rateLimit: readLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.ProjectTemplates],
|
||||||
description: "Get a project template by ID.",
|
description: "Get a project template by ID.",
|
||||||
params: z.object({
|
params: z.object({
|
||||||
templateId: z.string().uuid()
|
templateId: z.string().uuid()
|
||||||
@@ -176,6 +180,8 @@ export const registerProjectTemplateRouter = async (server: FastifyZodProvider)
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.ProjectTemplates],
|
||||||
description: "Create a project template.",
|
description: "Create a project template.",
|
||||||
body: z.object({
|
body: z.object({
|
||||||
name: slugSchema({ field: "name" })
|
name: slugSchema({ field: "name" })
|
||||||
@@ -219,6 +225,8 @@ export const registerProjectTemplateRouter = async (server: FastifyZodProvider)
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.ProjectTemplates],
|
||||||
description: "Update a project template.",
|
description: "Update a project template.",
|
||||||
params: z.object({ templateId: z.string().uuid().describe(ProjectTemplates.UPDATE.templateId) }),
|
params: z.object({ templateId: z.string().uuid().describe(ProjectTemplates.UPDATE.templateId) }),
|
||||||
body: z.object({
|
body: z.object({
|
||||||
@@ -269,6 +277,8 @@ export const registerProjectTemplateRouter = async (server: FastifyZodProvider)
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.ProjectTemplates],
|
||||||
description: "Delete a project template.",
|
description: "Delete a project template.",
|
||||||
params: z.object({ templateId: z.string().uuid().describe(ProjectTemplates.DELETE.templateId) }),
|
params: z.object({ templateId: z.string().uuid().describe(ProjectTemplates.DELETE.templateId) }),
|
||||||
|
|
||||||
|
@@ -223,12 +223,18 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
|
|||||||
samlConfigId: z.string().trim()
|
samlConfigId: z.string().trim()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
preValidation: passport.authenticate("saml", {
|
preValidation: passport.authenticate(
|
||||||
session: false,
|
"saml",
|
||||||
failureFlash: true,
|
{
|
||||||
failureRedirect: "/login/provider/error"
|
session: false
|
||||||
// this is due to zod type difference
|
},
|
||||||
}) as any,
|
async (req, res, err, user) => {
|
||||||
|
if (err) {
|
||||||
|
throw new BadRequestError({ message: `Saml authentication failed. ${err?.message}`, error: err });
|
||||||
|
}
|
||||||
|
req.passportUser = user as { isUserCompleted: boolean; providerAuthToken: string };
|
||||||
|
}
|
||||||
|
) as any, // this is due to zod type difference
|
||||||
handler: (req, res) => {
|
handler: (req, res) => {
|
||||||
if (req.passportUser.isUserCompleted) {
|
if (req.passportUser.isUserCompleted) {
|
||||||
return res.redirect(
|
return res.redirect(
|
||||||
|
@@ -277,8 +277,10 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
|
|||||||
reviewers: approvalRequestUser.extend({ status: z.string(), comment: z.string().optional() }).array(),
|
reviewers: approvalRequestUser.extend({ status: z.string(), comment: z.string().optional() }).array(),
|
||||||
secretPath: z.string(),
|
secretPath: z.string(),
|
||||||
commits: secretRawSchema
|
commits: secretRawSchema
|
||||||
.omit({ _id: true, environment: true, workspace: true, type: true, version: true })
|
.omit({ _id: true, environment: true, workspace: true, type: true, version: true, secretValue: true })
|
||||||
.extend({
|
.extend({
|
||||||
|
secretValue: z.string().optional(),
|
||||||
|
isRotatedSecret: z.boolean().optional(),
|
||||||
op: z.string(),
|
op: z.string(),
|
||||||
tags: SanitizedTagSchema.array().optional(),
|
tags: SanitizedTagSchema.array().optional(),
|
||||||
secretMetadata: ResourceMetadataSchema.nullish(),
|
secretMetadata: ResourceMetadataSchema.nullish(),
|
||||||
|
@@ -23,7 +23,8 @@ export const registerSecretRotationProviderRouter = async (server: FastifyZodPro
|
|||||||
title: z.string(),
|
title: z.string(),
|
||||||
image: z.string().optional(),
|
image: z.string().optional(),
|
||||||
description: z.string().optional(),
|
description: z.string().optional(),
|
||||||
template: z.any()
|
template: z.any(),
|
||||||
|
isDeprecated: z.boolean().optional()
|
||||||
})
|
})
|
||||||
.array()
|
.array()
|
||||||
})
|
})
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { SecretSnapshotsSchema } from "@app/db/schemas";
|
import { SecretSnapshotsSchema } from "@app/db/schemas";
|
||||||
import { PROJECTS } from "@app/lib/api-docs";
|
import { ApiDocsTags, PROJECTS } from "@app/lib/api-docs";
|
||||||
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { SanitizedTagSchema, secretRawSchema } from "@app/server/routes/sanitizedSchemas";
|
import { SanitizedTagSchema, secretRawSchema } from "@app/server/routes/sanitizedSchemas";
|
||||||
@@ -33,7 +33,8 @@ export const registerSnapshotRouter = async (server: FastifyZodProvider) => {
|
|||||||
.extend({
|
.extend({
|
||||||
secretValueHidden: z.boolean(),
|
secretValueHidden: z.boolean(),
|
||||||
secretId: z.string(),
|
secretId: z.string(),
|
||||||
tags: SanitizedTagSchema.array()
|
tags: SanitizedTagSchema.array(),
|
||||||
|
isRotatedSecret: z.boolean().optional()
|
||||||
})
|
})
|
||||||
.array(),
|
.array(),
|
||||||
folderVersion: z.object({ id: z.string(), name: z.string() }).array(),
|
folderVersion: z.object({ id: z.string(), name: z.string() }).array(),
|
||||||
@@ -64,6 +65,8 @@ export const registerSnapshotRouter = async (server: FastifyZodProvider) => {
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.Projects],
|
||||||
description: "Roll back project secrets to those captured in a secret snapshot version.",
|
description: "Roll back project secrets to those captured in a secret snapshot version.",
|
||||||
security: [
|
security: [
|
||||||
{
|
{
|
||||||
|
@@ -1,14 +1,15 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
|
import { normalizeSshPrivateKey } from "@app/ee/services/ssh/ssh-certificate-authority-fns";
|
||||||
import { sanitizedSshCa } from "@app/ee/services/ssh/ssh-certificate-authority-schema";
|
import { sanitizedSshCa } from "@app/ee/services/ssh/ssh-certificate-authority-schema";
|
||||||
import { SshCaStatus } from "@app/ee/services/ssh/ssh-certificate-authority-types";
|
import { SshCaKeySource, SshCaStatus } from "@app/ee/services/ssh/ssh-certificate-authority-types";
|
||||||
|
import { SshCertKeyAlgorithm } from "@app/ee/services/ssh-certificate/ssh-certificate-types";
|
||||||
import { sanitizedSshCertificateTemplate } from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-schema";
|
import { sanitizedSshCertificateTemplate } from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-schema";
|
||||||
import { SSH_CERTIFICATE_AUTHORITIES } from "@app/lib/api-docs";
|
import { ApiDocsTags, SSH_CERTIFICATE_AUTHORITIES } from "@app/lib/api-docs";
|
||||||
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
import { CertKeyAlgorithm } from "@app/services/certificate/certificate-types";
|
|
||||||
|
|
||||||
export const registerSshCaRouter = async (server: FastifyZodProvider) => {
|
export const registerSshCaRouter = async (server: FastifyZodProvider) => {
|
||||||
server.route({
|
server.route({
|
||||||
@@ -19,15 +20,37 @@ export const registerSshCaRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SshCertificateAuthorities],
|
||||||
description: "Create SSH CA",
|
description: "Create SSH CA",
|
||||||
body: z.object({
|
body: z
|
||||||
projectId: z.string().describe(SSH_CERTIFICATE_AUTHORITIES.CREATE.projectId),
|
.object({
|
||||||
friendlyName: z.string().describe(SSH_CERTIFICATE_AUTHORITIES.CREATE.friendlyName),
|
projectId: z.string().describe(SSH_CERTIFICATE_AUTHORITIES.CREATE.projectId),
|
||||||
keyAlgorithm: z
|
friendlyName: z.string().describe(SSH_CERTIFICATE_AUTHORITIES.CREATE.friendlyName),
|
||||||
.nativeEnum(CertKeyAlgorithm)
|
keyAlgorithm: z
|
||||||
.default(CertKeyAlgorithm.RSA_2048)
|
.nativeEnum(SshCertKeyAlgorithm)
|
||||||
.describe(SSH_CERTIFICATE_AUTHORITIES.CREATE.keyAlgorithm)
|
.default(SshCertKeyAlgorithm.ED25519)
|
||||||
}),
|
.describe(SSH_CERTIFICATE_AUTHORITIES.CREATE.keyAlgorithm),
|
||||||
|
publicKey: z.string().trim().optional().describe(SSH_CERTIFICATE_AUTHORITIES.CREATE.publicKey),
|
||||||
|
privateKey: z
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.optional()
|
||||||
|
.transform((val) => (val ? normalizeSshPrivateKey(val) : undefined))
|
||||||
|
.describe(SSH_CERTIFICATE_AUTHORITIES.CREATE.privateKey),
|
||||||
|
keySource: z
|
||||||
|
.nativeEnum(SshCaKeySource)
|
||||||
|
.default(SshCaKeySource.INTERNAL)
|
||||||
|
.describe(SSH_CERTIFICATE_AUTHORITIES.CREATE.keySource)
|
||||||
|
})
|
||||||
|
.refine((data) => data.keySource === SshCaKeySource.INTERNAL || (!!data.publicKey && !!data.privateKey), {
|
||||||
|
message: "publicKey and privateKey are required when keySource is external",
|
||||||
|
path: ["publicKey"]
|
||||||
|
})
|
||||||
|
.refine((data) => data.keySource === SshCaKeySource.EXTERNAL || !!data.keyAlgorithm, {
|
||||||
|
message: "keyAlgorithm is required when keySource is internal",
|
||||||
|
path: ["keyAlgorithm"]
|
||||||
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
ca: sanitizedSshCa.extend({
|
ca: sanitizedSshCa.extend({
|
||||||
@@ -71,6 +94,8 @@ export const registerSshCaRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SshCertificateAuthorities],
|
||||||
description: "Get SSH CA",
|
description: "Get SSH CA",
|
||||||
params: z.object({
|
params: z.object({
|
||||||
sshCaId: z.string().trim().describe(SSH_CERTIFICATE_AUTHORITIES.GET.sshCaId)
|
sshCaId: z.string().trim().describe(SSH_CERTIFICATE_AUTHORITIES.GET.sshCaId)
|
||||||
@@ -117,6 +142,8 @@ export const registerSshCaRouter = async (server: FastifyZodProvider) => {
|
|||||||
rateLimit: readLimit
|
rateLimit: readLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SshCertificateAuthorities],
|
||||||
description: "Get public key of SSH CA",
|
description: "Get public key of SSH CA",
|
||||||
params: z.object({
|
params: z.object({
|
||||||
sshCaId: z.string().trim().describe(SSH_CERTIFICATE_AUTHORITIES.GET_PUBLIC_KEY.sshCaId)
|
sshCaId: z.string().trim().describe(SSH_CERTIFICATE_AUTHORITIES.GET_PUBLIC_KEY.sshCaId)
|
||||||
@@ -142,6 +169,8 @@ export const registerSshCaRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SshCertificateAuthorities],
|
||||||
description: "Update SSH CA",
|
description: "Update SSH CA",
|
||||||
params: z.object({
|
params: z.object({
|
||||||
sshCaId: z.string().trim().describe(SSH_CERTIFICATE_AUTHORITIES.UPDATE.sshCaId)
|
sshCaId: z.string().trim().describe(SSH_CERTIFICATE_AUTHORITIES.UPDATE.sshCaId)
|
||||||
@@ -195,6 +224,8 @@ export const registerSshCaRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SshCertificateAuthorities],
|
||||||
description: "Delete SSH CA",
|
description: "Delete SSH CA",
|
||||||
params: z.object({
|
params: z.object({
|
||||||
sshCaId: z.string().trim().describe(SSH_CERTIFICATE_AUTHORITIES.DELETE.sshCaId)
|
sshCaId: z.string().trim().describe(SSH_CERTIFICATE_AUTHORITIES.DELETE.sshCaId)
|
||||||
@@ -240,6 +271,8 @@ export const registerSshCaRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SshCertificateAuthorities],
|
||||||
description: "Get list of certificate templates for the SSH CA",
|
description: "Get list of certificate templates for the SSH CA",
|
||||||
params: z.object({
|
params: z.object({
|
||||||
sshCaId: z.string().trim().describe(SSH_CERTIFICATE_AUTHORITIES.GET_CERTIFICATE_TEMPLATES.sshCaId)
|
sshCaId: z.string().trim().describe(SSH_CERTIFICATE_AUTHORITIES.GET_CERTIFICATE_TEMPLATES.sshCaId)
|
||||||
|
@@ -2,13 +2,13 @@ import { z } from "zod";
|
|||||||
|
|
||||||
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { SshCertType } from "@app/ee/services/ssh/ssh-certificate-authority-types";
|
import { SshCertType } from "@app/ee/services/ssh/ssh-certificate-authority-types";
|
||||||
import { SSH_CERTIFICATE_AUTHORITIES } from "@app/lib/api-docs";
|
import { SshCertKeyAlgorithm } from "@app/ee/services/ssh-certificate/ssh-certificate-types";
|
||||||
|
import { ApiDocsTags, SSH_CERTIFICATE_AUTHORITIES } from "@app/lib/api-docs";
|
||||||
import { ms } from "@app/lib/ms";
|
import { ms } from "@app/lib/ms";
|
||||||
import { writeLimit } from "@app/server/config/rateLimiter";
|
import { writeLimit } from "@app/server/config/rateLimiter";
|
||||||
import { getTelemetryDistinctId } from "@app/server/lib/telemetry";
|
import { getTelemetryDistinctId } from "@app/server/lib/telemetry";
|
||||||
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";
|
||||||
import { CertKeyAlgorithm } from "@app/services/certificate/certificate-types";
|
|
||||||
import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
|
import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
|
||||||
|
|
||||||
export const registerSshCertRouter = async (server: FastifyZodProvider) => {
|
export const registerSshCertRouter = async (server: FastifyZodProvider) => {
|
||||||
@@ -20,6 +20,8 @@ export const registerSshCertRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SshCertificates],
|
||||||
description: "Sign SSH public key",
|
description: "Sign SSH public key",
|
||||||
body: z.object({
|
body: z.object({
|
||||||
certificateTemplateId: z
|
certificateTemplateId: z
|
||||||
@@ -100,6 +102,8 @@ export const registerSshCertRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SshCertificates],
|
||||||
description: "Issue SSH credentials (certificate + key)",
|
description: "Issue SSH credentials (certificate + key)",
|
||||||
body: z.object({
|
body: z.object({
|
||||||
certificateTemplateId: z
|
certificateTemplateId: z
|
||||||
@@ -108,8 +112,8 @@ export const registerSshCertRouter = async (server: FastifyZodProvider) => {
|
|||||||
.min(1)
|
.min(1)
|
||||||
.describe(SSH_CERTIFICATE_AUTHORITIES.ISSUE_SSH_CREDENTIALS.certificateTemplateId),
|
.describe(SSH_CERTIFICATE_AUTHORITIES.ISSUE_SSH_CREDENTIALS.certificateTemplateId),
|
||||||
keyAlgorithm: z
|
keyAlgorithm: z
|
||||||
.nativeEnum(CertKeyAlgorithm)
|
.nativeEnum(SshCertKeyAlgorithm)
|
||||||
.default(CertKeyAlgorithm.RSA_2048)
|
.default(SshCertKeyAlgorithm.ED25519)
|
||||||
.describe(SSH_CERTIFICATE_AUTHORITIES.ISSUE_SSH_CREDENTIALS.keyAlgorithm),
|
.describe(SSH_CERTIFICATE_AUTHORITIES.ISSUE_SSH_CREDENTIALS.keyAlgorithm),
|
||||||
certType: z
|
certType: z
|
||||||
.nativeEnum(SshCertType)
|
.nativeEnum(SshCertType)
|
||||||
@@ -133,7 +137,7 @@ export const registerSshCertRouter = async (server: FastifyZodProvider) => {
|
|||||||
privateKey: z.string().describe(SSH_CERTIFICATE_AUTHORITIES.ISSUE_SSH_CREDENTIALS.privateKey),
|
privateKey: z.string().describe(SSH_CERTIFICATE_AUTHORITIES.ISSUE_SSH_CREDENTIALS.privateKey),
|
||||||
publicKey: z.string().describe(SSH_CERTIFICATE_AUTHORITIES.ISSUE_SSH_CREDENTIALS.publicKey),
|
publicKey: z.string().describe(SSH_CERTIFICATE_AUTHORITIES.ISSUE_SSH_CREDENTIALS.publicKey),
|
||||||
keyAlgorithm: z
|
keyAlgorithm: z
|
||||||
.nativeEnum(CertKeyAlgorithm)
|
.nativeEnum(SshCertKeyAlgorithm)
|
||||||
.describe(SSH_CERTIFICATE_AUTHORITIES.ISSUE_SSH_CREDENTIALS.keyAlgorithm)
|
.describe(SSH_CERTIFICATE_AUTHORITIES.ISSUE_SSH_CREDENTIALS.keyAlgorithm)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@@ -8,7 +8,7 @@ import {
|
|||||||
isValidHostPattern,
|
isValidHostPattern,
|
||||||
isValidUserPattern
|
isValidUserPattern
|
||||||
} from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-validators";
|
} from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-validators";
|
||||||
import { SSH_CERTIFICATE_TEMPLATES } from "@app/lib/api-docs";
|
import { ApiDocsTags, SSH_CERTIFICATE_TEMPLATES } from "@app/lib/api-docs";
|
||||||
import { ms } from "@app/lib/ms";
|
import { ms } from "@app/lib/ms";
|
||||||
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
@@ -22,6 +22,8 @@ export const registerSshCertificateTemplateRouter = async (server: FastifyZodPro
|
|||||||
rateLimit: readLimit
|
rateLimit: readLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SshCertificateTemplates],
|
||||||
params: z.object({
|
params: z.object({
|
||||||
certificateTemplateId: z.string().describe(SSH_CERTIFICATE_TEMPLATES.GET.certificateTemplateId)
|
certificateTemplateId: z.string().describe(SSH_CERTIFICATE_TEMPLATES.GET.certificateTemplateId)
|
||||||
}),
|
}),
|
||||||
@@ -61,6 +63,8 @@ export const registerSshCertificateTemplateRouter = async (server: FastifyZodPro
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SshCertificateTemplates],
|
||||||
body: z
|
body: z
|
||||||
.object({
|
.object({
|
||||||
sshCaId: z.string().describe(SSH_CERTIFICATE_TEMPLATES.CREATE.sshCaId),
|
sshCaId: z.string().describe(SSH_CERTIFICATE_TEMPLATES.CREATE.sshCaId),
|
||||||
@@ -92,8 +96,8 @@ export const registerSshCertificateTemplateRouter = async (server: FastifyZodPro
|
|||||||
allowHostCertificates: z.boolean().describe(SSH_CERTIFICATE_TEMPLATES.CREATE.allowHostCertificates),
|
allowHostCertificates: z.boolean().describe(SSH_CERTIFICATE_TEMPLATES.CREATE.allowHostCertificates),
|
||||||
allowCustomKeyIds: z.boolean().describe(SSH_CERTIFICATE_TEMPLATES.CREATE.allowCustomKeyIds)
|
allowCustomKeyIds: z.boolean().describe(SSH_CERTIFICATE_TEMPLATES.CREATE.allowCustomKeyIds)
|
||||||
})
|
})
|
||||||
.refine((data) => ms(data.maxTTL) > ms(data.ttl), {
|
.refine((data) => ms(data.maxTTL) >= ms(data.ttl), {
|
||||||
message: "Max TLL must be greater than TTL",
|
message: "Max TLL must be greater than or equal to TTL",
|
||||||
path: ["maxTTL"]
|
path: ["maxTTL"]
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
@@ -141,6 +145,8 @@ export const registerSshCertificateTemplateRouter = async (server: FastifyZodPro
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SshCertificateTemplates],
|
||||||
body: z.object({
|
body: z.object({
|
||||||
status: z.nativeEnum(SshCertTemplateStatus).optional(),
|
status: z.nativeEnum(SshCertTemplateStatus).optional(),
|
||||||
name: z
|
name: z
|
||||||
@@ -224,6 +230,8 @@ export const registerSshCertificateTemplateRouter = async (server: FastifyZodPro
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SshCertificateTemplates],
|
||||||
params: z.object({
|
params: z.object({
|
||||||
certificateTemplateId: z.string().describe(SSH_CERTIFICATE_TEMPLATES.DELETE.certificateTemplateId)
|
certificateTemplateId: z.string().describe(SSH_CERTIFICATE_TEMPLATES.DELETE.certificateTemplateId)
|
||||||
}),
|
}),
|
||||||
|
444
backend/src/ee/routes/v1/ssh-host-router.ts
Normal file
444
backend/src/ee/routes/v1/ssh-host-router.ts
Normal file
@@ -0,0 +1,444 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
|
import { SshCertKeyAlgorithm } from "@app/ee/services/ssh-certificate/ssh-certificate-types";
|
||||||
|
import { loginMappingSchema, sanitizedSshHost } from "@app/ee/services/ssh-host/ssh-host-schema";
|
||||||
|
import { isValidHostname } from "@app/ee/services/ssh-host/ssh-host-validators";
|
||||||
|
import { SSH_HOSTS } from "@app/lib/api-docs";
|
||||||
|
import { ms } from "@app/lib/ms";
|
||||||
|
import { publicSshCaLimit, readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
|
import { getTelemetryDistinctId } from "@app/server/lib/telemetry";
|
||||||
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
|
||||||
|
|
||||||
|
export const registerSshHostRouter = async (server: FastifyZodProvider) => {
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/",
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
response: {
|
||||||
|
200: z.array(
|
||||||
|
sanitizedSshHost.extend({
|
||||||
|
loginMappings: z.array(loginMappingSchema)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const hosts = await server.services.sshHost.listSshHosts({
|
||||||
|
actor: req.permission.type,
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actorAuthMethod: req.permission.authMethod,
|
||||||
|
actorOrgId: req.permission.orgId
|
||||||
|
});
|
||||||
|
|
||||||
|
return hosts;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/:sshHostId",
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
sshHostId: z.string().describe(SSH_HOSTS.GET.sshHostId)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: sanitizedSshHost.extend({
|
||||||
|
loginMappings: z.array(loginMappingSchema)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const host = await server.services.sshHost.getSshHost({
|
||||||
|
sshHostId: req.params.sshHostId,
|
||||||
|
actor: req.permission.type,
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actorAuthMethod: req.permission.authMethod,
|
||||||
|
actorOrgId: req.permission.orgId
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: host.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.GET_SSH_HOST,
|
||||||
|
metadata: {
|
||||||
|
sshHostId: host.id,
|
||||||
|
hostname: host.hostname
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "Add an SSH Host",
|
||||||
|
body: z.object({
|
||||||
|
projectId: z.string().describe(SSH_HOSTS.CREATE.projectId),
|
||||||
|
hostname: z
|
||||||
|
.string()
|
||||||
|
.min(1)
|
||||||
|
.refine((v) => isValidHostname(v), {
|
||||||
|
message: "Hostname must be a valid hostname"
|
||||||
|
})
|
||||||
|
.describe(SSH_HOSTS.CREATE.hostname),
|
||||||
|
userCertTtl: z
|
||||||
|
.string()
|
||||||
|
.refine((val) => ms(val) > 0, "TTL must be a positive number")
|
||||||
|
.default("8h")
|
||||||
|
.describe(SSH_HOSTS.CREATE.userCertTtl),
|
||||||
|
hostCertTtl: z
|
||||||
|
.string()
|
||||||
|
.refine((val) => ms(val) > 0, "TTL must be a positive number")
|
||||||
|
.default("1y")
|
||||||
|
.describe(SSH_HOSTS.CREATE.hostCertTtl),
|
||||||
|
loginMappings: z.array(loginMappingSchema).default([]).describe(SSH_HOSTS.CREATE.loginMappings),
|
||||||
|
userSshCaId: z.string().describe(SSH_HOSTS.CREATE.userSshCaId).optional(),
|
||||||
|
hostSshCaId: z.string().describe(SSH_HOSTS.CREATE.hostSshCaId).optional()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: sanitizedSshHost.extend({
|
||||||
|
loginMappings: z.array(loginMappingSchema)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const host = await server.services.sshHost.createSshHost({
|
||||||
|
...req.body,
|
||||||
|
actor: req.permission.type,
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actorAuthMethod: req.permission.authMethod,
|
||||||
|
actorOrgId: req.permission.orgId
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: host.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.CREATE_SSH_HOST,
|
||||||
|
metadata: {
|
||||||
|
sshHostId: host.id,
|
||||||
|
hostname: host.hostname,
|
||||||
|
userCertTtl: host.userCertTtl,
|
||||||
|
hostCertTtl: host.hostCertTtl,
|
||||||
|
loginMappings: host.loginMappings,
|
||||||
|
userSshCaId: host.userSshCaId,
|
||||||
|
hostSshCaId: host.hostSshCaId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "PATCH",
|
||||||
|
url: "/:sshHostId",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
schema: {
|
||||||
|
description: "Update SSH Host",
|
||||||
|
params: z.object({
|
||||||
|
sshHostId: z.string().trim().describe(SSH_HOSTS.UPDATE.sshHostId)
|
||||||
|
}),
|
||||||
|
body: z.object({
|
||||||
|
hostname: z
|
||||||
|
.string()
|
||||||
|
.min(1)
|
||||||
|
.refine((v) => isValidHostname(v), {
|
||||||
|
message: "Hostname must be a valid hostname"
|
||||||
|
})
|
||||||
|
.optional()
|
||||||
|
.describe(SSH_HOSTS.UPDATE.hostname),
|
||||||
|
userCertTtl: z
|
||||||
|
.string()
|
||||||
|
.refine((val) => ms(val) > 0, "TTL must be a positive number")
|
||||||
|
.optional()
|
||||||
|
.describe(SSH_HOSTS.UPDATE.userCertTtl),
|
||||||
|
hostCertTtl: z
|
||||||
|
.string()
|
||||||
|
.refine((val) => ms(val) > 0, "TTL must be a positive number")
|
||||||
|
.optional()
|
||||||
|
.describe(SSH_HOSTS.UPDATE.hostCertTtl),
|
||||||
|
loginMappings: z.array(loginMappingSchema).optional().describe(SSH_HOSTS.UPDATE.loginMappings)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: sanitizedSshHost.extend({
|
||||||
|
loginMappings: z.array(loginMappingSchema)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler: async (req) => {
|
||||||
|
const host = await server.services.sshHost.updateSshHost({
|
||||||
|
sshHostId: req.params.sshHostId,
|
||||||
|
actor: req.permission.type,
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actorAuthMethod: req.permission.authMethod,
|
||||||
|
actorOrgId: req.permission.orgId,
|
||||||
|
...req.body
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: host.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.UPDATE_SSH_HOST,
|
||||||
|
metadata: {
|
||||||
|
sshHostId: host.id,
|
||||||
|
hostname: host.hostname,
|
||||||
|
userCertTtl: host.userCertTtl,
|
||||||
|
hostCertTtl: host.hostCertTtl,
|
||||||
|
loginMappings: host.loginMappings,
|
||||||
|
userSshCaId: host.userSshCaId,
|
||||||
|
hostSshCaId: host.hostSshCaId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "DELETE",
|
||||||
|
url: "/:sshHostId",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
sshHostId: z.string().describe(SSH_HOSTS.DELETE.sshHostId)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: sanitizedSshHost.extend({
|
||||||
|
loginMappings: z.array(loginMappingSchema)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const host = await server.services.sshHost.deleteSshHost({
|
||||||
|
sshHostId: req.params.sshHostId,
|
||||||
|
actor: req.permission.type,
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actorAuthMethod: req.permission.authMethod,
|
||||||
|
actorOrgId: req.permission.orgId
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: host.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.DELETE_SSH_HOST,
|
||||||
|
metadata: {
|
||||||
|
sshHostId: host.id,
|
||||||
|
hostname: host.hostname
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/:sshHostId/issue-user-cert",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
schema: {
|
||||||
|
description: "Issue SSH certificate for user",
|
||||||
|
params: z.object({
|
||||||
|
sshHostId: z.string().describe(SSH_HOSTS.ISSUE_SSH_CREDENTIALS.sshHostId)
|
||||||
|
}),
|
||||||
|
body: z.object({
|
||||||
|
loginUser: z.string().describe(SSH_HOSTS.ISSUE_SSH_CREDENTIALS.loginUser)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
serialNumber: z.string().describe(SSH_HOSTS.ISSUE_SSH_CREDENTIALS.serialNumber),
|
||||||
|
signedKey: z.string().describe(SSH_HOSTS.ISSUE_SSH_CREDENTIALS.signedKey),
|
||||||
|
privateKey: z.string().describe(SSH_HOSTS.ISSUE_SSH_CREDENTIALS.privateKey),
|
||||||
|
publicKey: z.string().describe(SSH_HOSTS.ISSUE_SSH_CREDENTIALS.publicKey),
|
||||||
|
keyAlgorithm: z.nativeEnum(SshCertKeyAlgorithm).describe(SSH_HOSTS.ISSUE_SSH_CREDENTIALS.keyAlgorithm)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler: async (req) => {
|
||||||
|
const { serialNumber, signedPublicKey, privateKey, publicKey, keyAlgorithm, host, principals } =
|
||||||
|
await server.services.sshHost.issueSshHostUserCert({
|
||||||
|
sshHostId: req.params.sshHostId,
|
||||||
|
loginUser: req.body.loginUser,
|
||||||
|
actor: req.permission.type,
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actorAuthMethod: req.permission.authMethod,
|
||||||
|
actorOrgId: req.permission.orgId
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
event: {
|
||||||
|
type: EventType.ISSUE_SSH_HOST_USER_CERT,
|
||||||
|
metadata: {
|
||||||
|
sshHostId: req.params.sshHostId,
|
||||||
|
hostname: host.hostname,
|
||||||
|
loginUser: req.body.loginUser,
|
||||||
|
principals,
|
||||||
|
ttl: host.userCertTtl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.telemetry.sendPostHogEvents({
|
||||||
|
event: PostHogEventTypes.IssueSshHostUserCert,
|
||||||
|
distinctId: getTelemetryDistinctId(req),
|
||||||
|
properties: {
|
||||||
|
sshHostId: req.params.sshHostId,
|
||||||
|
hostname: host.hostname,
|
||||||
|
principals,
|
||||||
|
...req.auditLogInfo
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
serialNumber,
|
||||||
|
signedKey: signedPublicKey,
|
||||||
|
privateKey,
|
||||||
|
publicKey,
|
||||||
|
keyAlgorithm
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/:sshHostId/issue-host-cert",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
schema: {
|
||||||
|
description: "Issue SSH certificate for host",
|
||||||
|
params: z.object({
|
||||||
|
sshHostId: z.string().describe(SSH_HOSTS.ISSUE_HOST_CERT.sshHostId)
|
||||||
|
}),
|
||||||
|
body: z.object({
|
||||||
|
publicKey: z.string().describe(SSH_HOSTS.ISSUE_HOST_CERT.publicKey)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
serialNumber: z.string().describe(SSH_HOSTS.ISSUE_HOST_CERT.serialNumber),
|
||||||
|
signedKey: z.string().describe(SSH_HOSTS.ISSUE_HOST_CERT.signedKey)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler: async (req) => {
|
||||||
|
const { host, principals, serialNumber, signedPublicKey } = await server.services.sshHost.issueSshHostHostCert({
|
||||||
|
sshHostId: req.params.sshHostId,
|
||||||
|
publicKey: req.body.publicKey,
|
||||||
|
actor: req.permission.type,
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actorAuthMethod: req.permission.authMethod,
|
||||||
|
actorOrgId: req.permission.orgId
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
event: {
|
||||||
|
type: EventType.ISSUE_SSH_HOST_HOST_CERT,
|
||||||
|
metadata: {
|
||||||
|
sshHostId: req.params.sshHostId,
|
||||||
|
hostname: host.hostname,
|
||||||
|
principals,
|
||||||
|
serialNumber,
|
||||||
|
ttl: host.hostCertTtl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.telemetry.sendPostHogEvents({
|
||||||
|
event: PostHogEventTypes.IssueSshHostHostCert,
|
||||||
|
distinctId: getTelemetryDistinctId(req),
|
||||||
|
properties: {
|
||||||
|
sshHostId: req.params.sshHostId,
|
||||||
|
hostname: host.hostname,
|
||||||
|
principals,
|
||||||
|
...req.auditLogInfo
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
serialNumber,
|
||||||
|
signedKey: signedPublicKey
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/:sshHostId/user-ca-public-key",
|
||||||
|
config: {
|
||||||
|
rateLimit: publicSshCaLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "Get public key of the user SSH CA linked to the host",
|
||||||
|
params: z.object({
|
||||||
|
sshHostId: z.string().trim().describe(SSH_HOSTS.GET_USER_CA_PUBLIC_KEY.sshHostId)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.string().describe(SSH_HOSTS.GET_USER_CA_PUBLIC_KEY.publicKey)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler: async (req) => {
|
||||||
|
const publicKey = await server.services.sshHost.getSshHostUserCaPk(req.params.sshHostId);
|
||||||
|
return publicKey;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/:sshHostId/host-ca-public-key",
|
||||||
|
config: {
|
||||||
|
rateLimit: publicSshCaLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "Get public key of the host SSH CA linked to the host",
|
||||||
|
params: z.object({
|
||||||
|
sshHostId: z.string().trim().describe(SSH_HOSTS.GET_HOST_CA_PUBLIC_KEY.sshHostId)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.string().describe(SSH_HOSTS.GET_HOST_CA_PUBLIC_KEY.publicKey)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler: async (req) => {
|
||||||
|
const publicKey = await server.services.sshHost.getSshHostHostCaPk(req.params.sshHostId);
|
||||||
|
return publicKey;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
@@ -4,7 +4,7 @@ import { z } from "zod";
|
|||||||
import { IdentityProjectAdditionalPrivilegeTemporaryMode } from "@app/ee/services/identity-project-additional-privilege-v2/identity-project-additional-privilege-v2-types";
|
import { IdentityProjectAdditionalPrivilegeTemporaryMode } from "@app/ee/services/identity-project-additional-privilege-v2/identity-project-additional-privilege-v2-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";
|
||||||
import { IDENTITY_ADDITIONAL_PRIVILEGE_V2 } from "@app/lib/api-docs";
|
import { ApiDocsTags, IDENTITY_ADDITIONAL_PRIVILEGE_V2 } from "@app/lib/api-docs";
|
||||||
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";
|
||||||
@@ -21,6 +21,8 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.IdentitySpecificPrivilegesV2],
|
||||||
description: "Add an additional privilege for identity.",
|
description: "Add an additional privilege for identity.",
|
||||||
security: [
|
security: [
|
||||||
{
|
{
|
||||||
@@ -84,6 +86,8 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.IdentitySpecificPrivilegesV2],
|
||||||
description: "Update a specific identity privilege.",
|
description: "Update a specific identity privilege.",
|
||||||
security: [
|
security: [
|
||||||
{
|
{
|
||||||
@@ -148,6 +152,8 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.IdentitySpecificPrivilegesV2],
|
||||||
description: "Delete the specified identity privilege.",
|
description: "Delete the specified identity privilege.",
|
||||||
security: [
|
security: [
|
||||||
{
|
{
|
||||||
@@ -183,6 +189,8 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
rateLimit: readLimit
|
rateLimit: readLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.IdentitySpecificPrivilegesV2],
|
||||||
description: "Retrieve details of a specific privilege by id.",
|
description: "Retrieve details of a specific privilege by id.",
|
||||||
security: [
|
security: [
|
||||||
{
|
{
|
||||||
@@ -218,6 +226,8 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
rateLimit: readLimit
|
rateLimit: readLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.IdentitySpecificPrivilegesV2],
|
||||||
description: "Retrieve details of a specific privilege by slug.",
|
description: "Retrieve details of a specific privilege by slug.",
|
||||||
security: [
|
security: [
|
||||||
{
|
{
|
||||||
@@ -258,6 +268,8 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
rateLimit: readLimit
|
rateLimit: readLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.IdentitySpecificPrivilegesV2],
|
||||||
description: "List privileges for the specified identity by project.",
|
description: "List privileges for the specified identity by project.",
|
||||||
security: [
|
security: [
|
||||||
{
|
{
|
||||||
|
@@ -1,3 +1,8 @@
|
|||||||
|
import {
|
||||||
|
registerSecretRotationV2Router,
|
||||||
|
SECRET_ROTATION_REGISTER_ROUTER_MAP
|
||||||
|
} from "@app/ee/routes/v2/secret-rotation-v2-routers";
|
||||||
|
|
||||||
import { registerIdentityProjectAdditionalPrivilegeRouter } from "./identity-project-additional-privilege-router";
|
import { registerIdentityProjectAdditionalPrivilegeRouter } from "./identity-project-additional-privilege-router";
|
||||||
import { registerProjectRoleRouter } from "./project-role-router";
|
import { registerProjectRoleRouter } from "./project-role-router";
|
||||||
|
|
||||||
@@ -13,4 +18,17 @@ export const registerV2EERoutes = async (server: FastifyZodProvider) => {
|
|||||||
await server.register(registerIdentityProjectAdditionalPrivilegeRouter, {
|
await server.register(registerIdentityProjectAdditionalPrivilegeRouter, {
|
||||||
prefix: "/identity-project-additional-privilege"
|
prefix: "/identity-project-additional-privilege"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.register(
|
||||||
|
async (secretRotationV2Router) => {
|
||||||
|
// register generic secret rotation endpoints
|
||||||
|
await secretRotationV2Router.register(registerSecretRotationV2Router);
|
||||||
|
|
||||||
|
// register service specific secret rotation endpoints (secret-rotations/postgres-credentials, etc.)
|
||||||
|
for await (const [type, router] of Object.entries(SECRET_ROTATION_REGISTER_ROUTER_MAP)) {
|
||||||
|
await secretRotationV2Router.register(router, { prefix: `/${type}` });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ prefix: "/secret-rotations" }
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
@@ -4,7 +4,7 @@ import { z } from "zod";
|
|||||||
import { ProjectMembershipRole, ProjectRolesSchema } from "@app/db/schemas";
|
import { ProjectMembershipRole, ProjectRolesSchema } 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 { PROJECT_ROLE } from "@app/lib/api-docs";
|
import { ApiDocsTags, PROJECT_ROLE } from "@app/lib/api-docs";
|
||||||
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";
|
||||||
@@ -20,6 +20,8 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.ProjectRoles],
|
||||||
description: "Create a project role",
|
description: "Create a project role",
|
||||||
security: [
|
security: [
|
||||||
{
|
{
|
||||||
@@ -75,6 +77,8 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.ProjectRoles],
|
||||||
description: "Update a project role",
|
description: "Update a project role",
|
||||||
security: [
|
security: [
|
||||||
{
|
{
|
||||||
@@ -130,6 +134,8 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.ProjectRoles],
|
||||||
description: "Delete a project role",
|
description: "Delete a project role",
|
||||||
security: [
|
security: [
|
||||||
{
|
{
|
||||||
@@ -166,6 +172,8 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
rateLimit: readLimit
|
rateLimit: readLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.ProjectRoles],
|
||||||
description: "List project role",
|
description: "List project role",
|
||||||
security: [
|
security: [
|
||||||
{
|
{
|
||||||
@@ -204,6 +212,8 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
rateLimit: readLimit
|
rateLimit: readLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.ProjectRoles],
|
||||||
params: z.object({
|
params: z.object({
|
||||||
projectId: z.string().trim().describe(PROJECT_ROLE.GET_ROLE_BY_SLUG.projectId),
|
projectId: z.string().trim().describe(PROJECT_ROLE.GET_ROLE_BY_SLUG.projectId),
|
||||||
roleSlug: z.string().trim().describe(PROJECT_ROLE.GET_ROLE_BY_SLUG.roleSlug)
|
roleSlug: z.string().trim().describe(PROJECT_ROLE.GET_ROLE_BY_SLUG.roleSlug)
|
||||||
|
@@ -0,0 +1,19 @@
|
|||||||
|
import {
|
||||||
|
Auth0ClientSecretRotationGeneratedCredentialsSchema,
|
||||||
|
Auth0ClientSecretRotationSchema,
|
||||||
|
CreateAuth0ClientSecretRotationSchema,
|
||||||
|
UpdateAuth0ClientSecretRotationSchema
|
||||||
|
} from "@app/ee/services/secret-rotation-v2/auth0-client-secret";
|
||||||
|
import { SecretRotation } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-enums";
|
||||||
|
|
||||||
|
import { registerSecretRotationEndpoints } from "./secret-rotation-v2-endpoints";
|
||||||
|
|
||||||
|
export const registerAuth0ClientSecretRotationRouter = async (server: FastifyZodProvider) =>
|
||||||
|
registerSecretRotationEndpoints({
|
||||||
|
type: SecretRotation.Auth0ClientSecret,
|
||||||
|
server,
|
||||||
|
responseSchema: Auth0ClientSecretRotationSchema,
|
||||||
|
createSchema: CreateAuth0ClientSecretRotationSchema,
|
||||||
|
updateSchema: UpdateAuth0ClientSecretRotationSchema,
|
||||||
|
generatedCredentialsSchema: Auth0ClientSecretRotationGeneratedCredentialsSchema
|
||||||
|
});
|
16
backend/src/ee/routes/v2/secret-rotation-v2-routers/index.ts
Normal file
16
backend/src/ee/routes/v2/secret-rotation-v2-routers/index.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { SecretRotation } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-enums";
|
||||||
|
|
||||||
|
import { registerAuth0ClientSecretRotationRouter } from "./auth0-client-secret-rotation-router";
|
||||||
|
import { registerMsSqlCredentialsRotationRouter } from "./mssql-credentials-rotation-router";
|
||||||
|
import { registerPostgresCredentialsRotationRouter } from "./postgres-credentials-rotation-router";
|
||||||
|
|
||||||
|
export * from "./secret-rotation-v2-router";
|
||||||
|
|
||||||
|
export const SECRET_ROTATION_REGISTER_ROUTER_MAP: Record<
|
||||||
|
SecretRotation,
|
||||||
|
(server: FastifyZodProvider) => Promise<void>
|
||||||
|
> = {
|
||||||
|
[SecretRotation.PostgresCredentials]: registerPostgresCredentialsRotationRouter,
|
||||||
|
[SecretRotation.MsSqlCredentials]: registerMsSqlCredentialsRotationRouter,
|
||||||
|
[SecretRotation.Auth0ClientSecret]: registerAuth0ClientSecretRotationRouter
|
||||||
|
};
|
@@ -0,0 +1,19 @@
|
|||||||
|
import {
|
||||||
|
CreateMsSqlCredentialsRotationSchema,
|
||||||
|
MsSqlCredentialsRotationSchema,
|
||||||
|
UpdateMsSqlCredentialsRotationSchema
|
||||||
|
} from "@app/ee/services/secret-rotation-v2/mssql-credentials";
|
||||||
|
import { SecretRotation } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-enums";
|
||||||
|
import { SqlCredentialsRotationGeneratedCredentialsSchema } from "@app/ee/services/secret-rotation-v2/shared/sql-credentials";
|
||||||
|
|
||||||
|
import { registerSecretRotationEndpoints } from "./secret-rotation-v2-endpoints";
|
||||||
|
|
||||||
|
export const registerMsSqlCredentialsRotationRouter = async (server: FastifyZodProvider) =>
|
||||||
|
registerSecretRotationEndpoints({
|
||||||
|
type: SecretRotation.MsSqlCredentials,
|
||||||
|
server,
|
||||||
|
responseSchema: MsSqlCredentialsRotationSchema,
|
||||||
|
createSchema: CreateMsSqlCredentialsRotationSchema,
|
||||||
|
updateSchema: UpdateMsSqlCredentialsRotationSchema,
|
||||||
|
generatedCredentialsSchema: SqlCredentialsRotationGeneratedCredentialsSchema
|
||||||
|
});
|
@@ -0,0 +1,19 @@
|
|||||||
|
import {
|
||||||
|
CreatePostgresCredentialsRotationSchema,
|
||||||
|
PostgresCredentialsRotationSchema,
|
||||||
|
UpdatePostgresCredentialsRotationSchema
|
||||||
|
} from "@app/ee/services/secret-rotation-v2/postgres-credentials";
|
||||||
|
import { SecretRotation } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-enums";
|
||||||
|
import { SqlCredentialsRotationGeneratedCredentialsSchema } from "@app/ee/services/secret-rotation-v2/shared/sql-credentials";
|
||||||
|
|
||||||
|
import { registerSecretRotationEndpoints } from "./secret-rotation-v2-endpoints";
|
||||||
|
|
||||||
|
export const registerPostgresCredentialsRotationRouter = async (server: FastifyZodProvider) =>
|
||||||
|
registerSecretRotationEndpoints({
|
||||||
|
type: SecretRotation.PostgresCredentials,
|
||||||
|
server,
|
||||||
|
responseSchema: PostgresCredentialsRotationSchema,
|
||||||
|
createSchema: CreatePostgresCredentialsRotationSchema,
|
||||||
|
updateSchema: UpdatePostgresCredentialsRotationSchema,
|
||||||
|
generatedCredentialsSchema: SqlCredentialsRotationGeneratedCredentialsSchema
|
||||||
|
});
|
@@ -0,0 +1,445 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
|
import { SecretRotation } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-enums";
|
||||||
|
import { SECRET_ROTATION_NAME_MAP } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-maps";
|
||||||
|
import {
|
||||||
|
TRotateAtUtc,
|
||||||
|
TSecretRotationV2,
|
||||||
|
TSecretRotationV2GeneratedCredentials,
|
||||||
|
TSecretRotationV2Input
|
||||||
|
} from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-types";
|
||||||
|
import { ApiDocsTags, SecretRotations } from "@app/lib/api-docs";
|
||||||
|
import { startsWithVowel } from "@app/lib/fn";
|
||||||
|
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 registerSecretRotationEndpoints = <
|
||||||
|
T extends TSecretRotationV2,
|
||||||
|
I extends TSecretRotationV2Input,
|
||||||
|
C extends TSecretRotationV2GeneratedCredentials
|
||||||
|
>({
|
||||||
|
server,
|
||||||
|
type,
|
||||||
|
createSchema,
|
||||||
|
updateSchema,
|
||||||
|
responseSchema,
|
||||||
|
generatedCredentialsSchema
|
||||||
|
}: {
|
||||||
|
type: SecretRotation;
|
||||||
|
server: FastifyZodProvider;
|
||||||
|
createSchema: z.ZodType<{
|
||||||
|
name: string;
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
projectId: string;
|
||||||
|
connectionId: string;
|
||||||
|
parameters: I["parameters"];
|
||||||
|
secretsMapping: I["secretsMapping"];
|
||||||
|
description?: string | null;
|
||||||
|
isAutoRotationEnabled?: boolean;
|
||||||
|
rotationInterval: number;
|
||||||
|
rotateAtUtc?: TRotateAtUtc;
|
||||||
|
}>;
|
||||||
|
updateSchema: z.ZodType<{
|
||||||
|
connectionId?: string;
|
||||||
|
name?: string;
|
||||||
|
environment?: string;
|
||||||
|
secretPath?: string;
|
||||||
|
parameters?: I["parameters"];
|
||||||
|
secretsMapping?: I["secretsMapping"];
|
||||||
|
description?: string | null;
|
||||||
|
isAutoRotationEnabled?: boolean;
|
||||||
|
rotationInterval?: number;
|
||||||
|
rotateAtUtc?: TRotateAtUtc;
|
||||||
|
}>;
|
||||||
|
responseSchema: z.ZodTypeAny;
|
||||||
|
generatedCredentialsSchema: z.ZodTypeAny;
|
||||||
|
}) => {
|
||||||
|
const rotationType = SECRET_ROTATION_NAME_MAP[type];
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: `/`,
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SecretRotations],
|
||||||
|
description: `List the ${rotationType} Rotations for the specified project.`,
|
||||||
|
querystring: z.object({
|
||||||
|
projectId: z.string().trim().min(1, "Project ID required").describe(SecretRotations.LIST(type).projectId)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({ secretRotations: responseSchema.array() })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const {
|
||||||
|
query: { projectId }
|
||||||
|
} = req;
|
||||||
|
|
||||||
|
const secretRotations = (await server.services.secretRotationV2.listSecretRotationsByProjectId(
|
||||||
|
{ projectId, type },
|
||||||
|
req.permission
|
||||||
|
)) as T[];
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.GET_SECRET_ROTATIONS,
|
||||||
|
metadata: {
|
||||||
|
type,
|
||||||
|
count: secretRotations.length,
|
||||||
|
rotationIds: secretRotations.map((rotation) => rotation.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { secretRotations };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/:rotationId",
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SecretRotations],
|
||||||
|
description: `Get the specified ${rotationType} Rotation by ID.`,
|
||||||
|
params: z.object({
|
||||||
|
rotationId: z.string().uuid().describe(SecretRotations.GET_BY_ID(type).rotationId)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({ secretRotation: responseSchema })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const { rotationId } = req.params;
|
||||||
|
|
||||||
|
const secretRotation = (await server.services.secretRotationV2.findSecretRotationById(
|
||||||
|
{ rotationId, type },
|
||||||
|
req.permission
|
||||||
|
)) as T;
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: secretRotation.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.GET_SECRET_ROTATION,
|
||||||
|
metadata: {
|
||||||
|
rotationId,
|
||||||
|
type,
|
||||||
|
secretPath: secretRotation.folder.path,
|
||||||
|
environment: secretRotation.environment.slug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { secretRotation };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: `/rotation-name/:rotationName`,
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SecretRotations],
|
||||||
|
description: `Get the specified ${rotationType} Rotation by name, secret path, environment and project ID.`,
|
||||||
|
params: z.object({
|
||||||
|
rotationName: z
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.min(1, "Rotation name required")
|
||||||
|
.describe(SecretRotations.GET_BY_NAME(type).rotationName)
|
||||||
|
}),
|
||||||
|
querystring: z.object({
|
||||||
|
projectId: z
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.min(1, "Project ID required")
|
||||||
|
.describe(SecretRotations.GET_BY_NAME(type).projectId),
|
||||||
|
secretPath: z
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.min(1, "Secret path required")
|
||||||
|
.describe(SecretRotations.GET_BY_NAME(type).secretPath),
|
||||||
|
environment: z
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.min(1, "Environment required")
|
||||||
|
.describe(SecretRotations.GET_BY_NAME(type).environment)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({ secretRotation: responseSchema })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const { rotationName } = req.params;
|
||||||
|
const { projectId, secretPath, environment } = req.query;
|
||||||
|
|
||||||
|
const secretRotation = (await server.services.secretRotationV2.findSecretRotationByName(
|
||||||
|
{ rotationName, projectId, type, secretPath, environment },
|
||||||
|
req.permission
|
||||||
|
)) as T;
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.GET_SECRET_ROTATION,
|
||||||
|
metadata: {
|
||||||
|
rotationId: secretRotation.id,
|
||||||
|
type,
|
||||||
|
secretPath,
|
||||||
|
environment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { secretRotation };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SecretRotations],
|
||||||
|
description: `Create ${
|
||||||
|
startsWithVowel(rotationType) ? "an" : "a"
|
||||||
|
} ${rotationType} Rotation for the specified project.`,
|
||||||
|
body: createSchema,
|
||||||
|
response: {
|
||||||
|
200: z.object({ secretRotation: responseSchema })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const secretRotation = (await server.services.secretRotationV2.createSecretRotation(
|
||||||
|
{ ...req.body, type },
|
||||||
|
req.permission
|
||||||
|
)) as T;
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: secretRotation.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.CREATE_SECRET_ROTATION,
|
||||||
|
metadata: {
|
||||||
|
rotationId: secretRotation.id,
|
||||||
|
type,
|
||||||
|
...req.body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { secretRotation };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "PATCH",
|
||||||
|
url: "/:rotationId",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SecretRotations],
|
||||||
|
description: `Update the specified ${rotationType} Rotation.`,
|
||||||
|
params: z.object({
|
||||||
|
rotationId: z.string().uuid().describe(SecretRotations.UPDATE(type).rotationId)
|
||||||
|
}),
|
||||||
|
body: updateSchema,
|
||||||
|
response: {
|
||||||
|
200: z.object({ secretRotation: responseSchema })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const { rotationId } = req.params;
|
||||||
|
|
||||||
|
const secretRotation = (await server.services.secretRotationV2.updateSecretRotation(
|
||||||
|
{ ...req.body, rotationId, type },
|
||||||
|
req.permission
|
||||||
|
)) as T;
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: secretRotation.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.UPDATE_SECRET_ROTATION,
|
||||||
|
metadata: {
|
||||||
|
rotationId,
|
||||||
|
type,
|
||||||
|
...req.body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { secretRotation };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "DELETE",
|
||||||
|
url: `/:rotationId`,
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SecretRotations],
|
||||||
|
description: `Delete the specified ${rotationType} Rotation.`,
|
||||||
|
params: z.object({
|
||||||
|
rotationId: z.string().uuid().describe(SecretRotations.DELETE(type).rotationId)
|
||||||
|
}),
|
||||||
|
querystring: z.object({
|
||||||
|
deleteSecrets: z
|
||||||
|
.enum(["true", "false"])
|
||||||
|
.transform((value) => value === "true")
|
||||||
|
.describe(SecretRotations.DELETE(type).deleteSecrets),
|
||||||
|
revokeGeneratedCredentials: z
|
||||||
|
.enum(["true", "false"])
|
||||||
|
.transform((value) => value === "true")
|
||||||
|
.describe(SecretRotations.DELETE(type).revokeGeneratedCredentials)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({ secretRotation: responseSchema })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const { rotationId } = req.params;
|
||||||
|
const { deleteSecrets, revokeGeneratedCredentials } = req.query;
|
||||||
|
|
||||||
|
const secretRotation = (await server.services.secretRotationV2.deleteSecretRotation(
|
||||||
|
{ type, rotationId, deleteSecrets, revokeGeneratedCredentials },
|
||||||
|
req.permission
|
||||||
|
)) as T;
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: secretRotation.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.DELETE_SECRET_ROTATION,
|
||||||
|
metadata: {
|
||||||
|
type,
|
||||||
|
rotationId,
|
||||||
|
deleteSecrets,
|
||||||
|
revokeGeneratedCredentials
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { secretRotation };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/:rotationId/generated-credentials",
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SecretRotations],
|
||||||
|
description: `Get the generated credentials for the specified ${rotationType} Rotation.`,
|
||||||
|
params: z.object({
|
||||||
|
rotationId: z.string().uuid().describe(SecretRotations.GET_GENERATED_CREDENTIALS_BY_ID(type).rotationId)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
generatedCredentials: generatedCredentialsSchema,
|
||||||
|
activeIndex: z.number(),
|
||||||
|
rotationId: z.string().uuid(),
|
||||||
|
type: z.literal(type)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const { rotationId } = req.params;
|
||||||
|
|
||||||
|
const {
|
||||||
|
generatedCredentials,
|
||||||
|
secretRotation: { activeIndex, projectId, folder, environment }
|
||||||
|
} = await server.services.secretRotationV2.findSecretRotationGeneratedCredentialsById(
|
||||||
|
{
|
||||||
|
rotationId,
|
||||||
|
type
|
||||||
|
},
|
||||||
|
req.permission
|
||||||
|
);
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.GET_SECRET_ROTATION_GENERATED_CREDENTIALS,
|
||||||
|
metadata: {
|
||||||
|
type,
|
||||||
|
rotationId,
|
||||||
|
secretPath: folder.path,
|
||||||
|
environment: environment.slug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { generatedCredentials: generatedCredentials as C, activeIndex, rotationId, type };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/:rotationId/rotate-secrets",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SecretRotations],
|
||||||
|
description: `Rotate the generated credentials for the specified ${rotationType} Rotation.`,
|
||||||
|
params: z.object({
|
||||||
|
rotationId: z.string().uuid().describe(SecretRotations.ROTATE(type).rotationId)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({ secretRotation: responseSchema })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const { rotationId } = req.params;
|
||||||
|
|
||||||
|
const secretRotation = (await server.services.secretRotationV2.rotateSecretRotation(
|
||||||
|
{
|
||||||
|
rotationId,
|
||||||
|
type,
|
||||||
|
auditLogInfo: req.auditLogInfo
|
||||||
|
},
|
||||||
|
req.permission
|
||||||
|
)) as T;
|
||||||
|
|
||||||
|
return { secretRotation };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
@@ -0,0 +1,87 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
|
import { Auth0ClientSecretRotationListItemSchema } from "@app/ee/services/secret-rotation-v2/auth0-client-secret";
|
||||||
|
import { MsSqlCredentialsRotationListItemSchema } from "@app/ee/services/secret-rotation-v2/mssql-credentials";
|
||||||
|
import { PostgresCredentialsRotationListItemSchema } from "@app/ee/services/secret-rotation-v2/postgres-credentials";
|
||||||
|
import { SecretRotationV2Schema } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-union-schema";
|
||||||
|
import { ApiDocsTags, SecretRotations } from "@app/lib/api-docs";
|
||||||
|
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 SecretRotationV2OptionsSchema = z.discriminatedUnion("type", [
|
||||||
|
PostgresCredentialsRotationListItemSchema,
|
||||||
|
MsSqlCredentialsRotationListItemSchema,
|
||||||
|
Auth0ClientSecretRotationListItemSchema
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const registerSecretRotationV2Router = async (server: FastifyZodProvider) => {
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/options",
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SecretRotations],
|
||||||
|
description: "List the available Secret Rotation Options.",
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
secretRotationOptions: SecretRotationV2OptionsSchema.array()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: () => {
|
||||||
|
const secretRotationOptions = server.services.secretRotationV2.listSecretRotationOptions();
|
||||||
|
return { secretRotationOptions };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/",
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SecretRotations],
|
||||||
|
description: "List all the Secret Rotations for the specified project.",
|
||||||
|
querystring: z.object({
|
||||||
|
projectId: z.string().trim().min(1, "Project ID required").describe(SecretRotations.LIST().projectId)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({ secretRotations: SecretRotationV2Schema.array() })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const {
|
||||||
|
query: { projectId },
|
||||||
|
permission
|
||||||
|
} = req;
|
||||||
|
|
||||||
|
const secretRotations = await server.services.secretRotationV2.listSecretRotationsByProjectId(
|
||||||
|
{ projectId },
|
||||||
|
permission
|
||||||
|
);
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.GET_SECRET_ROTATIONS,
|
||||||
|
metadata: {
|
||||||
|
rotationIds: secretRotations.map((sync) => sync.id),
|
||||||
|
count: secretRotations.length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { secretRotations };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
@@ -94,7 +94,8 @@ export const accessApprovalRequestServiceFactory = ({
|
|||||||
actor,
|
actor,
|
||||||
actorOrgId,
|
actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
projectSlug
|
projectSlug,
|
||||||
|
note
|
||||||
}: TCreateAccessApprovalRequestDTO) => {
|
}: TCreateAccessApprovalRequestDTO) => {
|
||||||
const cfg = getConfig();
|
const cfg = getConfig();
|
||||||
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
||||||
@@ -209,7 +210,8 @@ export const accessApprovalRequestServiceFactory = ({
|
|||||||
requestedByUserId: actorId,
|
requestedByUserId: actorId,
|
||||||
temporaryRange: temporaryRange || null,
|
temporaryRange: temporaryRange || null,
|
||||||
permissions: JSON.stringify(requestedPermissions),
|
permissions: JSON.stringify(requestedPermissions),
|
||||||
isTemporary
|
isTemporary,
|
||||||
|
note: note || null
|
||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
@@ -232,7 +234,8 @@ export const accessApprovalRequestServiceFactory = ({
|
|||||||
secretPath,
|
secretPath,
|
||||||
environment: envSlug,
|
environment: envSlug,
|
||||||
permissions: accessTypes,
|
permissions: accessTypes,
|
||||||
approvalUrl
|
approvalUrl,
|
||||||
|
note
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -252,7 +255,8 @@ export const accessApprovalRequestServiceFactory = ({
|
|||||||
secretPath,
|
secretPath,
|
||||||
environment: envSlug,
|
environment: envSlug,
|
||||||
permissions: accessTypes,
|
permissions: accessTypes,
|
||||||
approvalUrl
|
approvalUrl,
|
||||||
|
note
|
||||||
},
|
},
|
||||||
template: SmtpTemplates.AccessApprovalRequest
|
template: SmtpTemplates.AccessApprovalRequest
|
||||||
});
|
});
|
||||||
|
@@ -24,6 +24,7 @@ export type TCreateAccessApprovalRequestDTO = {
|
|||||||
permissions: unknown;
|
permissions: unknown;
|
||||||
isTemporary: boolean;
|
isTemporary: boolean;
|
||||||
temporaryRange?: string;
|
temporaryRange?: string;
|
||||||
|
note?: string;
|
||||||
} & Omit<TProjectPermission, "projectId">;
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
export type TListApprovalRequestsDTO = {
|
export type TListApprovalRequestsDTO = {
|
||||||
|
@@ -9,13 +9,14 @@ import { logger } from "@app/lib/logger";
|
|||||||
import { QueueName } from "@app/queue";
|
import { QueueName } from "@app/queue";
|
||||||
import { ActorType } from "@app/services/auth/auth-type";
|
import { ActorType } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
import { EventType } from "./audit-log-types";
|
import { EventType, filterableSecretEvents } from "./audit-log-types";
|
||||||
|
|
||||||
export type TAuditLogDALFactory = ReturnType<typeof auditLogDALFactory>;
|
export type TAuditLogDALFactory = ReturnType<typeof auditLogDALFactory>;
|
||||||
|
|
||||||
type TFindQuery = {
|
type TFindQuery = {
|
||||||
actor?: string;
|
actor?: string;
|
||||||
projectId?: string;
|
projectId?: string;
|
||||||
|
environment?: string;
|
||||||
orgId?: string;
|
orgId?: string;
|
||||||
eventType?: string;
|
eventType?: string;
|
||||||
startDate?: string;
|
startDate?: string;
|
||||||
@@ -32,6 +33,7 @@ export const auditLogDALFactory = (db: TDbClient) => {
|
|||||||
{
|
{
|
||||||
orgId,
|
orgId,
|
||||||
projectId,
|
projectId,
|
||||||
|
environment,
|
||||||
userAgentType,
|
userAgentType,
|
||||||
startDate,
|
startDate,
|
||||||
endDate,
|
endDate,
|
||||||
@@ -40,12 +42,14 @@ export const auditLogDALFactory = (db: TDbClient) => {
|
|||||||
actorId,
|
actorId,
|
||||||
actorType,
|
actorType,
|
||||||
secretPath,
|
secretPath,
|
||||||
|
secretKey,
|
||||||
eventType,
|
eventType,
|
||||||
eventMetadata
|
eventMetadata
|
||||||
}: Omit<TFindQuery, "actor" | "eventType"> & {
|
}: Omit<TFindQuery, "actor" | "eventType"> & {
|
||||||
actorId?: string;
|
actorId?: string;
|
||||||
actorType?: ActorType;
|
actorType?: ActorType;
|
||||||
secretPath?: string;
|
secretPath?: string;
|
||||||
|
secretKey?: string;
|
||||||
eventType?: EventType[];
|
eventType?: EventType[];
|
||||||
eventMetadata?: Record<string, string>;
|
eventMetadata?: Record<string, string>;
|
||||||
},
|
},
|
||||||
@@ -90,8 +94,29 @@ export const auditLogDALFactory = (db: TDbClient) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (projectId && secretPath) {
|
const eventIsSecretType = !eventType?.length || eventType.some((event) => filterableSecretEvents.includes(event));
|
||||||
void sqlQuery.whereRaw(`"eventMetadata" @> jsonb_build_object('secretPath', ?::text)`, [secretPath]);
|
// We only want to filter for environment/secretPath/secretKey if the user is either checking for all event types
|
||||||
|
|
||||||
|
// ? Note(daniel): use the `eventMetadata" @> ?::jsonb` approach to properly use our GIN index
|
||||||
|
if (projectId && eventIsSecretType) {
|
||||||
|
if (environment || secretPath) {
|
||||||
|
// Handle both environment and secret path together to only use the GIN index once
|
||||||
|
void sqlQuery.whereRaw(`"eventMetadata" @> ?::jsonb`, [
|
||||||
|
JSON.stringify({
|
||||||
|
...(environment && { environment }),
|
||||||
|
...(secretPath && { secretPath })
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle secret key separately to include the OR condition
|
||||||
|
if (secretKey) {
|
||||||
|
void sqlQuery.whereRaw(
|
||||||
|
`("eventMetadata" @> ?::jsonb
|
||||||
|
OR "eventMetadata"->'secrets' @> ?::jsonb)`,
|
||||||
|
[JSON.stringify({ secretKey }), JSON.stringify([{ secretKey }])]
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter by actor type
|
// Filter by actor type
|
||||||
|
@@ -63,6 +63,8 @@ export const auditLogServiceFactory = ({
|
|||||||
actorType: filter.actorType,
|
actorType: filter.actorType,
|
||||||
eventMetadata: filter.eventMetadata,
|
eventMetadata: filter.eventMetadata,
|
||||||
secretPath: filter.secretPath,
|
secretPath: filter.secretPath,
|
||||||
|
secretKey: filter.secretKey,
|
||||||
|
environment: filter.environment,
|
||||||
...(filter.projectId ? { projectId: filter.projectId } : { orgId: actorOrgId })
|
...(filter.projectId ? { projectId: filter.projectId } : { orgId: actorOrgId })
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -2,9 +2,18 @@ import {
|
|||||||
TCreateProjectTemplateDTO,
|
TCreateProjectTemplateDTO,
|
||||||
TUpdateProjectTemplateDTO
|
TUpdateProjectTemplateDTO
|
||||||
} from "@app/ee/services/project-template/project-template-types";
|
} from "@app/ee/services/project-template/project-template-types";
|
||||||
|
import { SecretRotation, SecretRotationStatus } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-enums";
|
||||||
|
import {
|
||||||
|
TCreateSecretRotationV2DTO,
|
||||||
|
TDeleteSecretRotationV2DTO,
|
||||||
|
TSecretRotationV2Raw,
|
||||||
|
TUpdateSecretRotationV2DTO
|
||||||
|
} from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-types";
|
||||||
import { SshCaStatus, SshCertType } from "@app/ee/services/ssh/ssh-certificate-authority-types";
|
import { SshCaStatus, SshCertType } from "@app/ee/services/ssh/ssh-certificate-authority-types";
|
||||||
|
import { SshCertKeyAlgorithm } from "@app/ee/services/ssh-certificate/ssh-certificate-types";
|
||||||
import { SshCertTemplateStatus } from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-types";
|
import { SshCertTemplateStatus } from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-types";
|
||||||
import { SymmetricEncryption } from "@app/lib/crypto/cipher";
|
import { SymmetricKeyAlgorithm } from "@app/lib/crypto/cipher";
|
||||||
|
import { AsymmetricKeyAlgorithm, SigningAlgorithm } from "@app/lib/crypto/sign/types";
|
||||||
import { TProjectPermission } from "@app/lib/types";
|
import { TProjectPermission } from "@app/lib/types";
|
||||||
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||||
import { TCreateAppConnectionDTO, TUpdateAppConnectionDTO } from "@app/services/app-connection/app-connection-types";
|
import { TCreateAppConnectionDTO, TUpdateAppConnectionDTO } from "@app/services/app-connection/app-connection-types";
|
||||||
@@ -33,9 +42,11 @@ export type TListProjectAuditLogDTO = {
|
|||||||
endDate?: string;
|
endDate?: string;
|
||||||
startDate?: string;
|
startDate?: string;
|
||||||
projectId?: string;
|
projectId?: string;
|
||||||
|
environment?: string;
|
||||||
auditLogActorId?: string;
|
auditLogActorId?: string;
|
||||||
actorType?: ActorType;
|
actorType?: ActorType;
|
||||||
secretPath?: string;
|
secretPath?: string;
|
||||||
|
secretKey?: string;
|
||||||
eventMetadata?: Record<string, string>;
|
eventMetadata?: Record<string, string>;
|
||||||
};
|
};
|
||||||
} & Omit<TProjectPermission, "projectId">;
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
@@ -54,6 +65,8 @@ export type TCreateAuditLogDTO = {
|
|||||||
projectId?: string;
|
projectId?: string;
|
||||||
} & BaseAuthData;
|
} & BaseAuthData;
|
||||||
|
|
||||||
|
export type AuditLogInfo = Pick<TCreateAuditLogDTO, "userAgent" | "userAgentType" | "ipAddress" | "actor">;
|
||||||
|
|
||||||
interface BaseAuthData {
|
interface BaseAuthData {
|
||||||
ipAddress?: string;
|
ipAddress?: string;
|
||||||
userAgent?: string;
|
userAgent?: string;
|
||||||
@@ -178,6 +191,12 @@ export enum EventType {
|
|||||||
UPDATE_SSH_CERTIFICATE_TEMPLATE = "update-ssh-certificate-template",
|
UPDATE_SSH_CERTIFICATE_TEMPLATE = "update-ssh-certificate-template",
|
||||||
DELETE_SSH_CERTIFICATE_TEMPLATE = "delete-ssh-certificate-template",
|
DELETE_SSH_CERTIFICATE_TEMPLATE = "delete-ssh-certificate-template",
|
||||||
GET_SSH_CERTIFICATE_TEMPLATE = "get-ssh-certificate-template",
|
GET_SSH_CERTIFICATE_TEMPLATE = "get-ssh-certificate-template",
|
||||||
|
CREATE_SSH_HOST = "create-ssh-host",
|
||||||
|
UPDATE_SSH_HOST = "update-ssh-host",
|
||||||
|
DELETE_SSH_HOST = "delete-ssh-host",
|
||||||
|
GET_SSH_HOST = "get-ssh-host",
|
||||||
|
ISSUE_SSH_HOST_USER_CERT = "issue-ssh-host-user-cert",
|
||||||
|
ISSUE_SSH_HOST_HOST_CERT = "issue-ssh-host-host-cert",
|
||||||
CREATE_CA = "create-certificate-authority",
|
CREATE_CA = "create-certificate-authority",
|
||||||
GET_CA = "get-certificate-authority",
|
GET_CA = "get-certificate-authority",
|
||||||
UPDATE_CA = "update-certificate-authority",
|
UPDATE_CA = "update-certificate-authority",
|
||||||
@@ -237,6 +256,11 @@ export enum EventType {
|
|||||||
GET_CMEK = "get-cmek",
|
GET_CMEK = "get-cmek",
|
||||||
CMEK_ENCRYPT = "cmek-encrypt",
|
CMEK_ENCRYPT = "cmek-encrypt",
|
||||||
CMEK_DECRYPT = "cmek-decrypt",
|
CMEK_DECRYPT = "cmek-decrypt",
|
||||||
|
CMEK_SIGN = "cmek-sign",
|
||||||
|
CMEK_VERIFY = "cmek-verify",
|
||||||
|
CMEK_LIST_SIGNING_ALGORITHMS = "cmek-list-signing-algorithms",
|
||||||
|
CMEK_GET_PUBLIC_KEY = "cmek-get-public-key",
|
||||||
|
|
||||||
UPDATE_EXTERNAL_GROUP_ORG_ROLE_MAPPINGS = "update-external-group-org-role-mapping",
|
UPDATE_EXTERNAL_GROUP_ORG_ROLE_MAPPINGS = "update-external-group-org-role-mapping",
|
||||||
GET_EXTERNAL_GROUP_ORG_ROLE_MAPPINGS = "get-external-group-org-role-mapping",
|
GET_EXTERNAL_GROUP_ORG_ROLE_MAPPINGS = "get-external-group-org-role-mapping",
|
||||||
GET_PROJECT_TEMPLATES = "get-project-templates",
|
GET_PROJECT_TEMPLATES = "get-project-templates",
|
||||||
@@ -283,9 +307,29 @@ export enum EventType {
|
|||||||
KMIP_OPERATION_ACTIVATE = "kmip-operation-activate",
|
KMIP_OPERATION_ACTIVATE = "kmip-operation-activate",
|
||||||
KMIP_OPERATION_REVOKE = "kmip-operation-revoke",
|
KMIP_OPERATION_REVOKE = "kmip-operation-revoke",
|
||||||
KMIP_OPERATION_LOCATE = "kmip-operation-locate",
|
KMIP_OPERATION_LOCATE = "kmip-operation-locate",
|
||||||
KMIP_OPERATION_REGISTER = "kmip-operation-register"
|
KMIP_OPERATION_REGISTER = "kmip-operation-register",
|
||||||
|
|
||||||
|
GET_SECRET_ROTATIONS = "get-secret-rotations",
|
||||||
|
GET_SECRET_ROTATION = "get-secret-rotation",
|
||||||
|
GET_SECRET_ROTATION_GENERATED_CREDENTIALS = "get-secret-rotation-generated-credentials",
|
||||||
|
CREATE_SECRET_ROTATION = "create-secret-rotation",
|
||||||
|
UPDATE_SECRET_ROTATION = "update-secret-rotation",
|
||||||
|
DELETE_SECRET_ROTATION = "delete-secret-rotation",
|
||||||
|
SECRET_ROTATION_ROTATE_SECRETS = "secret-rotation-rotate-secrets",
|
||||||
|
|
||||||
|
PROJECT_ACCESS_REQUEST = "project-access-request"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const filterableSecretEvents: EventType[] = [
|
||||||
|
EventType.GET_SECRET,
|
||||||
|
EventType.DELETE_SECRETS,
|
||||||
|
EventType.CREATE_SECRETS,
|
||||||
|
EventType.UPDATE_SECRETS,
|
||||||
|
EventType.CREATE_SECRET,
|
||||||
|
EventType.UPDATE_SECRET,
|
||||||
|
EventType.DELETE_SECRET
|
||||||
|
];
|
||||||
|
|
||||||
interface UserActorMetadata {
|
interface UserActorMetadata {
|
||||||
userId: string;
|
userId: string;
|
||||||
email?: string | null;
|
email?: string | null;
|
||||||
@@ -1346,7 +1390,7 @@ interface IssueSshCreds {
|
|||||||
type: EventType.ISSUE_SSH_CREDS;
|
type: EventType.ISSUE_SSH_CREDS;
|
||||||
metadata: {
|
metadata: {
|
||||||
certificateTemplateId: string;
|
certificateTemplateId: string;
|
||||||
keyAlgorithm: CertKeyAlgorithm;
|
keyAlgorithm: SshCertKeyAlgorithm;
|
||||||
certType: SshCertType;
|
certType: SshCertType;
|
||||||
principals: string[];
|
principals: string[];
|
||||||
ttl: string;
|
ttl: string;
|
||||||
@@ -1442,6 +1486,80 @@ interface DeleteSshCertificateTemplate {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface CreateSshHost {
|
||||||
|
type: EventType.CREATE_SSH_HOST;
|
||||||
|
metadata: {
|
||||||
|
sshHostId: string;
|
||||||
|
hostname: string;
|
||||||
|
userCertTtl: string;
|
||||||
|
hostCertTtl: string;
|
||||||
|
loginMappings: {
|
||||||
|
loginUser: string;
|
||||||
|
allowedPrincipals: {
|
||||||
|
usernames: string[];
|
||||||
|
};
|
||||||
|
}[];
|
||||||
|
userSshCaId: string;
|
||||||
|
hostSshCaId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateSshHost {
|
||||||
|
type: EventType.UPDATE_SSH_HOST;
|
||||||
|
metadata: {
|
||||||
|
sshHostId: string;
|
||||||
|
hostname?: string;
|
||||||
|
userCertTtl?: string;
|
||||||
|
hostCertTtl?: string;
|
||||||
|
loginMappings?: {
|
||||||
|
loginUser: string;
|
||||||
|
allowedPrincipals: {
|
||||||
|
usernames: string[];
|
||||||
|
};
|
||||||
|
}[];
|
||||||
|
userSshCaId?: string;
|
||||||
|
hostSshCaId?: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteSshHost {
|
||||||
|
type: EventType.DELETE_SSH_HOST;
|
||||||
|
metadata: {
|
||||||
|
sshHostId: string;
|
||||||
|
hostname: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetSshHost {
|
||||||
|
type: EventType.GET_SSH_HOST;
|
||||||
|
metadata: {
|
||||||
|
sshHostId: string;
|
||||||
|
hostname: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IssueSshHostUserCert {
|
||||||
|
type: EventType.ISSUE_SSH_HOST_USER_CERT;
|
||||||
|
metadata: {
|
||||||
|
sshHostId: string;
|
||||||
|
hostname: string;
|
||||||
|
loginUser: string;
|
||||||
|
principals: string[];
|
||||||
|
ttl: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IssueSshHostHostCert {
|
||||||
|
type: EventType.ISSUE_SSH_HOST_HOST_CERT;
|
||||||
|
metadata: {
|
||||||
|
sshHostId: string;
|
||||||
|
hostname: string;
|
||||||
|
serialNumber: string;
|
||||||
|
principals: string[];
|
||||||
|
ttl: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
interface CreateCa {
|
interface CreateCa {
|
||||||
type: EventType.CREATE_CA;
|
type: EventType.CREATE_CA;
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -1885,7 +2003,7 @@ interface CreateCmekEvent {
|
|||||||
keyId: string;
|
keyId: string;
|
||||||
name: string;
|
name: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
encryptionAlgorithm: SymmetricEncryption;
|
encryptionAlgorithm: SymmetricKeyAlgorithm | AsymmetricKeyAlgorithm;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1933,6 +2051,39 @@ interface CmekDecryptEvent {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface CmekSignEvent {
|
||||||
|
type: EventType.CMEK_SIGN;
|
||||||
|
metadata: {
|
||||||
|
keyId: string;
|
||||||
|
signingAlgorithm: SigningAlgorithm;
|
||||||
|
signature: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CmekVerifyEvent {
|
||||||
|
type: EventType.CMEK_VERIFY;
|
||||||
|
metadata: {
|
||||||
|
keyId: string;
|
||||||
|
signingAlgorithm: SigningAlgorithm;
|
||||||
|
signature: string;
|
||||||
|
signatureValid: boolean;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CmekListSigningAlgorithmsEvent {
|
||||||
|
type: EventType.CMEK_LIST_SIGNING_ALGORITHMS;
|
||||||
|
metadata: {
|
||||||
|
keyId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CmekGetPublicKeyEvent {
|
||||||
|
type: EventType.CMEK_GET_PUBLIC_KEY;
|
||||||
|
metadata: {
|
||||||
|
keyId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
interface GetExternalGroupOrgRoleMappingsEvent {
|
interface GetExternalGroupOrgRoleMappingsEvent {
|
||||||
type: EventType.GET_EXTERNAL_GROUP_ORG_ROLE_MAPPINGS;
|
type: EventType.GET_EXTERNAL_GROUP_ORG_ROLE_MAPPINGS;
|
||||||
metadata?: Record<string, never>; // not needed, based off orgId
|
metadata?: Record<string, never>; // not needed, based off orgId
|
||||||
@@ -2265,6 +2416,15 @@ interface KmipOperationRegisterEvent {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ProjectAccessRequestEvent {
|
||||||
|
type: EventType.PROJECT_ACCESS_REQUEST;
|
||||||
|
metadata: {
|
||||||
|
projectId: string;
|
||||||
|
requesterId: string;
|
||||||
|
requesterEmail: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
interface SetupKmipEvent {
|
interface SetupKmipEvent {
|
||||||
type: EventType.SETUP_KMIP;
|
type: EventType.SETUP_KMIP;
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -2290,6 +2450,63 @@ interface RegisterKmipServerEvent {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface GetSecretRotationsEvent {
|
||||||
|
type: EventType.GET_SECRET_ROTATIONS;
|
||||||
|
metadata: {
|
||||||
|
type?: SecretRotation;
|
||||||
|
count: number;
|
||||||
|
rotationIds: string[];
|
||||||
|
secretPath?: string;
|
||||||
|
environment?: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetSecretRotationEvent {
|
||||||
|
type: EventType.GET_SECRET_ROTATION;
|
||||||
|
metadata: {
|
||||||
|
type: SecretRotation;
|
||||||
|
rotationId: string;
|
||||||
|
secretPath: string;
|
||||||
|
environment: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetSecretRotationCredentialsEvent {
|
||||||
|
type: EventType.GET_SECRET_ROTATION_GENERATED_CREDENTIALS;
|
||||||
|
metadata: {
|
||||||
|
type: SecretRotation;
|
||||||
|
rotationId: string;
|
||||||
|
secretPath: string;
|
||||||
|
environment: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CreateSecretRotationEvent {
|
||||||
|
type: EventType.CREATE_SECRET_ROTATION;
|
||||||
|
metadata: Omit<TCreateSecretRotationV2DTO, "projectId"> & { rotationId: string };
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateSecretRotationEvent {
|
||||||
|
type: EventType.UPDATE_SECRET_ROTATION;
|
||||||
|
metadata: TUpdateSecretRotationV2DTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteSecretRotationEvent {
|
||||||
|
type: EventType.DELETE_SECRET_ROTATION;
|
||||||
|
metadata: TDeleteSecretRotationV2DTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RotateSecretRotationEvent {
|
||||||
|
type: EventType.SECRET_ROTATION_ROTATE_SECRETS;
|
||||||
|
metadata: Pick<TSecretRotationV2Raw, "parameters" | "secretsMapping" | "type" | "connectionId" | "folderId"> & {
|
||||||
|
status: SecretRotationStatus;
|
||||||
|
rotationId: string;
|
||||||
|
jobId?: string | undefined;
|
||||||
|
occurredAt: Date;
|
||||||
|
message?: string | null | undefined;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export type Event =
|
export type Event =
|
||||||
| GetSecretsEvent
|
| GetSecretsEvent
|
||||||
| GetSecretEvent
|
| GetSecretEvent
|
||||||
@@ -2396,6 +2613,12 @@ export type Event =
|
|||||||
| UpdateSshCertificateTemplate
|
| UpdateSshCertificateTemplate
|
||||||
| GetSshCertificateTemplate
|
| GetSshCertificateTemplate
|
||||||
| DeleteSshCertificateTemplate
|
| DeleteSshCertificateTemplate
|
||||||
|
| CreateSshHost
|
||||||
|
| UpdateSshHost
|
||||||
|
| DeleteSshHost
|
||||||
|
| GetSshHost
|
||||||
|
| IssueSshHostUserCert
|
||||||
|
| IssueSshHostHostCert
|
||||||
| CreateCa
|
| CreateCa
|
||||||
| GetCa
|
| GetCa
|
||||||
| UpdateCa
|
| UpdateCa
|
||||||
@@ -2455,6 +2678,10 @@ export type Event =
|
|||||||
| GetCmeksEvent
|
| GetCmeksEvent
|
||||||
| CmekEncryptEvent
|
| CmekEncryptEvent
|
||||||
| CmekDecryptEvent
|
| CmekDecryptEvent
|
||||||
|
| CmekSignEvent
|
||||||
|
| CmekVerifyEvent
|
||||||
|
| CmekListSigningAlgorithmsEvent
|
||||||
|
| CmekGetPublicKeyEvent
|
||||||
| GetExternalGroupOrgRoleMappingsEvent
|
| GetExternalGroupOrgRoleMappingsEvent
|
||||||
| UpdateExternalGroupOrgRoleMappingsEvent
|
| UpdateExternalGroupOrgRoleMappingsEvent
|
||||||
| GetProjectTemplatesEvent
|
| GetProjectTemplatesEvent
|
||||||
@@ -2499,5 +2726,13 @@ export type Event =
|
|||||||
| KmipOperationRevokeEvent
|
| KmipOperationRevokeEvent
|
||||||
| KmipOperationLocateEvent
|
| KmipOperationLocateEvent
|
||||||
| KmipOperationRegisterEvent
|
| KmipOperationRegisterEvent
|
||||||
|
| ProjectAccessRequestEvent
|
||||||
| CreateSecretRequestEvent
|
| CreateSecretRequestEvent
|
||||||
| SecretApprovalRequestReview;
|
| SecretApprovalRequestReview
|
||||||
|
| GetSecretRotationsEvent
|
||||||
|
| GetSecretRotationEvent
|
||||||
|
| GetSecretRotationCredentialsEvent
|
||||||
|
| CreateSecretRotationEvent
|
||||||
|
| UpdateSecretRotationEvent
|
||||||
|
| DeleteSecretRotationEvent
|
||||||
|
| RotateSecretRotationEvent;
|
||||||
|
@@ -78,10 +78,6 @@ export const dynamicSecretLeaseServiceFactory = ({
|
|||||||
actorOrgId,
|
actorOrgId,
|
||||||
actionProjectType: ActionProjectType.SecretManager
|
actionProjectType: ActionProjectType.SecretManager
|
||||||
});
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
ProjectPermissionDynamicSecretActions.Lease,
|
|
||||||
subject(ProjectPermissionSub.DynamicSecrets, { environment: environmentSlug, secretPath: path })
|
|
||||||
);
|
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(actorOrgId);
|
const plan = await licenseService.getPlan(actorOrgId);
|
||||||
if (!plan?.dynamicSecret) {
|
if (!plan?.dynamicSecret) {
|
||||||
@@ -102,6 +98,15 @@ export const dynamicSecretLeaseServiceFactory = ({
|
|||||||
message: `Dynamic secret with name '${name}' in folder with path '${path}' not found`
|
message: `Dynamic secret with name '${name}' in folder with path '${path}' not found`
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionDynamicSecretActions.Lease,
|
||||||
|
subject(ProjectPermissionSub.DynamicSecrets, {
|
||||||
|
environment: environmentSlug,
|
||||||
|
secretPath: path,
|
||||||
|
metadata: dynamicSecretCfg.metadata
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
const totalLeasesTaken = await dynamicSecretLeaseDAL.countLeasesForDynamicSecret(dynamicSecretCfg.id);
|
const totalLeasesTaken = await dynamicSecretLeaseDAL.countLeasesForDynamicSecret(dynamicSecretCfg.id);
|
||||||
if (totalLeasesTaken >= appCfg.MAX_LEASE_LIMIT)
|
if (totalLeasesTaken >= appCfg.MAX_LEASE_LIMIT)
|
||||||
throw new BadRequestError({ message: `Max lease limit reached. Limit: ${appCfg.MAX_LEASE_LIMIT}` });
|
throw new BadRequestError({ message: `Max lease limit reached. Limit: ${appCfg.MAX_LEASE_LIMIT}` });
|
||||||
@@ -159,10 +164,6 @@ export const dynamicSecretLeaseServiceFactory = ({
|
|||||||
actorOrgId,
|
actorOrgId,
|
||||||
actionProjectType: ActionProjectType.SecretManager
|
actionProjectType: ActionProjectType.SecretManager
|
||||||
});
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
ProjectPermissionDynamicSecretActions.Lease,
|
|
||||||
subject(ProjectPermissionSub.DynamicSecrets, { environment: environmentSlug, secretPath: path })
|
|
||||||
);
|
|
||||||
|
|
||||||
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
|
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
type: KmsDataKey.SecretManager,
|
type: KmsDataKey.SecretManager,
|
||||||
@@ -183,11 +184,29 @@ export const dynamicSecretLeaseServiceFactory = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const dynamicSecretLease = await dynamicSecretLeaseDAL.findById(leaseId);
|
const dynamicSecretLease = await dynamicSecretLeaseDAL.findById(leaseId);
|
||||||
if (!dynamicSecretLease) {
|
if (!dynamicSecretLease || dynamicSecretLease.dynamicSecret.folderId !== folder.id) {
|
||||||
throw new NotFoundError({ message: `Dynamic secret lease with ID '${leaseId}' not found` });
|
throw new NotFoundError({ message: `Dynamic secret lease with ID '${leaseId}' not found` });
|
||||||
}
|
}
|
||||||
|
|
||||||
const dynamicSecretCfg = dynamicSecretLease.dynamicSecret;
|
const dynamicSecretCfg = await dynamicSecretDAL.findOne({
|
||||||
|
id: dynamicSecretLease.dynamicSecretId,
|
||||||
|
folderId: folder.id
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!dynamicSecretCfg)
|
||||||
|
throw new NotFoundError({
|
||||||
|
message: `Dynamic secret with ID '${dynamicSecretLease.dynamicSecretId}' not found`
|
||||||
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionDynamicSecretActions.Lease,
|
||||||
|
subject(ProjectPermissionSub.DynamicSecrets, {
|
||||||
|
environment: environmentSlug,
|
||||||
|
secretPath: path,
|
||||||
|
metadata: dynamicSecretCfg.metadata
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
const selectedProvider = dynamicSecretProviders[dynamicSecretCfg.type as DynamicSecretProviders];
|
const selectedProvider = dynamicSecretProviders[dynamicSecretCfg.type as DynamicSecretProviders];
|
||||||
const decryptedStoredInput = JSON.parse(
|
const decryptedStoredInput = JSON.parse(
|
||||||
secretManagerDecryptor({ cipherTextBlob: Buffer.from(dynamicSecretCfg.encryptedInput) }).toString()
|
secretManagerDecryptor({ cipherTextBlob: Buffer.from(dynamicSecretCfg.encryptedInput) }).toString()
|
||||||
@@ -239,10 +258,6 @@ export const dynamicSecretLeaseServiceFactory = ({
|
|||||||
actorOrgId,
|
actorOrgId,
|
||||||
actionProjectType: ActionProjectType.SecretManager
|
actionProjectType: ActionProjectType.SecretManager
|
||||||
});
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
ProjectPermissionDynamicSecretActions.Lease,
|
|
||||||
subject(ProjectPermissionSub.DynamicSecrets, { environment: environmentSlug, secretPath: path })
|
|
||||||
);
|
|
||||||
|
|
||||||
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
|
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
type: KmsDataKey.SecretManager,
|
type: KmsDataKey.SecretManager,
|
||||||
@@ -256,10 +271,28 @@ export const dynamicSecretLeaseServiceFactory = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const dynamicSecretLease = await dynamicSecretLeaseDAL.findById(leaseId);
|
const dynamicSecretLease = await dynamicSecretLeaseDAL.findById(leaseId);
|
||||||
if (!dynamicSecretLease)
|
if (!dynamicSecretLease || dynamicSecretLease.dynamicSecret.folderId !== folder.id)
|
||||||
throw new NotFoundError({ message: `Dynamic secret lease with ID '${leaseId}' not found` });
|
throw new NotFoundError({ message: `Dynamic secret lease with ID '${leaseId}' not found` });
|
||||||
|
|
||||||
const dynamicSecretCfg = dynamicSecretLease.dynamicSecret;
|
const dynamicSecretCfg = await dynamicSecretDAL.findOne({
|
||||||
|
id: dynamicSecretLease.dynamicSecretId,
|
||||||
|
folderId: folder.id
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!dynamicSecretCfg)
|
||||||
|
throw new NotFoundError({
|
||||||
|
message: `Dynamic secret with ID '${dynamicSecretLease.dynamicSecretId}' not found`
|
||||||
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionDynamicSecretActions.Lease,
|
||||||
|
subject(ProjectPermissionSub.DynamicSecrets, {
|
||||||
|
environment: environmentSlug,
|
||||||
|
secretPath: path,
|
||||||
|
metadata: dynamicSecretCfg.metadata
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
const selectedProvider = dynamicSecretProviders[dynamicSecretCfg.type as DynamicSecretProviders];
|
const selectedProvider = dynamicSecretProviders[dynamicSecretCfg.type as DynamicSecretProviders];
|
||||||
const decryptedStoredInput = JSON.parse(
|
const decryptedStoredInput = JSON.parse(
|
||||||
secretManagerDecryptor({ cipherTextBlob: Buffer.from(dynamicSecretCfg.encryptedInput) }).toString()
|
secretManagerDecryptor({ cipherTextBlob: Buffer.from(dynamicSecretCfg.encryptedInput) }).toString()
|
||||||
@@ -309,10 +342,6 @@ export const dynamicSecretLeaseServiceFactory = ({
|
|||||||
actorOrgId,
|
actorOrgId,
|
||||||
actionProjectType: ActionProjectType.SecretManager
|
actionProjectType: ActionProjectType.SecretManager
|
||||||
});
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
ProjectPermissionDynamicSecretActions.Lease,
|
|
||||||
subject(ProjectPermissionSub.DynamicSecrets, { environment: environmentSlug, secretPath: path })
|
|
||||||
);
|
|
||||||
|
|
||||||
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
|
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
|
||||||
if (!folder)
|
if (!folder)
|
||||||
@@ -326,6 +355,15 @@ export const dynamicSecretLeaseServiceFactory = ({
|
|||||||
message: `Dynamic secret with name '${name}' in folder with path '${path}' not found`
|
message: `Dynamic secret with name '${name}' in folder with path '${path}' not found`
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionDynamicSecretActions.Lease,
|
||||||
|
subject(ProjectPermissionSub.DynamicSecrets, {
|
||||||
|
environment: environmentSlug,
|
||||||
|
secretPath: path,
|
||||||
|
metadata: dynamicSecretCfg.metadata
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
const dynamicSecretLeases = await dynamicSecretLeaseDAL.find({ dynamicSecretId: dynamicSecretCfg.id });
|
const dynamicSecretLeases = await dynamicSecretLeaseDAL.find({ dynamicSecretId: dynamicSecretCfg.id });
|
||||||
return dynamicSecretLeases;
|
return dynamicSecretLeases;
|
||||||
};
|
};
|
||||||
@@ -352,10 +390,6 @@ export const dynamicSecretLeaseServiceFactory = ({
|
|||||||
actorOrgId,
|
actorOrgId,
|
||||||
actionProjectType: ActionProjectType.SecretManager
|
actionProjectType: ActionProjectType.SecretManager
|
||||||
});
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
ProjectPermissionDynamicSecretActions.Lease,
|
|
||||||
subject(ProjectPermissionSub.DynamicSecrets, { environment: environmentSlug, secretPath: path })
|
|
||||||
);
|
|
||||||
|
|
||||||
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
|
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
|
||||||
if (!folder) throw new NotFoundError({ message: `Folder with path '${path}' not found` });
|
if (!folder) throw new NotFoundError({ message: `Folder with path '${path}' not found` });
|
||||||
@@ -364,6 +398,25 @@ export const dynamicSecretLeaseServiceFactory = ({
|
|||||||
if (!dynamicSecretLease)
|
if (!dynamicSecretLease)
|
||||||
throw new NotFoundError({ message: `Dynamic secret lease with ID '${leaseId}' not found` });
|
throw new NotFoundError({ message: `Dynamic secret lease with ID '${leaseId}' not found` });
|
||||||
|
|
||||||
|
const dynamicSecretCfg = await dynamicSecretDAL.findOne({
|
||||||
|
id: dynamicSecretLease.dynamicSecretId,
|
||||||
|
folderId: folder.id
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!dynamicSecretCfg)
|
||||||
|
throw new NotFoundError({
|
||||||
|
message: `Dynamic secret with ID '${dynamicSecretLease.dynamicSecretId}' not found`
|
||||||
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionDynamicSecretActions.Lease,
|
||||||
|
subject(ProjectPermissionSub.DynamicSecrets, {
|
||||||
|
environment: environmentSlug,
|
||||||
|
secretPath: path,
|
||||||
|
metadata: dynamicSecretCfg.metadata
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
return dynamicSecretLease;
|
return dynamicSecretLease;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -1,9 +1,17 @@
|
|||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName } from "@app/db/schemas";
|
import { TableName, TDynamicSecrets } from "@app/db/schemas";
|
||||||
import { DatabaseError } from "@app/lib/errors";
|
import { DatabaseError } from "@app/lib/errors";
|
||||||
import { ormify, selectAllTableCols } from "@app/lib/knex";
|
import {
|
||||||
|
buildFindFilter,
|
||||||
|
ormify,
|
||||||
|
prependTableNameToFindFilter,
|
||||||
|
selectAllTableCols,
|
||||||
|
sqlNestRelationships,
|
||||||
|
TFindFilter,
|
||||||
|
TFindOpt
|
||||||
|
} from "@app/lib/knex";
|
||||||
import { OrderByDirection } from "@app/lib/types";
|
import { OrderByDirection } from "@app/lib/types";
|
||||||
import { SecretsOrderBy } from "@app/services/secret/secret-types";
|
import { SecretsOrderBy } from "@app/services/secret/secret-types";
|
||||||
|
|
||||||
@@ -12,6 +20,86 @@ export type TDynamicSecretDALFactory = ReturnType<typeof dynamicSecretDALFactory
|
|||||||
export const dynamicSecretDALFactory = (db: TDbClient) => {
|
export const dynamicSecretDALFactory = (db: TDbClient) => {
|
||||||
const orm = ormify(db, TableName.DynamicSecret);
|
const orm = ormify(db, TableName.DynamicSecret);
|
||||||
|
|
||||||
|
const findOne = async (filter: TFindFilter<TDynamicSecrets>, tx?: Knex) => {
|
||||||
|
const query = (tx || db.replicaNode())(TableName.DynamicSecret)
|
||||||
|
.leftJoin(
|
||||||
|
TableName.ResourceMetadata,
|
||||||
|
`${TableName.ResourceMetadata}.dynamicSecretId`,
|
||||||
|
`${TableName.DynamicSecret}.id`
|
||||||
|
)
|
||||||
|
.select(selectAllTableCols(TableName.DynamicSecret))
|
||||||
|
.select(
|
||||||
|
db.ref("id").withSchema(TableName.ResourceMetadata).as("metadataId"),
|
||||||
|
db.ref("key").withSchema(TableName.ResourceMetadata).as("metadataKey"),
|
||||||
|
db.ref("value").withSchema(TableName.ResourceMetadata).as("metadataValue")
|
||||||
|
)
|
||||||
|
.where(prependTableNameToFindFilter(TableName.DynamicSecret, filter));
|
||||||
|
|
||||||
|
const docs = sqlNestRelationships({
|
||||||
|
data: await query,
|
||||||
|
key: "id",
|
||||||
|
parentMapper: (el) => el,
|
||||||
|
childrenMapper: [
|
||||||
|
{
|
||||||
|
key: "metadataId",
|
||||||
|
label: "metadata" as const,
|
||||||
|
mapper: ({ metadataKey, metadataValue, metadataId }) => ({
|
||||||
|
id: metadataId,
|
||||||
|
key: metadataKey,
|
||||||
|
value: metadataValue
|
||||||
|
})
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
return docs[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
const findWithMetadata = async (
|
||||||
|
filter: TFindFilter<TDynamicSecrets>,
|
||||||
|
{ offset, limit, sort, tx }: TFindOpt<TDynamicSecrets> = {}
|
||||||
|
) => {
|
||||||
|
const query = (tx || db.replicaNode())(TableName.DynamicSecret)
|
||||||
|
.leftJoin(
|
||||||
|
TableName.ResourceMetadata,
|
||||||
|
`${TableName.ResourceMetadata}.dynamicSecretId`,
|
||||||
|
`${TableName.DynamicSecret}.id`
|
||||||
|
)
|
||||||
|
.select(selectAllTableCols(TableName.DynamicSecret))
|
||||||
|
.select(
|
||||||
|
db.ref("id").withSchema(TableName.ResourceMetadata).as("metadataId"),
|
||||||
|
db.ref("key").withSchema(TableName.ResourceMetadata).as("metadataKey"),
|
||||||
|
db.ref("value").withSchema(TableName.ResourceMetadata).as("metadataValue")
|
||||||
|
)
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
|
.where(buildFindFilter(filter));
|
||||||
|
|
||||||
|
if (limit) void query.limit(limit);
|
||||||
|
if (offset) void query.offset(offset);
|
||||||
|
if (sort) {
|
||||||
|
void query.orderBy(sort.map(([column, order, nulls]) => ({ column: column as string, order, nulls })));
|
||||||
|
}
|
||||||
|
|
||||||
|
const docs = sqlNestRelationships({
|
||||||
|
data: await query,
|
||||||
|
key: "id",
|
||||||
|
parentMapper: (el) => el,
|
||||||
|
childrenMapper: [
|
||||||
|
{
|
||||||
|
key: "metadataId",
|
||||||
|
label: "metadata" as const,
|
||||||
|
mapper: ({ metadataKey, metadataValue, metadataId }) => ({
|
||||||
|
id: metadataId,
|
||||||
|
key: metadataKey,
|
||||||
|
value: metadataValue
|
||||||
|
})
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
return docs;
|
||||||
|
};
|
||||||
|
|
||||||
// find dynamic secrets for multiple environments (folder IDs are cross env, thus need to rank for pagination)
|
// find dynamic secrets for multiple environments (folder IDs are cross env, thus need to rank for pagination)
|
||||||
const listDynamicSecretsByFolderIds = async (
|
const listDynamicSecretsByFolderIds = async (
|
||||||
{
|
{
|
||||||
@@ -39,18 +127,27 @@ export const dynamicSecretDALFactory = (db: TDbClient) => {
|
|||||||
void bd.whereILike(`${TableName.DynamicSecret}.name`, `%${search}%`);
|
void bd.whereILike(`${TableName.DynamicSecret}.name`, `%${search}%`);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.leftJoin(
|
||||||
|
TableName.ResourceMetadata,
|
||||||
|
`${TableName.ResourceMetadata}.dynamicSecretId`,
|
||||||
|
`${TableName.DynamicSecret}.id`
|
||||||
|
)
|
||||||
.leftJoin(TableName.SecretFolder, `${TableName.SecretFolder}.id`, `${TableName.DynamicSecret}.folderId`)
|
.leftJoin(TableName.SecretFolder, `${TableName.SecretFolder}.id`, `${TableName.DynamicSecret}.folderId`)
|
||||||
.leftJoin(TableName.Environment, `${TableName.SecretFolder}.envId`, `${TableName.Environment}.id`)
|
.leftJoin(TableName.Environment, `${TableName.SecretFolder}.envId`, `${TableName.Environment}.id`)
|
||||||
.select(
|
.select(
|
||||||
selectAllTableCols(TableName.DynamicSecret),
|
selectAllTableCols(TableName.DynamicSecret),
|
||||||
db.ref("slug").withSchema(TableName.Environment).as("environment"),
|
db.ref("slug").withSchema(TableName.Environment).as("environment"),
|
||||||
db.raw(`DENSE_RANK() OVER (ORDER BY ${TableName.DynamicSecret}."name" ${orderDirection}) as rank`)
|
db.raw(`DENSE_RANK() OVER (ORDER BY ${TableName.DynamicSecret}."name" ${orderDirection}) as rank`),
|
||||||
|
db.ref("id").withSchema(TableName.ResourceMetadata).as("metadataId"),
|
||||||
|
db.ref("key").withSchema(TableName.ResourceMetadata).as("metadataKey"),
|
||||||
|
db.ref("value").withSchema(TableName.ResourceMetadata).as("metadataValue")
|
||||||
)
|
)
|
||||||
.orderBy(`${TableName.DynamicSecret}.${orderBy}`, orderDirection);
|
.orderBy(`${TableName.DynamicSecret}.${orderBy}`, orderDirection);
|
||||||
|
|
||||||
|
let queryWithLimit;
|
||||||
if (limit) {
|
if (limit) {
|
||||||
const rankOffset = offset + 1;
|
const rankOffset = offset + 1;
|
||||||
return await (tx || db)
|
queryWithLimit = (tx || db.replicaNode())
|
||||||
.with("w", query)
|
.with("w", query)
|
||||||
.select("*")
|
.select("*")
|
||||||
.from<Awaited<typeof query>[number]>("w")
|
.from<Awaited<typeof query>[number]>("w")
|
||||||
@@ -58,7 +155,22 @@ export const dynamicSecretDALFactory = (db: TDbClient) => {
|
|||||||
.andWhere("w.rank", "<", rankOffset + limit);
|
.andWhere("w.rank", "<", rankOffset + limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
const dynamicSecrets = await query;
|
const dynamicSecrets = sqlNestRelationships({
|
||||||
|
data: await (queryWithLimit || query),
|
||||||
|
key: "id",
|
||||||
|
parentMapper: (el) => el,
|
||||||
|
childrenMapper: [
|
||||||
|
{
|
||||||
|
key: "metadataId",
|
||||||
|
label: "metadata" as const,
|
||||||
|
mapper: ({ metadataKey, metadataValue, metadataId }) => ({
|
||||||
|
id: metadataId,
|
||||||
|
key: metadataKey,
|
||||||
|
value: metadataValue
|
||||||
|
})
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
return dynamicSecrets;
|
return dynamicSecrets;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -66,5 +178,5 @@ export const dynamicSecretDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return { ...orm, listDynamicSecretsByFolderIds };
|
return { ...orm, listDynamicSecretsByFolderIds, findOne, findWithMetadata };
|
||||||
};
|
};
|
||||||
|
@@ -8,11 +8,13 @@ import { getDbConnectionHost } from "@app/lib/knex";
|
|||||||
|
|
||||||
export const verifyHostInputValidity = async (host: string, isGateway = false) => {
|
export const verifyHostInputValidity = async (host: string, isGateway = false) => {
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
// if (appCfg.NODE_ENV === "development") return; // incase you want to remove this check in dev
|
|
||||||
|
if (appCfg.isDevelopmentMode) return [host];
|
||||||
|
|
||||||
const reservedHosts = [appCfg.DB_HOST || getDbConnectionHost(appCfg.DB_CONNECTION_URI)].concat(
|
const reservedHosts = [appCfg.DB_HOST || getDbConnectionHost(appCfg.DB_CONNECTION_URI)].concat(
|
||||||
(appCfg.DB_READ_REPLICAS || []).map((el) => getDbConnectionHost(el.DB_CONNECTION_URI)),
|
(appCfg.DB_READ_REPLICAS || []).map((el) => getDbConnectionHost(el.DB_CONNECTION_URI)),
|
||||||
getDbConnectionHost(appCfg.REDIS_URL)
|
getDbConnectionHost(appCfg.REDIS_URL),
|
||||||
|
getDbConnectionHost(appCfg.AUDIT_LOGS_DB_CONNECTION_URI)
|
||||||
);
|
);
|
||||||
|
|
||||||
// get host db ip
|
// get host db ip
|
||||||
@@ -40,7 +42,7 @@ export const verifyHostInputValidity = async (host: string, isGateway = false) =
|
|||||||
inputHostIps.push(...resolvedIps);
|
inputHostIps.push(...resolvedIps);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isGateway) {
|
if (!isGateway && !(appCfg.DYNAMIC_SECRET_ALLOW_INTERNAL_IP || appCfg.ALLOW_INTERNAL_IP_CONNECTIONS)) {
|
||||||
const isInternalIp = inputHostIps.some((el) => isPrivateIp(el));
|
const isInternalIp = inputHostIps.some((el) => isPrivateIp(el));
|
||||||
if (isInternalIp) throw new BadRequestError({ message: "Invalid db host" });
|
if (isInternalIp) throw new BadRequestError({ message: "Invalid db host" });
|
||||||
}
|
}
|
||||||
|
@@ -12,6 +12,7 @@ import { OrderByDirection, OrgServiceActor } from "@app/lib/types";
|
|||||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||||
import { KmsDataKey } from "@app/services/kms/kms-types";
|
import { KmsDataKey } from "@app/services/kms/kms-types";
|
||||||
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||||
|
import { TResourceMetadataDALFactory } from "@app/services/resource-metadata/resource-metadata-dal";
|
||||||
import { TSecretFolderDALFactory } from "@app/services/secret-folder/secret-folder-dal";
|
import { TSecretFolderDALFactory } from "@app/services/secret-folder/secret-folder-dal";
|
||||||
|
|
||||||
import { TDynamicSecretLeaseDALFactory } from "../dynamic-secret-lease/dynamic-secret-lease-dal";
|
import { TDynamicSecretLeaseDALFactory } from "../dynamic-secret-lease/dynamic-secret-lease-dal";
|
||||||
@@ -46,6 +47,7 @@ type TDynamicSecretServiceFactoryDep = {
|
|||||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||||
projectGatewayDAL: Pick<TProjectGatewayDALFactory, "findOne">;
|
projectGatewayDAL: Pick<TProjectGatewayDALFactory, "findOne">;
|
||||||
|
resourceMetadataDAL: Pick<TResourceMetadataDALFactory, "insertMany" | "delete">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TDynamicSecretServiceFactory = ReturnType<typeof dynamicSecretServiceFactory>;
|
export type TDynamicSecretServiceFactory = ReturnType<typeof dynamicSecretServiceFactory>;
|
||||||
@@ -60,7 +62,8 @@ export const dynamicSecretServiceFactory = ({
|
|||||||
dynamicSecretQueueService,
|
dynamicSecretQueueService,
|
||||||
projectDAL,
|
projectDAL,
|
||||||
kmsService,
|
kmsService,
|
||||||
projectGatewayDAL
|
projectGatewayDAL,
|
||||||
|
resourceMetadataDAL
|
||||||
}: TDynamicSecretServiceFactoryDep) => {
|
}: TDynamicSecretServiceFactoryDep) => {
|
||||||
const create = async ({
|
const create = async ({
|
||||||
path,
|
path,
|
||||||
@@ -73,7 +76,8 @@ export const dynamicSecretServiceFactory = ({
|
|||||||
projectSlug,
|
projectSlug,
|
||||||
actorOrgId,
|
actorOrgId,
|
||||||
defaultTTL,
|
defaultTTL,
|
||||||
actorAuthMethod
|
actorAuthMethod,
|
||||||
|
metadata
|
||||||
}: TCreateDynamicSecretDTO) => {
|
}: TCreateDynamicSecretDTO) => {
|
||||||
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
||||||
if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` });
|
if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` });
|
||||||
@@ -87,9 +91,10 @@ export const dynamicSecretServiceFactory = ({
|
|||||||
actorOrgId,
|
actorOrgId,
|
||||||
actionProjectType: ActionProjectType.SecretManager
|
actionProjectType: ActionProjectType.SecretManager
|
||||||
});
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionDynamicSecretActions.CreateRootCredential,
|
ProjectPermissionDynamicSecretActions.CreateRootCredential,
|
||||||
subject(ProjectPermissionSub.DynamicSecrets, { environment: environmentSlug, secretPath: path })
|
subject(ProjectPermissionSub.DynamicSecrets, { environment: environmentSlug, secretPath: path, metadata })
|
||||||
);
|
);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(actorOrgId);
|
const plan = await licenseService.getPlan(actorOrgId);
|
||||||
@@ -131,16 +136,36 @@ export const dynamicSecretServiceFactory = ({
|
|||||||
projectId
|
projectId
|
||||||
});
|
});
|
||||||
|
|
||||||
const dynamicSecretCfg = await dynamicSecretDAL.create({
|
const dynamicSecretCfg = await dynamicSecretDAL.transaction(async (tx) => {
|
||||||
type: provider.type,
|
const cfg = await dynamicSecretDAL.create(
|
||||||
version: 1,
|
{
|
||||||
encryptedInput: secretManagerEncryptor({ plainText: Buffer.from(JSON.stringify(inputs)) }).cipherTextBlob,
|
type: provider.type,
|
||||||
maxTTL,
|
version: 1,
|
||||||
defaultTTL,
|
encryptedInput: secretManagerEncryptor({ plainText: Buffer.from(JSON.stringify(inputs)) }).cipherTextBlob,
|
||||||
folderId: folder.id,
|
maxTTL,
|
||||||
name,
|
defaultTTL,
|
||||||
projectGatewayId: selectedGatewayId
|
folderId: folder.id,
|
||||||
|
name,
|
||||||
|
projectGatewayId: selectedGatewayId
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
|
||||||
|
if (metadata) {
|
||||||
|
await resourceMetadataDAL.insertMany(
|
||||||
|
metadata.map(({ key, value }) => ({
|
||||||
|
key,
|
||||||
|
value,
|
||||||
|
dynamicSecretId: cfg.id,
|
||||||
|
orgId: actorOrgId
|
||||||
|
})),
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cfg;
|
||||||
});
|
});
|
||||||
|
|
||||||
return dynamicSecretCfg;
|
return dynamicSecretCfg;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -156,7 +181,8 @@ export const dynamicSecretServiceFactory = ({
|
|||||||
actorId,
|
actorId,
|
||||||
newName,
|
newName,
|
||||||
actorOrgId,
|
actorOrgId,
|
||||||
actorAuthMethod
|
actorAuthMethod,
|
||||||
|
metadata
|
||||||
}: TUpdateDynamicSecretDTO) => {
|
}: TUpdateDynamicSecretDTO) => {
|
||||||
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
||||||
if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` });
|
if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` });
|
||||||
@@ -171,10 +197,6 @@ export const dynamicSecretServiceFactory = ({
|
|||||||
actorOrgId,
|
actorOrgId,
|
||||||
actionProjectType: ActionProjectType.SecretManager
|
actionProjectType: ActionProjectType.SecretManager
|
||||||
});
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
ProjectPermissionDynamicSecretActions.EditRootCredential,
|
|
||||||
subject(ProjectPermissionSub.DynamicSecrets, { environment: environmentSlug, secretPath: path })
|
|
||||||
);
|
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(actorOrgId);
|
const plan = await licenseService.getPlan(actorOrgId);
|
||||||
if (!plan?.dynamicSecret) {
|
if (!plan?.dynamicSecret) {
|
||||||
@@ -193,6 +215,27 @@ export const dynamicSecretServiceFactory = ({
|
|||||||
message: `Dynamic secret with name '${name}' in folder '${folder.path}' not found`
|
message: `Dynamic secret with name '${name}' in folder '${folder.path}' not found`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionDynamicSecretActions.EditRootCredential,
|
||||||
|
subject(ProjectPermissionSub.DynamicSecrets, {
|
||||||
|
environment: environmentSlug,
|
||||||
|
secretPath: path,
|
||||||
|
metadata: dynamicSecretCfg.metadata
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
if (metadata) {
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionDynamicSecretActions.EditRootCredential,
|
||||||
|
subject(ProjectPermissionSub.DynamicSecrets, {
|
||||||
|
environment: environmentSlug,
|
||||||
|
secretPath: path,
|
||||||
|
metadata
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (newName) {
|
if (newName) {
|
||||||
const existingDynamicSecret = await dynamicSecretDAL.findOne({ name: newName, folderId: folder.id });
|
const existingDynamicSecret = await dynamicSecretDAL.findOne({ name: newName, folderId: folder.id });
|
||||||
if (existingDynamicSecret)
|
if (existingDynamicSecret)
|
||||||
@@ -231,14 +274,41 @@ export const dynamicSecretServiceFactory = ({
|
|||||||
const isConnected = await selectedProvider.validateConnection(newInput);
|
const isConnected = await selectedProvider.validateConnection(newInput);
|
||||||
if (!isConnected) throw new BadRequestError({ message: "Provider connection failed" });
|
if (!isConnected) throw new BadRequestError({ message: "Provider connection failed" });
|
||||||
|
|
||||||
const updatedDynamicCfg = await dynamicSecretDAL.updateById(dynamicSecretCfg.id, {
|
const updatedDynamicCfg = await dynamicSecretDAL.transaction(async (tx) => {
|
||||||
encryptedInput: secretManagerEncryptor({ plainText: Buffer.from(JSON.stringify(updatedInput)) }).cipherTextBlob,
|
const cfg = await dynamicSecretDAL.updateById(
|
||||||
maxTTL,
|
dynamicSecretCfg.id,
|
||||||
defaultTTL,
|
{
|
||||||
name: newName ?? name,
|
encryptedInput: secretManagerEncryptor({ plainText: Buffer.from(JSON.stringify(updatedInput)) })
|
||||||
status: null,
|
.cipherTextBlob,
|
||||||
statusDetails: null,
|
maxTTL,
|
||||||
projectGatewayId: selectedGatewayId
|
defaultTTL,
|
||||||
|
name: newName ?? name,
|
||||||
|
status: null,
|
||||||
|
projectGatewayId: selectedGatewayId
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
|
||||||
|
if (metadata) {
|
||||||
|
await resourceMetadataDAL.delete(
|
||||||
|
{
|
||||||
|
dynamicSecretId: cfg.id
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
|
||||||
|
await resourceMetadataDAL.insertMany(
|
||||||
|
metadata.map(({ key, value }) => ({
|
||||||
|
key,
|
||||||
|
value,
|
||||||
|
dynamicSecretId: cfg.id,
|
||||||
|
orgId: actorOrgId
|
||||||
|
})),
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cfg;
|
||||||
});
|
});
|
||||||
|
|
||||||
return updatedDynamicCfg;
|
return updatedDynamicCfg;
|
||||||
@@ -268,10 +338,6 @@ export const dynamicSecretServiceFactory = ({
|
|||||||
actorOrgId,
|
actorOrgId,
|
||||||
actionProjectType: ActionProjectType.SecretManager
|
actionProjectType: ActionProjectType.SecretManager
|
||||||
});
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
ProjectPermissionDynamicSecretActions.DeleteRootCredential,
|
|
||||||
subject(ProjectPermissionSub.DynamicSecrets, { environment: environmentSlug, secretPath: path })
|
|
||||||
);
|
|
||||||
|
|
||||||
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
|
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
|
||||||
if (!folder)
|
if (!folder)
|
||||||
@@ -282,6 +348,15 @@ export const dynamicSecretServiceFactory = ({
|
|||||||
throw new NotFoundError({ message: `Dynamic secret with name '${name}' in folder '${folder.path}' not found` });
|
throw new NotFoundError({ message: `Dynamic secret with name '${name}' in folder '${folder.path}' not found` });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionDynamicSecretActions.DeleteRootCredential,
|
||||||
|
subject(ProjectPermissionSub.DynamicSecrets, {
|
||||||
|
environment: environmentSlug,
|
||||||
|
secretPath: path,
|
||||||
|
metadata: dynamicSecretCfg.metadata
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
const leases = await dynamicSecretLeaseDAL.find({ dynamicSecretId: dynamicSecretCfg.id });
|
const leases = await dynamicSecretLeaseDAL.find({ dynamicSecretId: dynamicSecretCfg.id });
|
||||||
// when not forced we check with the external system to first remove the things
|
// when not forced we check with the external system to first remove the things
|
||||||
// we introduce a forced concept because consider the external lease got deleted by some other external like a human or another system
|
// we introduce a forced concept because consider the external lease got deleted by some other external like a human or another system
|
||||||
@@ -329,14 +404,6 @@ export const dynamicSecretServiceFactory = ({
|
|||||||
actorOrgId,
|
actorOrgId,
|
||||||
actionProjectType: ActionProjectType.SecretManager
|
actionProjectType: ActionProjectType.SecretManager
|
||||||
});
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
ProjectPermissionDynamicSecretActions.ReadRootCredential,
|
|
||||||
subject(ProjectPermissionSub.DynamicSecrets, { environment: environmentSlug, secretPath: path })
|
|
||||||
);
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
ProjectPermissionDynamicSecretActions.EditRootCredential,
|
|
||||||
subject(ProjectPermissionSub.DynamicSecrets, { environment: environmentSlug, secretPath: path })
|
|
||||||
);
|
|
||||||
|
|
||||||
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
|
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
|
||||||
if (!folder)
|
if (!folder)
|
||||||
@@ -346,6 +413,25 @@ export const dynamicSecretServiceFactory = ({
|
|||||||
if (!dynamicSecretCfg) {
|
if (!dynamicSecretCfg) {
|
||||||
throw new NotFoundError({ message: `Dynamic secret with name '${name} in folder '${path}' not found` });
|
throw new NotFoundError({ message: `Dynamic secret with name '${name} in folder '${path}' not found` });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionDynamicSecretActions.ReadRootCredential,
|
||||||
|
subject(ProjectPermissionSub.DynamicSecrets, {
|
||||||
|
environment: environmentSlug,
|
||||||
|
secretPath: path,
|
||||||
|
metadata: dynamicSecretCfg.metadata
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionDynamicSecretActions.EditRootCredential,
|
||||||
|
subject(ProjectPermissionSub.DynamicSecrets, {
|
||||||
|
environment: environmentSlug,
|
||||||
|
secretPath: path,
|
||||||
|
metadata: dynamicSecretCfg.metadata
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
|
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
type: KmsDataKey.SecretManager,
|
type: KmsDataKey.SecretManager,
|
||||||
projectId
|
projectId
|
||||||
@@ -356,6 +442,7 @@ export const dynamicSecretServiceFactory = ({
|
|||||||
) as object;
|
) as object;
|
||||||
const selectedProvider = dynamicSecretProviders[dynamicSecretCfg.type as DynamicSecretProviders];
|
const selectedProvider = dynamicSecretProviders[dynamicSecretCfg.type as DynamicSecretProviders];
|
||||||
const providerInputs = (await selectedProvider.validateProviderInputs(decryptedStoredInput)) as object;
|
const providerInputs = (await selectedProvider.validateProviderInputs(decryptedStoredInput)) as object;
|
||||||
|
|
||||||
return { ...dynamicSecretCfg, inputs: providerInputs };
|
return { ...dynamicSecretCfg, inputs: providerInputs };
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -426,7 +513,7 @@ export const dynamicSecretServiceFactory = ({
|
|||||||
});
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionDynamicSecretActions.ReadRootCredential,
|
ProjectPermissionDynamicSecretActions.ReadRootCredential,
|
||||||
subject(ProjectPermissionSub.DynamicSecrets, { environment: environmentSlug, secretPath: path })
|
ProjectPermissionSub.DynamicSecrets
|
||||||
);
|
);
|
||||||
|
|
||||||
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
|
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
|
||||||
@@ -473,16 +560,12 @@ export const dynamicSecretServiceFactory = ({
|
|||||||
actorOrgId,
|
actorOrgId,
|
||||||
actionProjectType: ActionProjectType.SecretManager
|
actionProjectType: ActionProjectType.SecretManager
|
||||||
});
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
ProjectPermissionDynamicSecretActions.ReadRootCredential,
|
|
||||||
subject(ProjectPermissionSub.DynamicSecrets, { environment: environmentSlug, secretPath: path })
|
|
||||||
);
|
|
||||||
|
|
||||||
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
|
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
|
||||||
if (!folder)
|
if (!folder)
|
||||||
throw new NotFoundError({ message: `Folder with path '${path}' in environment '${environmentSlug}' not found` });
|
throw new NotFoundError({ message: `Folder with path '${path}' in environment '${environmentSlug}' not found` });
|
||||||
|
|
||||||
const dynamicSecretCfg = await dynamicSecretDAL.find(
|
const dynamicSecretCfg = await dynamicSecretDAL.findWithMetadata(
|
||||||
{ folderId: folder.id, $search: search ? { name: `%${search}%` } : undefined },
|
{ folderId: folder.id, $search: search ? { name: `%${search}%` } : undefined },
|
||||||
{
|
{
|
||||||
limit,
|
limit,
|
||||||
@@ -490,7 +573,17 @@ export const dynamicSecretServiceFactory = ({
|
|||||||
sort: orderBy ? [[orderBy, orderDirection]] : undefined
|
sort: orderBy ? [[orderBy, orderDirection]] : undefined
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return dynamicSecretCfg;
|
|
||||||
|
return dynamicSecretCfg.filter((dynamicSecret) => {
|
||||||
|
return permission.can(
|
||||||
|
ProjectPermissionDynamicSecretActions.ReadRootCredential,
|
||||||
|
subject(ProjectPermissionSub.DynamicSecrets, {
|
||||||
|
environment: environmentSlug,
|
||||||
|
secretPath: path,
|
||||||
|
metadata: dynamicSecret.metadata
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const listDynamicSecretsByFolderIds = async (
|
const listDynamicSecretsByFolderIds = async (
|
||||||
@@ -542,24 +635,14 @@ export const dynamicSecretServiceFactory = ({
|
|||||||
isInternal,
|
isInternal,
|
||||||
...params
|
...params
|
||||||
}: TListDynamicSecretsMultiEnvDTO) => {
|
}: TListDynamicSecretsMultiEnvDTO) => {
|
||||||
if (!isInternal) {
|
const { permission } = await permissionService.getProjectPermission({
|
||||||
const { permission } = await permissionService.getProjectPermission({
|
actor,
|
||||||
actor,
|
actorId,
|
||||||
actorId,
|
projectId,
|
||||||
projectId,
|
actorAuthMethod,
|
||||||
actorAuthMethod,
|
actorOrgId,
|
||||||
actorOrgId,
|
actionProjectType: ActionProjectType.SecretManager
|
||||||
actionProjectType: ActionProjectType.SecretManager
|
});
|
||||||
});
|
|
||||||
|
|
||||||
// verify user has access to each env in request
|
|
||||||
environmentSlugs.forEach((environmentSlug) =>
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
|
||||||
ProjectPermissionDynamicSecretActions.ReadRootCredential,
|
|
||||||
subject(ProjectPermissionSub.DynamicSecrets, { environment: environmentSlug, secretPath: path })
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const folders = await folderDAL.findBySecretPathMultiEnv(projectId, environmentSlugs, path);
|
const folders = await folderDAL.findBySecretPathMultiEnv(projectId, environmentSlugs, path);
|
||||||
if (!folders.length)
|
if (!folders.length)
|
||||||
@@ -572,7 +655,16 @@ export const dynamicSecretServiceFactory = ({
|
|||||||
...params
|
...params
|
||||||
});
|
});
|
||||||
|
|
||||||
return dynamicSecretCfg;
|
return dynamicSecretCfg.filter((dynamicSecret) => {
|
||||||
|
return permission.can(
|
||||||
|
ProjectPermissionDynamicSecretActions.ReadRootCredential,
|
||||||
|
subject(ProjectPermissionSub.DynamicSecrets, {
|
||||||
|
environment: dynamicSecret.environment,
|
||||||
|
secretPath: path,
|
||||||
|
metadata: dynamicSecret.metadata
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchAzureEntraIdUsers = async ({
|
const fetchAzureEntraIdUsers = async ({
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { OrderByDirection, TProjectPermission } from "@app/lib/types";
|
import { OrderByDirection, TProjectPermission } from "@app/lib/types";
|
||||||
|
import { ResourceMetadataDTO } from "@app/services/resource-metadata/resource-metadata-schema";
|
||||||
import { SecretsOrderBy } from "@app/services/secret/secret-types";
|
import { SecretsOrderBy } from "@app/services/secret/secret-types";
|
||||||
|
|
||||||
import { DynamicSecretProviderSchema } from "./providers/models";
|
import { DynamicSecretProviderSchema } from "./providers/models";
|
||||||
@@ -20,6 +21,7 @@ export type TCreateDynamicSecretDTO = {
|
|||||||
environmentSlug: string;
|
environmentSlug: string;
|
||||||
name: string;
|
name: string;
|
||||||
projectSlug: string;
|
projectSlug: string;
|
||||||
|
metadata?: ResourceMetadataDTO;
|
||||||
} & Omit<TProjectPermission, "projectId">;
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
export type TUpdateDynamicSecretDTO = {
|
export type TUpdateDynamicSecretDTO = {
|
||||||
@@ -31,6 +33,7 @@ export type TUpdateDynamicSecretDTO = {
|
|||||||
environmentSlug: string;
|
environmentSlug: string;
|
||||||
inputs?: TProvider["inputs"];
|
inputs?: TProvider["inputs"];
|
||||||
projectSlug: string;
|
projectSlug: string;
|
||||||
|
metadata?: ResourceMetadataDTO;
|
||||||
} & Omit<TProjectPermission, "projectId">;
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
export type TDeleteDynamicSecretDTO = {
|
export type TDeleteDynamicSecretDTO = {
|
||||||
|
@@ -2,6 +2,7 @@ import handlebars from "handlebars";
|
|||||||
import ldapjs from "ldapjs";
|
import ldapjs from "ldapjs";
|
||||||
import ldif from "ldif";
|
import ldif from "ldif";
|
||||||
import { customAlphabet } from "nanoid";
|
import { customAlphabet } from "nanoid";
|
||||||
|
import RE2 from "re2";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
@@ -194,7 +195,8 @@ export const LdapProvider = (): TDynamicProviderFns => {
|
|||||||
const client = await $getClient(providerInputs);
|
const client = await $getClient(providerInputs);
|
||||||
|
|
||||||
if (providerInputs.credentialType === LdapCredentialType.Static) {
|
if (providerInputs.credentialType === LdapCredentialType.Static) {
|
||||||
const dnMatch = providerInputs.rotationLdif.match(/^dn:\s*(.+)/m);
|
const dnRegex = new RE2("^dn:\\s*(.+)", "m");
|
||||||
|
const dnMatch = dnRegex.exec(providerInputs.rotationLdif);
|
||||||
|
|
||||||
if (dnMatch) {
|
if (dnMatch) {
|
||||||
const username = dnMatch[1];
|
const username = dnMatch[1];
|
||||||
@@ -238,7 +240,8 @@ export const LdapProvider = (): TDynamicProviderFns => {
|
|||||||
const client = await $getClient(providerInputs);
|
const client = await $getClient(providerInputs);
|
||||||
|
|
||||||
if (providerInputs.credentialType === LdapCredentialType.Static) {
|
if (providerInputs.credentialType === LdapCredentialType.Static) {
|
||||||
const dnMatch = providerInputs.rotationLdif.match(/^dn:\s*(.+)/m);
|
const dnRegex = new RE2("^dn:\\s*(.+)", "m");
|
||||||
|
const dnMatch = dnRegex.exec(providerInputs.rotationLdif);
|
||||||
|
|
||||||
if (dnMatch) {
|
if (dnMatch) {
|
||||||
const username = dnMatch[1];
|
const username = dnMatch[1];
|
||||||
|
@@ -7,7 +7,7 @@ import { BadRequestError, InternalServerError, NotFoundError } from "@app/lib/er
|
|||||||
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
||||||
import { TKmsKeyDALFactory } from "@app/services/kms/kms-key-dal";
|
import { TKmsKeyDALFactory } from "@app/services/kms/kms-key-dal";
|
||||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||||
import { KmsDataKey } from "@app/services/kms/kms-types";
|
import { KmsDataKey, KmsKeyUsage } from "@app/services/kms/kms-types";
|
||||||
|
|
||||||
import { TLicenseServiceFactory } from "../license/license-service";
|
import { TLicenseServiceFactory } from "../license/license-service";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
|
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
|
||||||
@@ -115,6 +115,7 @@ export const externalKmsServiceFactory = ({
|
|||||||
{
|
{
|
||||||
isReserved: false,
|
isReserved: false,
|
||||||
description,
|
description,
|
||||||
|
keyUsage: KmsKeyUsage.ENCRYPT_DECRYPT,
|
||||||
name: kmsName,
|
name: kmsName,
|
||||||
orgId: actorOrgId
|
orgId: actorOrgId
|
||||||
},
|
},
|
||||||
|
@@ -92,7 +92,7 @@ export const GcpKmsProviderFactory = async ({ inputs }: GcpKmsProviderArgs): Pro
|
|||||||
plaintext: data
|
plaintext: data
|
||||||
});
|
});
|
||||||
if (!encryptedText[0].ciphertext) throw new Error("encryption failed");
|
if (!encryptedText[0].ciphertext) throw new Error("encryption failed");
|
||||||
return { encryptedBlob: Buffer.from(encryptedText[0].ciphertext) };
|
return { encryptedBlob: Buffer.from(encryptedText[0].ciphertext as Uint8Array) };
|
||||||
};
|
};
|
||||||
|
|
||||||
const decrypt = async (encryptedBlob: Buffer) => {
|
const decrypt = async (encryptedBlob: Buffer) => {
|
||||||
@@ -101,7 +101,7 @@ export const GcpKmsProviderFactory = async ({ inputs }: GcpKmsProviderArgs): Pro
|
|||||||
ciphertext: encryptedBlob
|
ciphertext: encryptedBlob
|
||||||
});
|
});
|
||||||
if (!decryptedText[0].plaintext) throw new Error("decryption failed");
|
if (!decryptedText[0].plaintext) throw new Error("decryption failed");
|
||||||
return { data: Buffer.from(decryptedText[0].plaintext) };
|
return { data: Buffer.from(decryptedText[0].plaintext as Uint8Array) };
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@@ -258,7 +258,7 @@ export const hsmServiceFactory = ({ hsmModule: { isInitialized, pkcs11 }, envCon
|
|||||||
const decrypt: {
|
const decrypt: {
|
||||||
(encryptedBlob: Buffer, providedSession: pkcs11js.Handle): Promise<Buffer>;
|
(encryptedBlob: Buffer, providedSession: pkcs11js.Handle): Promise<Buffer>;
|
||||||
(encryptedBlob: Buffer): Promise<Buffer>;
|
(encryptedBlob: Buffer): Promise<Buffer>;
|
||||||
} = async (encryptedBlob: Buffer, providedSession?: pkcs11js.Handle) => {
|
} = async (encryptedBlob: Buffer, providedSession?: pkcs11js.Handle): Promise<Buffer> => {
|
||||||
if (!pkcs11 || !isInitialized) {
|
if (!pkcs11 || !isInitialized) {
|
||||||
throw new Error("PKCS#11 module is not initialized");
|
throw new Error("PKCS#11 module is not initialized");
|
||||||
}
|
}
|
||||||
@@ -309,10 +309,10 @@ export const hsmServiceFactory = ({ hsmModule: { isInitialized, pkcs11 }, envCon
|
|||||||
|
|
||||||
pkcs11.C_DecryptInit(sessionHandle, decryptMechanism, aesKey);
|
pkcs11.C_DecryptInit(sessionHandle, decryptMechanism, aesKey);
|
||||||
|
|
||||||
const tempBuffer = Buffer.alloc(encryptedData.length);
|
const tempBuffer: Buffer = Buffer.alloc(encryptedData.length);
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||||
const decryptedData = pkcs11.C_Decrypt(sessionHandle, encryptedData, tempBuffer);
|
const decryptedData = pkcs11.C_Decrypt(sessionHandle, encryptedData, tempBuffer);
|
||||||
|
|
||||||
// Create a new buffer from the decrypted data
|
|
||||||
return Buffer.from(decryptedData);
|
return Buffer.from(decryptedData);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(error, "HSM: Failed to perform decryption");
|
logger.error(error, "HSM: Failed to perform decryption");
|
||||||
|
@@ -3,6 +3,7 @@ import { ForbiddenError } from "@casl/ability";
|
|||||||
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
import { TKmsKeyDALFactory } from "@app/services/kms/kms-key-dal";
|
import { TKmsKeyDALFactory } from "@app/services/kms/kms-key-dal";
|
||||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||||
|
import { KmsKeyUsage } from "@app/services/kms/kms-types";
|
||||||
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||||
|
|
||||||
import { OrgPermissionKmipActions, OrgPermissionSubjects } from "../permission/org-permission";
|
import { OrgPermissionKmipActions, OrgPermissionSubjects } from "../permission/org-permission";
|
||||||
@@ -403,6 +404,7 @@ export const kmipOperationServiceFactory = ({
|
|||||||
algorithm,
|
algorithm,
|
||||||
isReserved: false,
|
isReserved: false,
|
||||||
projectId,
|
projectId,
|
||||||
|
keyUsage: KmsKeyUsage.ENCRYPT_DECRYPT,
|
||||||
orgId: project.orgId
|
orgId: project.orgId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { SymmetricEncryption } from "@app/lib/crypto/cipher";
|
import { SymmetricKeyAlgorithm } from "@app/lib/crypto/cipher";
|
||||||
import { OrderByDirection, TOrgPermission, TProjectPermission } from "@app/lib/types";
|
import { OrderByDirection, TOrgPermission, TProjectPermission } from "@app/lib/types";
|
||||||
import { CertKeyAlgorithm } from "@app/services/certificate/certificate-types";
|
import { CertKeyAlgorithm } from "@app/services/certificate/certificate-types";
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ type KmipOperationBaseDTO = {
|
|||||||
} & Omit<TOrgPermission, "orgId">;
|
} & Omit<TOrgPermission, "orgId">;
|
||||||
|
|
||||||
export type TKmipCreateDTO = {
|
export type TKmipCreateDTO = {
|
||||||
algorithm: SymmetricEncryption;
|
algorithm: SymmetricKeyAlgorithm;
|
||||||
} & KmipOperationBaseDTO;
|
} & KmipOperationBaseDTO;
|
||||||
|
|
||||||
export type TKmipGetDTO = {
|
export type TKmipGetDTO = {
|
||||||
@@ -77,7 +77,7 @@ export type TKmipLocateDTO = KmipOperationBaseDTO;
|
|||||||
export type TKmipRegisterDTO = {
|
export type TKmipRegisterDTO = {
|
||||||
name: string;
|
name: string;
|
||||||
key: string;
|
key: string;
|
||||||
algorithm: SymmetricEncryption;
|
algorithm: SymmetricKeyAlgorithm;
|
||||||
} & KmipOperationBaseDTO;
|
} & KmipOperationBaseDTO;
|
||||||
|
|
||||||
export type TSetupOrgKmipDTO = {
|
export type TSetupOrgKmipDTO = {
|
||||||
|
@@ -39,7 +39,7 @@ export const getDefaultOnPremFeatures = (): TFeatureSet => ({
|
|||||||
trial_end: null,
|
trial_end: null,
|
||||||
has_used_trial: true,
|
has_used_trial: true,
|
||||||
secretApproval: false,
|
secretApproval: false,
|
||||||
secretRotation: true,
|
secretRotation: false,
|
||||||
caCrl: false,
|
caCrl: false,
|
||||||
instanceUserManagement: false,
|
instanceUserManagement: false,
|
||||||
externalKms: false,
|
externalKms: false,
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
// TODO(akhilmhdh): With tony find out the api structure and fill it here
|
// TODO(akhilmhdh): With tony find out the api structure and fill it here
|
||||||
|
|
||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
import { CronJob } from "cron";
|
||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { TKeyStoreFactory } from "@app/keystore/keystore";
|
import { TKeyStoreFactory } from "@app/keystore/keystore";
|
||||||
@@ -85,6 +86,20 @@ export const licenseServiceFactory = ({
|
|||||||
appCfg.LICENSE_KEY || ""
|
appCfg.LICENSE_KEY || ""
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const syncLicenseKeyOnPremFeatures = async (shouldThrow: boolean = false) => {
|
||||||
|
logger.info("Start syncing license key features");
|
||||||
|
try {
|
||||||
|
const {
|
||||||
|
data: { currentPlan }
|
||||||
|
} = await licenseServerOnPremApi.request.get<{ currentPlan: TFeatureSet }>("/api/license/v1/plan");
|
||||||
|
onPremFeatures = currentPlan;
|
||||||
|
logger.info("Successfully synchronized license key features");
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(error, "Failed to synchronize license key features");
|
||||||
|
if (shouldThrow) throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const init = async () => {
|
const init = async () => {
|
||||||
try {
|
try {
|
||||||
if (appCfg.LICENSE_SERVER_KEY) {
|
if (appCfg.LICENSE_SERVER_KEY) {
|
||||||
@@ -98,10 +113,7 @@ export const licenseServiceFactory = ({
|
|||||||
if (appCfg.LICENSE_KEY) {
|
if (appCfg.LICENSE_KEY) {
|
||||||
const token = await licenseServerOnPremApi.refreshLicense();
|
const token = await licenseServerOnPremApi.refreshLicense();
|
||||||
if (token) {
|
if (token) {
|
||||||
const {
|
await syncLicenseKeyOnPremFeatures(true);
|
||||||
data: { currentPlan }
|
|
||||||
} = await licenseServerOnPremApi.request.get<{ currentPlan: TFeatureSet }>("/api/license/v1/plan");
|
|
||||||
onPremFeatures = currentPlan;
|
|
||||||
instanceType = InstanceType.EnterpriseOnPrem;
|
instanceType = InstanceType.EnterpriseOnPrem;
|
||||||
logger.info(`Instance type: ${InstanceType.EnterpriseOnPrem}`);
|
logger.info(`Instance type: ${InstanceType.EnterpriseOnPrem}`);
|
||||||
isValidLicense = true;
|
isValidLicense = true;
|
||||||
@@ -147,6 +159,15 @@ export const licenseServiceFactory = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const initializeBackgroundSync = async () => {
|
||||||
|
if (appCfg.LICENSE_KEY) {
|
||||||
|
logger.info("Setting up background sync process for refresh onPremFeatures");
|
||||||
|
const job = new CronJob("*/10 * * * *", syncLicenseKeyOnPremFeatures);
|
||||||
|
job.start();
|
||||||
|
return job;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const getPlan = async (orgId: string, projectId?: string) => {
|
const getPlan = async (orgId: string, projectId?: string) => {
|
||||||
logger.info(`getPlan: attempting to fetch plan for [orgId=${orgId}] [projectId=${projectId}]`);
|
logger.info(`getPlan: attempting to fetch plan for [orgId=${orgId}] [projectId=${projectId}]`);
|
||||||
try {
|
try {
|
||||||
@@ -662,6 +683,7 @@ export const licenseServiceFactory = ({
|
|||||||
getOrgTaxInvoices,
|
getOrgTaxInvoices,
|
||||||
getOrgTaxIds,
|
getOrgTaxIds,
|
||||||
addOrgTaxId,
|
addOrgTaxId,
|
||||||
delOrgTaxId
|
delOrgTaxId,
|
||||||
|
initializeBackgroundSync
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@@ -56,7 +56,7 @@ export type TFeatureSet = {
|
|||||||
trial_end: null;
|
trial_end: null;
|
||||||
has_used_trial: true;
|
has_used_trial: true;
|
||||||
secretApproval: false;
|
secretApproval: false;
|
||||||
secretRotation: true;
|
secretRotation: false;
|
||||||
caCrl: false;
|
caCrl: false;
|
||||||
instanceUserManagement: false;
|
instanceUserManagement: false;
|
||||||
externalKms: false;
|
externalKms: false;
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName } from "@app/db/schemas";
|
import { TableName } from "@app/db/schemas";
|
||||||
import { DatabaseError } from "@app/lib/errors";
|
|
||||||
import { ormify } from "@app/lib/knex";
|
import { ormify } from "@app/lib/knex";
|
||||||
|
|
||||||
export type TOidcConfigDALFactory = ReturnType<typeof oidcConfigDALFactory>;
|
export type TOidcConfigDALFactory = ReturnType<typeof oidcConfigDALFactory>;
|
||||||
@@ -8,22 +7,5 @@ export type TOidcConfigDALFactory = ReturnType<typeof oidcConfigDALFactory>;
|
|||||||
export const oidcConfigDALFactory = (db: TDbClient) => {
|
export const oidcConfigDALFactory = (db: TDbClient) => {
|
||||||
const oidcCfgOrm = ormify(db, TableName.OidcConfig);
|
const oidcCfgOrm = ormify(db, TableName.OidcConfig);
|
||||||
|
|
||||||
const findEnforceableOidcCfg = async (orgId: string) => {
|
return oidcCfgOrm;
|
||||||
try {
|
|
||||||
const oidcCfg = await db
|
|
||||||
.replicaNode()(TableName.OidcConfig)
|
|
||||||
.where({
|
|
||||||
orgId,
|
|
||||||
isActive: true
|
|
||||||
})
|
|
||||||
.whereNotNull("lastUsed")
|
|
||||||
.first();
|
|
||||||
|
|
||||||
return oidcCfg;
|
|
||||||
} catch (error) {
|
|
||||||
throw new DatabaseError({ error, name: "Find org by id" });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return { ...oidcCfgOrm, findEnforceableOidcCfg };
|
|
||||||
};
|
};
|
||||||
|
@@ -165,7 +165,8 @@ export const oidcConfigServiceFactory = ({
|
|||||||
allowedEmailDomains: oidcCfg.allowedEmailDomains,
|
allowedEmailDomains: oidcCfg.allowedEmailDomains,
|
||||||
clientId,
|
clientId,
|
||||||
clientSecret,
|
clientSecret,
|
||||||
manageGroupMemberships: oidcCfg.manageGroupMemberships
|
manageGroupMemberships: oidcCfg.manageGroupMemberships,
|
||||||
|
jwtSignatureAlgorithm: oidcCfg.jwtSignatureAlgorithm
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -481,7 +482,8 @@ export const oidcConfigServiceFactory = ({
|
|||||||
userinfoEndpoint,
|
userinfoEndpoint,
|
||||||
clientId,
|
clientId,
|
||||||
clientSecret,
|
clientSecret,
|
||||||
manageGroupMemberships
|
manageGroupMemberships,
|
||||||
|
jwtSignatureAlgorithm
|
||||||
}: TUpdateOidcCfgDTO) => {
|
}: TUpdateOidcCfgDTO) => {
|
||||||
const org = await orgDAL.findOne({
|
const org = await orgDAL.findOne({
|
||||||
slug: orgSlug
|
slug: orgSlug
|
||||||
@@ -536,7 +538,8 @@ export const oidcConfigServiceFactory = ({
|
|||||||
jwksUri,
|
jwksUri,
|
||||||
isActive,
|
isActive,
|
||||||
lastUsed: null,
|
lastUsed: null,
|
||||||
manageGroupMemberships
|
manageGroupMemberships,
|
||||||
|
jwtSignatureAlgorithm
|
||||||
};
|
};
|
||||||
|
|
||||||
if (clientId !== undefined) {
|
if (clientId !== undefined) {
|
||||||
@@ -569,7 +572,8 @@ export const oidcConfigServiceFactory = ({
|
|||||||
userinfoEndpoint,
|
userinfoEndpoint,
|
||||||
clientId,
|
clientId,
|
||||||
clientSecret,
|
clientSecret,
|
||||||
manageGroupMemberships
|
manageGroupMemberships,
|
||||||
|
jwtSignatureAlgorithm
|
||||||
}: TCreateOidcCfgDTO) => {
|
}: TCreateOidcCfgDTO) => {
|
||||||
const org = await orgDAL.findOne({
|
const org = await orgDAL.findOne({
|
||||||
slug: orgSlug
|
slug: orgSlug
|
||||||
@@ -613,6 +617,7 @@ export const oidcConfigServiceFactory = ({
|
|||||||
userinfoEndpoint,
|
userinfoEndpoint,
|
||||||
orgId: org.id,
|
orgId: org.id,
|
||||||
manageGroupMemberships,
|
manageGroupMemberships,
|
||||||
|
jwtSignatureAlgorithm,
|
||||||
encryptedOidcClientId: encryptor({ plainText: Buffer.from(clientId) }).cipherTextBlob,
|
encryptedOidcClientId: encryptor({ plainText: Buffer.from(clientId) }).cipherTextBlob,
|
||||||
encryptedOidcClientSecret: encryptor({ plainText: Buffer.from(clientSecret) }).cipherTextBlob
|
encryptedOidcClientSecret: encryptor({ plainText: Buffer.from(clientSecret) }).cipherTextBlob
|
||||||
});
|
});
|
||||||
@@ -676,7 +681,8 @@ export const oidcConfigServiceFactory = ({
|
|||||||
const client = new issuer.Client({
|
const client = new issuer.Client({
|
||||||
client_id: oidcCfg.clientId,
|
client_id: oidcCfg.clientId,
|
||||||
client_secret: oidcCfg.clientSecret,
|
client_secret: oidcCfg.clientSecret,
|
||||||
redirect_uris: [`${appCfg.SITE_URL}/api/v1/sso/oidc/callback`]
|
redirect_uris: [`${appCfg.SITE_URL}/api/v1/sso/oidc/callback`],
|
||||||
|
id_token_signed_response_alg: oidcCfg.jwtSignatureAlgorithm
|
||||||
});
|
});
|
||||||
|
|
||||||
const strategy = new OpenIdStrategy(
|
const strategy = new OpenIdStrategy(
|
||||||
|
@@ -5,6 +5,12 @@ export enum OIDCConfigurationType {
|
|||||||
DISCOVERY_URL = "discoveryURL"
|
DISCOVERY_URL = "discoveryURL"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum OIDCJWTSignatureAlgorithm {
|
||||||
|
RS256 = "RS256",
|
||||||
|
HS256 = "HS256",
|
||||||
|
RS512 = "RS512"
|
||||||
|
}
|
||||||
|
|
||||||
export type TOidcLoginDTO = {
|
export type TOidcLoginDTO = {
|
||||||
externalId: string;
|
externalId: string;
|
||||||
email: string;
|
email: string;
|
||||||
@@ -40,6 +46,7 @@ export type TCreateOidcCfgDTO = {
|
|||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
orgSlug: string;
|
orgSlug: string;
|
||||||
manageGroupMemberships: boolean;
|
manageGroupMemberships: boolean;
|
||||||
|
jwtSignatureAlgorithm: OIDCJWTSignatureAlgorithm;
|
||||||
} & TGenericPermission;
|
} & TGenericPermission;
|
||||||
|
|
||||||
export type TUpdateOidcCfgDTO = Partial<{
|
export type TUpdateOidcCfgDTO = Partial<{
|
||||||
@@ -56,5 +63,6 @@ export type TUpdateOidcCfgDTO = Partial<{
|
|||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
orgSlug: string;
|
orgSlug: string;
|
||||||
manageGroupMemberships: boolean;
|
manageGroupMemberships: boolean;
|
||||||
|
jwtSignatureAlgorithm: OIDCJWTSignatureAlgorithm;
|
||||||
}> &
|
}> &
|
||||||
TGenericPermission;
|
TGenericPermission;
|
||||||
|
@@ -3,6 +3,7 @@ import { z } from "zod";
|
|||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import {
|
import {
|
||||||
IdentityProjectMembershipRoleSchema,
|
IdentityProjectMembershipRoleSchema,
|
||||||
|
OrgMembershipRole,
|
||||||
OrgMembershipsSchema,
|
OrgMembershipsSchema,
|
||||||
TableName,
|
TableName,
|
||||||
TProjectRoles,
|
TProjectRoles,
|
||||||
@@ -53,6 +54,7 @@ export const permissionDALFactory = (db: TDbClient) => {
|
|||||||
db.ref("slug").withSchema(TableName.OrgRoles).withSchema(TableName.OrgRoles).as("customRoleSlug"),
|
db.ref("slug").withSchema(TableName.OrgRoles).withSchema(TableName.OrgRoles).as("customRoleSlug"),
|
||||||
db.ref("permissions").withSchema(TableName.OrgRoles),
|
db.ref("permissions").withSchema(TableName.OrgRoles),
|
||||||
db.ref("authEnforced").withSchema(TableName.Organization).as("orgAuthEnforced"),
|
db.ref("authEnforced").withSchema(TableName.Organization).as("orgAuthEnforced"),
|
||||||
|
db.ref("bypassOrgAuthEnabled").withSchema(TableName.Organization).as("bypassOrgAuthEnabled"),
|
||||||
db.ref("groupId").withSchema("userGroups"),
|
db.ref("groupId").withSchema("userGroups"),
|
||||||
db.ref("groupOrgId").withSchema("userGroups"),
|
db.ref("groupOrgId").withSchema("userGroups"),
|
||||||
db.ref("groupName").withSchema("userGroups"),
|
db.ref("groupName").withSchema("userGroups"),
|
||||||
@@ -71,6 +73,7 @@ export const permissionDALFactory = (db: TDbClient) => {
|
|||||||
OrgMembershipsSchema.extend({
|
OrgMembershipsSchema.extend({
|
||||||
permissions: z.unknown(),
|
permissions: z.unknown(),
|
||||||
orgAuthEnforced: z.boolean().optional().nullable(),
|
orgAuthEnforced: z.boolean().optional().nullable(),
|
||||||
|
bypassOrgAuthEnabled: z.boolean(),
|
||||||
customRoleSlug: z.string().optional().nullable(),
|
customRoleSlug: z.string().optional().nullable(),
|
||||||
shouldUseNewPrivilegeSystem: z.boolean()
|
shouldUseNewPrivilegeSystem: z.boolean()
|
||||||
}).parse(el),
|
}).parse(el),
|
||||||
@@ -571,6 +574,11 @@ export const permissionDALFactory = (db: TDbClient) => {
|
|||||||
})
|
})
|
||||||
.join<TProjects>(TableName.Project, `${TableName.Project}.id`, db.raw("?", [projectId]))
|
.join<TProjects>(TableName.Project, `${TableName.Project}.id`, db.raw("?", [projectId]))
|
||||||
.join(TableName.Organization, `${TableName.Project}.orgId`, `${TableName.Organization}.id`)
|
.join(TableName.Organization, `${TableName.Project}.orgId`, `${TableName.Organization}.id`)
|
||||||
|
.join(TableName.OrgMembership, (qb) => {
|
||||||
|
void qb
|
||||||
|
.on(`${TableName.OrgMembership}.userId`, `${TableName.Users}.id`)
|
||||||
|
.andOn(`${TableName.OrgMembership}.orgId`, `${TableName.Organization}.id`);
|
||||||
|
})
|
||||||
.leftJoin(TableName.IdentityMetadata, (queryBuilder) => {
|
.leftJoin(TableName.IdentityMetadata, (queryBuilder) => {
|
||||||
void queryBuilder
|
void queryBuilder
|
||||||
.on(`${TableName.Users}.id`, `${TableName.IdentityMetadata}.userId`)
|
.on(`${TableName.Users}.id`, `${TableName.IdentityMetadata}.userId`)
|
||||||
@@ -670,6 +678,8 @@ export const permissionDALFactory = (db: TDbClient) => {
|
|||||||
db.ref("key").withSchema(TableName.IdentityMetadata).as("metadataKey"),
|
db.ref("key").withSchema(TableName.IdentityMetadata).as("metadataKey"),
|
||||||
db.ref("value").withSchema(TableName.IdentityMetadata).as("metadataValue"),
|
db.ref("value").withSchema(TableName.IdentityMetadata).as("metadataValue"),
|
||||||
db.ref("authEnforced").withSchema(TableName.Organization).as("orgAuthEnforced"),
|
db.ref("authEnforced").withSchema(TableName.Organization).as("orgAuthEnforced"),
|
||||||
|
db.ref("bypassOrgAuthEnabled").withSchema(TableName.Organization).as("bypassOrgAuthEnabled"),
|
||||||
|
db.ref("role").withSchema(TableName.OrgMembership).as("orgRole"),
|
||||||
db.ref("orgId").withSchema(TableName.Project),
|
db.ref("orgId").withSchema(TableName.Project),
|
||||||
db.ref("type").withSchema(TableName.Project).as("projectType"),
|
db.ref("type").withSchema(TableName.Project).as("projectType"),
|
||||||
db.ref("id").withSchema(TableName.Project).as("projectId"),
|
db.ref("id").withSchema(TableName.Project).as("projectId"),
|
||||||
@@ -683,6 +693,7 @@ export const permissionDALFactory = (db: TDbClient) => {
|
|||||||
orgId,
|
orgId,
|
||||||
username,
|
username,
|
||||||
orgAuthEnforced,
|
orgAuthEnforced,
|
||||||
|
orgRole,
|
||||||
membershipId,
|
membershipId,
|
||||||
groupMembershipId,
|
groupMembershipId,
|
||||||
membershipCreatedAt,
|
membershipCreatedAt,
|
||||||
@@ -690,10 +701,12 @@ export const permissionDALFactory = (db: TDbClient) => {
|
|||||||
groupMembershipUpdatedAt,
|
groupMembershipUpdatedAt,
|
||||||
membershipUpdatedAt,
|
membershipUpdatedAt,
|
||||||
projectType,
|
projectType,
|
||||||
shouldUseNewPrivilegeSystem
|
shouldUseNewPrivilegeSystem,
|
||||||
|
bypassOrgAuthEnabled
|
||||||
}) => ({
|
}) => ({
|
||||||
orgId,
|
orgId,
|
||||||
orgAuthEnforced,
|
orgAuthEnforced,
|
||||||
|
orgRole: orgRole as OrgMembershipRole,
|
||||||
userId,
|
userId,
|
||||||
projectId,
|
projectId,
|
||||||
username,
|
username,
|
||||||
@@ -701,7 +714,8 @@ export const permissionDALFactory = (db: TDbClient) => {
|
|||||||
id: membershipId || groupMembershipId,
|
id: membershipId || groupMembershipId,
|
||||||
createdAt: membershipCreatedAt || groupMembershipCreatedAt,
|
createdAt: membershipCreatedAt || groupMembershipCreatedAt,
|
||||||
updatedAt: membershipUpdatedAt || groupMembershipUpdatedAt,
|
updatedAt: membershipUpdatedAt || groupMembershipUpdatedAt,
|
||||||
shouldUseNewPrivilegeSystem
|
shouldUseNewPrivilegeSystem,
|
||||||
|
bypassOrgAuthEnabled
|
||||||
}),
|
}),
|
||||||
childrenMapper: [
|
childrenMapper: [
|
||||||
{
|
{
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user