Compare commits

...

503 Commits

Author SHA1 Message Date
Scott Wilson
76864ababa fix: correct doc casing 2025-05-12 18:37:05 -07:00
Scott Wilson
d17d40ebd9 improvements: refactor org security settings tab to sso page and update doc images 2025-05-12 17:18:40 -07:00
Daniel Hougaard
07df6803a5 Merge pull request #3581 from Infisical/daniel/unblock-dev
fix: move cli install to aws
2025-05-12 18:54:55 +04:00
Daniel Hougaard
a09d0e8948 fix: move cli install to aws 2025-05-12 18:47:02 +04:00
Daniel Hougaard
ee598560ec Merge pull request #3572 from Infisical/daniel/fix-secret-scaninng-public-keys
fix: update secret scanner to latest version
2025-05-12 11:13:51 +04:00
carlosmonastyrski
c629705c9c Merge pull request #3535 from Infisical/feat/addGroupsToSshHosts
feat(ssh-hosts): Add groups to ssh hosts allowed principals
2025-05-09 22:52:35 -03:00
Daniel Hougaard
be10f6e52a Merge pull request #3579 from Infisical/daniel/horizontal-scaling-ms-teams
fix(workflow-integrations): microsoft teams scaling issues
2025-05-10 01:11:37 +04:00
Scott Wilson
40c5ff0ad6 Merge pull request #3578 from Infisical/project-template-improvements
improvement(project-templates): Project templates UI improvements
2025-05-09 13:50:50 -07:00
Scott Wilson
8ecb5ca7bc remove extra margin 2025-05-09 13:47:28 -07:00
Daniel Hougaard
ab6a2b7dbb fix(workflow-integrations): microsoft teams scaling issues 2025-05-10 00:47:22 +04:00
carlosmonastyrski
81bfc04e7c Trim hostname input on SSH Host permission form and fix getWorkspaceUsers key invalidation 2025-05-09 17:10:01 -03:00
x032205
a757fceaed Merge pull request #3577 from Infisical/feat/docs-support-openapi-titles
feat(docs): Support OpenAPI titles for Zod descriptions
2025-05-09 15:49:49 -04:00
Scott Wilson
ce8e18f620 improvement: address feedback 2025-05-09 12:40:07 -07:00
Scott Wilson
d09c964647 fix: use tanstack router link 2025-05-09 12:32:37 -07:00
Scott Wilson
eeddbde600 improvement: update org project templates relocation banner 2025-05-09 12:23:05 -07:00
Daniel Hougaard
859b643e43 Delete ssh 2025-05-09 22:49:39 +04:00
Daniel Hougaard
91f71e0ef6 feat(cli): upgrade secret scanner 2025-05-09 22:48:56 +04:00
x032205
4e9e31eeb7 added credit 2025-05-09 13:45:36 -04:00
x032205
f6bc99b964 support openapi titles for zod description 2025-05-09 13:40:15 -04:00
Scott Wilson
679eb9dffc fix: correct project templates empty table display if feature is disabled 2025-05-09 10:14:03 -07:00
x032205
0754ae3aaf Merge pull request #3576 from Infisical/ENG-2692
feat(api): Rate limit for all email-sending endpoints
2025-05-09 11:37:08 -04:00
x032205
519a0c1bdf Merge branch 'main' into ENG-2692 2025-05-09 11:31:05 -04:00
x032205
e9d8979cf4 add rate limit to all email-sending endpoints 2025-05-09 11:29:53 -04:00
Maidul Islam
486d975fa0 Merge pull request #3575 from akhilmhdh/fix/octokit
feat: resolved esm error in octokit
2025-05-09 10:50:25 -04:00
=
42c49949b4 feat: resolved esm error in octokit 2025-05-09 20:13:08 +05:30
carlosmonastyrski
aea44088db Merge branch 'main' into feat/addGroupsToSshHosts 2025-05-09 09:21:29 -03:00
Daniel Hougaard
e584c9ea95 test 2025-05-09 09:04:30 +04:00
Maidul Islam
428c60880a Update jumpcloud.mdx 2025-05-09 00:28:20 -04:00
Maidul Islam
2179b9a4d7 Update general.mdx 2025-05-09 00:27:43 -04:00
Daniel Hougaard
1921763fa8 fix: update to upcoming version 2025-05-09 04:43:13 +04:00
Daniel Hougaard
5408859a18 fix: update gitleaks/go-diff to latest version 2025-05-09 04:40:09 +04:00
Daniel Hougaard
8dfc0cfbe0 Merge pull request #3571 from Infisical/daniel/identities-ldap-docs
docs(identities): ldap auth
2025-05-09 04:15:11 +04:00
Daniel Hougaard
060199e58c fix: machine identities -> identities 2025-05-09 04:13:11 +04:00
Daniel Hougaard
3b9b17f8d5 requested changes 2025-05-09 04:12:21 +04:00
Daniel Hougaard
6addde2650 docs(identities): ldap auth 2025-05-09 03:44:15 +04:00
Tuan Dang
a6b3be72a9 Make minor PR adjustments 2025-05-08 14:02:25 -07:00
Daniel Hougaard
394bd6755f Merge pull request #3566 from Infisical/daniel/identity-ldap-auth
feat(identities): ldap auth
2025-05-08 23:53:47 +04:00
Daniel Hougaard
c21873ac4b Update identity-ldap-auth-router.ts 2025-05-08 23:48:08 +04:00
Daniel Hougaard
64b8c1a2de added filter check 2025-05-08 23:44:30 +04:00
Daniel Hougaard
de443c5ea1 fix: requested changes 2025-05-08 23:20:18 +04:00
Daniel Hougaard
a3b7df4e6b fix: addressed requested changes 2025-05-08 23:13:46 +04:00
Sheen Capadngan
a4b648ad95 misc: addressed tooltip display issue 2025-05-08 21:24:26 +08:00
x032205
04a8931cf6 Merge pull request #3568 from Infisical/pki-merge-fix
small migration fix
2025-05-08 01:23:36 -04:00
x032205
ab0b8c0f10 migration tweak 2025-05-08 01:22:34 -04:00
x032205
258836a605 migration tweak 2025-05-08 01:17:47 -04:00
Daniel Hougaard
0b31d7f860 feat(identities): ldap auth, requested changes 2025-05-08 08:14:29 +04:00
Daniel Hougaard
5c91d380b8 feat(identities): ldap auth 2025-05-08 07:55:22 +04:00
Daniel Hougaard
b908893a68 feat(identities): ldap auth 2025-05-08 07:49:23 +04:00
Maidul Islam
4d0275e589 Merge pull request #3565 from Infisical/remove-migration-folder
Remove unused migration folder
2025-05-07 20:53:51 -04:00
Maidul Islam
6ca7a990f3 unused folder remove 2025-05-07 20:34:01 -04:00
Scott Wilson
befd77eec2 Merge pull request #3563 from Infisical/policy-selection-modal
improvement(project-roles): Add Policy Selection Modal
2025-05-07 16:49:05 -07:00
Daniel Hougaard
1d44774913 Merge pull request #3564 from Infisical/daniel/generator-doc-imp
docs(k8s/generators): improve documentation
2025-05-08 03:20:30 +04:00
Maidul Islam
984552eea9 rephrase generator overview 2025-05-07 19:18:45 -04:00
Scott Wilson
b6a957a30d fix: select all apply to filtered policies only, skip replacing existing policies 2025-05-07 15:34:34 -07:00
Daniel Hougaard
2f4efad8ae Update infisical-push-secret-crd.mdx 2025-05-08 01:47:00 +04:00
Scott Wilson
16c476d78c fix: correct policies typos 2025-05-07 14:09:32 -07:00
Scott Wilson
68c549f1c6 improvement: add select polices modal 2025-05-07 13:50:27 -07:00
Scott Wilson
0610416677 Merge pull request #3550 from Infisical/project-specific-default-roles
Improvements: Refactor Project Templates and Project Type Policy Filtering/Specific Roles
2025-05-07 12:50:01 -07:00
Daniel Hougaard
4a37dc9cb7 Merge pull request #3561 from Infisical/helm-update-v0.9.2
Update Helm chart to version v0.9.2
2025-05-07 22:37:58 +04:00
DanielHougaard
7e432a4297 Update Helm chart to version v0.9.2 2025-05-07 18:27:13 +00:00
Scott Wilson
794fc9c2a2 improvements: address feedback 2025-05-07 11:23:51 -07:00
Daniel Hougaard
d4e5d2c7ed Merge pull request #3540 from Infisical/daniel/generators
feat(k8s): generator support
2025-05-07 22:10:22 +04:00
Sheen
0c2e0bb0f9 Merge pull request #3560 from Infisical/misc/add-default-old-space-config
misc: add default old space config
2025-05-08 01:46:46 +08:00
Sheen Capadngan
e2a414ffff misc: add default old space config 2025-05-08 01:39:56 +08:00
=
0ca3c2bb68 feat: added password generator crd to samples 2025-05-07 22:50:49 +05:30
Daniel Hougaard
083581b51a Merge pull request #3554 from Infisical/feat/new-project-properties-for-tf-management
feat: adjustments to properties and validation
2025-05-07 20:22:23 +04:00
x032205
40e976133c Merge pull request #3528 from Infisical/ENG-2647
feat(admin): Invalidate Cache
2025-05-07 11:50:57 -04:00
x032205
ad2f002822 Merge pull request #3558 from Infisical/pki-docs-patch
docs fix
2025-05-07 11:06:24 -04:00
x032205
8842dfe5d1 docs fix 2025-05-07 11:01:19 -04:00
Sheen
b1eea4ae9c Merge pull request #3556 from Infisical/misc/remove-unnecessary-key-encryption-for-service-token
misc: removed unnecessary key encryption for service token
2025-05-07 16:41:51 +08:00
Sheen Capadngan
a8e0a8aca3 misc: removed unnecessary key encryption for service token 2025-05-07 16:36:10 +08:00
=
b37058d0e2 feat: switched to is fetching 2025-05-07 11:30:31 +05:30
x032205
334a05d5f1 fix lint 2025-05-06 18:08:08 -04:00
x032205
12c813928c fix polling 2025-05-06 18:00:24 -04:00
x032205
521fef6fca Merge branch 'main' into ENG-2647 2025-05-06 17:00:40 -04:00
=
8f8236c445 feat: simplied the caching panel logic and fixed permission issue 2025-05-07 01:37:26 +05:30
x032205
3cf5c534ff Merge pull request #3553 from Infisical/pki-docs-patch
patch(docs): mint.json update
2025-05-06 15:54:31 -04:00
Sheen Capadngan
2b03c295f9 feat: adjustments to properties and validation 2025-05-07 03:51:22 +08:00
x032205
4fc7a52941 patch(docs): mint.json update 2025-05-06 15:38:10 -04:00
Scott Wilson
0ded2e51ba fix: filter project templates polices by type 2025-05-06 11:59:59 -07:00
Maidul Islam
0d2b3adec7 Merge pull request #3551 from Infisical/maidul98-patch-11
Add Conduct and Enforcement to bug bounty
2025-05-06 14:50:17 -04:00
Maidul Islam
e695203c05 Update docs/internals/bug-bounty.mdx
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2025-05-06 14:49:38 -04:00
Maidul Islam
f9d76aae5d Update bug-bounty.mdx 2025-05-06 14:46:42 -04:00
Daniel Hougaard
1c280759d1 Merge pull request #3548 from Infisical/daniel/self-hosted-secret-scanning
docs: secret scanning self hosted documentation
2025-05-06 22:27:00 +04:00
Scott Wilson
4562f57b54 improvements: refactor project templates, filter policies by project type, project type specific roles 2025-05-06 11:26:09 -07:00
Daniel Hougaard
6005dce44d fix: allow secret scanning from all self-hosted orgs 2025-05-06 22:16:29 +04:00
carlosmonastyrski
bf85df7e36 Fix SSH table UI user groups issues 2025-05-06 08:37:19 -03:00
Daniel Hougaard
f7f7d2d528 fix: typo 2025-05-06 08:24:59 +04:00
Daniel Hougaard
57342cf2a0 docs: secret scanning self hosted documentation 2025-05-06 08:14:05 +04:00
Maidul Islam
d530604b51 Merge pull request #3547 from Infisical/add-host-to-envar
Add missing HOST environment var
2025-05-05 20:46:20 -04:00
Maidul Islam
229c7c0dcf Add missing HOST environment var
Added missing HOST environment var
2025-05-05 20:43:45 -04:00
Maidul Islam
6a79830e01 Update bug-bounty.mdx 2025-05-05 17:32:18 -04:00
x032205
722067f86c Merge pull request #3514 from Infisical/ENG-2685
feat(pki): Store Secret Key Alongside Certificate + Endpoints to Fetch PK / Cert Bundle
2025-05-05 16:12:48 -04:00
x032205
86bb2659b5 small ui tweaks 2025-05-05 16:07:04 -04:00
x032205
dc59f226b6 swapped polling to react query 2025-05-05 15:58:45 -04:00
Scott Wilson
cd9792822b Merge pull request #3545 from Infisical/fix-dns-resolve-fallback
fix(external-connections): Use DNS Lookup as Fallback for DNS Resolve
2025-05-05 12:37:26 -07:00
x032205
9175c1dffa Merge branch 'main' into ENG-2647 2025-05-05 15:27:25 -04:00
Scott Wilson
210f1dc2a2 fix: revert dev comment out 2025-05-05 12:24:12 -07:00
Scott Wilson
7851bb8710 improvement: address feedback 2025-05-05 12:23:18 -07:00
x032205
f6e802c017 review fixes: docs + frontend 2025-05-05 15:07:57 -04:00
Scott Wilson
d28c87ee67 fix: use dns lookup as fallback for dns resolve 2025-05-05 11:56:49 -07:00
x032205
b6e6a3c6be docs changes 2025-05-05 14:50:54 -04:00
Andrey Lyubavin
54927454bf ui fetch private key if permission allows it 2025-05-05 14:37:20 -04:00
carlosmonastyrski
b9070a8fa3 Merge branch 'main' into feat/addGroupsToSshHosts 2025-05-05 14:51:01 -03:00
Andrey Lyubavin
1ce06891a5 ui tweak for role policies 2025-05-05 13:43:38 -04:00
Andrey Lyubavin
3a8154eddc Merge branch 'main' into ENG-2685 2025-05-05 13:37:43 -04:00
Daniel Hougaard
95b6676976 Merge pull request #3539 from Infisical/daniel/gateway-helm-docs
docs(gateway-helm): helm deployment
2025-05-05 17:45:36 +04:00
Maidul Islam
15c0834d56 Merge pull request #3530 from Infisical/email-revamp
improvemet(email-templates): migrate email templates to react email
2025-05-04 23:04:38 -04:00
Daniel Hougaard
1e4dfd0c7c fix(k8s/generators): update base crds 2025-05-05 02:35:57 +04:00
Daniel Hougaard
34b7d28e2f requested changes 2025-05-05 02:30:59 +04:00
Daniel Hougaard
245a348517 Update generators.go 2025-05-05 02:13:12 +04:00
Daniel Hougaard
e0fc582e2e docs(k8s/generators): docs and minor fix 2025-05-05 02:09:21 +04:00
Daniel Hougaard
68ef897b6a fix: logs and rbac 2025-05-05 01:39:30 +04:00
Daniel Hougaard
1b060e76de Update kustomization.yaml 2025-05-05 01:08:22 +04:00
Daniel Hougaard
9f7599b2a1 feat(k8s): generators 2025-05-05 00:59:11 +04:00
Daniel Hougaard
edd415aed8 Update overview.mdx 2025-05-05 00:40:49 +04:00
Daniel Hougaard
c816cbc9a9 docs(gateway-helm): helm deployment 2025-05-05 00:09:59 +04:00
Daniel Hougaard
416811d594 Merge pull request #3524 from Infisical/daniel/gateway-helm
feat(helm): infisical helm
2025-05-04 23:52:19 +04:00
Maidul Islam
80a9d2bba9 Merge pull request #3538 from Infisical/doc/add-auto-deployment-ref-for-daemonsets-and-statefulsets
doc: added daemonset and statefulset auto-redeploy example
2025-05-04 14:16:41 -04:00
Sheen
f5e34ea59e doc: added daemonset and statefulset auto-redeploy example 2025-05-04 15:28:12 +00:00
x
9cbe70a6f3 lint fixes 2025-05-02 20:10:30 -04:00
x
f49fb534ab review fixes 2025-05-02 19:50:55 -04:00
x
6eea4c8364 frontend tweaks 2025-05-02 19:20:02 -04:00
x
1e206ee441 Merge branch 'main' into ENG-2647 2025-05-02 19:03:08 -04:00
Scott Wilson
bec3cec040 fix: correct secret-scanning link 2025-05-02 15:52:13 -07:00
x
85c1a1081e checkpoint 2025-05-02 18:43:07 -04:00
Maidul Islam
d1122886fd Merge pull request #3532 from Infisical/add-missing-identity-specific-privilege-v2-docs-api
Add identity-specific-privilege v2 API to docs
2025-05-02 16:46:45 -04:00
BlackMagiq
3757f190f0 Merge pull request #3522 from Infisical/host-groups
Infisical SSH - Add Support for Host Groups
2025-05-02 13:46:02 -07:00
Maidul Islam
fec55bc9f8 fix greptile recs 2025-05-02 16:40:56 -04:00
Tuan Dang
a285a14fff Fix SshHostsTable component 2025-05-02 13:38:21 -07:00
Tuan Dang
9ec7d0d03e Update login mapping rendering on ssh hosts 2025-05-02 13:37:39 -07:00
Tuan Dang
d5246c2891 Update rendering on login mappings on hosts table 2025-05-02 13:30:48 -07:00
Daniel Hougaard
dcb7215b7d requested changes 2025-05-03 00:20:25 +04:00
x032205
c0f383ce1d Merge pull request #3536 from Infisical/vite-allowed-hosts
feat(vite.config): Allowed Hosts Defined Through Env Variable
2025-05-02 16:16:40 -04:00
Tuan Dang
0dcb223f80 Fix merge conflicts 2025-05-02 13:06:18 -07:00
x
877485b45a queue job 2025-05-02 15:23:35 -04:00
Scott Wilson
f9f098af86 fix: try updating tsup.config to account for .tsx 2025-05-02 12:20:17 -07:00
Tuan Dang
6a5748150a Revise PR based on review 2025-05-02 12:16:51 -07:00
Scott Wilson
3ef053f255 fix: test adding explicity .tsx path 2025-05-02 12:13:23 -07:00
carlosmonastyrski
ed914d49ee Merge pull request #3531 from Infisical/feat/githubSsoDefaultOrganizationSetting
Add Github SSO users to default organization on signup
2025-05-02 15:59:33 -03:00
Scott Wilson
8f7a652741 fix: correct imports 2025-05-02 11:57:18 -07:00
x
e43f583eb6 feat(vite.config): Allowed Hosts Defined Through Env Variable 2025-05-02 14:45:44 -04:00
Scott Wilson
717c947e53 fix: try removing jsx usage 2025-05-02 11:42:20 -07:00
Scott Wilson
8ad334b3ab fix: try reverting ts jsx type 2025-05-02 11:34:18 -07:00
Scott Wilson
c7e707f20a improvement: address feedback 2025-05-02 11:08:41 -07:00
x
d13e685a81 emphasize that secrets cache is encrypted in frontend 2025-05-02 13:04:22 -04:00
x
9849a5f136 switched to applyJitter functions 2025-05-02 13:00:37 -04:00
x
26773a1444 merge 2025-05-02 12:57:28 -04:00
carlosmonastyrski
3ea450e94a Add groups to ssh hosts allowed principals fix delete principal row issue 2025-05-02 13:41:53 -03:00
carlosmonastyrski
7d0574087c Add groups to ssh hosts allowed principals bot improvements 2025-05-02 13:36:05 -03:00
carlosmonastyrski
46755f724c Improve /complete-account/signup body schema 2025-05-02 13:06:45 -03:00
carlosmonastyrski
e12f4ad253 Add cloud check on github add user to default org 2025-05-02 12:58:36 -03:00
carlosmonastyrski
36916704be Add groups to ssh hosts allowed principals 2025-05-02 11:14:43 -03:00
Daniel Hougaard
5dbded60f4 Delete Dockerfile.gateway 2025-05-02 16:38:31 +04:00
Daniel Hougaard
a80d5f10e5 fix(gateway-helm): requested changes 2025-05-02 16:38:02 +04:00
Sheen
0faa8f4bb0 Merge pull request #3533 from Infisical/doc/add-mention-of-pkce-and-eddsa-alg
doc: add mentions of PKCE and eddsa alg for oidc
2025-05-02 19:42:33 +08:00
carlosmonastyrski
365b4b975e Add minor improvements to Github SSO users added to default organization on signup 2025-05-02 08:22:47 -03:00
Sheen
fbf634f7da doc: add mentions of PKCE and eddsa alg for oidc 2025-05-02 07:57:37 +00:00
Maidul Islam
47bb3c10fa Add identity-specific-privilege v2 API to docs
Add identity-specific-privilege v2 API to docs
2025-05-02 00:32:17 -04:00
x032205
1f3e7da3b7 Merge pull request #3487 from Infisical/ENG-2633
feat(secret-sync): Hashicorp Vault App Connection & Secret Sync
2025-05-01 20:31:18 -04:00
x032205
81396f6b51 Small docs change 2025-05-01 20:23:29 -04:00
carlosmonastyrski
63279280fd Add Github SSO users to default organization on signup 2025-05-01 20:41:30 -03:00
Scott Wilson
66fbcc6806 improvemet(email-templates): migrate email templates to react email 2025-05-01 14:57:24 -07:00
x
a6f280197b spelling fix 2025-05-01 17:37:54 -04:00
x
346d2f213e improvements + review fixes 2025-05-01 17:33:24 -04:00
Daniel Hougaard
f2d9593660 Merge pull request #3486 from Infisical/daniel/ms-teams-integration
feat(workflow-integrations): microsoft teams
2025-05-02 00:46:19 +04:00
Daniel Hougaard
219964a242 fix: query invalidation 2025-05-02 00:41:46 +04:00
x
9f1ac77afa invalidate cache 2025-05-01 16:34:29 -04:00
Daniel Hougaard
240f558231 fix: added empty state 2025-05-01 23:49:18 +04:00
Daniel Hougaard
f3b3df1010 Update MicrosoftTeamsIntegrationForm.tsx 2025-05-01 20:43:23 +04:00
Daniel Hougaard
1fd6cd4787 Update MicrosoftTeamsIntegrationForm.tsx 2025-05-01 20:34:09 +04:00
Daniel Hougaard
a7d715ed08 Update MicrosoftTeamsIntegrationForm.tsx 2025-05-01 20:26:47 +04:00
x
a758503f40 new paths get created 2025-05-01 11:53:41 -04:00
Daniel Hougaard
550cb2b5ec smaller ui improvements 2025-05-01 19:50:50 +04:00
Daniel Hougaard
75cb259c51 add description tooltip 2025-05-01 19:15:29 +04:00
x
be2c5a9e57 merge conflicts 2025-05-01 10:48:33 -04:00
Daniel Hougaard
a077a9d6f2 Update OauthCallbackPage.tsx 2025-05-01 18:27:29 +04:00
x032205
296493484f Merge pull request #3525 from Infisical/ENG-2669
feat(agent): Sync Imported Secrets
2025-05-01 10:14:41 -04:00
Daniel Hougaard
835b2fba9c requested changes 2025-05-01 18:02:27 +04:00
Sheen
92bc9d48af Merge pull request #3527 from Infisical/misc/addressed-totp-visibility-issue
misc: addressed totp and sms visibility issue
2025-05-01 21:06:32 +08:00
Sheen Capadngan
a9c1c197f7 misc: added min width 2025-05-01 20:35:29 +08:00
Maidul Islam
5bd7dd4d65 Merge pull request #3521 from Infisical/bug-bounty-program
Add bug bounty program
2025-05-01 08:35:11 -04:00
Sheen Capadngan
8e2cfe2c03 misc: addressed totp visibility issue 2025-05-01 20:26:49 +08:00
x
0bb107d61d feat(agent): Sync Imported Secrets 2025-04-30 22:58:07 -04:00
Daniel Hougaard
82c7dad6c8 feat(helm): infisical helm 2025-05-01 06:45:40 +04:00
Tuan Dang
83df0850ce Fix frontend lint issues 2025-04-30 19:44:56 -07:00
Tuan Dang
ae43435509 Revise PR based on coderabbit, greptile review 2025-04-30 19:39:02 -07:00
Tuan Dang
7811178261 Fix merge conflicts 2025-04-30 18:32:56 -07:00
Tuan Dang
b21b0b340b Complete preliminary ssh host group feature 2025-04-30 18:14:31 -07:00
Maidul Islam
fdbb930940 Merge pull request #3520 from Infisical/daniel/fix-project-deletion
fix(api): project deletion failing
2025-04-30 20:21:02 -04:00
Daniel Hougaard
9e56790886 Update OauthCallbackPage.tsx 2025-05-01 04:13:46 +04:00
Daniel Hougaard
e08c5f265e fix: improve auth step to avoid takeovers 2025-05-01 04:08:58 +04:00
Maidul Islam
e7a55d8a27 Merge pull request #3440 from Infisical/feat/azureClientSecretsRotation
Feat/azure client secrets rotation
2025-04-30 19:45:02 -04:00
carlosmonastyrski
35b8adb0f6 Fix order of Secret Rotation docs 2025-04-30 20:13:20 -03:00
carlosmonastyrski
d161be1170 Improve error propagation and change appId to objectId to match azure 2025-04-30 20:06:13 -03:00
Maidul Islam
aabf933756 Add bug bounty program
Added a formal bounty program
2025-04-30 18:56:23 -04:00
Maidul Islam
5d44d58ff4 update postgres reqs 2025-04-30 17:53:41 -04:00
x
1268bc1238 coderabbit review fixes 2025-04-30 17:50:23 -04:00
x
07e4bc8eed review fixes 2025-04-30 17:46:05 -04:00
Daniel Hougaard
69ef7fdf3b Update index.ts 2025-05-01 01:32:45 +04:00
carlosmonastyrski
ff294dab8d Merge pull request #3507 from Infisical/feat/orgUserAuthTokenExpiration
feat(user-auth): make users auth token expiration customizable for orgs
2025-04-30 18:18:38 -03:00
carlosmonastyrski
a01a9f3f77 Fix bug on azure revokeCredentials and limit expiration to 5 years 2025-04-30 18:16:48 -03:00
carlosmonastyrski
c99440ba81 feat(user-auth): use ms library and update docs 2025-04-30 16:49:33 -03:00
carlosmonastyrski
6d5a6f42e0 Merge branch 'main' into feat/orgUserAuthTokenExpiration 2025-04-30 15:59:52 -03:00
x
235be96ded tweaks 2025-04-30 14:53:57 -04:00
carlosmonastyrski
d0a642a63a Change Azure Client Secret Rotation to show app client id 2025-04-30 15:17:24 -03:00
x
30471bfcad Merge branch 'main' into ENG-2685 2025-04-30 13:41:14 -04:00
carlosmonastyrski
cf84dde0fa Address PR comments for Azure Client Secret Rotation 2025-04-30 13:56:01 -03:00
x032205
0c027fdc43 Merge pull request #3516 from Infisical/feat/teamcity-root-project
remove _Root filter for projects
2025-04-30 12:07:24 -04:00
x
727a6a7701 remove _Root filter for projects 2025-04-30 10:31:40 -04:00
carlosmonastyrski
98bb5d7aa7 Address PR comments for Azure Client Secret Rotation 2025-04-30 10:11:38 -03:00
carlosmonastyrski
7f1f9e7fd0 Merge pull request #3491 from Infisical/feat/improveSecretReferenceWarning
feat(secrets-ui): Add direct reference warning on secrets updates and add secret sync warning on deletion
2025-04-30 08:17:55 -03:00
Tuan Dang
b06eeb0d40 Add add/remove/list hosts in ssh host groups functionality 2025-04-29 23:31:57 -07:00
x
eedffffc38 review fixes 2025-04-30 02:07:07 -04:00
x
5d366687a5 review fixes 2025-04-30 01:16:40 -04:00
x
4720914839 Merge branch 'main' into ENG-2633 2025-04-30 00:54:37 -04:00
x
9f487ad026 frontend type fixes 2025-04-30 00:53:31 -04:00
x
c70b9e665e more tweaks and type fix 2025-04-30 00:39:10 -04:00
x
d460e96052 Merge branch 'main' into ENG-2685 2025-04-30 00:34:37 -04:00
x
e475774910 made certificates store PK and chain in relation to the main table, added /bundle endpoints, new audit log and permission entries 2025-04-30 00:33:46 -04:00
Daniel Hougaard
98f742a807 Merge pull request #3513 from Infisical/daniel/k8s-hsm-docs
docs: fix hsm kubernetes documentation
2025-04-30 06:10:30 +04:00
Daniel Hougaard
66f1967f88 Update hsm-integration.mdx 2025-04-30 05:37:55 +04:00
Daniel Hougaard
da6cf85c8d fix: remove log output file 2025-04-30 05:37:07 +04:00
Daniel Hougaard
e8b6eb0573 docs: fix hsm kubernetes documentation 2025-04-30 05:09:39 +04:00
Maidul Islam
03ad5c5db0 Merge pull request #3512 from Infisical/daniel/kms-docs
docs: prerequisite for aws key
2025-04-29 20:39:30 -04:00
x
e81c49500b get certificate private key endpoint + migrations 2025-04-29 20:34:39 -04:00
Daniel Hougaard
e6c4c27a87 docs: added pre-req for aws key 2025-04-30 03:36:07 +04:00
carlosmonastyrski
2a28d74bde Address PR comments for Azure Client Secret Rotation 2025-04-29 20:19:30 -03:00
Daniel Hougaard
d4ac4f8d8f Update CollapsibleSecretImports.tsx 2025-04-30 03:13:10 +04:00
Daniel Hougaard
aedc6e16ad Update .infisicalignore 2025-04-30 02:51:48 +04:00
Daniel Hougaard
1ec7c67212 Merge branch 'heads/main' into daniel/ms-teams-integration 2025-04-30 02:39:08 +04:00
Daniel Hougaard
ff0ff622a6 requested changes 2025-04-30 02:35:07 +04:00
carlosmonastyrski
511becabd8 Merge branch 'main' into feat/azureClientSecretsRotation 2025-04-29 19:26:14 -03:00
carlosmonastyrski
f0229c5ecf feat(user-auth): fix migration bug for e2e suite 2025-04-29 18:48:08 -03:00
carlosmonastyrski
8d711af23b feat(secrets-ui): change secret sync icon color 2025-04-29 18:39:41 -03:00
carlosmonastyrski
7bd61d88fc feat(user-auth): improve token refresh logic and default values 2025-04-29 18:28:18 -03:00
Tuan Dang
a9a16c9bd1 Begin work on ssh host groups 2025-04-29 13:39:24 -07:00
Daniel Hougaard
929434d17f docs: improved ms teams workflow integration self-hosting docs 2025-04-30 00:15:58 +04:00
Scott Wilson
ba94b91974 Merge pull request #3510 from Infisical/internal-ip-check-fix
fix(external-connections): Use Hostname for Blocking Internal IPs DNS Resolve
2025-04-29 12:37:46 -07:00
Scott Wilson
b65f62fda8 fix: use hostname for blocking internal IPs 2025-04-29 12:26:29 -07:00
carlosmonastyrski
c47d76a6c7 feat(secrets-ui): improve warning message table 2025-04-29 14:19:52 -03:00
x032205
9138a9e71d Merge pull request #3509 from Infisical/feat/teamcity-ignore-inherited-secrets
feat(secret-sync): TeamCity ignore inherited and non-env values
2025-04-29 12:49:01 -04:00
x
8e4ad8baf8 docs tweak 2025-04-29 12:43:44 -04:00
x
9f158d5b3f feat(docs): Added note stating that inherited secrets are ignored 2025-04-29 10:35:56 -04:00
x
0e1cb4ebb2 Merge branch 'main' into feat/teamcity-ignore-inherited-secrets 2025-04-29 10:31:51 -04:00
carlosmonastyrski
e959ed7fab feat(secrets-ui): improve warning message and logic for secret-sync on secret imports 2025-04-29 10:15:53 -03:00
carlosmonastyrski
4e4b1b689b Merge branch 'main' into feat/improveSecretReferenceWarning 2025-04-29 08:43:35 -03:00
Maidul Islam
8f07f43fbd Merge pull request #3504 from akhilmhdh/doc/assume-privilege
doc: added doc for assume privilege feature
2025-04-28 20:08:44 -07:00
Maidul Islam
023f5d1286 revise docs 2025-04-28 23:06:37 -04:00
Daniel Hougaard
72b03d4bdf Merge pull request #3506 from Infisical/daniel/build-strict-find-filter
feat: strict find filter
2025-04-29 05:41:39 +04:00
Daniel Hougaard
e870e35002 consolidated filtering functions into one 2025-04-29 04:27:10 +04:00
carlosmonastyrski
4544f621af Merge pull request #3478 from Infisical/fix/UISecretEditPermissionButNotReadValuePermission
fix(secrets-table): UI fix for users with edit permissions but not read secret value permission
2025-04-28 20:23:34 -03:00
x
ddb5098eda only sync non-inherited environment variables 2025-04-28 19:09:13 -04:00
carlosmonastyrski
35749e8d12 feat(user-auth): allow edit overwritter rotation value on overview table 2025-04-28 20:02:50 -03:00
x
ee2e2246da solved merge conflicts 2025-04-28 18:51:20 -04:00
x
e30d400afa Support for namespaces (for HCP) 2025-04-28 18:34:33 -04:00
carlosmonastyrski
024ed0c0d8 feat(user-auth): add pr suggestions 2025-04-28 18:19:44 -03:00
carlosmonastyrski
e99e360339 feat(user-auth): make users auth token expiration customizable for orgs 2025-04-28 17:43:10 -03:00
Daniel Hougaard
85965184f8 Update secret-v2-bridge-dal.ts 2025-04-29 00:18:13 +04:00
Daniel Hougaard
a1bbd50c0b feat: build strict find filter 2025-04-29 00:09:30 +04:00
carlosmonastyrski
f9c936865a feat(secrets-ui): minor improvements from PR suggestions 2025-04-28 16:49:29 -03:00
Sheen
2be10b5f9d Merge pull request #3503 from Infisical/feat/add-support-for-eddsa-jwt-alg
feat: add support for eddsa jwt alg for oidc
2025-04-29 03:27:58 +08:00
Maidul Islam
3b6e35e13c Merge pull request #3505 from akhilmhdh/feat/cache-jitter
feat: increased secret caching to 10mins with jitter of 2min
2025-04-28 12:16:00 -07:00
=
fcf984965e feat: increased secret caching to 10mins with jitter of 2min 2025-04-29 00:36:39 +05:30
=
6bca854475 doc: added doc for assume privilege feature 2025-04-29 00:12:37 +05:30
x032205
a69ce50da9 Merge pull request #3495 from Infisical/ENG-2656
feat(login): Update all SSO login methods to use PKCE
2025-04-28 14:33:02 -04:00
Sheen Capadngan
1b798bd5d5 misc: fixed casing 2025-04-29 02:08:13 +08:00
Sheen Capadngan
bd3ebe75c9 feat: add support for eddsa jwt alg for oidc 2025-04-29 02:05:19 +08:00
Maidul Islam
0f2b8e4266 Update github-org-sync.mdx 2025-04-28 14:04:02 -04:00
x
c4ae8f2987 Remove false comment 2025-04-28 13:30:06 -04:00
x
b50a022d11 PKCE check logic fix 2025-04-28 13:28:47 -04:00
x
8a035c8d82 check if OIDC provider supports PKCE before applying it 2025-04-28 12:51:18 -04:00
carlosmonastyrski
4fa7ba2ec7 Merge branch 'main' into fix/UISecretEditPermissionButNotReadValuePermission 2025-04-28 13:33:05 -03:00
x
03d7f9f786 scope fix for google strategy 2025-04-28 12:17:04 -04:00
x
1b3e8b0a1c fixed merge conflicts 2025-04-28 10:52:12 -04:00
Sheen
6a26a11cbb Merge pull request #3471 from Infisical/feat/add-support-for-org-sso-bypass-for-sso
feat: enabled sso (google, gitlab, github) to bypass org sso
2025-04-28 22:35:53 +08:00
Maidul Islam
d673c8d8e9 Merge pull request #3498 from akhilmhdh/feat/gh-sync
feat: github org sync
2025-04-28 07:26:07 -07:00
=
b39c7070b5 feat: linted merge issues 2025-04-28 19:51:10 +05:30
=
fa3dd03074 feat: updated review comments by @sheen 2025-04-28 19:48:57 +05:30
=
ee40ffd304 feat: changed get user to get org membership details 2025-04-28 19:48:56 +05:30
=
d3d76467ac feat: addressed rabbit and reptile feedback 2025-04-28 19:48:56 +05:30
=
58940f31e3 docs: added doc for github org sync 2025-04-28 19:48:56 +05:30
=
6d2175cf9f feat: completed github org sync 2025-04-28 19:48:56 +05:30
Maidul Islam
dbb0b28453 Merge pull request #3494 from Infisical/fix/moveablePermissionList
feat(project-permissions): allow users to sort permissions on the UI
2025-04-28 07:14:57 -07:00
Daniel Hougaard
225862aed8 Merge pull request #3453 from Infisical/daniel/reminders
feat(reminders): specify recipients
2025-04-28 18:14:23 +04:00
Maidul Islam
8d1bd6aabb Merge pull request #3447 from akhilmhdh/feat/assume-role
Implemented project permission impersonation
2025-04-28 06:59:09 -07:00
Maidul Islam
740c650441 fix import 2025-04-28 09:54:02 -04:00
BlackMagiq
78ccb5acb7 Merge pull request #3497 from Infisical/ssh-host-alias
Infisical SSH: Add Alias Field to SSH Hosts
2025-04-28 06:41:29 -07:00
Maidul Islam
e9aa8b317b Merge branch 'main' into feat/assume-role 2025-04-28 06:33:26 -07:00
=
7b42f666f9 feat: updated files on review changes 2025-04-28 18:56:17 +05:30
Maidul Islam
8a0cfa34d2 Merge pull request #3501 from Infisical/fix-kms-memory-leak
Fix KMS memory leak
2025-04-28 05:02:26 -07:00
Maidul Islam
ca9825c1fe remove unused logger 2025-04-28 07:59:00 -04:00
Maidul Islam
1dfc9511c1 throw only error and remove bool return 2025-04-28 07:55:33 -04:00
Maidul Islam
694ab35f53 Fix KMS memory leak
Adds a clean up method because KMS clients like GCP use a persistent connection snd if not closed, will continue to eat up the memory.
2025-04-28 07:48:31 -04:00
Daniel Hougaard
f35cd2d6a6 Update project-service.ts 2025-04-28 05:20:56 +04:00
Daniel Hougaard
b259428075 fix: secret scanning & route mismatch 2025-04-28 05:16:33 +04:00
Daniel Hougaard
f54a10f626 Merge branch 'heads/main' into daniel/ms-teams-integration 2025-04-28 05:08:04 +04:00
Daniel Hougaard
63a3ce2dba feat(workflow-integrations): ms-teams audit logs and pagination support 2025-04-28 04:58:25 +04:00
Daniel Hougaard
9aabc3ced7 better error logs 2025-04-28 04:07:32 +04:00
Daniel Hougaard
fe9ec6b030 docs(workflow-integrations): microsoft teams 2025-04-28 04:07:01 +04:00
Tuan Dang
44ae0519d1 Revise ssh host alias field handling/validation 2025-04-27 14:34:26 -07:00
Tuan Dang
3d89a7f45d Revise ssh host alias PR 2025-04-26 18:18:22 -07:00
Tuan Dang
de63c8cb6c Add alias field to ssh hosts for improved ux 2025-04-26 18:04:21 -07:00
Scott Wilson
632572f7c3 Merge pull request #3452 from Infisical/ldaps-connection-and-password-rotation
Feature: LDAP Connection and Password Rotation
2025-04-26 09:13:08 -07:00
Daniel Hougaard
bef55043f7 Update OrgWorkflowIntegrationTab.tsx 2025-04-26 10:16:30 +04:00
Daniel Hougaard
0323d152da feat(microsoft-teams): better authentication flow and doc references 2025-04-26 09:46:23 +04:00
Daniel Hougaard
0a5f6274f5 Update CreateReminderForm.tsx 2025-04-26 05:56:11 +04:00
Daniel Hougaard
11ee13676d fix: deletion corner cases 2025-04-26 05:55:25 +04:00
Daniel Hougaard
e7783fe6cc requested changes & edge cases 2025-04-26 05:19:02 +04:00
Scott Wilson
a524690d01 deconflict merge 2025-04-25 17:20:30 -07:00
carlosmonastyrski
c229d6888c feat(secrets-ui): allow read access to personal overrides 2025-04-25 20:41:44 -03:00
x
b6566943c6 solve merge conflicts 2025-04-25 19:11:00 -04:00
carlosmonastyrski
2e459c161d feat(project-permissions): type fix 2025-04-25 19:51:08 -03:00
x
680f1a2230 Merge branch 'main' into ENG-2656 2025-04-25 18:46:05 -04:00
x
68e21ba8ce PKCE for Github, Gitlab, Google, and OIDC SSO 2025-04-25 18:45:23 -04:00
carlosmonastyrski
1e9722474f feat(project-permissions): allow users to sort permissions on the UI 2025-04-25 19:35:42 -03:00
Scott Wilson
f93edbb37f Merge pull request #3493 from Infisical/improve-aws-connection-error-propagation
improvement(app-connections): Improve AWS Connection Error Propagation
2025-04-25 15:25:55 -07:00
Scott Wilson
fa8154ecdd improvement: add undefined handling 2025-04-25 15:06:16 -07:00
Scott Wilson
d977092502 improvement: improve validate aws connection error propagation 2025-04-25 15:05:22 -07:00
carlosmonastyrski
f345801bd6 feat(secrets-ui): improve types and code quality 2025-04-25 18:17:33 -03:00
carlosmonastyrski
f460acf9b4 fix(secrets-permissions): Fix case for rotated secrets 2025-04-25 17:56:56 -03:00
carlosmonastyrski
4160009913 feat(secrets-ui): add direct reference warning on secrets updates 2025-04-25 17:38:43 -03:00
Andrey
cceb29b93a Merge pull request #3476 from Infisical/ENG-2625
feat(secret-sync): TeamCity App Connection & Secret Sync
2025-04-25 15:44:37 -04:00
carlosmonastyrski
02b44365f1 Merge pull request #3470 from Infisical/feat/awsSecretRotationV2
feat(secret-rotation-v2): Add AWS IAM User Secret rotation
2025-04-25 16:43:22 -03:00
carlosmonastyrski
b506393765 feat(aws-iam-rotation): docs improvements 2025-04-25 16:35:57 -03:00
carlosmonastyrski
d5065af7e9 feat(secrets-ui): add secret syncs to referenced secret warning 2025-04-25 15:26:34 -03:00
carlosmonastyrski
204269a10d Merge pull request #3480 from Infisical/feat/paginationAndFilterOnProjectMembers
feat(project-members): Persist pagination setting and add role filtering
2025-04-25 14:51:05 -03:00
BlackMagiq
cf1f83aaa3 Merge pull request #3446 from Infisical/ssh-non-interactive
Improvements to Infisical V2: Support for Non-Interactive Mode, Updating Default SSH CAs.
2025-04-25 10:15:06 -07:00
Andrey
7894181234 Merge pull request #3490 from Infisical/ENG-2546
feat(auth): Persist pre-login-redirect path and redirect after login
2025-04-25 13:12:46 -04:00
Tuan Dang
0c214a2f26 Adjust CLI flags to be dash-case 2025-04-25 10:03:51 -07:00
Tuan Dang
f5862cbb9a Merge 2025-04-25 09:32:48 -07:00
Tuan Dang
bb699ecb5f Merge remote-tracking branch 'origin' into ssh-non-interactive 2025-04-25 09:31:39 -07:00
carlosmonastyrski
68e88ddef8 feat(azure-client-secrets-rotation): add show credentials modal 2025-04-25 13:16:13 -03:00
x
04b20ed11d feat(auth): Persist pre-login-redirect path and redirect after login 2025-04-25 12:09:18 -04:00
Sheen
cd1e2af9bf Merge pull request #3489 from Infisical/feat/add-user-get-token-and-revamp-session-management
feat: add user get token CLI and revamp session management
2025-04-25 23:45:38 +08:00
carlosmonastyrski
a2909b8030 Merge branch 'main' into feat/azureClientSecretsRotation 2025-04-25 12:42:48 -03:00
carlosmonastyrski
7a4a877e39 feat(aws-iam-rotation): remove credentials validation due to excesive await time 2025-04-25 12:38:41 -03:00
carlosmonastyrski
8f670bde88 feat(aws-iam-rotation): add credentials validation 2025-04-25 12:06:30 -03:00
carlosmonastyrski
ff9011c899 feat(aws-iam-rotation): add view credentials component 2025-04-25 11:23:43 -03:00
carlosmonastyrski
57c96abe03 feat(aws-iam-rotation): address PR comments 2025-04-25 11:01:35 -03:00
Sheen Capadngan
178acc412d misc: added optional accesS 2025-04-25 20:52:55 +08:00
Sheen Capadngan
b0288c49c0 feat: add user get token CLI and revamp session management 2025-04-25 20:43:20 +08:00
carlosmonastyrski
3de5fa066b fix(secrets-permissions): Fix setTimeout and eye icon size 2025-04-25 08:54:25 -03:00
carlosmonastyrski
f5bb0d4a86 Merge pull request #3484 from Infisical/fix/dynamicSecretSqlErrorPropagation
fix(dynamic-secret): improve error propagation and add FAQ to docs
2025-04-25 08:41:42 -03:00
Daniel Hougaard
8987938642 fix(microsoft-teams-integration): bug fixes 2025-04-25 11:03:31 +04:00
x
3f00359459 implemented blockLocalAndPrivateIpAddresses 2025-04-24 23:53:20 -04:00
x
a5b5b90ca1 nit: make docs a bit more future proof and descriptive 2025-04-24 23:48:09 -04:00
x
fd0a00023b nit: organize docs sidebar alphabetically 2025-04-24 23:40:47 -04:00
x
7699705334 tiny encodeURIComponent tweak 2025-04-24 23:36:11 -04:00
x
7c49f6e302 review fixes 2025-04-24 23:30:35 -04:00
x
dd112b3850 review fixes 2025-04-24 22:39:20 -04:00
Scott Wilson
b329b5aa4b improvements: address feedback 2025-04-24 19:35:56 -07:00
x
c01c58fdcb small nit for consistency 2025-04-24 22:10:21 -04:00
x
4bba207552 fix UpdateHCVaultConnectionSchema only supporting AccessToken 2025-04-24 22:09:06 -04:00
x
0882c181d0 docs(native-integrations): Add deprication warnings on Windmill + TeamCity 2025-04-24 21:55:44 -04:00
Daniel Hougaard
8563eb850b fix: ts errors 2025-04-25 05:40:28 +04:00
x
8672dd641a Merge branch 'main' into ENG-2625 2025-04-24 21:26:05 -04:00
x
4225bf6e0e Merge branch 'main' into ENG-2633 2025-04-24 21:23:38 -04:00
x
fab385fdd9 feat(docs): Hashicorp Vault App Connection & Secret Sync Docs 2025-04-24 21:22:44 -04:00
Daniel Hougaard
a204629bef Merge branch 'heads/main' into daniel/ms-teams-integration 2025-04-25 05:22:35 +04:00
Daniel Hougaard
50679ba29d fix: requested changes 2025-04-25 05:22:17 +04:00
Daniel Hougaard
f5fa57d6c5 fix: further cleanup 2025-04-25 04:53:00 +04:00
Daniel Hougaard
6088ae09ab fix: cleanup 2025-04-25 04:40:46 +04:00
Daniel Hougaard
0de15bf70c fix: remove logs 2025-04-25 04:37:22 +04:00
Daniel Hougaard
b5d229a7c5 feat(native-integrations): microsoft teams 2025-04-25 04:35:40 +04:00
Maidul Islam
c613bb642e Merge pull request #3485 from Infisical/daniel/kms-logs
fix(kms): better error logs
2025-04-24 17:06:01 -07:00
Daniel Hougaard
90fdba0b77 Update kms-service.ts 2025-04-25 04:04:26 +04:00
Daniel Hougaard
795ce11062 Update kms-service.ts 2025-04-25 04:00:14 +04:00
Daniel Hougaard
2d4adfc651 fix(kms): better error logs 2025-04-25 03:54:59 +04:00
x
92084ccd47 feat(secrey-sync): Hashicorp Vault Secret Sync (and minor app connection fixes) 2025-04-24 18:54:05 -04:00
carlosmonastyrski
cb826f1a77 fix(dynamic-secret): improve error propagation and add FAQ to docs 2025-04-24 19:21:30 -03:00
Maidul Islam
55f6a06440 Merge pull request #2718 from akhilmhdh/doc/infisical-package
docs: added new docs for infisical package installation instructions
2025-04-24 14:18:07 -07:00
Maidul Islam
a19e5ff905 add min version 2025-04-24 14:16:56 -07:00
Maidul Islam
dccada8a12 Update docs/self-hosting/deployment-options/native/linux-package/installation.mdx
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2025-04-24 14:13:59 -07:00
Maidul Islam
68bbff455f Update docs/self-hosting/overview.mdx
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2025-04-24 14:12:59 -07:00
Maidul Islam
fcb59a1482 Update docs/self-hosting/overview.mdx
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2025-04-24 14:12:45 -07:00
Maidul Islam
b92bc2183a Update docs/self-hosting/deployment-options/native/linux-package/commands-configuration.mdx
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2025-04-24 14:12:27 -07:00
Maidul Islam
aff318cf3c Merge branch 'main' into doc/infisical-package 2025-04-24 14:12:01 -07:00
Maidul Islam
c97a3f07a7 update linux docs 2025-04-24 14:10:21 -07:00
Scott Wilson
e0dc2dd6d8 improvements: address feedback 2025-04-24 13:44:43 -07:00
x
418ac20f91 feat(app-connections): Hashicorp Vault App Connection 2025-04-24 15:41:21 -04:00
carlosmonastyrski
8bf5b0f457 Merge pull request #3481 from Infisical/fix/AddDeleteProjectProtectedTooltip
fix(delete-project): Add tooltip for delete project button when it has protection enabled
2025-04-24 12:59:35 -03:00
carlosmonastyrski
4973447676 feat(project-members): PR suggestions improvements 2025-04-24 12:21:19 -03:00
carlosmonastyrski
bd2e2b7931 feat(project-members): PR suggestions improvements 2025-04-24 12:14:06 -03:00
Andrey
13b7729af8 Merge pull request #3472 from Infisical/ENG-2618
Admin SSO bypass (break-glass login) sends out email to all org admins + creates audit log
2025-04-24 10:37:00 -04:00
x
e25c1199bc Made email URL use SITE_URL 2025-04-24 10:24:42 -04:00
carlosmonastyrski
b377d2a6b1 fix(secrets-permissions): Fix setTimeout 2025-04-24 11:15:42 -03:00
Akhil Mohan
6b3726957a Merge pull request #3443 from akhilmhdh/doc/sql-change
Updated doc to have europe infisical aws account id
2025-04-24 19:07:43 +05:30
carlosmonastyrski
c64e6310a6 fix(delete-project): Add tooltip for delete project button when it has protection enabled 2025-04-24 10:26:54 -03:00
carlosmonastyrski
aa893a40a9 feat(project-members): Persist pagination setting and add role filtering 2025-04-24 10:06:09 -03:00
carlosmonastyrski
350272aa57 fix(secrets-permissions): UI improvements 2025-04-24 08:10:10 -03:00
Vlad Matsiiako
0e488d840f Merge pull request #3479 from Infisical/update-org-structure-blueprint
Update the organization structure guide to include organizations and …
2025-04-23 21:18:43 -07:00
carlosmonastyrski
95489e1b0a fix(secrets-permissions): UI improvements 2025-04-23 22:24:41 -03:00
ArshBallagan
d6186f1fe8 Update organization-structure.mdx 2025-04-23 17:48:26 -07:00
ArshBallagan
cd199f9d3e Update the organization structure guide to include organizations and clusters 2025-04-23 17:44:51 -07:00
Scott Wilson
71258b6ea7 Merge pull request #3477 from Infisical/native-integration-deleted-import-fix
Fix: Filter Out Deleted Imports with Replication
2025-04-23 17:22:04 -07:00
carlosmonastyrski
56b3e7a76d fix(secrets-permissions): UI fix for users with edit permissions but not read secret value permission 2025-04-23 21:09:19 -03:00
Scott Wilson
49c90c801e fix: filter out deleted imports with replication 2025-04-23 17:03:33 -07:00
x
d019011822 Made findOrgMembersByUsername use replicaNode to stay consistent 2025-04-23 19:53:14 -04:00
x
8bd21ffa63 Attached settings URL to email, actor no longer a recipient, removed error handling for email send, used read replica node for findOrgMembersByRole 2025-04-23 19:46:25 -04:00
Maidul Islam
024a1891d3 Merge pull request #3450 from Infisical/google-cloud-run-guide
Adding a guide on deploying Infisical using Google Cloud Run
2025-04-23 16:08:26 -07:00
Maidul Islam
ac7ac79463 add to nav bar 2025-04-23 16:00:30 -07:00
x
23df78eff8 feat(secret-sync): Only import secrets that have a value from destination to infisical: 2025-04-23 18:57:08 -04:00
x
84255d1b26 remove debug logs, update comments, other nitpicks 2025-04-23 18:44:14 -04:00
x
3a6b2a593b Merge branch 'main' into ENG-2625 2025-04-23 17:59:34 -04:00
x
d3ee30f5e6 feat(secret-sync): TeamCity App Connection & Secret Sync 2025-04-23 17:58:59 -04:00
ArshBallagan
317b15157d Update google-cloud-run.mdx 2025-04-23 10:44:39 -07:00
Daniel Hougaard
9ea6eca560 requested changes 2025-04-23 21:40:01 +04:00
Daniel Hougaard
f145a00ef5 Merge pull request #3451 from Infisical/daniel/kms-improvements
improvement(kms): return kms key id in project response
2025-04-23 21:35:51 +04:00
ArshBallagan
2e34167a24 Update google-cloud-run.mdx 2025-04-23 10:29:13 -07:00
Maidul Islam
0fc7d04455 Merge pull request #3475 from akhilmhdh/feat/secret-cache-v2
feat(api): implemented secret caching version 2
2025-04-23 09:58:00 -07:00
=
af12518f54 fix: resolved lints, addressed feedback from rabbit, reptile and maidul 2025-04-23 22:23:32 +05:30
Andrey
cc193b9a9f Merge pull request #3459 from Infisical/ENG-2635
Moved certificate manager overview tabs to left sidebar
2025-04-23 12:42:48 -04:00
Sheen
0e95600db3 Merge pull request #3469 from Infisical/misc/reordered-kube-auth-not-found-check
misc: reordered kube auth not found check
2025-04-23 22:18:54 +08:00
=
b60172f2be feat(api): implemented secret caching version 2 2025-04-23 19:15:50 +05:30
Scott Wilson
33dea34061 chore: removed unused pick 2025-04-22 18:51:40 -07:00
ArshBallagan
bc1cce62ab Adding more architecture detail to the Cloud Run document 2025-04-22 18:50:45 -07:00
Scott Wilson
da68073e86 chore: revert secret rotation flag 2025-04-22 18:06:44 -07:00
Scott Wilson
7bd312a287 improvements: update regex checks 2025-04-22 17:57:59 -07:00
Scott Wilson
d61e6752d6 Merge branch 'main' into ldaps-connection-and-password-rotation 2025-04-22 17:42:48 -07:00
Scott Wilson
636aee2ea9 improvements: address feedback 2025-04-22 17:36:18 -07:00
Maidul Islam
b20e6a9265 Merge pull request #3473 from Infisical/add-winget-dcs
docs: add winget docs
2025-04-22 15:43:36 -07:00
Maidul Islam
5de9bf25e0 add winget docs 2025-04-22 15:37:45 -07:00
carlosmonastyrski
5819b8c576 PR fix suggestions for aws secret rotations 2025-04-22 17:40:15 -03:00
Sheen Capadngan
d5888f9de7 misc: only append isAdminLogin query param when relevant 2025-04-23 03:27:22 +08:00
Sheen Capadngan
1590b528bf misc: used url search params 2025-04-23 03:07:50 +08:00
x
a838f84601 Revert license overwrites, fix type errors, add error handling to email function 2025-04-22 14:58:17 -04:00
carlosmonastyrski
e30a05e3e8 Remove unnecessary password type 2025-04-22 15:49:05 -03:00
carlosmonastyrski
ce7798c48b Fix redirect url for azure secrets 2025-04-22 15:44:21 -03:00
x
a32b590dc5 Merge branch 'main' into ENG-2618 2025-04-22 14:37:22 -04:00
x
b330fdbc58 Admin SSO bypass (breakglass login) sends out email to all org admins + creates audit log 2025-04-22 14:36:31 -04:00
Sheen Capadngan
75f1ce7b86 feat: enabled sso to bypass org sso 2025-04-23 02:28:58 +08:00
Maidul Islam
4e10f51e50 Merge pull request #3455 from akhilmhdh/feat/hide-swagger
Hide non public endpoints in swagger
2025-04-22 10:42:29 -07:00
carlosmonastyrski
6ce1c4e19e Merge branch 'main' into feat/azureClientSecretsRotation 2025-04-22 14:25:56 -03:00
carlosmonastyrski
f08de1599d PR fix suggestions 2025-04-22 14:25:52 -03:00
carlosmonastyrski
b85809293c Lint fix 2025-04-22 13:53:56 -03:00
carlosmonastyrski
f143d8c358 Merge branch 'main' into feat/awsSecretRotationV2 2025-04-22 13:46:35 -03:00
Scott Wilson
26c14119be Merge pull request #3463 from Infisical/fix-enterprise-plan-display
Fix: Correct Enterprise Plan Display
2025-04-22 09:33:31 -07:00
carlosmonastyrski
2e3330bf69 Add AWS secret rotation V2 2025-04-22 13:26:48 -03:00
Sheen Capadngan
778d6b9bbf misc: reordered kube auth not found check 2025-04-22 23:06:47 +08:00
Akhil Mohan
b4e831d3e2 Merge pull request #3468 from akhilmhdh/fix/remove-banner
feat: removed banner on ui for subscription crossing
2025-04-22 19:38:02 +05:30
=
8818d5c94b feat: removed banner for now 2025-04-22 19:32:48 +05:30
=
8bfbac153c feat: nit fixing 2025-04-22 12:44:45 +05:30
Maidul Islam
d7af9e84be added more validation to region 2025-04-21 22:09:52 -07:00
Scott Wilson
f2a984e6b6 fix: correct plan check for when to display enterprise plan 2025-04-21 19:39:13 -07:00
Andrey
2cff90913b Merge pull request #3461 from Infisical/ENG-2623
Removed low entropy password regexes that threw false positives
2025-04-21 22:25:58 -04:00
Daniel Hougaard
c783fa32e9 Merge pull request #3462 from Infisical/daniel/fix-saml-sso-creation
fix: stuck on saml sso creation page
2025-04-22 06:19:52 +04:00
Daniel Hougaard
109971916b fix: stuck on saml sso creation page 2025-04-22 06:07:14 +04:00
x
f7d35e61f7 removed low entropy password regexes that threw false positives 2025-04-21 19:40:20 -04:00
x
ddd46acbde replace alerting icon with notification bell, add new notification bell lotties icon, update permission check wrapper to display access restricted popup 2025-04-21 19:01:12 -04:00
x
e6165f7790 remove commented code, combine a UI if-check, split permission check for cert section and pki collection section 2025-04-21 17:39:42 -04:00
x
ac12f9fc66 update file and export names to be accurate 2025-04-21 16:59:37 -04:00
Scott Wilson
6107adcc15 Merge pull request #3460 from Infisical/improve-sql-connection-valdiation-error-propogtation
Improvement: Improve SQL Connection Validation Error Propogation
2025-04-21 13:54:41 -07:00
x
7408d38065 fix an import issue 2025-04-21 16:51:30 -04:00
Scott Wilson
a4eb2e77c2 improvement: move client instantation to try/catch for sql connection validation for error propogation 2025-04-21 13:49:09 -07:00
x
e0c458df4b Merge branch 'ENG-2635' of https://github.com/Infisical/infisical into ENG-2635 2025-04-21 16:21:56 -04:00
x
6a751e720c Changed cert-manager overview tabs to be proper routes 2025-04-21 16:16:47 -04:00
Sheen
40d119b462 Merge pull request #3457 from Infisical/misc/moved-regex-use-to-re2
misc: moved regex use to re2
2025-04-22 04:02:54 +08:00
carlosmonastyrski
6f738d7ed0 Merge pull request #3458 from Infisical/fix/SamlRemovalCornerCase
Allow user to remove SAML config
2025-04-21 15:45:36 -03:00
carlosmonastyrski
7f4d4b931b Add entryPoint zod validation 2025-04-21 15:28:59 -03:00
=
a80520e425 feat: removed all impersonate word in ui 2025-04-21 23:29:25 +05:30
carlosmonastyrski
608e9a644c Make entryPoint mandatory on SSOModal and check all fields on isSamlConfigured check 2025-04-21 14:52:33 -03:00
Scott Wilson
35f0e8f49a Merge pull request #3456 from Infisical/fix/secretVersionReferenceIssue
Fix SecretVersionV2 reference issue blocking users and identities deletion
2025-04-21 10:20:54 -07:00
carlosmonastyrski
efb8b69777 Fix SecretVersionV2 reference issue blocking users and identities deletion 2025-04-21 14:06:33 -03:00
=
4aa3552060 feat: fixed ts issues 2025-04-21 21:30:28 +05:30
Akhil Mohan
b4226e7e1b Merge pull request #3427 from akhilmhdh/feat/block-user-on-trail
Block user on crossing the identity limit
2025-04-21 20:06:22 +05:30
=
40781949a6 feat: updated ui based on feedback 2025-04-21 20:02:23 +05:30
carlosmonastyrski
7d4f223174 lint fix 2025-04-21 10:36:27 -03:00
carlosmonastyrski
ef47d0056f Merge branch 'main' into feat/azureClientSecretsRotation 2025-04-21 10:27:56 -03:00
carlosmonastyrski
ccd7b0062e Fix MAX_GENERATED_CREDENTIALS_LENGTH for azure credentials 2025-04-21 10:14:55 -03:00
=
2ee423174a feat: updated code by rabbit, reptile and maidul changes 2025-04-21 18:43:21 +05:30
=
649f7b560f feat: added audit log for assume 2025-04-21 18:43:21 +05:30
=
7219ba3b46 feat: implemented user role impersonation 2025-04-21 18:43:21 +05:30
=
ca1f7d3448 feat: reptile and rabbit changes 2025-04-21 15:23:48 +05:30
=
4d569d70d6 fix: broken docs 2025-04-21 14:36:33 +05:30
=
5fccc62213 feat: updated docs to include various endpoints in cli only 2025-04-21 13:22:42 +05:30
Daniel Hougaard
6e65656360 Update CreateReminderForm.tsx 2025-04-19 07:15:29 +04:00
Daniel Hougaard
e0491c2056 Update types.ts 2025-04-19 07:11:22 +04:00
Daniel Hougaard
b8db15563a Update 20250419004044_secret-reminder-recipients.ts 2025-04-19 07:07:45 +04:00
Daniel Hougaard
9982ade219 feat(reminders): specify recipients 2025-04-19 06:59:22 +04:00
Scott Wilson
9032bbe514 feature: ldap connection and password rotation 2025-04-18 17:55:03 -07:00
Tuan Dang
1ea8e5a81e Add frontend uniqueness check for ssh hostnames 2025-04-18 15:25:13 -07:00
Daniel Hougaard
39ff7fddee improvement: add ID to external KMS list and add copy button 2025-04-19 00:20:18 +04:00
Daniel Hougaard
a0014230f9 improvement: include kms secret manager key ID on project response 2025-04-19 00:19:57 +04:00
ArshBallagan
60d0bc827c Update google-cloud-run.mdx 2025-04-18 12:37:18 -07:00
ArshBallagan
6e9651d188 Adding a guide on deploying Infisical using Google Cloud Run 2025-04-18 11:35:59 -07:00
Tuan Dang
42aa3c3d46 Remove extra tx in ssh nullable ca defaults migration, update ssh docs 2025-04-18 11:06:59 -07:00
=
7364717f60 feat: added an additional 10 as threshold 2025-04-18 22:35:41 +05:30
Tuan Dang
184d353de5 Update infisical ssh docs to clarify ssh connect command in different modes 2025-04-17 23:29:20 -07:00
Tuan Dang
b2360f9cc8 Reuse writeToFile fn in ssh connect command 2025-04-17 23:12:44 -07:00
Tuan Dang
846a5a6e19 impl improvements according to greptile 2025-04-17 23:08:33 -07:00
Tuan Dang
c6cd3a8cc0 Add audit logs to project ssh config endpoints 2025-04-17 23:00:46 -07:00
Tuan Dang
796f5510ca Add cli docs for infisical ssh connect command 2025-04-17 22:40:43 -07:00
Tuan Dang
0265665e83 Make infisical ssh v2 work in non-interactive mode, allow reassignment of default ssh cas 2025-04-17 22:35:25 -07:00
=
79e425d807 feat: updated doc to have europe infisical aws account id 2025-04-17 14:25:55 +05:30
carlosmonastyrski
c403ffa9f6 Add Azure Client Secrets Rotation docs 2025-04-16 06:33:38 -03:00
carlosmonastyrski
1184ea1b11 Add Azure Client Secrets Rotation 2025-04-16 05:04:41 -03:00
carlosmonastyrski
7d97a76ecc Merge branch 'auth0-connection-and-secret-rotation' into feat/azureClientSecretsRotation 2025-04-15 23:58:27 -03:00
carlosmonastyrski
a889f92528 Add Azure Client Secrets App Connection 2025-04-15 23:39:06 -03:00
=
5b20c1feba feat: reptile jaw spaced 2025-04-16 00:30:11 +05:30
=
ac73800acb feat: added banner on crossing user/identity limit 2025-04-16 00:25:21 +05:30
=
dd323eccd4 feat: added banner on projects when limit reached 2025-04-15 22:00:22 +05:30
=
c1570930a9 docs: added new docs for infisical package installation instructions 2024-11-11 19:23:31 +05:30
1231 changed files with 44775 additions and 12221 deletions

View File

@@ -0,0 +1,27 @@
name: Release Gateway Helm Chart
on:
workflow_dispatch:
jobs:
release-helm:
name: Release Helm Chart
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Helm
uses: azure/setup-helm@v3
with:
version: v3.10.0
- name: Install python
uses: actions/setup-python@v4
- name: Install Cloudsmith CLI
run: pip install --upgrade cloudsmith-cli
- name: Build and push helm package to CloudSmith
run: cd helm-charts && sh upload-gateway-cloudsmith.sh
env:
CLOUDSMITH_API_KEY: ${{ secrets.CLOUDSMITH_API_KEY }}

View File

@@ -24,3 +24,7 @@ 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 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:281
docs/documentation/platform/kms/overview.mdx:generic-api-key:344 docs/documentation/platform/kms/overview.mdx:generic-api-key:344
frontend/src/pages/secret-manager/OverviewPage/components/SecretOverviewTableRow/SecretOverviewTableRow.tsx:generic-api-key:85
docs/cli/commands/user.mdx:generic-api-key:51
frontend/src/pages/secret-manager/OverviewPage/components/SecretOverviewTableRow/SecretOverviewTableRow.tsx:generic-api-key:76
docs/integrations/app-connections/hashicorp-vault.mdx:generic-api-key:188

View File

@@ -133,8 +133,8 @@ RUN apt-get update && apt-get install -y \
RUN printf "[FreeTDS]\nDescription = FreeTDS Driver\nDriver = /usr/lib/x86_64-linux-gnu/odbc/libtdsodbc.so\nSetup = /usr/lib/x86_64-linux-gnu/odbc/libtdsS.so\nFileUsage = 1\n" > /etc/odbcinst.ini RUN printf "[FreeTDS]\nDescription = FreeTDS Driver\nDriver = /usr/lib/x86_64-linux-gnu/odbc/libtdsodbc.so\nSetup = /usr/lib/x86_64-linux-gnu/odbc/libtdsS.so\nFileUsage = 1\n" > /etc/odbcinst.ini
# Install Infisical CLI # Install Infisical CLI
RUN curl -1sLf 'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.deb.sh' | bash \ RUN curl -1sLf 'https://artifacts-cli.infisical.com/setup.deb.sh' | bash \
&& apt-get update && apt-get install -y infisical=0.31.1 \ && apt-get update && apt-get install -y infisical=0.41.2 \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
RUN groupadd -r -g 1001 nodejs && useradd -r -u 1001 -g nodejs non-root-user RUN groupadd -r -g 1001 nodejs && useradd -r -u 1001 -g nodejs non-root-user
@@ -171,6 +171,7 @@ ENV NODE_ENV production
ENV STANDALONE_BUILD true ENV STANDALONE_BUILD true
ENV STANDALONE_MODE true ENV STANDALONE_MODE true
ENV ChrystokiConfigurationPath=/usr/safenet/lunaclient/ ENV ChrystokiConfigurationPath=/usr/safenet/lunaclient/
ENV NODE_OPTIONS="--max-old-space-size=1024"
WORKDIR /backend WORKDIR /backend

View File

@@ -127,8 +127,8 @@ RUN apt-get update && apt-get install -y \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
# Install Infisical CLI # Install Infisical CLI
RUN curl -1sLf 'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.deb.sh' | bash \ RUN curl -1sLf 'https://artifacts-cli.infisical.com/setup.deb.sh' | bash \
&& apt-get update && apt-get install -y infisical=0.31.1 \ && apt-get update && apt-get install -y infisical=0.41.2 \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
WORKDIR / WORKDIR /
@@ -168,6 +168,7 @@ ENV HTTPS_ENABLED false
ENV NODE_ENV production ENV NODE_ENV production
ENV STANDALONE_BUILD true ENV STANDALONE_BUILD true
ENV STANDALONE_MODE true ENV STANDALONE_MODE true
ENV NODE_OPTIONS="--max-old-space-size=1024"
WORKDIR /backend WORKDIR /backend

View File

@@ -69,6 +69,15 @@ module.exports = {
["^\\."] ["^\\."]
] ]
} }
],
"import/extensions": [
"error",
"ignorePackages",
{
"": "never", // this is required to get the .tsx to work...
ts: "never",
tsx: "never"
}
] ]
} }
}; };

View File

@@ -54,8 +54,8 @@ COPY --from=build /app .
# Install Infisical CLI # Install Infisical CLI
RUN apt-get install -y curl bash && \ RUN apt-get install -y curl bash && \
curl -1sLf 'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.deb.sh' | bash && \ curl -1sLf 'https://artifacts-cli.infisical.com/setup.deb.sh' | bash && \
apt-get update && apt-get install -y infisical=0.8.1 git apt-get update && apt-get install -y infisical=0.41.2 git
HEALTHCHECK --interval=10s --timeout=3s --start-period=10s \ HEALTHCHECK --interval=10s --timeout=3s --start-period=10s \
CMD node healthcheck.js CMD node healthcheck.js

View File

@@ -55,9 +55,9 @@ RUN mkdir -p /etc/softhsm2/tokens && \
# ? App setup # ? App setup
# Install Infisical CLI # Install Infisical CLI
RUN curl -1sLf 'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.deb.sh' | bash && \ RUN curl -1sLf 'https://artifacts-cli.infisical.com/setup.deb.sh' | bash && \
apt-get update && \ apt-get update && \
apt-get install -y infisical=0.8.1 apt-get install -y infisical=0.41.2
WORKDIR /app WORKDIR /app

View File

@@ -64,9 +64,9 @@ RUN wget https://www.openssl.org/source/openssl-3.1.2.tar.gz \
# ? App setup # ? App setup
# Install Infisical CLI # Install Infisical CLI
RUN curl -1sLf 'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.deb.sh' | bash && \ RUN curl -1sLf 'https://artifacts-cli.infisical.com/setup.deb.sh' | bash && \
apt-get update && \ apt-get update && \
apt-get install -y infisical=0.8.1 apt-get install -y infisical=0.41.2
WORKDIR /app WORKDIR /app

View File

@@ -1,4 +1,8 @@
import RE2 from "re2";
import { TKeyStoreFactory } from "@app/keystore/keystore"; import { TKeyStoreFactory } from "@app/keystore/keystore";
import { applyJitter } from "@app/lib/dates";
import { delay as delayMs } from "@app/lib/delay";
import { Lock } from "@app/lib/red-lock"; import { Lock } from "@app/lib/red-lock";
export const mockKeyStore = (): TKeyStoreFactory => { export const mockKeyStore = (): TKeyStoreFactory => {
@@ -18,6 +22,27 @@ export const mockKeyStore = (): TKeyStoreFactory => {
delete store[key]; delete store[key];
return 1; return 1;
}, },
deleteItems: async ({ pattern, batchSize = 500, delay = 1500, jitter = 200 }) => {
const regex = new RE2(`^${pattern.replace(/[-[\]/{}()+?.\\^$|]/g, "\\$&").replace(/\*/g, ".*")}$`);
let totalDeleted = 0;
const keys = Object.keys(store);
for (let i = 0; i < keys.length; i += batchSize) {
const batch = keys.slice(i, i + batchSize);
for (const key of batch) {
if (regex.test(key)) {
delete store[key];
totalDeleted += 1;
}
}
// eslint-disable-next-line no-await-in-loop
await delayMs(Math.max(0, applyJitter(delay, jitter)));
}
return totalDeleted;
},
getItem: async (key) => { getItem: async (key) => {
const value = store[key]; const value = store[key];
if (typeof value === "string") { if (typeof value === "string") {

3370
backend/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -72,7 +72,8 @@
"seed:new": "tsx ./scripts/create-seed-file.ts", "seed:new": "tsx ./scripts/create-seed-file.ts",
"seed": "knex --knexfile ./dist/db/knexfile.ts --client pg seed:run", "seed": "knex --knexfile ./dist/db/knexfile.ts --client pg seed:run",
"seed-dev": "knex --knexfile ./src/db/knexfile.ts --client pg seed:run", "seed-dev": "knex --knexfile ./src/db/knexfile.ts --client pg seed:run",
"db:reset": "npm run migration:rollback -- --all && npm run migration:latest" "db:reset": "npm run migration:rollback -- --all && npm run migration:latest",
"email:dev": "email dev --dir src/services/smtp/emails"
}, },
"keywords": [], "keywords": [],
"author": "", "author": "",
@@ -91,12 +92,12 @@
"@types/lodash.isequal": "^4.5.8", "@types/lodash.isequal": "^4.5.8",
"@types/node": "^20.17.30", "@types/node": "^20.17.30",
"@types/nodemailer": "^6.4.14", "@types/nodemailer": "^6.4.14",
"@types/passport-github": "^1.1.12",
"@types/passport-google-oauth20": "^2.0.14", "@types/passport-google-oauth20": "^2.0.14",
"@types/pg": "^8.10.9", "@types/pg": "^8.10.9",
"@types/picomatch": "^2.3.3", "@types/picomatch": "^2.3.3",
"@types/pkcs11js": "^1.0.4", "@types/pkcs11js": "^1.0.4",
"@types/prompt-sync": "^4.2.3", "@types/prompt-sync": "^4.2.3",
"@types/react": "^19.1.2",
"@types/resolve": "^1.20.6", "@types/resolve": "^1.20.6",
"@types/safe-regex": "^1.1.6", "@types/safe-regex": "^1.1.6",
"@types/sjcl": "^1.0.34", "@types/sjcl": "^1.0.34",
@@ -116,6 +117,7 @@
"nodemon": "^3.0.2", "nodemon": "^3.0.2",
"pino-pretty": "^10.2.3", "pino-pretty": "^10.2.3",
"prompt-sync": "^4.2.0", "prompt-sync": "^4.2.0",
"react-email": "4.0.7",
"rimraf": "^5.0.5", "rimraf": "^5.0.5",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"tsc-alias": "^1.8.8", "tsc-alias": "^1.8.8",
@@ -150,6 +152,8 @@
"@infisical/quic": "^1.0.8", "@infisical/quic": "^1.0.8",
"@node-saml/passport-saml": "^5.0.1", "@node-saml/passport-saml": "^5.0.1",
"@octokit/auth-app": "^7.1.1", "@octokit/auth-app": "^7.1.1",
"@octokit/core": "^5.2.1",
"@octokit/plugin-paginate-graphql": "^4.0.1",
"@octokit/plugin-retry": "^5.0.5", "@octokit/plugin-retry": "^5.0.5",
"@octokit/rest": "^20.0.2", "@octokit/rest": "^20.0.2",
"@octokit/webhooks-types": "^7.3.1", "@octokit/webhooks-types": "^7.3.1",
@@ -164,6 +168,7 @@
"@opentelemetry/semantic-conventions": "^1.27.0", "@opentelemetry/semantic-conventions": "^1.27.0",
"@peculiar/asn1-schema": "^2.3.8", "@peculiar/asn1-schema": "^2.3.8",
"@peculiar/x509": "^1.12.1", "@peculiar/x509": "^1.12.1",
"@react-email/components": "0.0.36",
"@serdnam/pino-cloudwatch-transport": "^1.0.4", "@serdnam/pino-cloudwatch-transport": "^1.0.4",
"@sindresorhus/slugify": "1.1.0", "@sindresorhus/slugify": "1.1.0",
"@slack/oauth": "^3.0.2", "@slack/oauth": "^3.0.2",
@@ -175,6 +180,7 @@
"axios": "^1.6.7", "axios": "^1.6.7",
"axios-retry": "^4.0.0", "axios-retry": "^4.0.0",
"bcrypt": "^5.1.1", "bcrypt": "^5.1.1",
"botbuilder": "^4.23.2",
"bullmq": "^5.4.2", "bullmq": "^5.4.2",
"cassandra-driver": "^4.7.2", "cassandra-driver": "^4.7.2",
"connect-redis": "^7.1.1", "connect-redis": "^7.1.1",
@@ -208,10 +214,10 @@
"ora": "^7.0.1", "ora": "^7.0.1",
"oracledb": "^6.4.0", "oracledb": "^6.4.0",
"otplib": "^12.0.1", "otplib": "^12.0.1",
"passport-github": "^1.1.0",
"passport-gitlab2": "^5.0.0", "passport-gitlab2": "^5.0.0",
"passport-google-oauth20": "^2.0.0", "passport-google-oauth20": "^2.0.0",
"passport-ldapauth": "^3.0.1", "passport-ldapauth": "^3.0.1",
"passport-oauth2": "^1.8.0",
"pg": "^8.11.3", "pg": "^8.11.3",
"pg-boss": "^10.1.5", "pg-boss": "^10.1.5",
"pg-query-stream": "^4.5.3", "pg-query-stream": "^4.5.3",
@@ -222,6 +228,8 @@
"posthog-node": "^3.6.2", "posthog-node": "^3.6.2",
"probot": "^13.3.8", "probot": "^13.3.8",
"re2": "^1.21.4", "re2": "^1.21.4",
"react": "19.1.0",
"react-dom": "19.1.0",
"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",
@@ -233,6 +241,6 @@
"tweetnacl-util": "^0.15.1", "tweetnacl-util": "^0.15.1",
"uuid": "^9.0.1", "uuid": "^9.0.1",
"zod": "^3.22.4", "zod": "^3.22.4",
"zod-to-json-schema": "^3.22.4" "zod-to-json-schema": "^3.24.5"
} }
} }

View File

@@ -5,6 +5,7 @@ import { Redis } from "ioredis";
import { TUsers } from "@app/db/schemas"; import { TUsers } from "@app/db/schemas";
import { TAccessApprovalPolicyServiceFactory } from "@app/ee/services/access-approval-policy/access-approval-policy-service"; import { TAccessApprovalPolicyServiceFactory } from "@app/ee/services/access-approval-policy/access-approval-policy-service";
import { TAccessApprovalRequestServiceFactory } from "@app/ee/services/access-approval-request/access-approval-request-service"; import { TAccessApprovalRequestServiceFactory } from "@app/ee/services/access-approval-request/access-approval-request-service";
import { TAssumePrivilegeServiceFactory } from "@app/ee/services/assume-privilege/assume-privilege-service";
import { TAuditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-service"; import { TAuditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-service";
import { TCreateAuditLogDTO } from "@app/ee/services/audit-log/audit-log-types"; import { TCreateAuditLogDTO } from "@app/ee/services/audit-log/audit-log-types";
import { TAuditLogStreamServiceFactory } from "@app/ee/services/audit-log-stream/audit-log-stream-service"; import { TAuditLogStreamServiceFactory } from "@app/ee/services/audit-log-stream/audit-log-stream-service";
@@ -14,6 +15,7 @@ import { TDynamicSecretServiceFactory } from "@app/ee/services/dynamic-secret/dy
import { TDynamicSecretLeaseServiceFactory } from "@app/ee/services/dynamic-secret-lease/dynamic-secret-lease-service"; import { TDynamicSecretLeaseServiceFactory } from "@app/ee/services/dynamic-secret-lease/dynamic-secret-lease-service";
import { TExternalKmsServiceFactory } from "@app/ee/services/external-kms/external-kms-service"; import { TExternalKmsServiceFactory } from "@app/ee/services/external-kms/external-kms-service";
import { TGatewayServiceFactory } from "@app/ee/services/gateway/gateway-service"; import { TGatewayServiceFactory } from "@app/ee/services/gateway/gateway-service";
import { TGithubOrgSyncServiceFactory } from "@app/ee/services/github-org-sync/github-org-sync-service";
import { TGroupServiceFactory } from "@app/ee/services/group/group-service"; import { TGroupServiceFactory } from "@app/ee/services/group/group-service";
import { TIdentityProjectAdditionalPrivilegeServiceFactory } from "@app/ee/services/identity-project-additional-privilege/identity-project-additional-privilege-service"; import { TIdentityProjectAdditionalPrivilegeServiceFactory } from "@app/ee/services/identity-project-additional-privilege/identity-project-additional-privilege-service";
import { TIdentityProjectAdditionalPrivilegeV2ServiceFactory } from "@app/ee/services/identity-project-additional-privilege-v2/identity-project-additional-privilege-v2-service"; import { TIdentityProjectAdditionalPrivilegeV2ServiceFactory } from "@app/ee/services/identity-project-additional-privilege-v2/identity-project-additional-privilege-v2-service";
@@ -39,6 +41,7 @@ import { TSecretSnapshotServiceFactory } from "@app/ee/services/secret-snapshot/
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 { TSshHostServiceFactory } from "@app/ee/services/ssh-host/ssh-host-service";
import { TSshHostGroupServiceFactory } from "@app/ee/services/ssh-host-group/ssh-host-group-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";
@@ -63,12 +66,15 @@ import { TIdentityAzureAuthServiceFactory } from "@app/services/identity-azure-a
import { TIdentityGcpAuthServiceFactory } from "@app/services/identity-gcp-auth/identity-gcp-auth-service"; import { TIdentityGcpAuthServiceFactory } from "@app/services/identity-gcp-auth/identity-gcp-auth-service";
import { TIdentityJwtAuthServiceFactory } from "@app/services/identity-jwt-auth/identity-jwt-auth-service"; import { TIdentityJwtAuthServiceFactory } from "@app/services/identity-jwt-auth/identity-jwt-auth-service";
import { TIdentityKubernetesAuthServiceFactory } from "@app/services/identity-kubernetes-auth/identity-kubernetes-auth-service"; import { TIdentityKubernetesAuthServiceFactory } from "@app/services/identity-kubernetes-auth/identity-kubernetes-auth-service";
import { TIdentityLdapAuthServiceFactory } from "@app/services/identity-ldap-auth/identity-ldap-auth-service";
import { TAllowedFields } from "@app/services/identity-ldap-auth/identity-ldap-auth-types";
import { TIdentityOidcAuthServiceFactory } from "@app/services/identity-oidc-auth/identity-oidc-auth-service"; import { TIdentityOidcAuthServiceFactory } from "@app/services/identity-oidc-auth/identity-oidc-auth-service";
import { TIdentityProjectServiceFactory } from "@app/services/identity-project/identity-project-service"; import { TIdentityProjectServiceFactory } from "@app/services/identity-project/identity-project-service";
import { TIdentityTokenAuthServiceFactory } from "@app/services/identity-token-auth/identity-token-auth-service"; import { TIdentityTokenAuthServiceFactory } from "@app/services/identity-token-auth/identity-token-auth-service";
import { TIdentityUaServiceFactory } from "@app/services/identity-ua/identity-ua-service"; import { TIdentityUaServiceFactory } from "@app/services/identity-ua/identity-ua-service";
import { TIntegrationServiceFactory } from "@app/services/integration/integration-service"; import { TIntegrationServiceFactory } from "@app/services/integration/integration-service";
import { TIntegrationAuthServiceFactory } from "@app/services/integration-auth/integration-auth-service"; import { TIntegrationAuthServiceFactory } from "@app/services/integration-auth/integration-auth-service";
import { TMicrosoftTeamsServiceFactory } from "@app/services/microsoft-teams/microsoft-teams-service";
import { TOrgRoleServiceFactory } from "@app/services/org/org-role-service"; import { TOrgRoleServiceFactory } from "@app/services/org/org-role-service";
import { TOrgServiceFactory } from "@app/services/org/org-service"; import { TOrgServiceFactory } from "@app/services/org/org-service";
import { TOrgAdminServiceFactory } from "@app/services/org-admin/org-admin-service"; import { TOrgAdminServiceFactory } from "@app/services/org-admin/org-admin-service";
@@ -109,12 +115,14 @@ declare module "@fastify/request-context" {
}; };
}; };
identityPermissionMetadata?: Record<string, unknown>; // filled by permission service identityPermissionMetadata?: Record<string, unknown>; // filled by permission service
assumedPrivilegeDetails?: { requesterId: string; actorId: string; actorType: ActorType; projectId: string };
} }
} }
declare module "fastify" { declare module "fastify" {
interface Session { interface Session {
callbackPort: string; callbackPort: string;
isAdminLogin: boolean;
} }
interface FastifyRequest { interface FastifyRequest {
@@ -138,6 +146,14 @@ declare module "fastify" {
passportUser: { passportUser: {
isUserCompleted: boolean; isUserCompleted: boolean;
providerAuthToken: string; providerAuthToken: string;
externalProviderAccessToken?: string;
};
passportMachineIdentity: {
identityId: string;
user: {
uid: string;
mail?: string;
};
}; };
kmipUser: { kmipUser: {
projectId: string; projectId: string;
@@ -146,7 +162,9 @@ declare module "fastify" {
}; };
auditLogInfo: Pick<TCreateAuditLogDTO, "userAgent" | "userAgentType" | "ipAddress" | "actor">; auditLogInfo: Pick<TCreateAuditLogDTO, "userAgent" | "userAgentType" | "ipAddress" | "actor">;
ssoConfig: Awaited<ReturnType<TSamlConfigServiceFactory["getSaml"]>>; ssoConfig: Awaited<ReturnType<TSamlConfigServiceFactory["getSaml"]>>;
ldapConfig: Awaited<ReturnType<TLdapConfigServiceFactory["getLdapCfg"]>>; ldapConfig: Awaited<ReturnType<TLdapConfigServiceFactory["getLdapCfg"]>> & {
allowedFields?: TAllowedFields[];
};
} }
interface FastifyInstance { interface FastifyInstance {
@@ -192,6 +210,7 @@ declare module "fastify" {
identityAzureAuth: TIdentityAzureAuthServiceFactory; identityAzureAuth: TIdentityAzureAuthServiceFactory;
identityOidcAuth: TIdentityOidcAuthServiceFactory; identityOidcAuth: TIdentityOidcAuthServiceFactory;
identityJwtAuth: TIdentityJwtAuthServiceFactory; identityJwtAuth: TIdentityJwtAuthServiceFactory;
identityLdapAuth: TIdentityLdapAuthServiceFactory;
accessApprovalPolicy: TAccessApprovalPolicyServiceFactory; accessApprovalPolicy: TAccessApprovalPolicyServiceFactory;
accessApprovalRequest: TAccessApprovalRequestServiceFactory; accessApprovalRequest: TAccessApprovalRequestServiceFactory;
secretApprovalPolicy: TSecretApprovalPolicyServiceFactory; secretApprovalPolicy: TSecretApprovalPolicyServiceFactory;
@@ -208,6 +227,7 @@ declare module "fastify" {
sshCertificateAuthority: TSshCertificateAuthorityServiceFactory; sshCertificateAuthority: TSshCertificateAuthorityServiceFactory;
sshCertificateTemplate: TSshCertificateTemplateServiceFactory; sshCertificateTemplate: TSshCertificateTemplateServiceFactory;
sshHost: TSshHostServiceFactory; sshHost: TSshHostServiceFactory;
sshHostGroup: TSshHostGroupServiceFactory;
certificateAuthority: TCertificateAuthorityServiceFactory; certificateAuthority: TCertificateAuthorityServiceFactory;
certificateAuthorityCrl: TCertificateAuthorityCrlServiceFactory; certificateAuthorityCrl: TCertificateAuthorityCrlServiceFactory;
certificateEst: TCertificateEstServiceFactory; certificateEst: TCertificateEstServiceFactory;
@@ -241,6 +261,9 @@ declare module "fastify" {
kmipOperation: TKmipOperationServiceFactory; kmipOperation: TKmipOperationServiceFactory;
gateway: TGatewayServiceFactory; gateway: TGatewayServiceFactory;
secretRotationV2: TSecretRotationV2ServiceFactory; secretRotationV2: TSecretRotationV2ServiceFactory;
microsoftTeams: TMicrosoftTeamsServiceFactory;
assumePrivileges: TAssumePrivilegeServiceFactory;
githubOrgSync: TGithubOrgSyncServiceFactory;
}; };
// 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

View File

@@ -83,6 +83,9 @@ import {
TGitAppOrg, TGitAppOrg,
TGitAppOrgInsert, TGitAppOrgInsert,
TGitAppOrgUpdate, TGitAppOrgUpdate,
TGithubOrgSyncConfigs,
TGithubOrgSyncConfigsInsert,
TGithubOrgSyncConfigsUpdate,
TGroupProjectMembershipRoles, TGroupProjectMembershipRoles,
TGroupProjectMembershipRolesInsert, TGroupProjectMembershipRolesInsert,
TGroupProjectMembershipRolesUpdate, TGroupProjectMembershipRolesUpdate,
@@ -383,6 +386,12 @@ import {
TSshCertificateTemplates, TSshCertificateTemplates,
TSshCertificateTemplatesInsert, TSshCertificateTemplatesInsert,
TSshCertificateTemplatesUpdate, TSshCertificateTemplatesUpdate,
TSshHostGroupMemberships,
TSshHostGroupMembershipsInsert,
TSshHostGroupMembershipsUpdate,
TSshHostGroups,
TSshHostGroupsInsert,
TSshHostGroupsUpdate,
TSshHostLoginUserMappings, TSshHostLoginUserMappings,
TSshHostLoginUserMappingsInsert, TSshHostLoginUserMappingsInsert,
TSshHostLoginUserMappingsUpdate, TSshHostLoginUserMappingsUpdate,
@@ -423,6 +432,26 @@ import {
TWorkflowIntegrationsInsert, TWorkflowIntegrationsInsert,
TWorkflowIntegrationsUpdate TWorkflowIntegrationsUpdate
} from "@app/db/schemas"; } from "@app/db/schemas";
import {
TIdentityLdapAuths,
TIdentityLdapAuthsInsert,
TIdentityLdapAuthsUpdate
} from "@app/db/schemas/identity-ldap-auths";
import {
TMicrosoftTeamsIntegrations,
TMicrosoftTeamsIntegrationsInsert,
TMicrosoftTeamsIntegrationsUpdate
} from "@app/db/schemas/microsoft-teams-integrations";
import {
TProjectMicrosoftTeamsConfigs,
TProjectMicrosoftTeamsConfigsInsert,
TProjectMicrosoftTeamsConfigsUpdate
} from "@app/db/schemas/project-microsoft-teams-configs";
import {
TSecretReminderRecipients,
TSecretReminderRecipientsInsert,
TSecretReminderRecipientsUpdate
} from "@app/db/schemas/secret-reminder-recipients";
declare module "knex" { declare module "knex" {
namespace Knex { namespace Knex {
@@ -437,6 +466,16 @@ 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.SshHostGroup]: KnexOriginal.CompositeTableType<
TSshHostGroups,
TSshHostGroupsInsert,
TSshHostGroupsUpdate
>;
[TableName.SshHostGroupMembership]: KnexOriginal.CompositeTableType<
TSshHostGroupMemberships,
TSshHostGroupMembershipsInsert,
TSshHostGroupMembershipsUpdate
>;
[TableName.SshHost]: KnexOriginal.CompositeTableType<TSshHosts, TSshHostsInsert, TSshHostsUpdate>; [TableName.SshHost]: KnexOriginal.CompositeTableType<TSshHosts, TSshHostsInsert, TSshHostsUpdate>;
[TableName.SshCertificateAuthority]: KnexOriginal.CompositeTableType< [TableName.SshCertificateAuthority]: KnexOriginal.CompositeTableType<
TSshCertificateAuthorities, TSshCertificateAuthorities,
@@ -701,6 +740,11 @@ declare module "knex/types/tables" {
TIdentityJwtAuthsInsert, TIdentityJwtAuthsInsert,
TIdentityJwtAuthsUpdate TIdentityJwtAuthsUpdate
>; >;
[TableName.IdentityLdapAuth]: KnexOriginal.CompositeTableType<
TIdentityLdapAuths,
TIdentityLdapAuthsInsert,
TIdentityLdapAuthsUpdate
>;
[TableName.IdentityUaClientSecret]: KnexOriginal.CompositeTableType< [TableName.IdentityUaClientSecret]: KnexOriginal.CompositeTableType<
TIdentityUaClientSecrets, TIdentityUaClientSecrets,
TIdentityUaClientSecretsInsert, TIdentityUaClientSecretsInsert,
@@ -994,5 +1038,25 @@ declare module "knex/types/tables" {
TSecretRotationV2SecretMappingsInsert, TSecretRotationV2SecretMappingsInsert,
TSecretRotationV2SecretMappingsUpdate TSecretRotationV2SecretMappingsUpdate
>; >;
[TableName.MicrosoftTeamsIntegrations]: KnexOriginal.CompositeTableType<
TMicrosoftTeamsIntegrations,
TMicrosoftTeamsIntegrationsInsert,
TMicrosoftTeamsIntegrationsUpdate
>;
[TableName.ProjectMicrosoftTeamsConfigs]: KnexOriginal.CompositeTableType<
TProjectMicrosoftTeamsConfigs,
TProjectMicrosoftTeamsConfigsInsert,
TProjectMicrosoftTeamsConfigsUpdate
>;
[TableName.SecretReminderRecipients]: KnexOriginal.CompositeTableType<
TSecretReminderRecipients,
TSecretReminderRecipientsInsert,
TSecretReminderRecipientsUpdate
>;
[TableName.GithubOrgSyncConfig]: KnexOriginal.CompositeTableType<
TGithubOrgSyncConfigs,
TGithubOrgSyncConfigsInsert,
TGithubOrgSyncConfigsUpdate
>;
} }
} }

View File

@@ -0,0 +1,34 @@
import { Knex } from "knex";
import { TableName } from "../schemas";
export async function up(knex: Knex): Promise<void> {
const hasSecretReminderRecipientsTable = await knex.schema.hasTable(TableName.SecretReminderRecipients);
if (!hasSecretReminderRecipientsTable) {
await knex.schema.createTable(TableName.SecretReminderRecipients, (table) => {
table.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
table.timestamps(true, true, true);
table.uuid("secretId").notNullable();
table.uuid("userId").notNullable();
table.string("projectId").notNullable();
// Based on userId rather than project membership ID so we can easily extend group support in the future if need be.
// This does however mean we need to manually clean up once a user is removed from a project.
table.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE");
table.foreign("secretId").references("id").inTable(TableName.SecretV2).onDelete("CASCADE");
table.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
table.index("secretId");
table.unique(["secretId", "userId"]);
});
}
}
export async function down(knex: Knex): Promise<void> {
const hasSecretReminderRecipientsTable = await knex.schema.hasTable(TableName.SecretReminderRecipients);
if (hasSecretReminderRecipientsTable) {
await knex.schema.dropTableIfExists(TableName.SecretReminderRecipients);
}
}

View File

@@ -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);
});
}

View File

@@ -0,0 +1,130 @@
import { Knex } from "knex";
import { TableName } from "../schemas";
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
export async function up(knex: Knex): Promise<void> {
const superAdminHasEncryptedMicrosoftTeamsClientIdColumn = await knex.schema.hasColumn(
TableName.SuperAdmin,
"encryptedMicrosoftTeamsAppId"
);
const superAdminHasEncryptedMicrosoftTeamsClientSecret = await knex.schema.hasColumn(
TableName.SuperAdmin,
"encryptedMicrosoftTeamsClientSecret"
);
const superAdminHasEncryptedMicrosoftTeamsBotId = await knex.schema.hasColumn(
TableName.SuperAdmin,
"encryptedMicrosoftTeamsBotId"
);
if (
!superAdminHasEncryptedMicrosoftTeamsClientIdColumn ||
!superAdminHasEncryptedMicrosoftTeamsClientSecret ||
!superAdminHasEncryptedMicrosoftTeamsBotId
) {
await knex.schema.alterTable(TableName.SuperAdmin, (table) => {
if (!superAdminHasEncryptedMicrosoftTeamsClientIdColumn) {
table.binary("encryptedMicrosoftTeamsAppId").nullable();
}
if (!superAdminHasEncryptedMicrosoftTeamsClientSecret) {
table.binary("encryptedMicrosoftTeamsClientSecret").nullable();
}
if (!superAdminHasEncryptedMicrosoftTeamsBotId) {
table.binary("encryptedMicrosoftTeamsBotId").nullable();
}
});
}
if (!(await knex.schema.hasColumn(TableName.WorkflowIntegrations, "status"))) {
await knex.schema.alterTable(TableName.WorkflowIntegrations, (table) => {
table.enu("status", ["pending", "installed", "failed"]).notNullable().defaultTo("installed"); // defaults to installed so we can have backwards compatibility with existing workflow integrations
});
}
if (!(await knex.schema.hasTable(TableName.MicrosoftTeamsIntegrations))) {
await knex.schema.createTable(TableName.MicrosoftTeamsIntegrations, (table) => {
table.uuid("id", { primaryKey: true }).notNullable();
table.foreign("id").references("id").inTable(TableName.WorkflowIntegrations).onDelete("CASCADE"); // the ID itself is the workflow integration ID
table.string("internalTeamsAppId").nullable();
table.string("tenantId").notNullable();
table.binary("encryptedAccessToken").nullable();
table.binary("encryptedBotAccessToken").nullable();
table.timestamp("accessTokenExpiresAt").nullable();
table.timestamp("botAccessTokenExpiresAt").nullable();
table.timestamps(true, true, true);
});
await createOnUpdateTrigger(knex, TableName.MicrosoftTeamsIntegrations);
}
if (!(await knex.schema.hasTable(TableName.ProjectMicrosoftTeamsConfigs))) {
await knex.schema.createTable(TableName.ProjectMicrosoftTeamsConfigs, (tb) => {
tb.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
tb.string("projectId").notNullable().unique();
tb.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
tb.uuid("microsoftTeamsIntegrationId").notNullable();
tb.foreign("microsoftTeamsIntegrationId")
.references("id")
.inTable(TableName.MicrosoftTeamsIntegrations)
.onDelete("CASCADE");
tb.boolean("isAccessRequestNotificationEnabled").notNullable().defaultTo(false);
tb.boolean("isSecretRequestNotificationEnabled").notNullable().defaultTo(false);
tb.jsonb("accessRequestChannels").notNullable(); // {teamId: string, channelIds: string[]}
tb.jsonb("secretRequestChannels").notNullable(); // {teamId: string, channelIds: string[]}
tb.timestamps(true, true, true);
});
await createOnUpdateTrigger(knex, TableName.ProjectMicrosoftTeamsConfigs);
}
}
export async function down(knex: Knex): Promise<void> {
const hasEncryptedMicrosoftTeamsClientIdColumn = await knex.schema.hasColumn(
TableName.SuperAdmin,
"encryptedMicrosoftTeamsAppId"
);
const hasEncryptedMicrosoftTeamsClientSecret = await knex.schema.hasColumn(
TableName.SuperAdmin,
"encryptedMicrosoftTeamsClientSecret"
);
const hasEncryptedMicrosoftTeamsBotId = await knex.schema.hasColumn(
TableName.SuperAdmin,
"encryptedMicrosoftTeamsBotId"
);
if (
hasEncryptedMicrosoftTeamsClientIdColumn ||
hasEncryptedMicrosoftTeamsClientSecret ||
hasEncryptedMicrosoftTeamsBotId
) {
await knex.schema.alterTable(TableName.SuperAdmin, (table) => {
if (hasEncryptedMicrosoftTeamsClientIdColumn) {
table.dropColumn("encryptedMicrosoftTeamsAppId");
}
if (hasEncryptedMicrosoftTeamsClientSecret) {
table.dropColumn("encryptedMicrosoftTeamsClientSecret");
}
if (hasEncryptedMicrosoftTeamsBotId) {
table.dropColumn("encryptedMicrosoftTeamsBotId");
}
});
}
if (await knex.schema.hasColumn(TableName.WorkflowIntegrations, "status")) {
await knex.schema.alterTable(TableName.WorkflowIntegrations, (table) => {
table.dropColumn("status");
});
}
if (await knex.schema.hasTable(TableName.ProjectMicrosoftTeamsConfigs)) {
await knex.schema.dropTableIfExists(TableName.ProjectMicrosoftTeamsConfigs);
await dropOnUpdateTrigger(knex, TableName.ProjectMicrosoftTeamsConfigs);
}
if (await knex.schema.hasTable(TableName.MicrosoftTeamsIntegrations)) {
await knex.schema.dropTableIfExists(TableName.MicrosoftTeamsIntegrations);
await dropOnUpdateTrigger(knex, TableName.MicrosoftTeamsIntegrations);
}
}

View File

@@ -0,0 +1,47 @@
import { Knex } from "knex";
import { ProjectType, TableName } from "../schemas";
export async function up(knex: Knex): Promise<void> {
const hasDefaultUserCaCol = await knex.schema.hasColumn(TableName.ProjectSshConfig, "defaultUserSshCaId");
const hasDefaultHostCaCol = await knex.schema.hasColumn(TableName.ProjectSshConfig, "defaultHostSshCaId");
if (hasDefaultUserCaCol && hasDefaultHostCaCol) {
await knex.schema.alterTable(TableName.ProjectSshConfig, (t) => {
t.dropForeign(["defaultUserSshCaId"]);
t.dropForeign(["defaultHostSshCaId"]);
});
await knex.schema.alterTable(TableName.ProjectSshConfig, (t) => {
// allow nullable (does not wipe existing values)
t.uuid("defaultUserSshCaId").nullable().alter();
t.uuid("defaultHostSshCaId").nullable().alter();
// re-add with SET NULL behavior (previously CASCADE)
t.foreign("defaultUserSshCaId").references("id").inTable(TableName.SshCertificateAuthority).onDelete("SET NULL");
t.foreign("defaultHostSshCaId").references("id").inTable(TableName.SshCertificateAuthority).onDelete("SET NULL");
});
}
// (dangtony98): backfill by adding null defaults CAs for all existing Infisical SSH projects
// that do not have an associated ProjectSshConfig record introduced in Infisical SSH V2.
const allProjects = await knex(TableName.Project).where("type", ProjectType.SSH).select("id");
const projectsWithConfig = await knex(TableName.ProjectSshConfig).select("projectId");
const projectIdsWithConfig = new Set(projectsWithConfig.map((config) => config.projectId));
const projectsNeedingConfig = allProjects.filter((project) => !projectIdsWithConfig.has(project.id));
if (projectsNeedingConfig.length > 0) {
const configsToInsert = projectsNeedingConfig.map((project) => ({
projectId: project.id,
defaultUserSshCaId: null,
defaultHostSshCaId: null,
createdAt: new Date(),
updatedAt: new Date()
}));
await knex.batchInsert(TableName.ProjectSshConfig, configsToInsert);
}
}
export async function down(): Promise<void> {}

View File

@@ -0,0 +1,23 @@
import { Knex } from "knex";
import { TableName } from "../schemas";
export async function up(knex: Knex): Promise<void> {
const hasAliasColumn = await knex.schema.hasColumn(TableName.SshHost, "alias");
if (!hasAliasColumn) {
await knex.schema.alterTable(TableName.SshHost, (t) => {
t.string("alias").nullable();
t.unique(["projectId", "alias"]);
});
}
}
export async function down(knex: Knex): Promise<void> {
const hasAliasColumn = await knex.schema.hasColumn(TableName.SshHost, "alias");
if (hasAliasColumn) {
await knex.schema.alterTable(TableName.SshHost, (t) => {
t.dropUnique(["projectId", "alias"]);
t.dropColumn("alias");
});
}
}

View File

@@ -0,0 +1,26 @@
import { Knex } from "knex";
import { TableName } from "../schemas";
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
export async function up(knex: Knex): Promise<void> {
const hasTable = await knex.schema.hasTable(TableName.GithubOrgSyncConfig);
if (!hasTable) {
await knex.schema.createTable(TableName.GithubOrgSyncConfig, (t) => {
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
t.string("githubOrgName").notNullable();
t.boolean("isActive").defaultTo(false);
t.binary("encryptedGithubOrgAccessToken");
t.uuid("orgId").notNullable().unique();
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
t.timestamps(true, true, true);
});
}
await createOnUpdateTrigger(knex, TableName.GithubOrgSyncConfig);
}
export async function down(knex: Knex): Promise<void> {
await knex.schema.dropTableIfExists(TableName.GithubOrgSyncConfig);
await dropOnUpdateTrigger(knex, TableName.GithubOrgSyncConfig);
}

View File

@@ -0,0 +1,27 @@
import { Knex } from "knex";
import { getConfig } from "@app/lib/config/env";
import { TableName } from "../schemas";
export async function up(knex: Knex): Promise<void> {
const appCfg = getConfig();
const tokenDuration = appCfg?.JWT_REFRESH_LIFETIME;
if (!(await knex.schema.hasColumn(TableName.Organization, "userTokenExpiration"))) {
await knex.schema.alterTable(TableName.Organization, (t) => {
t.string("userTokenExpiration");
});
if (tokenDuration) {
await knex(TableName.Organization).update({ userTokenExpiration: tokenDuration });
}
}
}
export async function down(knex: Knex): Promise<void> {
if (await knex.schema.hasColumn(TableName.Organization, "userTokenExpiration")) {
await knex.schema.alterTable(TableName.Organization, (t) => {
t.dropColumn("userTokenExpiration");
});
}
}

View File

@@ -0,0 +1,55 @@
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.SshHostGroup))) {
await knex.schema.createTable(TableName.SshHostGroup, (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("name").notNullable();
t.unique(["projectId", "name"]);
});
await createOnUpdateTrigger(knex, TableName.SshHostGroup);
}
if (!(await knex.schema.hasTable(TableName.SshHostGroupMembership))) {
await knex.schema.createTable(TableName.SshHostGroupMembership, (t) => {
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
t.timestamps(true, true, true);
t.uuid("sshHostGroupId").notNullable();
t.foreign("sshHostGroupId").references("id").inTable(TableName.SshHostGroup).onDelete("CASCADE");
t.uuid("sshHostId").notNullable();
t.foreign("sshHostId").references("id").inTable(TableName.SshHost).onDelete("CASCADE");
t.unique(["sshHostGroupId", "sshHostId"]);
});
await createOnUpdateTrigger(knex, TableName.SshHostGroupMembership);
}
const hasGroupColumn = await knex.schema.hasColumn(TableName.SshHostLoginUser, "sshHostGroupId");
if (!hasGroupColumn) {
await knex.schema.alterTable(TableName.SshHostLoginUser, (t) => {
t.uuid("sshHostGroupId").nullable();
t.foreign("sshHostGroupId").references("id").inTable(TableName.SshHostGroup).onDelete("CASCADE");
t.uuid("sshHostId").nullable().alter();
});
}
}
export async function down(knex: Knex): Promise<void> {
const hasGroupColumn = await knex.schema.hasColumn(TableName.SshHostLoginUser, "sshHostGroupId");
if (hasGroupColumn) {
await knex.schema.alterTable(TableName.SshHostLoginUser, (t) => {
t.dropColumn("sshHostGroupId");
});
}
await knex.schema.dropTableIfExists(TableName.SshHostGroupMembership);
await dropOnUpdateTrigger(knex, TableName.SshHostGroupMembership);
await knex.schema.dropTableIfExists(TableName.SshHostGroup);
await dropOnUpdateTrigger(knex, TableName.SshHostGroup);
}

View File

@@ -0,0 +1,33 @@
import { Knex } from "knex";
import { TableName } from "../schemas";
export async function up(knex: Knex): Promise<void> {
if (!(await knex.schema.hasColumn(TableName.CertificateBody, "encryptedCertificateChain"))) {
await knex.schema.alterTable(TableName.CertificateBody, (t) => {
t.binary("encryptedCertificateChain").nullable();
});
}
if (!(await knex.schema.hasTable(TableName.CertificateSecret))) {
await knex.schema.createTable(TableName.CertificateSecret, (t) => {
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
t.timestamps(true, true, true);
t.uuid("certId").notNullable().unique();
t.foreign("certId").references("id").inTable(TableName.Certificate).onDelete("CASCADE");
t.binary("encryptedPrivateKey").notNullable();
});
}
}
export async function down(knex: Knex): Promise<void> {
if (await knex.schema.hasTable(TableName.CertificateSecret)) {
await knex.schema.dropTable(TableName.CertificateSecret);
}
if (await knex.schema.hasColumn(TableName.CertificateBody, "encryptedCertificateChain")) {
await knex.schema.alterTable(TableName.CertificateBody, (t) => {
t.dropColumn("encryptedCertificateChain");
});
}
}

View File

@@ -0,0 +1,22 @@
import { Knex } from "knex";
import { TableName } from "../schemas";
export async function up(knex: Knex): Promise<void> {
if (!(await knex.schema.hasColumn(TableName.SshHostLoginUserMapping, "groupId"))) {
await knex.schema.alterTable(TableName.SshHostLoginUserMapping, (t) => {
t.uuid("groupId").nullable();
t.foreign("groupId").references("id").inTable(TableName.Groups).onDelete("CASCADE");
t.unique(["sshHostLoginUserId", "groupId"]);
});
}
}
export async function down(knex: Knex): Promise<void> {
if (await knex.schema.hasColumn(TableName.SshHostLoginUserMapping, "groupId")) {
await knex.schema.alterTable(TableName.SshHostLoginUserMapping, (t) => {
t.dropUnique(["sshHostLoginUserId", "groupId"]);
t.dropColumn("groupId");
});
}
}

View File

@@ -0,0 +1,22 @@
import { Knex } from "knex";
import { ProjectType, TableName } from "../schemas";
export async function up(knex: Knex): Promise<void> {
if (!(await knex.schema.hasColumn(TableName.ProjectTemplates, "type"))) {
await knex.schema.alterTable(TableName.ProjectTemplates, (t) => {
// defaulting to sm for migration to set existing, new ones will always be specified on creation
t.string("type").defaultTo(ProjectType.SecretManager).notNullable();
t.jsonb("environments").nullable().alter();
});
}
}
export async function down(knex: Knex): Promise<void> {
if (await knex.schema.hasColumn(TableName.ProjectTemplates, "type")) {
await knex.schema.alterTable(TableName.ProjectTemplates, (t) => {
t.dropColumn("type");
// not reverting nullable environments
});
}
}

View File

@@ -0,0 +1,39 @@
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.IdentityLdapAuth))) {
await knex.schema.createTable(TableName.IdentityLdapAuth, (t) => {
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
t.bigInteger("accessTokenTTL").defaultTo(7200).notNullable();
t.bigInteger("accessTokenMaxTTL").defaultTo(7200).notNullable();
t.bigInteger("accessTokenNumUsesLimit").defaultTo(0).notNullable();
t.jsonb("accessTokenTrustedIps").notNullable();
t.uuid("identityId").notNullable().unique();
t.foreign("identityId").references("id").inTable(TableName.Identity).onDelete("CASCADE");
t.binary("encryptedBindDN").notNullable();
t.binary("encryptedBindPass").notNullable();
t.binary("encryptedLdapCaCertificate").nullable();
t.string("url").notNullable();
t.string("searchBase").notNullable();
t.string("searchFilter").notNullable();
t.jsonb("allowedFields").nullable();
t.timestamps(true, true, true);
});
}
await createOnUpdateTrigger(knex, TableName.IdentityLdapAuth);
}
export async function down(knex: Knex): Promise<void> {
await knex.schema.dropTableIfExists(TableName.IdentityLdapAuth);
await dropOnUpdateTrigger(knex, TableName.IdentityLdapAuth);
}

View File

@@ -14,7 +14,8 @@ export const CertificateBodiesSchema = z.object({
createdAt: z.date(), createdAt: z.date(),
updatedAt: z.date(), updatedAt: z.date(),
certId: z.string().uuid(), certId: z.string().uuid(),
encryptedCertificate: zodBuffer encryptedCertificate: zodBuffer,
encryptedCertificateChain: zodBuffer.nullable().optional()
}); });
export type TCertificateBodies = z.infer<typeof CertificateBodiesSchema>; export type TCertificateBodies = z.infer<typeof CertificateBodiesSchema>;

View File

@@ -5,6 +5,8 @@
import { z } from "zod"; import { z } from "zod";
import { zodBuffer } from "@app/lib/zod";
import { TImmutableDBKeys } from "./models"; import { TImmutableDBKeys } from "./models";
export const CertificateSecretsSchema = z.object({ export const CertificateSecretsSchema = z.object({
@@ -12,8 +14,7 @@ export const CertificateSecretsSchema = z.object({
createdAt: z.date(), createdAt: z.date(),
updatedAt: z.date(), updatedAt: z.date(),
certId: z.string().uuid(), certId: z.string().uuid(),
pk: z.string(), encryptedPrivateKey: zodBuffer
sk: z.string()
}); });
export type TCertificateSecrets = z.infer<typeof CertificateSecretsSchema>; export type TCertificateSecrets = z.infer<typeof CertificateSecretsSchema>;

View File

@@ -20,7 +20,7 @@ export const CertificatesSchema = z.object({
notAfter: z.date(), notAfter: z.date(),
revokedAt: z.date().nullable().optional(), revokedAt: z.date().nullable().optional(),
revocationReason: z.number().nullable().optional(), revocationReason: z.number().nullable().optional(),
altNames: z.string().default("").nullable().optional(), altNames: z.string().nullable().optional(),
caCertId: z.string().uuid(), caCertId: z.string().uuid(),
certificateTemplateId: z.string().uuid().nullable().optional(), certificateTemplateId: z.string().uuid().nullable().optional(),
keyUsages: z.string().array().nullable().optional(), keyUsages: z.string().array().nullable().optional(),

View 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 { zodBuffer } from "@app/lib/zod";
import { TImmutableDBKeys } from "./models";
export const GithubOrgSyncConfigsSchema = z.object({
id: z.string().uuid(),
githubOrgName: z.string(),
isActive: z.boolean().default(false).nullable().optional(),
encryptedGithubOrgAccessToken: zodBuffer.nullable().optional(),
orgId: z.string().uuid(),
createdAt: z.date(),
updatedAt: z.date()
});
export type TGithubOrgSyncConfigs = z.infer<typeof GithubOrgSyncConfigsSchema>;
export type TGithubOrgSyncConfigsInsert = Omit<z.input<typeof GithubOrgSyncConfigsSchema>, TImmutableDBKeys>;
export type TGithubOrgSyncConfigsUpdate = Partial<Omit<z.input<typeof GithubOrgSyncConfigsSchema>, TImmutableDBKeys>>;

View File

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

View File

@@ -25,6 +25,7 @@ export * from "./external-kms";
export * from "./gateways"; export * from "./gateways";
export * from "./git-app-install-sessions"; export * from "./git-app-install-sessions";
export * from "./git-app-org"; export * from "./git-app-org";
export * from "./github-org-sync-configs";
export * from "./group-project-membership-roles"; export * from "./group-project-membership-roles";
export * from "./group-project-memberships"; export * from "./group-project-memberships";
export * from "./groups"; export * from "./groups";
@@ -57,6 +58,7 @@ export * from "./kms-keys";
export * from "./kms-root-config"; export * from "./kms-root-config";
export * from "./ldap-configs"; export * from "./ldap-configs";
export * from "./ldap-group-maps"; export * from "./ldap-group-maps";
export * from "./microsoft-teams-integrations";
export * from "./models"; export * from "./models";
export * from "./oidc-configs"; export * from "./oidc-configs";
export * from "./org-bots"; export * from "./org-bots";
@@ -126,6 +128,8 @@ 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-group-memberships";
export * from "./ssh-host-groups";
export * from "./ssh-host-login-user-mappings"; export * from "./ssh-host-login-user-mappings";
export * from "./ssh-host-login-users"; export * from "./ssh-host-login-users";
export * from "./ssh-hosts"; export * from "./ssh-hosts";

View File

@@ -13,7 +13,7 @@ export const KmipOrgServerCertificatesSchema = z.object({
id: z.string().uuid(), id: z.string().uuid(),
orgId: z.string().uuid(), orgId: z.string().uuid(),
commonName: z.string(), commonName: z.string(),
altNames: z.string(), altNames: z.string().nullable().optional(),
serialNumber: z.string(), serialNumber: z.string(),
keyAlgorithm: z.string(), keyAlgorithm: z.string(),
issuedAt: z.date(), issuedAt: z.date(),

View File

@@ -0,0 +1,31 @@
// 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 MicrosoftTeamsIntegrationsSchema = z.object({
id: z.string().uuid(),
internalTeamsAppId: z.string().nullable().optional(),
tenantId: z.string(),
encryptedAccessToken: zodBuffer.nullable().optional(),
encryptedBotAccessToken: zodBuffer.nullable().optional(),
accessTokenExpiresAt: z.date().nullable().optional(),
botAccessTokenExpiresAt: z.date().nullable().optional(),
createdAt: z.date(),
updatedAt: z.date()
});
export type TMicrosoftTeamsIntegrations = z.infer<typeof MicrosoftTeamsIntegrationsSchema>;
export type TMicrosoftTeamsIntegrationsInsert = Omit<
z.input<typeof MicrosoftTeamsIntegrationsSchema>,
TImmutableDBKeys
>;
export type TMicrosoftTeamsIntegrationsUpdate = Partial<
Omit<z.input<typeof MicrosoftTeamsIntegrationsSchema>, TImmutableDBKeys>
>;

View File

@@ -2,6 +2,8 @@ import { z } from "zod";
export enum TableName { export enum TableName {
Users = "users", Users = "users",
SshHostGroup = "ssh_host_groups",
SshHostGroupMembership = "ssh_host_group_memberships",
SshHost = "ssh_hosts", SshHost = "ssh_hosts",
SshHostLoginUser = "ssh_host_login_users", SshHostLoginUser = "ssh_host_login_users",
SshHostLoginUserMapping = "ssh_host_login_user_mappings", SshHostLoginUserMapping = "ssh_host_login_user_mappings",
@@ -78,6 +80,7 @@ export enum TableName {
IdentityAwsAuth = "identity_aws_auths", IdentityAwsAuth = "identity_aws_auths",
IdentityOidcAuth = "identity_oidc_auths", IdentityOidcAuth = "identity_oidc_auths",
IdentityJwtAuth = "identity_jwt_auths", IdentityJwtAuth = "identity_jwt_auths",
IdentityLdapAuth = "identity_ldap_auths",
IdentityOrgMembership = "identity_org_memberships", IdentityOrgMembership = "identity_org_memberships",
IdentityProjectMembership = "identity_project_memberships", IdentityProjectMembership = "identity_project_memberships",
IdentityProjectMembershipRole = "identity_project_membership_role", IdentityProjectMembershipRole = "identity_project_membership_role",
@@ -146,7 +149,11 @@ export enum TableName {
KmipOrgServerCertificates = "kmip_org_server_certificates", KmipOrgServerCertificates = "kmip_org_server_certificates",
KmipClientCertificates = "kmip_client_certificates", KmipClientCertificates = "kmip_client_certificates",
SecretRotationV2 = "secret_rotations_v2", SecretRotationV2 = "secret_rotations_v2",
SecretRotationV2SecretMapping = "secret_rotation_v2_secret_mappings" SecretRotationV2SecretMapping = "secret_rotation_v2_secret_mappings",
MicrosoftTeamsIntegrations = "microsoft_teams_integrations",
ProjectMicrosoftTeamsConfigs = "project_microsoft_teams_configs",
SecretReminderRecipients = "secret_reminder_recipients",
GithubOrgSyncConfig = "github_org_sync_configs"
} }
export type TImmutableDBKeys = "id" | "createdAt" | "updatedAt"; export type TImmutableDBKeys = "id" | "createdAt" | "updatedAt";
@@ -179,11 +186,16 @@ export enum OrgMembershipStatus {
} }
export enum ProjectMembershipRole { export enum ProjectMembershipRole {
// general
Admin = "admin", Admin = "admin",
Member = "member", Member = "member",
Custom = "custom", Custom = "custom",
Viewer = "viewer", Viewer = "viewer",
NoAccess = "no-access" NoAccess = "no-access",
// ssh
SshHostBootstrapper = "ssh-host-bootstrapper",
// kms
KmsCryptographicOperator = "cryptographic-operator"
} }
export enum SecretEncryptionAlgo { export enum SecretEncryptionAlgo {
@@ -221,7 +233,8 @@ export enum IdentityAuthMethod {
AWS_AUTH = "aws-auth", AWS_AUTH = "aws-auth",
AZURE_AUTH = "azure-auth", AZURE_AUTH = "azure-auth",
OIDC_AUTH = "oidc-auth", OIDC_AUTH = "oidc-auth",
JWT_AUTH = "jwt-auth" JWT_AUTH = "jwt-auth",
LDAP_AUTH = "ldap-auth"
} }
export enum ProjectType { export enum ProjectType {

View File

@@ -30,9 +30,9 @@ 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") jwtSignatureAlgorithm: z.string().default("RS256")
}); });

View File

@@ -27,7 +27,8 @@ export const OrganizationsSchema = z.object({
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(),
bypassOrgAuthEnabled: z.boolean().default(false) bypassOrgAuthEnabled: z.boolean().default(false),
userTokenExpiration: z.string().nullable().optional()
}); });
export type TOrganizations = z.infer<typeof OrganizationsSchema>; export type TOrganizations = z.infer<typeof OrganizationsSchema>;

View File

@@ -0,0 +1,29 @@
// Code generated by automation script, DO NOT EDIT.
// Automated by pulling database and generating zod schema
// To update. Just run npm run generate:schema
// Written by akhilmhdh.
import { z } from "zod";
import { TImmutableDBKeys } from "./models";
export const ProjectMicrosoftTeamsConfigsSchema = z.object({
id: z.string().uuid(),
projectId: z.string(),
microsoftTeamsIntegrationId: z.string().uuid(),
isAccessRequestNotificationEnabled: z.boolean().default(false),
isSecretRequestNotificationEnabled: z.boolean().default(false),
accessRequestChannels: z.unknown(),
secretRequestChannels: z.unknown(),
createdAt: z.date(),
updatedAt: z.date()
});
export type TProjectMicrosoftTeamsConfigs = z.infer<typeof ProjectMicrosoftTeamsConfigsSchema>;
export type TProjectMicrosoftTeamsConfigsInsert = Omit<
z.input<typeof ProjectMicrosoftTeamsConfigsSchema>,
TImmutableDBKeys
>;
export type TProjectMicrosoftTeamsConfigsUpdate = Partial<
Omit<z.input<typeof ProjectMicrosoftTeamsConfigsSchema>, TImmutableDBKeys>
>;

View File

@@ -12,10 +12,11 @@ export const ProjectTemplatesSchema = z.object({
name: z.string(), name: z.string(),
description: z.string().nullable().optional(), description: z.string().nullable().optional(),
roles: z.unknown(), roles: z.unknown(),
environments: z.unknown(), environments: z.unknown().nullable().optional(),
orgId: z.string().uuid(), orgId: z.string().uuid(),
createdAt: z.date(), createdAt: z.date(),
updatedAt: z.date() updatedAt: z.date(),
type: z.string().default("secret-manager")
}); });
export type TProjectTemplates = z.infer<typeof ProjectTemplatesSchema>; export type TProjectTemplates = z.infer<typeof ProjectTemplatesSchema>;

View File

@@ -27,7 +27,7 @@ export const ProjectsSchema = z.object({
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() hasDeleteProtection: z.boolean().default(false).nullable().optional()
}); });
export type TProjects = z.infer<typeof ProjectsSchema>; export type TProjects = z.infer<typeof ProjectsSchema>;

View 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 SecretReminderRecipientsSchema = z.object({
id: z.string().uuid(),
createdAt: z.date(),
updatedAt: z.date(),
secretId: z.string().uuid(),
userId: z.string().uuid(),
projectId: z.string()
});
export type TSecretReminderRecipients = z.infer<typeof SecretReminderRecipientsSchema>;
export type TSecretReminderRecipientsInsert = Omit<z.input<typeof SecretReminderRecipientsSchema>, TImmutableDBKeys>;
export type TSecretReminderRecipientsUpdate = Partial<
Omit<z.input<typeof SecretReminderRecipientsSchema>, TImmutableDBKeys>
>;

View 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 SshHostGroupMembershipsSchema = z.object({
id: z.string().uuid(),
createdAt: z.date(),
updatedAt: z.date(),
sshHostGroupId: z.string().uuid(),
sshHostId: z.string().uuid()
});
export type TSshHostGroupMemberships = z.infer<typeof SshHostGroupMembershipsSchema>;
export type TSshHostGroupMembershipsInsert = Omit<z.input<typeof SshHostGroupMembershipsSchema>, TImmutableDBKeys>;
export type TSshHostGroupMembershipsUpdate = Partial<
Omit<z.input<typeof SshHostGroupMembershipsSchema>, TImmutableDBKeys>
>;

View 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 SshHostGroupsSchema = z.object({
id: z.string().uuid(),
createdAt: z.date(),
updatedAt: z.date(),
projectId: z.string(),
name: z.string()
});
export type TSshHostGroups = z.infer<typeof SshHostGroupsSchema>;
export type TSshHostGroupsInsert = Omit<z.input<typeof SshHostGroupsSchema>, TImmutableDBKeys>;
export type TSshHostGroupsUpdate = Partial<Omit<z.input<typeof SshHostGroupsSchema>, TImmutableDBKeys>>;

View File

@@ -12,7 +12,8 @@ export const SshHostLoginUserMappingsSchema = z.object({
createdAt: z.date(), createdAt: z.date(),
updatedAt: z.date(), updatedAt: z.date(),
sshHostLoginUserId: z.string().uuid(), sshHostLoginUserId: z.string().uuid(),
userId: z.string().uuid().nullable().optional() userId: z.string().uuid().nullable().optional(),
groupId: z.string().uuid().nullable().optional()
}); });
export type TSshHostLoginUserMappings = z.infer<typeof SshHostLoginUserMappingsSchema>; export type TSshHostLoginUserMappings = z.infer<typeof SshHostLoginUserMappingsSchema>;

View File

@@ -11,8 +11,9 @@ export const SshHostLoginUsersSchema = z.object({
id: z.string().uuid(), id: z.string().uuid(),
createdAt: z.date(), createdAt: z.date(),
updatedAt: z.date(), updatedAt: z.date(),
sshHostId: z.string().uuid(), sshHostId: z.string().uuid().nullable().optional(),
loginUser: z.string() loginUser: z.string(),
sshHostGroupId: z.string().uuid().nullable().optional()
}); });
export type TSshHostLoginUsers = z.infer<typeof SshHostLoginUsersSchema>; export type TSshHostLoginUsers = z.infer<typeof SshHostLoginUsersSchema>;

View File

@@ -16,7 +16,8 @@ export const SshHostsSchema = z.object({
userCertTtl: z.string(), userCertTtl: z.string(),
hostCertTtl: z.string(), hostCertTtl: z.string(),
userSshCaId: z.string().uuid(), userSshCaId: z.string().uuid(),
hostSshCaId: z.string().uuid() hostSshCaId: z.string().uuid(),
alias: z.string().nullable().optional()
}); });
export type TSshHosts = z.infer<typeof SshHostsSchema>; export type TSshHosts = z.infer<typeof SshHostsSchema>;

View File

@@ -26,7 +26,10 @@ export const SuperAdminSchema = z.object({
encryptedSlackClientSecret: zodBuffer.nullable().optional(), encryptedSlackClientSecret: zodBuffer.nullable().optional(),
authConsentContent: z.string().nullable().optional(), authConsentContent: z.string().nullable().optional(),
pageFrameContent: z.string().nullable().optional(), pageFrameContent: z.string().nullable().optional(),
adminIdentityIds: z.string().array().nullable().optional() adminIdentityIds: z.string().array().nullable().optional(),
encryptedMicrosoftTeamsAppId: zodBuffer.nullable().optional(),
encryptedMicrosoftTeamsClientSecret: zodBuffer.nullable().optional(),
encryptedMicrosoftTeamsBotId: zodBuffer.nullable().optional()
}); });
export type TSuperAdmin = z.infer<typeof SuperAdminSchema>; export type TSuperAdmin = z.infer<typeof SuperAdminSchema>;

View File

@@ -14,7 +14,8 @@ export const WorkflowIntegrationsSchema = z.object({
orgId: z.string().uuid(), orgId: z.string().uuid(),
description: z.string().nullable().optional(), description: z.string().nullable().optional(),
createdAt: z.date(), createdAt: z.date(),
updatedAt: z.date() updatedAt: z.date(),
status: z.string().default("installed")
}); });
export type TWorkflowIntegrations = z.infer<typeof WorkflowIntegrationsSchema>; export type TWorkflowIntegrations = z.infer<typeof WorkflowIntegrationsSchema>;

View File

@@ -2,6 +2,7 @@ import { z } from "zod";
import { AccessApprovalRequestsReviewersSchema, AccessApprovalRequestsSchema, UsersSchema } from "@app/db/schemas"; import { AccessApprovalRequestsReviewersSchema, AccessApprovalRequestsSchema, UsersSchema } from "@app/db/schemas";
import { ApprovalStatus } from "@app/ee/services/access-approval-request/access-approval-request-types"; import { ApprovalStatus } from "@app/ee/services/access-approval-request/access-approval-request-types";
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";
import { AuthMode } from "@app/services/auth/auth-type"; import { AuthMode } from "@app/services/auth/auth-type";
@@ -18,6 +19,9 @@ export const registerAccessApprovalRequestRouter = async (server: FastifyZodProv
server.route({ server.route({
url: "/", url: "/",
method: "POST", method: "POST",
config: {
rateLimit: writeLimit
},
schema: { schema: {
body: z.object({ body: z.object({
permissions: z.any().array(), permissions: z.any().array(),

View File

@@ -0,0 +1,124 @@
import { requestContext } from "@fastify/request-context";
import { z } from "zod";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { getConfig } from "@app/lib/config/env";
import { BadRequestError } from "@app/lib/errors";
import { writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { ActorType, AuthMode } from "@app/services/auth/auth-type";
export const registerAssumePrivilegeRouter = async (server: FastifyZodProvider) => {
server.route({
method: "POST",
url: "/:projectId/assume-privileges",
config: {
rateLimit: writeLimit
},
schema: {
params: z.object({
projectId: z.string()
}),
body: z.object({
actorType: z.enum([ActorType.USER, ActorType.IDENTITY]),
actorId: z.string()
}),
response: {
200: z.object({
message: z.string()
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req, res) => {
if (req.auth.authMode === AuthMode.JWT) {
const payload = await server.services.assumePrivileges.assumeProjectPrivileges({
targetActorType: req.body.actorType,
targetActorId: req.body.actorId,
projectId: req.params.projectId,
actorPermissionDetails: req.permission,
tokenVersionId: req.auth.tokenVersionId
});
const appCfg = getConfig();
void res.setCookie("infisical-project-assume-privileges", payload.assumePrivilegesToken, {
httpOnly: true,
path: "/",
sameSite: "strict",
secure: appCfg.HTTPS_ENABLED,
maxAge: 3600 // 1 hour in seconds
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: req.permission.orgId,
event: {
type: EventType.PROJECT_ASSUME_PRIVILEGE_SESSION_START,
metadata: {
projectId: req.params.projectId,
requesterEmail: req.auth.user.username,
requesterId: req.auth.user.id,
targetActorType: req.body.actorType,
targetActorId: req.body.actorId,
duration: "1hr"
}
}
});
return { message: "Successfully assumed role" };
}
throw new BadRequestError({ message: "Invalid auth mode" });
}
});
server.route({
method: "DELETE",
url: "/:projectId/assume-privileges",
config: {
rateLimit: writeLimit
},
schema: {
params: z.object({
projectId: z.string()
}),
response: {
200: z.object({
message: z.string()
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req, res) => {
const assumedPrivilegeDetails = requestContext.get("assumedPrivilegeDetails");
if (req.auth.authMode === AuthMode.JWT && assumedPrivilegeDetails) {
const appCfg = getConfig();
void res.setCookie("infisical-project-assume-privileges", "", {
httpOnly: true,
path: "/",
sameSite: "strict",
secure: appCfg.HTTPS_ENABLED,
expires: new Date(0)
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: req.permission.orgId,
event: {
type: EventType.PROJECT_ASSUME_PRIVILEGE_SESSION_END,
metadata: {
projectId: req.params.projectId,
requesterEmail: req.auth.user.username,
requesterId: req.auth.user.id,
targetActorId: assumedPrivilegeDetails.actorId,
targetActorType: assumedPrivilegeDetails.actorType
}
}
});
return { message: "Successfully exited assumed role" };
}
throw new BadRequestError({ message: "Invalid auth mode" });
}
});
};

View File

@@ -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)
}), }),

View File

@@ -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";
@@ -21,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),
@@ -111,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)
}), }),
@@ -179,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)
}), }),
@@ -215,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)
}), }),
@@ -253,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),
@@ -284,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({

View File

@@ -0,0 +1,129 @@
import { z } from "zod";
import { GithubOrgSyncConfigsSchema } from "@app/db/schemas";
import { CharacterType, zodValidateCharacters } from "@app/lib/validator/validate-string";
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
const SanitizedGithubOrgSyncSchema = GithubOrgSyncConfigsSchema.pick({
isActive: true,
id: true,
createdAt: true,
updatedAt: true,
orgId: true,
githubOrgName: true
});
const githubOrgNameValidator = zodValidateCharacters([CharacterType.AlphaNumeric, CharacterType.Hyphen]);
export const registerGithubOrgSyncRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/",
method: "POST",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
body: z.object({
githubOrgName: githubOrgNameValidator(z.string().trim(), "GitHub Org Name"),
githubOrgAccessToken: z.string().trim().max(1000).optional(),
isActive: z.boolean().default(false)
}),
response: {
200: z.object({
githubOrgSyncConfig: SanitizedGithubOrgSyncSchema
})
}
},
handler: async (req) => {
const githubOrgSyncConfig = await server.services.githubOrgSync.createGithubOrgSync({
orgPermission: req.permission,
githubOrgName: req.body.githubOrgName,
githubOrgAccessToken: req.body.githubOrgAccessToken,
isActive: req.body.isActive
});
return { githubOrgSyncConfig };
}
});
server.route({
url: "/",
method: "PATCH",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
body: z
.object({
githubOrgName: githubOrgNameValidator(z.string().trim(), "GitHub Org Name"),
githubOrgAccessToken: z.string().trim().max(1000),
isActive: z.boolean()
})
.partial(),
response: {
200: z.object({
githubOrgSyncConfig: SanitizedGithubOrgSyncSchema
})
}
},
handler: async (req) => {
const githubOrgSyncConfig = await server.services.githubOrgSync.updateGithubOrgSync({
orgPermission: req.permission,
githubOrgName: req.body.githubOrgName,
githubOrgAccessToken: req.body.githubOrgAccessToken,
isActive: req.body.isActive
});
return { githubOrgSyncConfig };
}
});
server.route({
url: "/",
method: "DELETE",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
response: {
200: z.object({
githubOrgSyncConfig: SanitizedGithubOrgSyncSchema
})
}
},
handler: async (req) => {
const githubOrgSyncConfig = await server.services.githubOrgSync.deleteGithubOrgSync({
orgPermission: req.permission
});
return { githubOrgSyncConfig };
}
});
server.route({
url: "/",
method: "GET",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
response: {
200: z.object({
githubOrgSyncConfig: SanitizedGithubOrgSyncSchema
})
}
},
handler: async (req) => {
const githubOrgSyncConfig = await server.services.githubOrgSync.getGithubOrgSync({
orgPermission: req.permission
});
return { githubOrgSyncConfig };
}
});
};

View File

@@ -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)

View File

@@ -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: [
{ {

View File

@@ -2,12 +2,14 @@ import { registerProjectTemplateRouter } from "@app/ee/routes/v1/project-templat
import { registerAccessApprovalPolicyRouter } from "./access-approval-policy-router"; import { registerAccessApprovalPolicyRouter } from "./access-approval-policy-router";
import { registerAccessApprovalRequestRouter } from "./access-approval-request-router"; import { registerAccessApprovalRequestRouter } from "./access-approval-request-router";
import { registerAssumePrivilegeRouter } from "./assume-privilege-router";
import { registerAuditLogStreamRouter } from "./audit-log-stream-router"; import { registerAuditLogStreamRouter } from "./audit-log-stream-router";
import { registerCaCrlRouter } from "./certificate-authority-crl-router"; import { registerCaCrlRouter } from "./certificate-authority-crl-router";
import { registerDynamicSecretLeaseRouter } from "./dynamic-secret-lease-router"; import { registerDynamicSecretLeaseRouter } from "./dynamic-secret-lease-router";
import { registerDynamicSecretRouter } from "./dynamic-secret-router"; import { registerDynamicSecretRouter } from "./dynamic-secret-router";
import { registerExternalKmsRouter } from "./external-kms-router"; import { registerExternalKmsRouter } from "./external-kms-router";
import { registerGatewayRouter } from "./gateway-router"; import { registerGatewayRouter } from "./gateway-router";
import { registerGithubOrgSyncRouter } from "./github-org-sync-router";
import { registerGroupRouter } from "./group-router"; import { registerGroupRouter } from "./group-router";
import { registerIdentityProjectAdditionalPrivilegeRouter } from "./identity-project-additional-privilege-router"; import { registerIdentityProjectAdditionalPrivilegeRouter } from "./identity-project-additional-privilege-router";
import { registerKmipRouter } from "./kmip-router"; import { registerKmipRouter } from "./kmip-router";
@@ -32,6 +34,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 { registerSshHostGroupRouter } from "./ssh-host-group-router";
import { registerSshHostRouter } from "./ssh-host-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";
@@ -45,6 +48,7 @@ export const registerV1EERoutes = async (server: FastifyZodProvider) => {
await projectRouter.register(registerProjectRoleRouter); await projectRouter.register(registerProjectRoleRouter);
await projectRouter.register(registerProjectRouter); await projectRouter.register(registerProjectRouter);
await projectRouter.register(registerTrustedIpRouter); await projectRouter.register(registerTrustedIpRouter);
await projectRouter.register(registerAssumePrivilegeRouter);
}, },
{ prefix: "/workspace" } { prefix: "/workspace" }
); );
@@ -70,6 +74,7 @@ export const registerV1EERoutes = async (server: FastifyZodProvider) => {
); );
await server.register(registerGatewayRouter, { prefix: "/gateways" }); await server.register(registerGatewayRouter, { prefix: "/gateways" });
await server.register(registerGithubOrgSyncRouter, { prefix: "/github-org-sync-config" });
await server.register( await server.register(
async (pkiRouter) => { async (pkiRouter) => {
@@ -84,6 +89,7 @@ export const registerV1EERoutes = async (server: FastifyZodProvider) => {
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" }); await sshRouter.register(registerSshHostRouter, { prefix: "/hosts" });
await sshRouter.register(registerSshHostGroupRouter, { prefix: "/host-groups" });
}, },
{ prefix: "/ssh" } { prefix: "/ssh" }
); );

View File

@@ -98,6 +98,9 @@ export const registerLdapRouter = async (server: FastifyZodProvider) => {
server.route({ server.route({
url: "/login", url: "/login",
method: "POST", method: "POST",
config: {
rateLimit: writeLimit
},
schema: { schema: {
body: z.object({ body: z.object({
organizationSlug: z.string().trim() organizationSlug: z.string().trim()

View File

@@ -1,7 +1,7 @@
import { packRules } from "@casl/ability/extra"; import { packRules } from "@casl/ability/extra";
import { z } from "zod"; import { z } from "zod";
import { ProjectMembershipRole, ProjectMembershipsSchema, ProjectRolesSchema } from "@app/db/schemas"; import { ProjectMembershipRole, ProjectRolesSchema } from "@app/db/schemas";
import { import {
backfillPermissionV1SchemaToV2Schema, backfillPermissionV1SchemaToV2Schema,
ProjectPermissionV1Schema ProjectPermissionV1Schema
@@ -245,13 +245,22 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
response: { response: {
200: z.object({ 200: z.object({
data: z.object({ data: z.object({
membership: ProjectMembershipsSchema.extend({ membership: z.object({
id: z.string(),
roles: z roles: z
.object({ .object({
role: z.string() role: z.string()
}) })
.array() .array()
}), }),
assumedPrivilegeDetails: z
.object({
actorId: z.string(),
actorType: z.string(),
actorName: z.string(),
actorEmail: z.string().optional()
})
.optional(),
permissions: z.any().array() permissions: z.any().array()
}) })
}) })
@@ -259,14 +268,20 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
}, },
onRequest: verifyAuth([AuthMode.JWT]), onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => { handler: async (req) => {
const { permissions, membership } = await server.services.projectRole.getUserPermission( const { permissions, membership, assumedPrivilegeDetails } = await server.services.projectRole.getUserPermission(
req.permission.id, req.permission.id,
req.params.projectId, req.params.projectId,
req.permission.authMethod, req.permission.authMethod,
req.permission.orgId req.permission.orgId
); );
return { data: { permissions, membership } }; return {
data: {
permissions,
membership,
assumedPrivilegeDetails
}
};
} }
}); });
}; };

View File

@@ -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: [
{ {

View File

@@ -1,11 +1,10 @@
import { z } from "zod"; import { z } from "zod";
import { ProjectMembershipRole, ProjectTemplatesSchema } from "@app/db/schemas"; import { ProjectMembershipRole, ProjectTemplatesSchema, ProjectType } from "@app/db/schemas";
import { EventType } from "@app/ee/services/audit-log/audit-log-types"; import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission"; import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
import { 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";
@@ -35,6 +34,7 @@ const SanitizedProjectTemplateSchema = ProjectTemplatesSchema.extend({
position: z.number().min(1) position: z.number().min(1)
}) })
.array() .array()
.nullable()
}); });
const ProjectTemplateRolesSchema = z const ProjectTemplateRolesSchema = z
@@ -101,7 +101,12 @@ 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.",
querystring: z.object({
type: z.nativeEnum(ProjectType).optional().describe(ProjectTemplates.LIST.type)
}),
response: { response: {
200: z.object({ 200: z.object({
projectTemplates: SanitizedProjectTemplateSchema.array() projectTemplates: SanitizedProjectTemplateSchema.array()
@@ -110,7 +115,8 @@ export const registerProjectTemplateRouter = async (server: FastifyZodProvider)
}, },
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => { handler: async (req) => {
const projectTemplates = await server.services.projectTemplate.listProjectTemplatesByOrg(req.permission); const { type } = req.query;
const projectTemplates = await server.services.projectTemplate.listProjectTemplatesByOrg(req.permission, type);
const auditTemplates = projectTemplates.filter((template) => !isInfisicalProjectTemplate(template.name)); const auditTemplates = projectTemplates.filter((template) => !isInfisicalProjectTemplate(template.name));
@@ -137,6 +143,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,8 +184,11 @@ 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({
type: z.nativeEnum(ProjectType).describe(ProjectTemplates.CREATE.type),
name: slugSchema({ field: "name" }) name: slugSchema({ field: "name" })
.refine((val) => !isInfisicalProjectTemplate(val), { .refine((val) => !isInfisicalProjectTemplate(val), {
message: `The requested project template name is reserved.` message: `The requested project template name is reserved.`
@@ -185,9 +196,7 @@ export const registerProjectTemplateRouter = async (server: FastifyZodProvider)
.describe(ProjectTemplates.CREATE.name), .describe(ProjectTemplates.CREATE.name),
description: z.string().max(256).trim().optional().describe(ProjectTemplates.CREATE.description), description: z.string().max(256).trim().optional().describe(ProjectTemplates.CREATE.description),
roles: ProjectTemplateRolesSchema.default([]).describe(ProjectTemplates.CREATE.roles), roles: ProjectTemplateRolesSchema.default([]).describe(ProjectTemplates.CREATE.roles),
environments: ProjectTemplateEnvironmentsSchema.default(ProjectTemplateDefaultEnvironments).describe( environments: ProjectTemplateEnvironmentsSchema.describe(ProjectTemplates.CREATE.environments).optional()
ProjectTemplates.CREATE.environments
)
}), }),
response: { response: {
200: z.object({ 200: z.object({
@@ -219,6 +228,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 +280,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) }),

View File

@@ -166,6 +166,9 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
server.route({ server.route({
url: "/redirect/saml2/organizations/:orgSlug", url: "/redirect/saml2/organizations/:orgSlug",
method: "GET", method: "GET",
config: {
rateLimit: readLimit
},
schema: { schema: {
params: z.object({ params: z.object({
orgSlug: z.string().trim() orgSlug: z.string().trim()
@@ -192,6 +195,9 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
server.route({ server.route({
url: "/redirect/saml2/:samlConfigId", url: "/redirect/saml2/:samlConfigId",
method: "GET", method: "GET",
config: {
rateLimit: readLimit
},
schema: { schema: {
params: z.object({ params: z.object({
samlConfigId: z.string().trim() samlConfigId: z.string().trim()
@@ -218,6 +224,9 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
server.route({ server.route({
url: "/saml2/:samlConfigId", url: "/saml2/:samlConfigId",
method: "POST", method: "POST",
config: {
rateLimit: writeLimit
},
schema: { schema: {
params: z.object({ params: z.object({
samlConfigId: z.string().trim() samlConfigId: z.string().trim()

View File

@@ -196,6 +196,9 @@ export const registerScimRouter = async (server: FastifyZodProvider) => {
server.route({ server.route({
url: "/Users", url: "/Users",
method: "POST", method: "POST",
config: {
rateLimit: writeLimit
},
schema: { schema: {
body: z.object({ body: z.object({
schemas: z.array(z.string()), schemas: z.array(z.string()),

View File

@@ -1,11 +1,11 @@
import { z } from "zod"; import { z } from "zod";
import { GitAppOrgSchema, SecretScanningGitRisksSchema } from "@app/db/schemas"; import { GitAppOrgSchema, SecretScanningGitRisksSchema } from "@app/db/schemas";
import { canUseSecretScanning } from "@app/ee/services/secret-scanning/secret-scanning-fns";
import { import {
SecretScanningResolvedStatus, SecretScanningResolvedStatus,
SecretScanningRiskStatus SecretScanningRiskStatus
} from "@app/ee/services/secret-scanning/secret-scanning-types"; } from "@app/ee/services/secret-scanning/secret-scanning-types";
import { getConfig } from "@app/lib/config/env";
import { BadRequestError } from "@app/lib/errors"; import { BadRequestError } from "@app/lib/errors";
import { OrderByDirection } from "@app/lib/types"; import { OrderByDirection } from "@app/lib/types";
import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
@@ -23,14 +23,14 @@ export const registerSecretScanningRouter = async (server: FastifyZodProvider) =
body: z.object({ organizationId: z.string().trim() }), body: z.object({ organizationId: z.string().trim() }),
response: { response: {
200: z.object({ 200: z.object({
sessionId: z.string() sessionId: z.string(),
gitAppSlug: z.string()
}) })
} }
}, },
onRequest: verifyAuth([AuthMode.JWT]), onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => { handler: async (req) => {
const appCfg = getConfig(); if (!canUseSecretScanning(req.auth.orgId)) {
if (!appCfg.SECRET_SCANNING_ORG_WHITELIST?.includes(req.auth.orgId)) {
throw new BadRequestError({ throw new BadRequestError({
message: "Secret scanning is temporarily unavailable." message: "Secret scanning is temporarily unavailable."
}); });

View File

@@ -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";
@@ -65,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: [
{ {

View File

@@ -6,7 +6,7 @@ import { sanitizedSshCa } from "@app/ee/services/ssh/ssh-certificate-authority-s
import { SshCaKeySource, 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 { 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";
@@ -20,6 +20,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: "Create SSH CA", description: "Create SSH CA",
body: z body: z
.object({ .object({
@@ -92,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)
@@ -138,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)
@@ -163,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)
@@ -216,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)
@@ -261,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)

View File

@@ -3,7 +3,7 @@ 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 { SshCertKeyAlgorithm } from "@app/ee/services/ssh-certificate/ssh-certificate-types"; import { SshCertKeyAlgorithm } from "@app/ee/services/ssh-certificate/ssh-certificate-types";
import { SSH_CERTIFICATE_AUTHORITIES } from "@app/lib/api-docs"; 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";
@@ -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

View File

@@ -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),
@@ -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)
}), }),

View File

@@ -0,0 +1,360 @@
import { z } from "zod";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { loginMappingSchema, sanitizedSshHost } from "@app/ee/services/ssh-host/ssh-host-schema";
import { sanitizedSshHostGroup } from "@app/ee/services/ssh-host-group/ssh-host-group-schema";
import { EHostGroupMembershipFilter } from "@app/ee/services/ssh-host-group/ssh-host-group-types";
import { ApiDocsTags, SSH_HOST_GROUPS } from "@app/lib/api-docs";
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { slugSchema } from "@app/server/lib/schemas";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
export const registerSshHostGroupRouter = async (server: FastifyZodProvider) => {
server.route({
method: "GET",
url: "/:sshHostGroupId",
config: {
rateLimit: readLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.SshHostGroups],
description: "Get SSH Host Group",
params: z.object({
sshHostGroupId: z.string().describe(SSH_HOST_GROUPS.GET.sshHostGroupId)
}),
response: {
200: sanitizedSshHostGroup.extend({
loginMappings: z.array(loginMappingSchema)
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const sshHostGroup = await server.services.sshHostGroup.getSshHostGroup({
sshHostGroupId: req.params.sshHostGroupId,
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: sshHostGroup.projectId,
event: {
type: EventType.GET_SSH_HOST_GROUP,
metadata: {
sshHostGroupId: sshHostGroup.id,
name: sshHostGroup.name
}
}
});
return sshHostGroup;
}
});
server.route({
method: "POST",
url: "/",
config: {
rateLimit: writeLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.SshHostGroups],
description: "Create SSH Host Group",
body: z.object({
projectId: z.string().describe(SSH_HOST_GROUPS.CREATE.projectId),
name: slugSchema({ min: 1, max: 64, field: "name" }).describe(SSH_HOST_GROUPS.CREATE.name),
loginMappings: z.array(loginMappingSchema).default([]).describe(SSH_HOST_GROUPS.CREATE.loginMappings)
}),
response: {
200: sanitizedSshHostGroup.extend({
loginMappings: z.array(loginMappingSchema)
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const sshHostGroup = await server.services.sshHostGroup.createSshHostGroup({
...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: sshHostGroup.projectId,
event: {
type: EventType.CREATE_SSH_HOST_GROUP,
metadata: {
sshHostGroupId: sshHostGroup.id,
name: sshHostGroup.name,
loginMappings: sshHostGroup.loginMappings
}
}
});
return sshHostGroup;
}
});
server.route({
method: "PATCH",
url: "/:sshHostGroupId",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
hide: false,
tags: [ApiDocsTags.SshHostGroups],
description: "Update SSH Host Group",
params: z.object({
sshHostGroupId: z.string().trim().describe(SSH_HOST_GROUPS.UPDATE.sshHostGroupId)
}),
body: z.object({
name: slugSchema({ min: 1, max: 64, field: "name" }).describe(SSH_HOST_GROUPS.UPDATE.name).optional(),
loginMappings: z.array(loginMappingSchema).optional().describe(SSH_HOST_GROUPS.UPDATE.loginMappings)
}),
response: {
200: sanitizedSshHostGroup.extend({
loginMappings: z.array(loginMappingSchema)
})
}
},
handler: async (req) => {
const sshHostGroup = await server.services.sshHostGroup.updateSshHostGroup({
sshHostGroupId: req.params.sshHostGroupId,
...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: sshHostGroup.projectId,
event: {
type: EventType.UPDATE_SSH_HOST_GROUP,
metadata: {
sshHostGroupId: sshHostGroup.id,
name: sshHostGroup.name,
loginMappings: sshHostGroup.loginMappings
}
}
});
return sshHostGroup;
}
});
server.route({
method: "DELETE",
url: "/:sshHostGroupId",
config: {
rateLimit: writeLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.SshHostGroups],
description: "Delete SSH Host Group",
params: z.object({
sshHostGroupId: z.string().describe(SSH_HOST_GROUPS.DELETE.sshHostGroupId)
}),
response: {
200: sanitizedSshHostGroup.extend({
loginMappings: z.array(loginMappingSchema)
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const sshHostGroup = await server.services.sshHostGroup.deleteSshHostGroup({
sshHostGroupId: req.params.sshHostGroupId,
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: sshHostGroup.projectId,
event: {
type: EventType.DELETE_SSH_HOST_GROUP,
metadata: {
sshHostGroupId: sshHostGroup.id,
name: sshHostGroup.name
}
}
});
return sshHostGroup;
}
});
server.route({
method: "GET",
url: "/:sshHostGroupId/hosts",
config: {
rateLimit: readLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.SshHostGroups],
description: "Get SSH Hosts in a Host Group",
params: z.object({
sshHostGroupId: z.string().describe(SSH_HOST_GROUPS.GET.sshHostGroupId)
}),
querystring: z.object({
filter: z.nativeEnum(EHostGroupMembershipFilter).optional().describe(SSH_HOST_GROUPS.GET.filter)
}),
response: {
200: z.object({
hosts: sanitizedSshHost
.pick({
id: true,
hostname: true,
alias: true
})
.merge(
z.object({
isPartOfGroup: z.boolean(),
joinedGroupAt: z.date().nullable()
})
)
.array(),
totalCount: z.number()
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const { sshHostGroup, hosts, totalCount } = await server.services.sshHostGroup.listSshHostGroupHosts({
sshHostGroupId: req.params.sshHostGroupId,
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.query
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: sshHostGroup.projectId,
event: {
type: EventType.GET_SSH_HOST_GROUP_HOSTS,
metadata: {
sshHostGroupId: req.params.sshHostGroupId,
name: sshHostGroup.name
}
}
});
return { hosts, totalCount };
}
});
server.route({
method: "POST",
url: "/:sshHostGroupId/hosts/:hostId",
config: {
rateLimit: writeLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.SshHostGroups],
description: "Add an SSH Host to a Host Group",
params: z.object({
sshHostGroupId: z.string().describe(SSH_HOST_GROUPS.ADD_HOST.sshHostGroupId),
hostId: z.string().describe(SSH_HOST_GROUPS.ADD_HOST.hostId)
}),
response: {
200: sanitizedSshHost.extend({
loginMappings: z.array(loginMappingSchema)
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const { sshHostGroup, sshHost } = await server.services.sshHostGroup.addHostToSshHostGroup({
sshHostGroupId: req.params.sshHostGroupId,
hostId: req.params.hostId,
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: sshHost.projectId,
event: {
type: EventType.ADD_HOST_TO_SSH_HOST_GROUP,
metadata: {
sshHostGroupId: sshHostGroup.id,
sshHostId: sshHost.id,
hostname: sshHost.hostname
}
}
});
return sshHost;
}
});
server.route({
method: "DELETE",
url: "/:sshHostGroupId/hosts/:hostId",
config: {
rateLimit: writeLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.SshHostGroups],
description: "Remove an SSH Host from a Host Group",
params: z.object({
sshHostGroupId: z.string().describe(SSH_HOST_GROUPS.DELETE_HOST.sshHostGroupId),
hostId: z.string().describe(SSH_HOST_GROUPS.DELETE_HOST.hostId)
}),
response: {
200: sanitizedSshHost.extend({
loginMappings: z.array(loginMappingSchema)
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const { sshHostGroup, sshHost } = await server.services.sshHostGroup.removeHostFromSshHostGroup({
sshHostGroupId: req.params.sshHostGroupId,
hostId: req.params.hostId,
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: sshHost.projectId,
event: {
type: EventType.REMOVE_HOST_FROM_SSH_HOST_GROUP,
metadata: {
sshHostGroupId: sshHostGroup.id,
sshHostId: sshHost.id,
hostname: sshHost.hostname
}
}
});
return sshHost;
}
});
};

View File

@@ -3,10 +3,12 @@ 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 { SshCertKeyAlgorithm } from "@app/ee/services/ssh-certificate/ssh-certificate-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 { loginMappingSchema, sanitizedSshHost } from "@app/ee/services/ssh-host/ssh-host-schema";
import { LoginMappingSource } from "@app/ee/services/ssh-host/ssh-host-types";
import { isValidHostname } from "@app/ee/services/ssh-host/ssh-host-validators"; import { isValidHostname } from "@app/ee/services/ssh-host/ssh-host-validators";
import { SSH_HOSTS } from "@app/lib/api-docs"; import { ApiDocsTags, SSH_HOSTS } from "@app/lib/api-docs";
import { ms } from "@app/lib/ms"; import { ms } from "@app/lib/ms";
import { publicSshCaLimit, readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { publicSshCaLimit, readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { slugSchema } from "@app/server/lib/schemas";
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";
@@ -20,10 +22,16 @@ export const registerSshHostRouter = async (server: FastifyZodProvider) => {
rateLimit: readLimit rateLimit: readLimit
}, },
schema: { schema: {
hide: false,
tags: [ApiDocsTags.SshHosts],
response: { response: {
200: z.array( 200: z.array(
sanitizedSshHost.extend({ sanitizedSshHost.extend({
loginMappings: z.array(loginMappingSchema) loginMappings: loginMappingSchema
.extend({
source: z.nativeEnum(LoginMappingSource)
})
.array()
}) })
) )
} }
@@ -48,12 +56,18 @@ export const registerSshHostRouter = async (server: FastifyZodProvider) => {
rateLimit: readLimit rateLimit: readLimit
}, },
schema: { schema: {
hide: false,
tags: [ApiDocsTags.SshHosts],
params: z.object({ params: z.object({
sshHostId: z.string().describe(SSH_HOSTS.GET.sshHostId) sshHostId: z.string().describe(SSH_HOSTS.GET.sshHostId)
}), }),
response: { response: {
200: sanitizedSshHost.extend({ 200: sanitizedSshHost.extend({
loginMappings: z.array(loginMappingSchema) loginMappings: loginMappingSchema
.extend({
source: z.nativeEnum(LoginMappingSource)
})
.array()
}) })
} }
}, },
@@ -90,16 +104,20 @@ export const registerSshHostRouter = async (server: FastifyZodProvider) => {
rateLimit: writeLimit rateLimit: writeLimit
}, },
schema: { schema: {
description: "Add an SSH Host", hide: false,
tags: [ApiDocsTags.SshHosts],
description: "Register SSH Host",
body: z.object({ body: z.object({
projectId: z.string().describe(SSH_HOSTS.CREATE.projectId), projectId: z.string().describe(SSH_HOSTS.CREATE.projectId),
hostname: z hostname: z
.string() .string()
.min(1) .min(1)
.trim()
.refine((v) => isValidHostname(v), { .refine((v) => isValidHostname(v), {
message: "Hostname must be a valid hostname" message: "Hostname must be a valid hostname"
}) })
.describe(SSH_HOSTS.CREATE.hostname), .describe(SSH_HOSTS.CREATE.hostname),
alias: slugSchema({ min: 0, max: 64, field: "alias" }).describe(SSH_HOSTS.CREATE.alias).default(""),
userCertTtl: z userCertTtl: z
.string() .string()
.refine((val) => ms(val) > 0, "TTL must be a positive number") .refine((val) => ms(val) > 0, "TTL must be a positive number")
@@ -116,7 +134,11 @@ export const registerSshHostRouter = async (server: FastifyZodProvider) => {
}), }),
response: { response: {
200: sanitizedSshHost.extend({ 200: sanitizedSshHost.extend({
loginMappings: z.array(loginMappingSchema) loginMappings: loginMappingSchema
.extend({
source: z.nativeEnum(LoginMappingSource)
})
.array()
}) })
} }
}, },
@@ -138,6 +160,7 @@ export const registerSshHostRouter = async (server: FastifyZodProvider) => {
metadata: { metadata: {
sshHostId: host.id, sshHostId: host.id,
hostname: host.hostname, hostname: host.hostname,
alias: host.alias ?? null,
userCertTtl: host.userCertTtl, userCertTtl: host.userCertTtl,
hostCertTtl: host.hostCertTtl, hostCertTtl: host.hostCertTtl,
loginMappings: host.loginMappings, loginMappings: host.loginMappings,
@@ -159,6 +182,8 @@ export const registerSshHostRouter = 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.SshHosts],
description: "Update SSH Host", description: "Update SSH Host",
params: z.object({ params: z.object({
sshHostId: z.string().trim().describe(SSH_HOSTS.UPDATE.sshHostId) sshHostId: z.string().trim().describe(SSH_HOSTS.UPDATE.sshHostId)
@@ -166,12 +191,14 @@ export const registerSshHostRouter = async (server: FastifyZodProvider) => {
body: z.object({ body: z.object({
hostname: z hostname: z
.string() .string()
.trim()
.min(1) .min(1)
.refine((v) => isValidHostname(v), { .refine((v) => isValidHostname(v), {
message: "Hostname must be a valid hostname" message: "Hostname must be a valid hostname"
}) })
.optional() .optional()
.describe(SSH_HOSTS.UPDATE.hostname), .describe(SSH_HOSTS.UPDATE.hostname),
alias: slugSchema({ min: 0, max: 64, field: "alias" }).describe(SSH_HOSTS.UPDATE.alias).optional(),
userCertTtl: z userCertTtl: z
.string() .string()
.refine((val) => ms(val) > 0, "TTL must be a positive number") .refine((val) => ms(val) > 0, "TTL must be a positive number")
@@ -186,7 +213,11 @@ export const registerSshHostRouter = async (server: FastifyZodProvider) => {
}), }),
response: { response: {
200: sanitizedSshHost.extend({ 200: sanitizedSshHost.extend({
loginMappings: z.array(loginMappingSchema) loginMappings: loginMappingSchema
.extend({
source: z.nativeEnum(LoginMappingSource)
})
.array()
}) })
} }
}, },
@@ -208,6 +239,7 @@ export const registerSshHostRouter = async (server: FastifyZodProvider) => {
metadata: { metadata: {
sshHostId: host.id, sshHostId: host.id,
hostname: host.hostname, hostname: host.hostname,
alias: host.alias,
userCertTtl: host.userCertTtl, userCertTtl: host.userCertTtl,
hostCertTtl: host.hostCertTtl, hostCertTtl: host.hostCertTtl,
loginMappings: host.loginMappings, loginMappings: host.loginMappings,
@@ -228,12 +260,19 @@ export const registerSshHostRouter = async (server: FastifyZodProvider) => {
rateLimit: writeLimit rateLimit: writeLimit
}, },
schema: { schema: {
hide: false,
tags: [ApiDocsTags.SshHosts],
description: "Delete SSH Host",
params: z.object({ params: z.object({
sshHostId: z.string().describe(SSH_HOSTS.DELETE.sshHostId) sshHostId: z.string().describe(SSH_HOSTS.DELETE.sshHostId)
}), }),
response: { response: {
200: sanitizedSshHost.extend({ 200: sanitizedSshHost.extend({
loginMappings: z.array(loginMappingSchema) loginMappings: loginMappingSchema
.extend({
source: z.nativeEnum(LoginMappingSource)
})
.array()
}) })
} }
}, },
@@ -271,6 +310,8 @@ export const registerSshHostRouter = async (server: FastifyZodProvider) => {
}, },
onRequest: verifyAuth([AuthMode.JWT]), onRequest: verifyAuth([AuthMode.JWT]),
schema: { schema: {
hide: false,
tags: [ApiDocsTags.SshHosts],
description: "Issue SSH certificate for user", description: "Issue SSH certificate for user",
params: z.object({ params: z.object({
sshHostId: z.string().describe(SSH_HOSTS.ISSUE_SSH_CREDENTIALS.sshHostId) sshHostId: z.string().describe(SSH_HOSTS.ISSUE_SSH_CREDENTIALS.sshHostId)
@@ -343,6 +384,8 @@ export const registerSshHostRouter = 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.SshHosts],
description: "Issue SSH certificate for host", description: "Issue SSH certificate for host",
params: z.object({ params: z.object({
sshHostId: z.string().describe(SSH_HOSTS.ISSUE_HOST_CERT.sshHostId) sshHostId: z.string().describe(SSH_HOSTS.ISSUE_HOST_CERT.sshHostId)
@@ -407,6 +450,8 @@ export const registerSshHostRouter = async (server: FastifyZodProvider) => {
rateLimit: publicSshCaLimit rateLimit: publicSshCaLimit
}, },
schema: { schema: {
hide: false,
tags: [ApiDocsTags.SshHosts],
description: "Get public key of the user SSH CA linked to the host", description: "Get public key of the user SSH CA linked to the host",
params: z.object({ params: z.object({
sshHostId: z.string().trim().describe(SSH_HOSTS.GET_USER_CA_PUBLIC_KEY.sshHostId) sshHostId: z.string().trim().describe(SSH_HOSTS.GET_USER_CA_PUBLIC_KEY.sshHostId)
@@ -428,6 +473,8 @@ export const registerSshHostRouter = async (server: FastifyZodProvider) => {
rateLimit: publicSshCaLimit rateLimit: publicSshCaLimit
}, },
schema: { schema: {
hide: false,
tags: [ApiDocsTags.SshHosts],
description: "Get public key of the host SSH CA linked to the host", description: "Get public key of the host SSH CA linked to the host",
params: z.object({ params: z.object({
sshHostId: z.string().trim().describe(SSH_HOSTS.GET_HOST_CA_PUBLIC_KEY.sshHostId) sshHostId: z.string().trim().describe(SSH_HOSTS.GET_HOST_CA_PUBLIC_KEY.sshHostId)

View File

@@ -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: [
{ {

View File

@@ -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)

View File

@@ -0,0 +1,19 @@
import {
AwsIamUserSecretRotationGeneratedCredentialsSchema,
AwsIamUserSecretRotationSchema,
CreateAwsIamUserSecretRotationSchema,
UpdateAwsIamUserSecretRotationSchema
} from "@app/ee/services/secret-rotation-v2/aws-iam-user-secret";
import { SecretRotation } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-enums";
import { registerSecretRotationEndpoints } from "./secret-rotation-v2-endpoints";
export const registerAwsIamUserSecretRotationRouter = async (server: FastifyZodProvider) =>
registerSecretRotationEndpoints({
type: SecretRotation.AwsIamUserSecret,
server,
responseSchema: AwsIamUserSecretRotationSchema,
createSchema: CreateAwsIamUserSecretRotationSchema,
updateSchema: UpdateAwsIamUserSecretRotationSchema,
generatedCredentialsSchema: AwsIamUserSecretRotationGeneratedCredentialsSchema
});

View File

@@ -0,0 +1,19 @@
import {
AzureClientSecretRotationGeneratedCredentialsSchema,
AzureClientSecretRotationSchema,
CreateAzureClientSecretRotationSchema,
UpdateAzureClientSecretRotationSchema
} from "@app/ee/services/secret-rotation-v2/azure-client-secret";
import { SecretRotation } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-enums";
import { registerSecretRotationEndpoints } from "./secret-rotation-v2-endpoints";
export const registerAzureClientSecretRotationRouter = async (server: FastifyZodProvider) =>
registerSecretRotationEndpoints({
type: SecretRotation.AzureClientSecret,
server,
responseSchema: AzureClientSecretRotationSchema,
createSchema: CreateAzureClientSecretRotationSchema,
updateSchema: UpdateAzureClientSecretRotationSchema,
generatedCredentialsSchema: AzureClientSecretRotationGeneratedCredentialsSchema
});

View File

@@ -1,6 +1,9 @@
import { SecretRotation } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-enums"; import { SecretRotation } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-enums";
import { registerAuth0ClientSecretRotationRouter } from "./auth0-client-secret-rotation-router"; import { registerAuth0ClientSecretRotationRouter } from "./auth0-client-secret-rotation-router";
import { registerAwsIamUserSecretRotationRouter } from "./aws-iam-user-secret-rotation-router";
import { registerAzureClientSecretRotationRouter } from "./azure-client-secret-rotation-router";
import { registerLdapPasswordRotationRouter } from "./ldap-password-rotation-router";
import { registerMsSqlCredentialsRotationRouter } from "./mssql-credentials-rotation-router"; import { registerMsSqlCredentialsRotationRouter } from "./mssql-credentials-rotation-router";
import { registerPostgresCredentialsRotationRouter } from "./postgres-credentials-rotation-router"; import { registerPostgresCredentialsRotationRouter } from "./postgres-credentials-rotation-router";
@@ -12,5 +15,8 @@ export const SECRET_ROTATION_REGISTER_ROUTER_MAP: Record<
> = { > = {
[SecretRotation.PostgresCredentials]: registerPostgresCredentialsRotationRouter, [SecretRotation.PostgresCredentials]: registerPostgresCredentialsRotationRouter,
[SecretRotation.MsSqlCredentials]: registerMsSqlCredentialsRotationRouter, [SecretRotation.MsSqlCredentials]: registerMsSqlCredentialsRotationRouter,
[SecretRotation.Auth0ClientSecret]: registerAuth0ClientSecretRotationRouter [SecretRotation.Auth0ClientSecret]: registerAuth0ClientSecretRotationRouter,
[SecretRotation.AzureClientSecret]: registerAzureClientSecretRotationRouter,
[SecretRotation.AwsIamUserSecret]: registerAwsIamUserSecretRotationRouter,
[SecretRotation.LdapPassword]: registerLdapPasswordRotationRouter
}; };

View File

@@ -0,0 +1,19 @@
import {
CreateLdapPasswordRotationSchema,
LdapPasswordRotationGeneratedCredentialsSchema,
LdapPasswordRotationSchema,
UpdateLdapPasswordRotationSchema
} from "@app/ee/services/secret-rotation-v2/ldap-password";
import { SecretRotation } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-enums";
import { registerSecretRotationEndpoints } from "./secret-rotation-v2-endpoints";
export const registerLdapPasswordRotationRouter = async (server: FastifyZodProvider) =>
registerSecretRotationEndpoints({
type: SecretRotation.LdapPassword,
server,
responseSchema: LdapPasswordRotationSchema,
createSchema: CreateLdapPasswordRotationSchema,
updateSchema: UpdateLdapPasswordRotationSchema,
generatedCredentialsSchema: LdapPasswordRotationGeneratedCredentialsSchema
});

View File

@@ -9,7 +9,7 @@ import {
TSecretRotationV2GeneratedCredentials, TSecretRotationV2GeneratedCredentials,
TSecretRotationV2Input TSecretRotationV2Input
} from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-types"; } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-types";
import { SecretRotations } from "@app/lib/api-docs"; import { ApiDocsTags, SecretRotations } from "@app/lib/api-docs";
import { startsWithVowel } from "@app/lib/fn"; import { startsWithVowel } 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";
@@ -66,6 +66,8 @@ export const registerSecretRotationEndpoints = <
rateLimit: readLimit rateLimit: readLimit
}, },
schema: { schema: {
hide: false,
tags: [ApiDocsTags.SecretRotations],
description: `List the ${rotationType} Rotations for the specified project.`, description: `List the ${rotationType} Rotations for the specified project.`,
querystring: z.object({ querystring: z.object({
projectId: z.string().trim().min(1, "Project ID required").describe(SecretRotations.LIST(type).projectId) projectId: z.string().trim().min(1, "Project ID required").describe(SecretRotations.LIST(type).projectId)
@@ -109,6 +111,8 @@ export const registerSecretRotationEndpoints = <
rateLimit: readLimit rateLimit: readLimit
}, },
schema: { schema: {
hide: false,
tags: [ApiDocsTags.SecretRotations],
description: `Get the specified ${rotationType} Rotation by ID.`, description: `Get the specified ${rotationType} Rotation by ID.`,
params: z.object({ params: z.object({
rotationId: z.string().uuid().describe(SecretRotations.GET_BY_ID(type).rotationId) rotationId: z.string().uuid().describe(SecretRotations.GET_BY_ID(type).rotationId)
@@ -151,6 +155,8 @@ export const registerSecretRotationEndpoints = <
rateLimit: readLimit rateLimit: readLimit
}, },
schema: { schema: {
hide: false,
tags: [ApiDocsTags.SecretRotations],
description: `Get the specified ${rotationType} Rotation by name, secret path, environment and project ID.`, description: `Get the specified ${rotationType} Rotation by name, secret path, environment and project ID.`,
params: z.object({ params: z.object({
rotationName: z rotationName: z
@@ -215,6 +221,8 @@ export const registerSecretRotationEndpoints = <
rateLimit: writeLimit rateLimit: writeLimit
}, },
schema: { schema: {
hide: false,
tags: [ApiDocsTags.SecretRotations],
description: `Create ${ description: `Create ${
startsWithVowel(rotationType) ? "an" : "a" startsWithVowel(rotationType) ? "an" : "a"
} ${rotationType} Rotation for the specified project.`, } ${rotationType} Rotation for the specified project.`,
@@ -254,6 +262,8 @@ export const registerSecretRotationEndpoints = <
rateLimit: writeLimit rateLimit: writeLimit
}, },
schema: { schema: {
hide: false,
tags: [ApiDocsTags.SecretRotations],
description: `Update the specified ${rotationType} Rotation.`, description: `Update the specified ${rotationType} Rotation.`,
params: z.object({ params: z.object({
rotationId: z.string().uuid().describe(SecretRotations.UPDATE(type).rotationId) rotationId: z.string().uuid().describe(SecretRotations.UPDATE(type).rotationId)
@@ -296,6 +306,8 @@ export const registerSecretRotationEndpoints = <
rateLimit: writeLimit rateLimit: writeLimit
}, },
schema: { schema: {
hide: false,
tags: [ApiDocsTags.SecretRotations],
description: `Delete the specified ${rotationType} Rotation.`, description: `Delete the specified ${rotationType} Rotation.`,
params: z.object({ params: z.object({
rotationId: z.string().uuid().describe(SecretRotations.DELETE(type).rotationId) rotationId: z.string().uuid().describe(SecretRotations.DELETE(type).rotationId)
@@ -349,6 +361,8 @@ export const registerSecretRotationEndpoints = <
rateLimit: readLimit rateLimit: readLimit
}, },
schema: { schema: {
hide: false,
tags: [ApiDocsTags.SecretRotations],
description: `Get the generated credentials for the specified ${rotationType} Rotation.`, description: `Get the generated credentials for the specified ${rotationType} Rotation.`,
params: z.object({ params: z.object({
rotationId: z.string().uuid().describe(SecretRotations.GET_GENERATED_CREDENTIALS_BY_ID(type).rotationId) rotationId: z.string().uuid().describe(SecretRotations.GET_GENERATED_CREDENTIALS_BY_ID(type).rotationId)
@@ -402,6 +416,8 @@ export const registerSecretRotationEndpoints = <
rateLimit: writeLimit rateLimit: writeLimit
}, },
schema: { schema: {
hide: false,
tags: [ApiDocsTags.SecretRotations],
description: `Rotate the generated credentials for the specified ${rotationType} Rotation.`, description: `Rotate the generated credentials for the specified ${rotationType} Rotation.`,
params: z.object({ params: z.object({
rotationId: z.string().uuid().describe(SecretRotations.ROTATE(type).rotationId) rotationId: z.string().uuid().describe(SecretRotations.ROTATE(type).rotationId)

View File

@@ -2,10 +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 { Auth0ClientSecretRotationListItemSchema } from "@app/ee/services/secret-rotation-v2/auth0-client-secret"; import { Auth0ClientSecretRotationListItemSchema } from "@app/ee/services/secret-rotation-v2/auth0-client-secret";
import { AwsIamUserSecretRotationListItemSchema } from "@app/ee/services/secret-rotation-v2/aws-iam-user-secret";
import { AzureClientSecretRotationListItemSchema } from "@app/ee/services/secret-rotation-v2/azure-client-secret";
import { LdapPasswordRotationListItemSchema } from "@app/ee/services/secret-rotation-v2/ldap-password";
import { MsSqlCredentialsRotationListItemSchema } from "@app/ee/services/secret-rotation-v2/mssql-credentials"; import { MsSqlCredentialsRotationListItemSchema } from "@app/ee/services/secret-rotation-v2/mssql-credentials";
import { PostgresCredentialsRotationListItemSchema } from "@app/ee/services/secret-rotation-v2/postgres-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 { SecretRotationV2Schema } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-union-schema";
import { SecretRotations } from "@app/lib/api-docs"; import { ApiDocsTags, SecretRotations } from "@app/lib/api-docs";
import { readLimit } from "@app/server/config/rateLimiter"; import { readLimit } 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";
@@ -13,7 +16,10 @@ import { AuthMode } from "@app/services/auth/auth-type";
const SecretRotationV2OptionsSchema = z.discriminatedUnion("type", [ const SecretRotationV2OptionsSchema = z.discriminatedUnion("type", [
PostgresCredentialsRotationListItemSchema, PostgresCredentialsRotationListItemSchema,
MsSqlCredentialsRotationListItemSchema, MsSqlCredentialsRotationListItemSchema,
Auth0ClientSecretRotationListItemSchema Auth0ClientSecretRotationListItemSchema,
AzureClientSecretRotationListItemSchema,
AwsIamUserSecretRotationListItemSchema,
LdapPasswordRotationListItemSchema
]); ]);
export const registerSecretRotationV2Router = async (server: FastifyZodProvider) => { export const registerSecretRotationV2Router = async (server: FastifyZodProvider) => {
@@ -24,6 +30,8 @@ export const registerSecretRotationV2Router = async (server: FastifyZodProvider)
rateLimit: readLimit rateLimit: readLimit
}, },
schema: { schema: {
hide: false,
tags: [ApiDocsTags.SecretRotations],
description: "List the available Secret Rotation Options.", description: "List the available Secret Rotation Options.",
response: { response: {
200: z.object({ 200: z.object({
@@ -45,6 +53,8 @@ export const registerSecretRotationV2Router = async (server: FastifyZodProvider)
rateLimit: readLimit rateLimit: readLimit
}, },
schema: { schema: {
hide: false,
tags: [ApiDocsTags.SecretRotations],
description: "List all the Secret Rotations for the specified project.", description: "List all the Secret Rotations for the specified project.",
querystring: z.object({ querystring: z.object({
projectId: z.string().trim().min(1, "Project ID required").describe(SecretRotations.LIST().projectId) projectId: z.string().trim().min(1, "Project ID required").describe(SecretRotations.LIST().projectId)

View File

@@ -6,13 +6,15 @@ import { getConfig } from "@app/lib/config/env";
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors"; import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
import { ms } from "@app/lib/ms"; import { ms } from "@app/lib/ms";
import { alphaNumericNanoId } from "@app/lib/nanoid"; import { alphaNumericNanoId } from "@app/lib/nanoid";
import { triggerWorkflowIntegrationNotification } from "@app/lib/workflow-integrations/trigger-notification";
import { TriggerFeature } from "@app/lib/workflow-integrations/types";
import { TKmsServiceFactory } from "@app/services/kms/kms-service"; import { TKmsServiceFactory } from "@app/services/kms/kms-service";
import { TMicrosoftTeamsServiceFactory } from "@app/services/microsoft-teams/microsoft-teams-service";
import { TProjectMicrosoftTeamsConfigDALFactory } from "@app/services/microsoft-teams/project-microsoft-teams-config-dal";
import { TProjectDALFactory } from "@app/services/project/project-dal"; import { TProjectDALFactory } from "@app/services/project/project-dal";
import { TProjectEnvDALFactory } from "@app/services/project-env/project-env-dal"; import { TProjectEnvDALFactory } from "@app/services/project-env/project-env-dal";
import { TProjectMembershipDALFactory } from "@app/services/project-membership/project-membership-dal"; import { TProjectMembershipDALFactory } from "@app/services/project-membership/project-membership-dal";
import { TProjectSlackConfigDALFactory } from "@app/services/slack/project-slack-config-dal"; import { TProjectSlackConfigDALFactory } from "@app/services/slack/project-slack-config-dal";
import { triggerSlackNotification } from "@app/services/slack/slack-fns";
import { SlackTriggerFeature } from "@app/services/slack/slack-types";
import { SmtpTemplates, TSmtpService } from "@app/services/smtp/smtp-service"; import { SmtpTemplates, TSmtpService } from "@app/services/smtp/smtp-service";
import { TUserDALFactory } from "@app/services/user/user-dal"; import { TUserDALFactory } from "@app/services/user/user-dal";
@@ -67,6 +69,8 @@ type TSecretApprovalRequestServiceFactoryDep = {
>; >;
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">; kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
projectSlackConfigDAL: Pick<TProjectSlackConfigDALFactory, "getIntegrationDetailsByProject">; projectSlackConfigDAL: Pick<TProjectSlackConfigDALFactory, "getIntegrationDetailsByProject">;
microsoftTeamsService: Pick<TMicrosoftTeamsServiceFactory, "sendNotification">;
projectMicrosoftTeamsConfigDAL: Pick<TProjectMicrosoftTeamsConfigDALFactory, "getIntegrationDetailsByProject">;
}; };
export type TAccessApprovalRequestServiceFactory = ReturnType<typeof accessApprovalRequestServiceFactory>; export type TAccessApprovalRequestServiceFactory = ReturnType<typeof accessApprovalRequestServiceFactory>;
@@ -84,6 +88,8 @@ export const accessApprovalRequestServiceFactory = ({
smtpService, smtpService,
userDAL, userDAL,
kmsService, kmsService,
microsoftTeamsService,
projectMicrosoftTeamsConfigDAL,
projectSlackConfigDAL projectSlackConfigDAL
}: TSecretApprovalRequestServiceFactoryDep) => { }: TSecretApprovalRequestServiceFactoryDep) => {
const createAccessApprovalRequest = async ({ const createAccessApprovalRequest = async ({
@@ -219,24 +225,30 @@ export const accessApprovalRequestServiceFactory = ({
const requesterFullName = `${requestedByUser.firstName} ${requestedByUser.lastName}`; const requesterFullName = `${requestedByUser.firstName} ${requestedByUser.lastName}`;
const approvalUrl = `${cfg.SITE_URL}/secret-manager/${project.id}/approval`; const approvalUrl = `${cfg.SITE_URL}/secret-manager/${project.id}/approval`;
await triggerSlackNotification({ await triggerWorkflowIntegrationNotification({
projectId: project.id, input: {
projectSlackConfigDAL, notification: {
projectDAL, type: TriggerFeature.ACCESS_REQUEST,
kmsService, payload: {
notification: { projectName: project.name,
type: SlackTriggerFeature.ACCESS_REQUEST, requesterFullName,
payload: { isTemporary,
projectName: project.name, requesterEmail: requestedByUser.email as string,
requesterFullName, secretPath,
isTemporary, environment: envSlug,
requesterEmail: requestedByUser.email as string, permissions: accessTypes,
secretPath, approvalUrl,
environment: envSlug, note
permissions: accessTypes, }
approvalUrl, },
note projectId: project.id
} },
dependencies: {
projectDAL,
projectSlackConfigDAL,
kmsService,
microsoftTeamsService,
projectMicrosoftTeamsConfigDAL
} }
}); });

View File

@@ -0,0 +1,101 @@
import { ForbiddenError } from "@casl/ability";
import jwt from "jsonwebtoken";
import { ActionProjectType } from "@app/db/schemas";
import { getConfig } from "@app/lib/config/env";
import { ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
import { ActorType } from "@app/services/auth/auth-type";
import { TProjectDALFactory } from "@app/services/project/project-dal";
import { TPermissionServiceFactory } from "../permission/permission-service";
import {
ProjectPermissionIdentityActions,
ProjectPermissionMemberActions,
ProjectPermissionSub
} from "../permission/project-permission";
import { TAssumeProjectPrivilegeDTO } from "./assume-privilege-types";
type TAssumePrivilegeServiceFactoryDep = {
projectDAL: Pick<TProjectDALFactory, "findById">;
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
};
export type TAssumePrivilegeServiceFactory = ReturnType<typeof assumePrivilegeServiceFactory>;
export const assumePrivilegeServiceFactory = ({ projectDAL, permissionService }: TAssumePrivilegeServiceFactoryDep) => {
const assumeProjectPrivileges = async ({
targetActorType,
targetActorId,
projectId,
actorPermissionDetails,
tokenVersionId
}: TAssumeProjectPrivilegeDTO) => {
const project = await projectDAL.findById(projectId);
if (!project) throw new NotFoundError({ message: `Project with ID '${projectId}' not found` });
const { permission } = await permissionService.getProjectPermission({
actor: actorPermissionDetails.type,
actorId: actorPermissionDetails.id,
projectId,
actorAuthMethod: actorPermissionDetails.authMethod,
actorOrgId: actorPermissionDetails.orgId,
actionProjectType: ActionProjectType.Any
});
if (targetActorType === ActorType.USER) {
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionMemberActions.AssumePrivileges,
ProjectPermissionSub.Member
);
} else {
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionIdentityActions.AssumePrivileges,
ProjectPermissionSub.Identity
);
}
// check entity is part of project
await permissionService.getProjectPermission({
actor: targetActorType,
actorId: targetActorId,
projectId,
actorAuthMethod: actorPermissionDetails.authMethod,
actorOrgId: actorPermissionDetails.orgId,
actionProjectType: ActionProjectType.Any
});
const appCfg = getConfig();
const assumePrivilegesToken = jwt.sign(
{
tokenVersionId,
actorType: targetActorType,
actorId: targetActorId,
projectId,
requesterId: actorPermissionDetails.id
},
appCfg.AUTH_SECRET,
{ expiresIn: "1hr" }
);
return { actorType: targetActorType, actorId: targetActorId, projectId, assumePrivilegesToken };
};
const verifyAssumePrivilegeToken = (token: string, tokenVersionId: string) => {
const appCfg = getConfig();
const decodedToken = jwt.verify(token, appCfg.AUTH_SECRET) as {
tokenVersionId: string;
projectId: string;
requesterId: string;
actorType: ActorType;
actorId: string;
};
if (decodedToken.tokenVersionId !== tokenVersionId) {
throw new ForbiddenRequestError({ message: "Invalid token version" });
}
return decodedToken;
};
return {
assumeProjectPrivileges,
verifyAssumePrivilegeToken
};
};

View File

@@ -0,0 +1,10 @@
import { OrgServiceActor } from "@app/lib/types";
import { ActorType } from "@app/services/auth/auth-type";
export type TAssumeProjectPrivilegeDTO = {
targetActorType: ActorType.USER | ActorType.IDENTITY;
targetActorId: string;
projectId: string;
tokenVersionId: string;
actorPermissionDetails: OrgServiceActor;
};

View File

@@ -12,6 +12,7 @@ import {
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 { 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 { TLoginMapping } from "@app/ee/services/ssh-host/ssh-host-types";
import { SymmetricKeyAlgorithm } from "@app/lib/crypto/cipher"; import { SymmetricKeyAlgorithm } from "@app/lib/crypto/cipher";
import { AsymmetricKeyAlgorithm, SigningAlgorithm } from "@app/lib/crypto/sign/types"; import { AsymmetricKeyAlgorithm, SigningAlgorithm } from "@app/lib/crypto/sign/types";
import { TProjectPermission } from "@app/lib/types"; import { TProjectPermission } from "@app/lib/types";
@@ -21,6 +22,7 @@ import { ActorType } from "@app/services/auth/auth-type";
import { CertKeyAlgorithm } from "@app/services/certificate/certificate-types"; import { CertKeyAlgorithm } from "@app/services/certificate/certificate-types";
import { CaStatus } from "@app/services/certificate-authority/certificate-authority-types"; import { CaStatus } from "@app/services/certificate-authority/certificate-authority-types";
import { TIdentityTrustedIp } from "@app/services/identity/identity-types"; import { TIdentityTrustedIp } from "@app/services/identity/identity-types";
import { TAllowedFields } from "@app/services/identity-ldap-auth/identity-ldap-auth-types";
import { PkiItemType } from "@app/services/pki-collection/pki-collection-types"; import { PkiItemType } from "@app/services/pki-collection/pki-collection-types";
import { SecretSync, SecretSyncImportBehavior } from "@app/services/secret-sync/secret-sync-enums"; import { SecretSync, SecretSyncImportBehavior } from "@app/services/secret-sync/secret-sync-enums";
import { import {
@@ -29,6 +31,7 @@ import {
TSecretSyncRaw, TSecretSyncRaw,
TUpdateSecretSyncDTO TUpdateSecretSyncDTO
} from "@app/services/secret-sync/secret-sync-types"; } from "@app/services/secret-sync/secret-sync-types";
import { WorkflowIntegration } from "@app/services/workflow-integration/workflow-integration-types";
import { KmipPermission } from "../kmip/kmip-enum"; import { KmipPermission } from "../kmip/kmip-enum";
import { ApprovalStatus } from "../secret-approval-request/secret-approval-request-types"; import { ApprovalStatus } from "../secret-approval-request/secret-approval-request-types";
@@ -117,44 +120,60 @@ export enum EventType {
CREATE_TOKEN_IDENTITY_TOKEN_AUTH = "create-token-identity-token-auth", CREATE_TOKEN_IDENTITY_TOKEN_AUTH = "create-token-identity-token-auth",
UPDATE_TOKEN_IDENTITY_TOKEN_AUTH = "update-token-identity-token-auth", UPDATE_TOKEN_IDENTITY_TOKEN_AUTH = "update-token-identity-token-auth",
GET_TOKENS_IDENTITY_TOKEN_AUTH = "get-tokens-identity-token-auth", GET_TOKENS_IDENTITY_TOKEN_AUTH = "get-tokens-identity-token-auth",
ADD_IDENTITY_TOKEN_AUTH = "add-identity-token-auth", ADD_IDENTITY_TOKEN_AUTH = "add-identity-token-auth",
UPDATE_IDENTITY_TOKEN_AUTH = "update-identity-token-auth", UPDATE_IDENTITY_TOKEN_AUTH = "update-identity-token-auth",
GET_IDENTITY_TOKEN_AUTH = "get-identity-token-auth", GET_IDENTITY_TOKEN_AUTH = "get-identity-token-auth",
REVOKE_IDENTITY_TOKEN_AUTH = "revoke-identity-token-auth", REVOKE_IDENTITY_TOKEN_AUTH = "revoke-identity-token-auth",
LOGIN_IDENTITY_KUBERNETES_AUTH = "login-identity-kubernetes-auth", LOGIN_IDENTITY_KUBERNETES_AUTH = "login-identity-kubernetes-auth",
ADD_IDENTITY_KUBERNETES_AUTH = "add-identity-kubernetes-auth", ADD_IDENTITY_KUBERNETES_AUTH = "add-identity-kubernetes-auth",
UPDATE_IDENTITY_KUBENETES_AUTH = "update-identity-kubernetes-auth", UPDATE_IDENTITY_KUBENETES_AUTH = "update-identity-kubernetes-auth",
GET_IDENTITY_KUBERNETES_AUTH = "get-identity-kubernetes-auth", GET_IDENTITY_KUBERNETES_AUTH = "get-identity-kubernetes-auth",
REVOKE_IDENTITY_KUBERNETES_AUTH = "revoke-identity-kubernetes-auth", REVOKE_IDENTITY_KUBERNETES_AUTH = "revoke-identity-kubernetes-auth",
LOGIN_IDENTITY_OIDC_AUTH = "login-identity-oidc-auth", LOGIN_IDENTITY_OIDC_AUTH = "login-identity-oidc-auth",
ADD_IDENTITY_OIDC_AUTH = "add-identity-oidc-auth", ADD_IDENTITY_OIDC_AUTH = "add-identity-oidc-auth",
UPDATE_IDENTITY_OIDC_AUTH = "update-identity-oidc-auth", UPDATE_IDENTITY_OIDC_AUTH = "update-identity-oidc-auth",
GET_IDENTITY_OIDC_AUTH = "get-identity-oidc-auth", GET_IDENTITY_OIDC_AUTH = "get-identity-oidc-auth",
REVOKE_IDENTITY_OIDC_AUTH = "revoke-identity-oidc-auth", REVOKE_IDENTITY_OIDC_AUTH = "revoke-identity-oidc-auth",
LOGIN_IDENTITY_JWT_AUTH = "login-identity-jwt-auth", LOGIN_IDENTITY_JWT_AUTH = "login-identity-jwt-auth",
ADD_IDENTITY_JWT_AUTH = "add-identity-jwt-auth", ADD_IDENTITY_JWT_AUTH = "add-identity-jwt-auth",
UPDATE_IDENTITY_JWT_AUTH = "update-identity-jwt-auth", UPDATE_IDENTITY_JWT_AUTH = "update-identity-jwt-auth",
GET_IDENTITY_JWT_AUTH = "get-identity-jwt-auth", GET_IDENTITY_JWT_AUTH = "get-identity-jwt-auth",
REVOKE_IDENTITY_JWT_AUTH = "revoke-identity-jwt-auth", REVOKE_IDENTITY_JWT_AUTH = "revoke-identity-jwt-auth",
CREATE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET = "create-identity-universal-auth-client-secret", CREATE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET = "create-identity-universal-auth-client-secret",
REVOKE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET = "revoke-identity-universal-auth-client-secret", REVOKE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET = "revoke-identity-universal-auth-client-secret",
GET_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRETS = "get-identity-universal-auth-client-secret", GET_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRETS = "get-identity-universal-auth-client-secret",
GET_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET_BY_ID = "get-identity-universal-auth-client-secret-by-id", GET_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET_BY_ID = "get-identity-universal-auth-client-secret-by-id",
LOGIN_IDENTITY_GCP_AUTH = "login-identity-gcp-auth", LOGIN_IDENTITY_GCP_AUTH = "login-identity-gcp-auth",
ADD_IDENTITY_GCP_AUTH = "add-identity-gcp-auth", ADD_IDENTITY_GCP_AUTH = "add-identity-gcp-auth",
UPDATE_IDENTITY_GCP_AUTH = "update-identity-gcp-auth", UPDATE_IDENTITY_GCP_AUTH = "update-identity-gcp-auth",
REVOKE_IDENTITY_GCP_AUTH = "revoke-identity-gcp-auth", REVOKE_IDENTITY_GCP_AUTH = "revoke-identity-gcp-auth",
GET_IDENTITY_GCP_AUTH = "get-identity-gcp-auth", GET_IDENTITY_GCP_AUTH = "get-identity-gcp-auth",
LOGIN_IDENTITY_AWS_AUTH = "login-identity-aws-auth", LOGIN_IDENTITY_AWS_AUTH = "login-identity-aws-auth",
ADD_IDENTITY_AWS_AUTH = "add-identity-aws-auth", ADD_IDENTITY_AWS_AUTH = "add-identity-aws-auth",
UPDATE_IDENTITY_AWS_AUTH = "update-identity-aws-auth", UPDATE_IDENTITY_AWS_AUTH = "update-identity-aws-auth",
REVOKE_IDENTITY_AWS_AUTH = "revoke-identity-aws-auth", REVOKE_IDENTITY_AWS_AUTH = "revoke-identity-aws-auth",
GET_IDENTITY_AWS_AUTH = "get-identity-aws-auth", GET_IDENTITY_AWS_AUTH = "get-identity-aws-auth",
LOGIN_IDENTITY_AZURE_AUTH = "login-identity-azure-auth", LOGIN_IDENTITY_AZURE_AUTH = "login-identity-azure-auth",
ADD_IDENTITY_AZURE_AUTH = "add-identity-azure-auth", ADD_IDENTITY_AZURE_AUTH = "add-identity-azure-auth",
UPDATE_IDENTITY_AZURE_AUTH = "update-identity-azure-auth", UPDATE_IDENTITY_AZURE_AUTH = "update-identity-azure-auth",
GET_IDENTITY_AZURE_AUTH = "get-identity-azure-auth", GET_IDENTITY_AZURE_AUTH = "get-identity-azure-auth",
REVOKE_IDENTITY_AZURE_AUTH = "revoke-identity-azure-auth", REVOKE_IDENTITY_AZURE_AUTH = "revoke-identity-azure-auth",
LOGIN_IDENTITY_LDAP_AUTH = "login-identity-ldap-auth",
ADD_IDENTITY_LDAP_AUTH = "add-identity-ldap-auth",
UPDATE_IDENTITY_LDAP_AUTH = "update-identity-ldap-auth",
GET_IDENTITY_LDAP_AUTH = "get-identity-ldap-auth",
REVOKE_IDENTITY_LDAP_AUTH = "revoke-identity-ldap-auth",
CREATE_ENVIRONMENT = "create-environment", CREATE_ENVIRONMENT = "create-environment",
UPDATE_ENVIRONMENT = "update-environment", UPDATE_ENVIRONMENT = "update-environment",
DELETE_ENVIRONMENT = "delete-environment", DELETE_ENVIRONMENT = "delete-environment",
@@ -191,12 +210,19 @@ 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",
GET_SSH_HOST = "get-ssh-host",
CREATE_SSH_HOST = "create-ssh-host", CREATE_SSH_HOST = "create-ssh-host",
UPDATE_SSH_HOST = "update-ssh-host", UPDATE_SSH_HOST = "update-ssh-host",
DELETE_SSH_HOST = "delete-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_USER_CERT = "issue-ssh-host-user-cert",
ISSUE_SSH_HOST_HOST_CERT = "issue-ssh-host-host-cert", ISSUE_SSH_HOST_HOST_CERT = "issue-ssh-host-host-cert",
GET_SSH_HOST_GROUP = "get-ssh-host-group",
CREATE_SSH_HOST_GROUP = "create-ssh-host-group",
UPDATE_SSH_HOST_GROUP = "update-ssh-host-group",
DELETE_SSH_HOST_GROUP = "delete-ssh-host-group",
GET_SSH_HOST_GROUP_HOSTS = "get-ssh-host-group-hosts",
ADD_HOST_TO_SSH_HOST_GROUP = "add-host-to-ssh-host-group",
REMOVE_HOST_FROM_SSH_HOST_GROUP = "remove-host-from-ssh-host-group",
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",
@@ -215,6 +241,8 @@ export enum EventType {
DELETE_CERT = "delete-cert", DELETE_CERT = "delete-cert",
REVOKE_CERT = "revoke-cert", REVOKE_CERT = "revoke-cert",
GET_CERT_BODY = "get-cert-body", GET_CERT_BODY = "get-cert-body",
GET_CERT_PRIVATE_KEY = "get-cert-private-key",
GET_CERT_BUNDLE = "get-cert-bundle",
CREATE_PKI_ALERT = "create-pki-alert", CREATE_PKI_ALERT = "create-pki-alert",
GET_PKI_ALERT = "get-pki-alert", GET_PKI_ALERT = "get-pki-alert",
UPDATE_PKI_ALERT = "update-pki-alert", UPDATE_PKI_ALERT = "update-pki-alert",
@@ -234,6 +262,7 @@ export enum EventType {
GET_PROJECT_KMS_BACKUP = "get-project-kms-backup", GET_PROJECT_KMS_BACKUP = "get-project-kms-backup",
LOAD_PROJECT_KMS_BACKUP = "load-project-kms-backup", LOAD_PROJECT_KMS_BACKUP = "load-project-kms-backup",
ORG_ADMIN_ACCESS_PROJECT = "org-admin-accessed-project", ORG_ADMIN_ACCESS_PROJECT = "org-admin-accessed-project",
ORG_ADMIN_BYPASS_SSO = "org-admin-bypassed-sso",
CREATE_CERTIFICATE_TEMPLATE = "create-certificate-template", CREATE_CERTIFICATE_TEMPLATE = "create-certificate-template",
UPDATE_CERTIFICATE_TEMPLATE = "update-certificate-template", UPDATE_CERTIFICATE_TEMPLATE = "update-certificate-template",
DELETE_CERTIFICATE_TEMPLATE = "delete-certificate-template", DELETE_CERTIFICATE_TEMPLATE = "delete-certificate-template",
@@ -243,11 +272,16 @@ export enum EventType {
GET_CERTIFICATE_TEMPLATE_EST_CONFIG = "get-certificate-template-est-config", GET_CERTIFICATE_TEMPLATE_EST_CONFIG = "get-certificate-template-est-config",
ATTEMPT_CREATE_SLACK_INTEGRATION = "attempt-create-slack-integration", ATTEMPT_CREATE_SLACK_INTEGRATION = "attempt-create-slack-integration",
ATTEMPT_REINSTALL_SLACK_INTEGRATION = "attempt-reinstall-slack-integration", ATTEMPT_REINSTALL_SLACK_INTEGRATION = "attempt-reinstall-slack-integration",
GET_PROJECT_SLACK_CONFIG = "get-project-slack-config",
UPDATE_PROJECT_SLACK_CONFIG = "update-project-slack-config",
GET_SLACK_INTEGRATION = "get-slack-integration", GET_SLACK_INTEGRATION = "get-slack-integration",
UPDATE_SLACK_INTEGRATION = "update-slack-integration", UPDATE_SLACK_INTEGRATION = "update-slack-integration",
DELETE_SLACK_INTEGRATION = "delete-slack-integration", DELETE_SLACK_INTEGRATION = "delete-slack-integration",
GET_PROJECT_SLACK_CONFIG = "get-project-slack-config", GET_PROJECT_WORKFLOW_INTEGRATION_CONFIG = "get-project-workflow-integration-config",
UPDATE_PROJECT_SLACK_CONFIG = "update-project-slack-config", UPDATE_PROJECT_WORKFLOW_INTEGRATION_CONFIG = "update-project-workflow-integration-config",
GET_PROJECT_SSH_CONFIG = "get-project-ssh-config",
UPDATE_PROJECT_SSH_CONFIG = "update-project-ssh-config",
INTEGRATION_SYNCED = "integration-synced", INTEGRATION_SYNCED = "integration-synced",
CREATE_CMEK = "create-cmek", CREATE_CMEK = "create-cmek",
UPDATE_CMEK = "update-cmek", UPDATE_CMEK = "update-cmek",
@@ -317,7 +351,18 @@ export enum EventType {
DELETE_SECRET_ROTATION = "delete-secret-rotation", DELETE_SECRET_ROTATION = "delete-secret-rotation",
SECRET_ROTATION_ROTATE_SECRETS = "secret-rotation-rotate-secrets", SECRET_ROTATION_ROTATE_SECRETS = "secret-rotation-rotate-secrets",
PROJECT_ACCESS_REQUEST = "project-access-request" PROJECT_ACCESS_REQUEST = "project-access-request",
MICROSOFT_TEAMS_WORKFLOW_INTEGRATION_CREATE = "microsoft-teams-workflow-integration-create",
MICROSOFT_TEAMS_WORKFLOW_INTEGRATION_DELETE = "microsoft-teams-workflow-integration-delete",
MICROSOFT_TEAMS_WORKFLOW_INTEGRATION_UPDATE = "microsoft-teams-workflow-integration-update",
MICROSOFT_TEAMS_WORKFLOW_INTEGRATION_CHECK_INSTALLATION_STATUS = "microsoft-teams-workflow-integration-check-installation-status",
MICROSOFT_TEAMS_WORKFLOW_INTEGRATION_GET_TEAMS = "microsoft-teams-workflow-integration-get-teams",
MICROSOFT_TEAMS_WORKFLOW_INTEGRATION_GET = "microsoft-teams-workflow-integration-get",
MICROSOFT_TEAMS_WORKFLOW_INTEGRATION_LIST = "microsoft-teams-workflow-integration-list",
PROJECT_ASSUME_PRIVILEGE_SESSION_START = "project-assume-privileges-session-start",
PROJECT_ASSUME_PRIVILEGE_SESSION_END = "project-assume-privileges-session-end"
} }
export const filterableSecretEvents: EventType[] = [ export const filterableSecretEvents: EventType[] = [
@@ -1006,6 +1051,55 @@ interface GetIdentityAzureAuthEvent {
}; };
} }
interface LoginIdentityLdapAuthEvent {
type: EventType.LOGIN_IDENTITY_LDAP_AUTH;
metadata: {
identityId: string;
ldapUsername: string;
ldapEmail?: string;
};
}
interface AddIdentityLdapAuthEvent {
type: EventType.ADD_IDENTITY_LDAP_AUTH;
metadata: {
identityId: string;
accessTokenTTL?: number;
accessTokenMaxTTL?: number;
accessTokenNumUsesLimit?: number;
accessTokenTrustedIps?: Array<TIdentityTrustedIp>;
allowedFields?: TAllowedFields[];
url: string;
};
}
interface UpdateIdentityLdapAuthEvent {
type: EventType.UPDATE_IDENTITY_LDAP_AUTH;
metadata: {
identityId: string;
accessTokenTTL?: number;
accessTokenMaxTTL?: number;
accessTokenNumUsesLimit?: number;
accessTokenTrustedIps?: Array<TIdentityTrustedIp>;
allowedFields?: TAllowedFields[];
url?: string;
};
}
interface GetIdentityLdapAuthEvent {
type: EventType.GET_IDENTITY_LDAP_AUTH;
metadata: {
identityId: string;
};
}
interface RevokeIdentityLdapAuthEvent {
type: EventType.REVOKE_IDENTITY_LDAP_AUTH;
metadata: {
identityId: string;
};
}
interface LoginIdentityOidcAuthEvent { interface LoginIdentityOidcAuthEvent {
type: EventType.LOGIN_IDENTITY_OIDC_AUTH; type: EventType.LOGIN_IDENTITY_OIDC_AUTH;
metadata: { metadata: {
@@ -1491,14 +1585,10 @@ interface CreateSshHost {
metadata: { metadata: {
sshHostId: string; sshHostId: string;
hostname: string; hostname: string;
alias: string | null;
userCertTtl: string; userCertTtl: string;
hostCertTtl: string; hostCertTtl: string;
loginMappings: { loginMappings: TLoginMapping[];
loginUser: string;
allowedPrincipals: {
usernames: string[];
};
}[];
userSshCaId: string; userSshCaId: string;
hostSshCaId: string; hostSshCaId: string;
}; };
@@ -1509,14 +1599,10 @@ interface UpdateSshHost {
metadata: { metadata: {
sshHostId: string; sshHostId: string;
hostname?: string; hostname?: string;
alias?: string | null;
userCertTtl?: string; userCertTtl?: string;
hostCertTtl?: string; hostCertTtl?: string;
loginMappings?: { loginMappings?: TLoginMapping[];
loginUser: string;
allowedPrincipals: {
usernames: string[];
};
}[];
userSshCaId?: string; userSshCaId?: string;
hostSshCaId?: string; hostSshCaId?: string;
}; };
@@ -1560,6 +1646,66 @@ interface IssueSshHostHostCert {
}; };
} }
interface GetSshHostGroupEvent {
type: EventType.GET_SSH_HOST_GROUP;
metadata: {
sshHostGroupId: string;
name: string;
};
}
interface CreateSshHostGroupEvent {
type: EventType.CREATE_SSH_HOST_GROUP;
metadata: {
sshHostGroupId: string;
name: string;
loginMappings: TLoginMapping[];
};
}
interface UpdateSshHostGroupEvent {
type: EventType.UPDATE_SSH_HOST_GROUP;
metadata: {
sshHostGroupId: string;
name?: string;
loginMappings?: TLoginMapping[];
};
}
interface DeleteSshHostGroupEvent {
type: EventType.DELETE_SSH_HOST_GROUP;
metadata: {
sshHostGroupId: string;
name: string;
};
}
interface GetSshHostGroupHostsEvent {
type: EventType.GET_SSH_HOST_GROUP_HOSTS;
metadata: {
sshHostGroupId: string;
name: string;
};
}
interface AddHostToSshHostGroupEvent {
type: EventType.ADD_HOST_TO_SSH_HOST_GROUP;
metadata: {
sshHostGroupId: string;
sshHostId: string;
hostname: string;
};
}
interface RemoveHostFromSshHostGroupEvent {
type: EventType.REMOVE_HOST_FROM_SSH_HOST_GROUP;
metadata: {
sshHostGroupId: string;
sshHostId: string;
hostname: string;
};
}
interface CreateCa { interface CreateCa {
type: EventType.CREATE_CA; type: EventType.CREATE_CA;
metadata: { metadata: {
@@ -1712,6 +1858,24 @@ interface GetCertBody {
}; };
} }
interface GetCertPrivateKey {
type: EventType.GET_CERT_PRIVATE_KEY;
metadata: {
certId: string;
cn: string;
serialNumber: string;
};
}
interface GetCertBundle {
type: EventType.GET_CERT_BUNDLE;
metadata: {
certId: string;
cn: string;
serialNumber: string;
};
}
interface CreatePkiAlert { interface CreatePkiAlert {
type: EventType.CREATE_PKI_ALERT; type: EventType.CREATE_PKI_ALERT;
metadata: { metadata: {
@@ -1907,6 +2071,11 @@ interface OrgAdminAccessProjectEvent {
}; // no metadata yet }; // no metadata yet
} }
interface OrgAdminBypassSSOEvent {
type: EventType.ORG_ADMIN_BYPASS_SSO;
metadata: Record<string, string>; // no metadata yet
}
interface CreateCertificateTemplateEstConfig { interface CreateCertificateTemplateEstConfig {
type: EventType.CREATE_CERTIFICATE_TEMPLATE_EST_CONFIG; type: EventType.CREATE_CERTIFICATE_TEMPLATE_EST_CONFIG;
metadata: { metadata: {
@@ -1968,24 +2137,45 @@ interface GetSlackIntegration {
}; };
} }
interface UpdateProjectSlackConfig { interface UpdateProjectWorkflowIntegrationConfig {
type: EventType.UPDATE_PROJECT_SLACK_CONFIG; type: EventType.UPDATE_PROJECT_WORKFLOW_INTEGRATION_CONFIG;
metadata: { metadata: {
id: string; id: string;
slackIntegrationId: string; integrationId: string;
integration: WorkflowIntegration;
isAccessRequestNotificationEnabled: boolean; isAccessRequestNotificationEnabled: boolean;
accessRequestChannels: string; accessRequestChannels?: string | { teamId: string; channelIds: string[] };
isSecretRequestNotificationEnabled: boolean; isSecretRequestNotificationEnabled: boolean;
secretRequestChannels: string; secretRequestChannels?: string | { teamId: string; channelIds: string[] };
}; };
} }
interface GetProjectSlackConfig { interface GetProjectWorkflowIntegrationConfig {
type: EventType.GET_PROJECT_SLACK_CONFIG; type: EventType.GET_PROJECT_WORKFLOW_INTEGRATION_CONFIG;
metadata: { metadata: {
id: string; id: string;
integration: WorkflowIntegration;
}; };
} }
interface GetProjectSshConfig {
type: EventType.GET_PROJECT_SSH_CONFIG;
metadata: {
id: string;
projectId: string;
};
}
interface UpdateProjectSshConfig {
type: EventType.UPDATE_PROJECT_SSH_CONFIG;
metadata: {
id: string;
projectId: string;
defaultUserSshCaId?: string | null;
defaultHostSshCaId?: string | null;
};
}
interface IntegrationSyncedEvent { interface IntegrationSyncedEvent {
type: EventType.INTEGRATION_SYNCED; type: EventType.INTEGRATION_SYNCED;
metadata: { metadata: {
@@ -2425,6 +2615,29 @@ interface ProjectAccessRequestEvent {
}; };
} }
interface ProjectAssumePrivilegesEvent {
type: EventType.PROJECT_ASSUME_PRIVILEGE_SESSION_START;
metadata: {
projectId: string;
requesterId: string;
requesterEmail: string;
targetActorType: ActorType;
targetActorId: string;
duration: string;
};
}
interface ProjectAssumePrivilegesExitEvent {
type: EventType.PROJECT_ASSUME_PRIVILEGE_SESSION_END;
metadata: {
projectId: string;
requesterId: string;
requesterEmail: string;
targetActorType: ActorType;
targetActorId: string;
};
}
interface SetupKmipEvent { interface SetupKmipEvent {
type: EventType.SETUP_KMIP; type: EventType.SETUP_KMIP;
metadata: { metadata: {
@@ -2507,6 +2720,66 @@ interface RotateSecretRotationEvent {
}; };
} }
interface MicrosoftTeamsWorkflowIntegrationCreateEvent {
type: EventType.MICROSOFT_TEAMS_WORKFLOW_INTEGRATION_CREATE;
metadata: {
tenantId: string;
slug: string;
description?: string;
};
}
interface MicrosoftTeamsWorkflowIntegrationDeleteEvent {
type: EventType.MICROSOFT_TEAMS_WORKFLOW_INTEGRATION_DELETE;
metadata: {
tenantId: string;
id: string;
slug: string;
};
}
interface MicrosoftTeamsWorkflowIntegrationCheckInstallationStatusEvent {
type: EventType.MICROSOFT_TEAMS_WORKFLOW_INTEGRATION_CHECK_INSTALLATION_STATUS;
metadata: {
tenantId: string;
slug: string;
};
}
interface MicrosoftTeamsWorkflowIntegrationGetTeamsEvent {
type: EventType.MICROSOFT_TEAMS_WORKFLOW_INTEGRATION_GET_TEAMS;
metadata: {
tenantId: string;
slug: string;
id: string;
};
}
interface MicrosoftTeamsWorkflowIntegrationGetEvent {
type: EventType.MICROSOFT_TEAMS_WORKFLOW_INTEGRATION_GET;
metadata: {
tenantId: string;
slug: string;
id: string;
};
}
interface MicrosoftTeamsWorkflowIntegrationListEvent {
type: EventType.MICROSOFT_TEAMS_WORKFLOW_INTEGRATION_LIST;
metadata: Record<string, string>;
}
interface MicrosoftTeamsWorkflowIntegrationUpdateEvent {
type: EventType.MICROSOFT_TEAMS_WORKFLOW_INTEGRATION_UPDATE;
metadata: {
tenantId: string;
slug: string;
id: string;
newSlug?: string;
newDescription?: string;
};
}
export type Event = export type Event =
| GetSecretsEvent | GetSecretsEvent
| GetSecretEvent | GetSecretEvent
@@ -2578,6 +2851,11 @@ export type Event =
| UpdateIdentityJwtAuthEvent | UpdateIdentityJwtAuthEvent
| GetIdentityJwtAuthEvent | GetIdentityJwtAuthEvent
| DeleteIdentityJwtAuthEvent | DeleteIdentityJwtAuthEvent
| LoginIdentityLdapAuthEvent
| AddIdentityLdapAuthEvent
| UpdateIdentityLdapAuthEvent
| GetIdentityLdapAuthEvent
| RevokeIdentityLdapAuthEvent
| CreateEnvironmentEvent | CreateEnvironmentEvent
| GetEnvironmentEvent | GetEnvironmentEvent
| UpdateEnvironmentEvent | UpdateEnvironmentEvent
@@ -2637,6 +2915,8 @@ export type Event =
| DeleteCert | DeleteCert
| RevokeCert | RevokeCert
| GetCertBody | GetCertBody
| GetCertPrivateKey
| GetCertBundle
| CreatePkiAlert | CreatePkiAlert
| GetPkiAlert | GetPkiAlert
| UpdatePkiAlert | UpdatePkiAlert
@@ -2656,6 +2936,7 @@ export type Event =
| GetProjectKmsBackupEvent | GetProjectKmsBackupEvent
| LoadProjectKmsBackupEvent | LoadProjectKmsBackupEvent
| OrgAdminAccessProjectEvent | OrgAdminAccessProjectEvent
| OrgAdminBypassSSOEvent
| CreateCertificateTemplate | CreateCertificateTemplate
| UpdateCertificateTemplate | UpdateCertificateTemplate
| GetCertificateTemplate | GetCertificateTemplate
@@ -2668,8 +2949,10 @@ export type Event =
| UpdateSlackIntegration | UpdateSlackIntegration
| DeleteSlackIntegration | DeleteSlackIntegration
| GetSlackIntegration | GetSlackIntegration
| UpdateProjectSlackConfig | UpdateProjectWorkflowIntegrationConfig
| GetProjectSlackConfig | GetProjectWorkflowIntegrationConfig
| GetProjectSshConfig
| UpdateProjectSshConfig
| IntegrationSyncedEvent | IntegrationSyncedEvent
| CreateCmekEvent | CreateCmekEvent
| UpdateCmekEvent | UpdateCmekEvent
@@ -2696,6 +2979,13 @@ export type Event =
| CreateAppConnectionEvent | CreateAppConnectionEvent
| UpdateAppConnectionEvent | UpdateAppConnectionEvent
| DeleteAppConnectionEvent | DeleteAppConnectionEvent
| GetSshHostGroupEvent
| CreateSshHostGroupEvent
| UpdateSshHostGroupEvent
| DeleteSshHostGroupEvent
| GetSshHostGroupHostsEvent
| AddHostToSshHostGroupEvent
| RemoveHostFromSshHostGroupEvent
| CreateSharedSecretEvent | CreateSharedSecretEvent
| DeleteSharedSecretEvent | DeleteSharedSecretEvent
| ReadSharedSecretEvent | ReadSharedSecretEvent
@@ -2727,6 +3017,8 @@ export type Event =
| KmipOperationLocateEvent | KmipOperationLocateEvent
| KmipOperationRegisterEvent | KmipOperationRegisterEvent
| ProjectAccessRequestEvent | ProjectAccessRequestEvent
| ProjectAssumePrivilegesEvent
| ProjectAssumePrivilegesExitEvent
| CreateSecretRequestEvent | CreateSecretRequestEvent
| SecretApprovalRequestReview | SecretApprovalRequestReview
| GetSecretRotationsEvent | GetSecretRotationsEvent
@@ -2735,4 +3027,11 @@ export type Event =
| CreateSecretRotationEvent | CreateSecretRotationEvent
| UpdateSecretRotationEvent | UpdateSecretRotationEvent
| DeleteSecretRotationEvent | DeleteSecretRotationEvent
| RotateSecretRotationEvent; | RotateSecretRotationEvent
| MicrosoftTeamsWorkflowIntegrationCreateEvent
| MicrosoftTeamsWorkflowIntegrationDeleteEvent
| MicrosoftTeamsWorkflowIntegrationCheckInstallationStatusEvent
| MicrosoftTeamsWorkflowIntegrationGetTeamsEvent
| MicrosoftTeamsWorkflowIntegrationGetEvent
| MicrosoftTeamsWorkflowIntegrationListEvent
| MicrosoftTeamsWorkflowIntegrationUpdateEvent;

View File

@@ -130,7 +130,17 @@ export const dynamicSecretLeaseServiceFactory = ({
if (expireAt > maxExpiryDate) throw new BadRequestError({ message: "TTL cannot be larger than max TTL" }); if (expireAt > maxExpiryDate) throw new BadRequestError({ message: "TTL cannot be larger than max TTL" });
} }
const { entityId, data } = await selectedProvider.create(decryptedStoredInput, expireAt.getTime()); let result;
try {
result = await selectedProvider.create(decryptedStoredInput, expireAt.getTime());
} catch (error: unknown) {
if (error && typeof error === "object" && error !== null && "sqlMessage" in error) {
throw new BadRequestError({ message: error.sqlMessage as string });
}
throw error;
}
const { entityId, data } = result;
const dynamicSecretLease = await dynamicSecretLeaseDAL.create({ const dynamicSecretLease = await dynamicSecretLeaseDAL.create({
expireAt, expireAt,
version: 1, version: 1,

View File

@@ -24,8 +24,16 @@ export const verifyHostInputValidity = async (host: string, isGateway = false) =
if (net.isIPv4(el)) { if (net.isIPv4(el)) {
exclusiveIps.push(el); exclusiveIps.push(el);
} else { } else {
const resolvedIps = await dns.resolve4(el); try {
exclusiveIps.push(...resolvedIps); const resolvedIps = await dns.resolve4(el);
exclusiveIps.push(...resolvedIps);
} catch (error) {
// only try lookup if not found
if ((error as { code: string })?.code !== "ENOTFOUND") throw error;
const resolvedIps = (await dns.lookup(el, { all: true, family: 4 })).map(({ address }) => address);
exclusiveIps.push(...resolvedIps);
}
} }
} }
} }
@@ -38,8 +46,16 @@ export const verifyHostInputValidity = async (host: string, isGateway = false) =
if (normalizedHost === "localhost" || normalizedHost === "host.docker.internal") { if (normalizedHost === "localhost" || normalizedHost === "host.docker.internal") {
throw new BadRequestError({ message: "Invalid db host" }); throw new BadRequestError({ message: "Invalid db host" });
} }
const resolvedIps = await dns.resolve4(host); try {
inputHostIps.push(...resolvedIps); const resolvedIps = await dns.resolve4(host);
inputHostIps.push(...resolvedIps);
} catch (error) {
// only try lookup if not found
if ((error as { code: string })?.code !== "ENOTFOUND") throw error;
const resolvedIps = (await dns.lookup(host, { all: true, family: 4 })).map(({ address }) => address);
inputHostIps.push(...resolvedIps);
}
} }
if (!isGateway && !(appCfg.DYNAMIC_SECRET_ALLOW_INTERNAL_IP || appCfg.ALLOW_INTERNAL_IP_CONNECTIONS)) { if (!isGateway && !(appCfg.DYNAMIC_SECRET_ALLOW_INTERNAL_IP || appCfg.ALLOW_INTERNAL_IP_CONNECTIONS)) {

View File

@@ -83,18 +83,26 @@ export const externalKmsServiceFactory = ({
throw error; throw error;
}); });
// if missing kms key this generate a new kms key id and returns new provider input try {
const newProviderInput = await externalKms.generateInputKmsKey(); // if missing kms key this generate a new kms key id and returns new provider input
sanitizedProviderInput = JSON.stringify(newProviderInput); const newProviderInput = await externalKms.generateInputKmsKey();
sanitizedProviderInput = JSON.stringify(newProviderInput);
await externalKms.validateConnection(); await externalKms.validateConnection();
} finally {
await externalKms.cleanup();
}
} }
break; break;
case KmsProviders.Gcp: case KmsProviders.Gcp:
{ {
const externalKms = await GcpKmsProviderFactory({ inputs: provider.inputs }); const externalKms = await GcpKmsProviderFactory({ inputs: provider.inputs });
await externalKms.validateConnection(); try {
sanitizedProviderInput = JSON.stringify(provider.inputs); await externalKms.validateConnection();
sanitizedProviderInput = JSON.stringify(provider.inputs);
} finally {
await externalKms.cleanup();
}
} }
break; break;
default: default:
@@ -186,8 +194,12 @@ export const externalKmsServiceFactory = ({
); );
const updatedProviderInput = { ...decryptedProviderInput, ...provider.inputs }; const updatedProviderInput = { ...decryptedProviderInput, ...provider.inputs };
const externalKms = await AwsKmsProviderFactory({ inputs: updatedProviderInput }); const externalKms = await AwsKmsProviderFactory({ inputs: updatedProviderInput });
await externalKms.validateConnection(); try {
sanitizedProviderInput = JSON.stringify(updatedProviderInput); await externalKms.validateConnection();
sanitizedProviderInput = JSON.stringify(updatedProviderInput);
} finally {
await externalKms.cleanup();
}
} }
break; break;
case KmsProviders.Gcp: case KmsProviders.Gcp:
@@ -197,8 +209,12 @@ export const externalKmsServiceFactory = ({
); );
const updatedProviderInput = { ...decryptedProviderInput, ...provider.inputs }; const updatedProviderInput = { ...decryptedProviderInput, ...provider.inputs };
const externalKms = await GcpKmsProviderFactory({ inputs: updatedProviderInput }); const externalKms = await GcpKmsProviderFactory({ inputs: updatedProviderInput });
await externalKms.validateConnection(); try {
sanitizedProviderInput = JSON.stringify(updatedProviderInput); await externalKms.validateConnection();
sanitizedProviderInput = JSON.stringify(updatedProviderInput);
} finally {
await externalKms.cleanup();
}
} }
break; break;
default: default:
@@ -368,7 +384,11 @@ export const externalKmsServiceFactory = ({
const fetchGcpKeys = async ({ credential, gcpRegion }: Pick<TExternalKmsGcpSchema, "credential" | "gcpRegion">) => { const fetchGcpKeys = async ({ credential, gcpRegion }: Pick<TExternalKmsGcpSchema, "credential" | "gcpRegion">) => {
const externalKms = await GcpKmsProviderFactory({ inputs: { credential, gcpRegion, keyName: "" } }); const externalKms = await GcpKmsProviderFactory({ inputs: { credential, gcpRegion, keyName: "" } });
return externalKms.getKeysList(); try {
return await externalKms.getKeysList();
} finally {
await externalKms.cleanup();
}
}; };
return { return {

View File

@@ -102,10 +102,19 @@ export const AwsKmsProviderFactory = async ({ inputs }: AwsKmsProviderArgs): Pro
return { data: Buffer.from(decryptionCommand.Plaintext) }; return { data: Buffer.from(decryptionCommand.Plaintext) };
}; };
const cleanup = async () => {
try {
awsClient.destroy();
} catch (error) {
throw new Error("Failed to cleanup AWS KMS client", { cause: error });
}
};
return { return {
generateInputKmsKey, generateInputKmsKey,
validateConnection, validateConnection,
encrypt, encrypt,
decrypt decrypt,
cleanup
}; };
}; };

View File

@@ -45,6 +45,14 @@ export const GcpKmsProviderFactory = async ({ inputs }: GcpKmsProviderArgs): Pro
} }
}; };
const cleanup = async () => {
try {
await gcpKmsClient.close();
} catch (error) {
throw new Error("Failed to cleanup GCP KMS client", { cause: error });
}
};
// Used when adding the KMS to fetch the list of keys in specified region // Used when adding the KMS to fetch the list of keys in specified region
const getKeysList = async () => { const getKeysList = async () => {
try { try {
@@ -108,6 +116,7 @@ export const GcpKmsProviderFactory = async ({ inputs }: GcpKmsProviderArgs): Pro
validateConnection, validateConnection,
getKeysList, getKeysList,
encrypt, encrypt,
decrypt decrypt,
cleanup
}; };
}; };

View File

@@ -98,4 +98,5 @@ export type TExternalKmsProviderFns = {
validateConnection: () => Promise<boolean>; validateConnection: () => Promise<boolean>;
encrypt: (data: Buffer) => Promise<{ encryptedBlob: Buffer }>; encrypt: (data: Buffer) => Promise<{ encryptedBlob: Buffer }>;
decrypt: (encryptedBlob: Buffer) => Promise<{ data: Buffer }>; decrypt: (encryptedBlob: Buffer) => Promise<{ data: Buffer }>;
cleanup: () => Promise<void>;
}; };

View File

@@ -0,0 +1,10 @@
import { TDbClient } from "@app/db";
import { TableName } from "@app/db/schemas";
import { ormify } from "@app/lib/knex";
export type TGithubOrgSyncDALFactory = ReturnType<typeof githubOrgSyncDALFactory>;
export const githubOrgSyncDALFactory = (db: TDbClient) => {
const orm = ormify(db, TableName.GithubOrgSyncConfig);
return orm;
};

View File

@@ -0,0 +1,354 @@
import { ForbiddenError } from "@casl/ability";
import { Octokit } from "@octokit/core";
import { paginateGraphql } from "@octokit/plugin-paginate-graphql";
import { Octokit as OctokitRest } from "@octokit/rest";
import { OrgMembershipRole } from "@app/db/schemas";
import { BadRequestError, NotFoundError } from "@app/lib/errors";
import { groupBy } from "@app/lib/fn";
import { logger } from "@app/lib/logger";
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
import { KmsDataKey } from "@app/services/kms/kms-types";
import { TGroupDALFactory } from "../group/group-dal";
import { TUserGroupMembershipDALFactory } from "../group/user-group-membership-dal";
import { TLicenseServiceFactory } from "../license/license-service";
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
import { TPermissionServiceFactory } from "../permission/permission-service";
import { TGithubOrgSyncDALFactory } from "./github-org-sync-dal";
import { TCreateGithubOrgSyncDTO, TDeleteGithubOrgSyncDTO, TUpdateGithubOrgSyncDTO } from "./github-org-sync-types";
const OctokitWithPlugin = Octokit.plugin(paginateGraphql);
type TGithubOrgSyncServiceFactoryDep = {
githubOrgSyncDAL: TGithubOrgSyncDALFactory;
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
userGroupMembershipDAL: Pick<
TUserGroupMembershipDALFactory,
"findGroupMembershipsByUserIdInOrg" | "insertMany" | "delete"
>;
groupDAL: Pick<TGroupDALFactory, "insertMany" | "transaction" | "find">;
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
};
export type TGithubOrgSyncServiceFactory = ReturnType<typeof githubOrgSyncServiceFactory>;
export const githubOrgSyncServiceFactory = ({
githubOrgSyncDAL,
permissionService,
kmsService,
userGroupMembershipDAL,
groupDAL,
licenseService
}: TGithubOrgSyncServiceFactoryDep) => {
const createGithubOrgSync = async ({
githubOrgName,
orgPermission,
githubOrgAccessToken,
isActive
}: TCreateGithubOrgSyncDTO) => {
const { permission } = await permissionService.getOrgPermission(
orgPermission.type,
orgPermission.id,
orgPermission.orgId,
orgPermission.authMethod,
orgPermission.orgId
);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.GithubOrgSync);
const plan = await licenseService.getPlan(orgPermission.orgId);
if (!plan.githubOrgSync) {
throw new BadRequestError({
message:
"Failed to create github organization team sync due to plan restriction. Upgrade plan to create github organization sync."
});
}
const existingConfig = await githubOrgSyncDAL.findOne({ orgId: orgPermission.orgId });
if (existingConfig)
throw new BadRequestError({
message: `Organization ${orgPermission.orgId} already has GitHub Organization sync config.`
});
const octokit = new OctokitRest({
auth: githubOrgAccessToken,
request: {
signal: AbortSignal.timeout(5000)
}
});
const { data } = await octokit.rest.orgs.get({
org: githubOrgName
});
if (data.login.toLowerCase() !== githubOrgName.toLowerCase())
throw new BadRequestError({ message: "Invalid GitHub organisation" });
const { encryptor } = await kmsService.createCipherPairWithDataKey({
type: KmsDataKey.Organization,
orgId: orgPermission.orgId
});
const config = await githubOrgSyncDAL.create({
orgId: orgPermission.orgId,
githubOrgName,
isActive,
encryptedGithubOrgAccessToken: githubOrgAccessToken
? encryptor({ plainText: Buffer.from(githubOrgAccessToken) }).cipherTextBlob
: null
});
return config;
};
const updateGithubOrgSync = async ({
githubOrgName,
orgPermission,
githubOrgAccessToken,
isActive
}: TUpdateGithubOrgSyncDTO) => {
const { permission } = await permissionService.getOrgPermission(
orgPermission.type,
orgPermission.id,
orgPermission.orgId,
orgPermission.authMethod,
orgPermission.orgId
);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.GithubOrgSync);
const plan = await licenseService.getPlan(orgPermission.orgId);
if (!plan.githubOrgSync) {
throw new BadRequestError({
message:
"Failed to update github organization team sync due to plan restriction. Upgrade plan to update github organization sync."
});
}
const existingConfig = await githubOrgSyncDAL.findOne({ orgId: orgPermission.orgId });
if (!existingConfig)
throw new BadRequestError({
message: `Organization ${orgPermission.orgId} GitHub organization sync config missing.`
});
const { encryptor, decryptor } = await kmsService.createCipherPairWithDataKey({
type: KmsDataKey.Organization,
orgId: orgPermission.orgId
});
const newData = {
githubOrgName: githubOrgName || existingConfig.githubOrgName,
githubOrgAccessToken:
githubOrgAccessToken ||
(existingConfig.encryptedGithubOrgAccessToken
? decryptor({ cipherTextBlob: existingConfig.encryptedGithubOrgAccessToken }).toString()
: null)
};
if (githubOrgName || githubOrgAccessToken) {
const octokit = new OctokitRest({
auth: newData.githubOrgAccessToken,
request: {
signal: AbortSignal.timeout(5000)
}
});
const { data } = await octokit.rest.orgs.get({
org: newData.githubOrgName
});
if (data.login.toLowerCase() !== newData.githubOrgName.toLowerCase())
throw new BadRequestError({ message: "Invalid GitHub organisation" });
}
const config = await githubOrgSyncDAL.updateById(existingConfig.id, {
orgId: orgPermission.orgId,
githubOrgName: newData.githubOrgName,
isActive,
encryptedGithubOrgAccessToken: newData.githubOrgAccessToken
? encryptor({ plainText: Buffer.from(newData.githubOrgAccessToken) }).cipherTextBlob
: null
});
return config;
};
const deleteGithubOrgSync = async ({ orgPermission }: TDeleteGithubOrgSyncDTO) => {
const { permission } = await permissionService.getOrgPermission(
orgPermission.type,
orgPermission.id,
orgPermission.orgId,
orgPermission.authMethod,
orgPermission.orgId
);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.GithubOrgSync);
const plan = await licenseService.getPlan(orgPermission.orgId);
if (!plan.githubOrgSync) {
throw new BadRequestError({
message:
"Failed to delete github organization team sync due to plan restriction. Upgrade plan to delete github organization sync."
});
}
const existingConfig = await githubOrgSyncDAL.findOne({ orgId: orgPermission.orgId });
if (!existingConfig)
throw new BadRequestError({
message: `Organization ${orgPermission.orgId} GitHub organization sync config missing.`
});
const config = await githubOrgSyncDAL.deleteById(existingConfig.id);
return config;
};
const getGithubOrgSync = async ({ orgPermission }: TDeleteGithubOrgSyncDTO) => {
const { permission } = await permissionService.getOrgPermission(
orgPermission.type,
orgPermission.id,
orgPermission.orgId,
orgPermission.authMethod,
orgPermission.orgId
);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.GithubOrgSync);
const existingConfig = await githubOrgSyncDAL.findOne({ orgId: orgPermission.orgId });
if (!existingConfig)
throw new NotFoundError({
message: `Organization ${orgPermission.orgId} GitHub organization sync config missing.`
});
return existingConfig;
};
const syncUserGroups = async (orgId: string, userId: string, accessToken: string) => {
const config = await githubOrgSyncDAL.findOne({ orgId });
if (!config || !config?.isActive) return;
const infisicalUserGroups = await userGroupMembershipDAL.findGroupMembershipsByUserIdInOrg(userId, orgId);
const infisicalUserGroupSet = new Set(infisicalUserGroups.map((el) => el.groupName));
const octoRest = new OctokitRest({
auth: accessToken,
request: {
signal: AbortSignal.timeout(5000)
}
});
const { data: userOrgMembershipDetails } = await octoRest.rest.orgs
.getMembershipForAuthenticatedUser({
org: config.githubOrgName
})
.catch((err) => {
logger.error(err, "User not part of GitHub synced organization");
throw new BadRequestError({ message: "User not part of GitHub synced organization" });
});
const username = userOrgMembershipDetails?.user?.login;
if (!username) throw new BadRequestError({ message: "User not part of GitHub synced organization" });
const octokit = new OctokitWithPlugin({
auth: accessToken,
request: {
signal: AbortSignal.timeout(5000)
}
});
const data = await octokit.graphql
.paginate<{
organization: { teams: { totalCount: number; edges: { node: { name: string; description: string } }[] } };
}>(
`
query orgTeams($cursor: String,$org: String!, $username: String!){
organization(login: $org) {
teams(first: 100, userLogins: [$username], after: $cursor) {
totalCount
edges {
node {
name
description
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
`,
{
org: config.githubOrgName,
username
}
)
.catch((err) => {
if ((err as Error)?.message?.includes("Although you appear to have the correct authorization credential")) {
throw new BadRequestError({
message:
"Please check your organization have approved Infisical Oauth application. For more info: https://infisical.com/docs/documentation/platform/github-org-sync#troubleshooting"
});
}
throw new BadRequestError({ message: (err as Error)?.message });
});
const {
organization: { teams }
} = data;
const githubUserTeams = teams?.edges?.map((el) => el.node.name.toLowerCase()) || [];
const githubUserTeamSet = new Set(githubUserTeams);
const githubUserTeamOnInfisical = await groupDAL.find({ orgId, $in: { name: githubUserTeams } });
const githubUserTeamOnInfisicalGroupByName = groupBy(githubUserTeamOnInfisical, (i) => i.name);
const newTeams = githubUserTeams.filter(
(el) => !infisicalUserGroupSet.has(el) && !Object.hasOwn(githubUserTeamOnInfisicalGroupByName, el)
);
const updateTeams = githubUserTeams.filter(
(el) => !infisicalUserGroupSet.has(el) && Object.hasOwn(githubUserTeamOnInfisicalGroupByName, el)
);
const removeFromTeams = infisicalUserGroups.filter((el) => !githubUserTeamSet.has(el.groupName));
if (newTeams.length || updateTeams.length || removeFromTeams.length) {
await groupDAL.transaction(async (tx) => {
if (newTeams.length) {
const newGroups = await groupDAL.insertMany(
newTeams.map((newGroupName) => ({
name: newGroupName,
role: OrgMembershipRole.Member,
slug: newGroupName,
orgId
})),
tx
);
await userGroupMembershipDAL.insertMany(
newGroups.map((el) => ({
groupId: el.id,
userId
})),
tx
);
}
if (updateTeams.length) {
await userGroupMembershipDAL.insertMany(
updateTeams.map((el) => ({
groupId: githubUserTeamOnInfisicalGroupByName[el][0].id,
userId
})),
tx
);
}
if (removeFromTeams.length) {
await userGroupMembershipDAL.delete(
{ userId, $in: { groupId: removeFromTeams.map((el) => el.groupId) } },
tx
);
}
});
}
};
return {
createGithubOrgSync,
updateGithubOrgSync,
deleteGithubOrgSync,
getGithubOrgSync,
syncUserGroups
};
};

View File

@@ -0,0 +1,23 @@
import { OrgServiceActor } from "@app/lib/types";
export interface TCreateGithubOrgSyncDTO {
orgPermission: OrgServiceActor;
githubOrgName: string;
githubOrgAccessToken?: string;
isActive?: boolean;
}
export interface TUpdateGithubOrgSyncDTO {
orgPermission: OrgServiceActor;
githubOrgName?: string;
githubOrgAccessToken?: string;
isActive?: boolean;
}
export interface TDeleteGithubOrgSyncDTO {
orgPermission: OrgServiceActor;
}
export interface TGetGithubOrgSyncDTO {
orgPermission: OrgServiceActor;
}

View File

@@ -153,7 +153,19 @@ export const groupDALFactory = (db: TDbClient) => {
totalCount: Number(members?.[0]?.total_count ?? 0) totalCount: Number(members?.[0]?.total_count ?? 0)
}; };
} catch (error) { } catch (error) {
throw new DatabaseError({ error, name: "Find all org members" }); throw new DatabaseError({ error, name: "Find all user group members" });
}
};
const findGroupsByProjectId = async (projectId: string, tx?: Knex) => {
try {
const docs = await (tx || db.replicaNode())(TableName.Groups)
.join(TableName.GroupProjectMembership, `${TableName.Groups}.id`, `${TableName.GroupProjectMembership}.groupId`)
.where(`${TableName.GroupProjectMembership}.projectId`, projectId)
.select(selectAllTableCols(TableName.Groups));
return docs;
} catch (error) {
throw new DatabaseError({ error, name: "Find groups by project id" });
} }
}; };
@@ -161,6 +173,7 @@ export const groupDALFactory = (db: TDbClient) => {
findGroups, findGroups,
findByOrgId, findByOrgId,
findAllGroupPossibleMembers, findAllGroupPossibleMembers,
findGroupsByProjectId,
...groupOrm ...groupOrm
}; };
}; };

View File

@@ -176,7 +176,8 @@ export const userGroupMembershipDALFactory = (db: TDbClient) => {
db.ref("name").withSchema(TableName.Groups).as("groupName"), db.ref("name").withSchema(TableName.Groups).as("groupName"),
db.ref("id").withSchema(TableName.OrgMembership).as("orgMembershipId"), db.ref("id").withSchema(TableName.OrgMembership).as("orgMembershipId"),
db.ref("firstName").withSchema(TableName.Users).as("firstName"), db.ref("firstName").withSchema(TableName.Users).as("firstName"),
db.ref("lastName").withSchema(TableName.Users).as("lastName") db.ref("lastName").withSchema(TableName.Users).as("lastName"),
db.ref("slug").withSchema(TableName.Groups).as("groupSlug")
); );
return docs; return docs;

View File

@@ -14,6 +14,11 @@ export type TLDAPConfig = {
caCert: string; caCert: string;
}; };
export type TTestLDAPConfigDTO = Omit<
TLDAPConfig,
"organization" | "id" | "groupSearchBase" | "groupSearchFilter" | "isActive" | "uniqueUserAttribute" | "searchBase"
>;
export type TCreateLdapCfgDTO = { export type TCreateLdapCfgDTO = {
orgId: string; orgId: string;
isActive: boolean; isActive: boolean;

View File

@@ -2,15 +2,14 @@ import ldapjs from "ldapjs";
import { logger } from "@app/lib/logger"; import { logger } from "@app/lib/logger";
import { TLDAPConfig } from "./ldap-config-types"; import { TLDAPConfig, TTestLDAPConfigDTO } from "./ldap-config-types";
export const isValidLdapFilter = (filter: string) => { export const isValidLdapFilter = (filter: string) => {
try { try {
ldapjs.parseFilter(filter); ldapjs.parseFilter(filter);
return true; return true;
} catch (error) { } catch (error) {
logger.error("Invalid LDAP filter"); logger.error(error, "Invalid LDAP filter");
logger.error(error);
return false; return false;
} }
}; };
@@ -20,7 +19,7 @@ export const isValidLdapFilter = (filter: string) => {
* @param ldapConfig - The LDAP configuration to test * @param ldapConfig - The LDAP configuration to test
* @returns {Boolean} isConnected - Whether or not the connection was successful * @returns {Boolean} isConnected - Whether or not the connection was successful
*/ */
export const testLDAPConfig = async (ldapConfig: TLDAPConfig): Promise<boolean> => { export const testLDAPConfig = async (ldapConfig: TTestLDAPConfigDTO): Promise<boolean> => {
return new Promise((resolve) => { return new Promise((resolve) => {
const ldapClient = ldapjs.createClient({ const ldapClient = ldapjs.createClient({
url: ldapConfig.url, url: ldapConfig.url,

View File

@@ -28,7 +28,8 @@ export const getDefaultOnPremFeatures = () => {
has_used_trial: true, has_used_trial: true,
secretApproval: true, secretApproval: true,
secretRotation: true, secretRotation: true,
caCrl: false caCrl: false,
sshHostGroups: false
}; };
}; };

View File

@@ -10,6 +10,7 @@ export const BillingPlanRows = {
CustomAlerts: { name: "Custom alerts", field: "customAlerts" }, CustomAlerts: { name: "Custom alerts", field: "customAlerts" },
AuditLogs: { name: "Audit logs", field: "auditLogs" }, AuditLogs: { name: "Audit logs", field: "auditLogs" },
SamlSSO: { name: "SAML SSO", field: "samlSSO" }, SamlSSO: { name: "SAML SSO", field: "samlSSO" },
SshHostGroups: { name: "SSH Host Groups", field: "sshHostGroups" },
Hsm: { name: "Hardware Security Module (HSM)", field: "hsm" }, Hsm: { name: "Hardware Security Module (HSM)", field: "hsm" },
OidcSSO: { name: "OIDC SSO", field: "oidcSSO" }, OidcSSO: { name: "OIDC SSO", field: "oidcSSO" },
SecretApproval: { name: "Secret approvals", field: "secretApproval" }, SecretApproval: { name: "Secret approvals", field: "secretApproval" },

View File

@@ -22,6 +22,7 @@ export const getDefaultOnPremFeatures = (): TFeatureSet => ({
pitRecovery: false, pitRecovery: false,
ipAllowlisting: false, ipAllowlisting: false,
rbac: false, rbac: false,
githubOrgSync: false,
customRateLimits: false, customRateLimits: false,
customAlerts: false, customAlerts: false,
secretAccessInsights: false, secretAccessInsights: false,
@@ -52,7 +53,8 @@ export const getDefaultOnPremFeatures = (): TFeatureSet => ({
enforceMfa: false, enforceMfa: false,
projectTemplates: false, projectTemplates: false,
kmip: false, kmip: false,
gateway: false gateway: false,
sshHostGroups: false
}); });
export const setupLicenseRequestWithStore = (baseURL: string, refreshUrl: string, licenseKey: string) => { export const setupLicenseRequestWithStore = (baseURL: string, refreshUrl: string, licenseKey: string) => {

View File

@@ -45,6 +45,7 @@ export type TFeatureSet = {
auditLogsRetentionDays: 0; auditLogsRetentionDays: 0;
auditLogStreams: false; auditLogStreams: false;
auditLogStreamLimit: 3; auditLogStreamLimit: 3;
githubOrgSync: false;
samlSSO: false; samlSSO: false;
hsm: false; hsm: false;
oidcSSO: false; oidcSSO: false;
@@ -70,6 +71,7 @@ export type TFeatureSet = {
projectTemplates: false; projectTemplates: false;
kmip: false; kmip: false;
gateway: false; gateway: false;
sshHostGroups: false;
}; };
export type TOrgPlansTableDTO = { export type TOrgPlansTableDTO = {

View File

@@ -685,10 +685,16 @@ export const oidcConfigServiceFactory = ({
id_token_signed_response_alg: oidcCfg.jwtSignatureAlgorithm id_token_signed_response_alg: oidcCfg.jwtSignatureAlgorithm
}); });
// Check if the OIDC provider supports PKCE
const codeChallengeMethods = client.issuer.metadata.code_challenge_methods_supported;
const supportsPKCE = Array.isArray(codeChallengeMethods) && codeChallengeMethods.includes("S256");
const strategy = new OpenIdStrategy( const strategy = new OpenIdStrategy(
{ {
client, client,
passReqToCallback: true passReqToCallback: true,
usePKCE: supportsPKCE,
params: supportsPKCE ? { code_challenge_method: "S256" } : undefined
}, },
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
(_req: any, tokenSet: TokenSet, cb: any) => { (_req: any, tokenSet: TokenSet, cb: any) => {

View File

@@ -8,7 +8,8 @@ export enum OIDCConfigurationType {
export enum OIDCJWTSignatureAlgorithm { export enum OIDCJWTSignatureAlgorithm {
RS256 = "RS256", RS256 = "RS256",
HS256 = "HS256", HS256 = "HS256",
RS512 = "RS512" RS512 = "RS512",
EDDSA = "EdDSA"
} }
export type TOidcLoginDTO = { export type TOidcLoginDTO = {

View File

@@ -0,0 +1,448 @@
import { AbilityBuilder, createMongoAbility, MongoAbility } from "@casl/ability";
import {
ProjectPermissionActions,
ProjectPermissionCertificateActions,
ProjectPermissionCmekActions,
ProjectPermissionDynamicSecretActions,
ProjectPermissionGroupActions,
ProjectPermissionIdentityActions,
ProjectPermissionKmipActions,
ProjectPermissionMemberActions,
ProjectPermissionSecretActions,
ProjectPermissionSecretRotationActions,
ProjectPermissionSecretSyncActions,
ProjectPermissionSet,
ProjectPermissionSshHostActions,
ProjectPermissionSub
} from "@app/ee/services/permission/project-permission";
const buildAdminPermissionRules = () => {
const { can, rules } = new AbilityBuilder<MongoAbility<ProjectPermissionSet>>(createMongoAbility);
// Admins get full access to everything
[
ProjectPermissionSub.SecretFolders,
ProjectPermissionSub.SecretImports,
ProjectPermissionSub.SecretApproval,
ProjectPermissionSub.Role,
ProjectPermissionSub.Integrations,
ProjectPermissionSub.Webhooks,
ProjectPermissionSub.ServiceTokens,
ProjectPermissionSub.Settings,
ProjectPermissionSub.Environments,
ProjectPermissionSub.Tags,
ProjectPermissionSub.AuditLogs,
ProjectPermissionSub.IpAllowList,
ProjectPermissionSub.CertificateAuthorities,
ProjectPermissionSub.CertificateTemplates,
ProjectPermissionSub.PkiAlerts,
ProjectPermissionSub.PkiCollections,
ProjectPermissionSub.SshCertificateAuthorities,
ProjectPermissionSub.SshCertificates,
ProjectPermissionSub.SshCertificateTemplates,
ProjectPermissionSub.SshHostGroups
].forEach((el) => {
can(
[
ProjectPermissionActions.Read,
ProjectPermissionActions.Edit,
ProjectPermissionActions.Create,
ProjectPermissionActions.Delete
],
el
);
});
can(
[
ProjectPermissionCertificateActions.Read,
ProjectPermissionCertificateActions.Edit,
ProjectPermissionCertificateActions.Create,
ProjectPermissionCertificateActions.Delete,
ProjectPermissionCertificateActions.ReadPrivateKey
],
ProjectPermissionSub.Certificates
);
can(
[
ProjectPermissionSshHostActions.Edit,
ProjectPermissionSshHostActions.Read,
ProjectPermissionSshHostActions.Create,
ProjectPermissionSshHostActions.Delete,
ProjectPermissionSshHostActions.IssueHostCert
],
ProjectPermissionSub.SshHosts
);
can(
[
ProjectPermissionMemberActions.Create,
ProjectPermissionMemberActions.Edit,
ProjectPermissionMemberActions.Delete,
ProjectPermissionMemberActions.Read,
ProjectPermissionMemberActions.GrantPrivileges,
ProjectPermissionMemberActions.AssumePrivileges
],
ProjectPermissionSub.Member
);
can(
[
ProjectPermissionGroupActions.Create,
ProjectPermissionGroupActions.Edit,
ProjectPermissionGroupActions.Delete,
ProjectPermissionGroupActions.Read,
ProjectPermissionGroupActions.GrantPrivileges
],
ProjectPermissionSub.Groups
);
can(
[
ProjectPermissionIdentityActions.Create,
ProjectPermissionIdentityActions.Edit,
ProjectPermissionIdentityActions.Delete,
ProjectPermissionIdentityActions.Read,
ProjectPermissionIdentityActions.GrantPrivileges,
ProjectPermissionIdentityActions.AssumePrivileges
],
ProjectPermissionSub.Identity
);
can(
[
ProjectPermissionSecretActions.DescribeAndReadValue,
ProjectPermissionSecretActions.DescribeSecret,
ProjectPermissionSecretActions.ReadValue,
ProjectPermissionSecretActions.Create,
ProjectPermissionSecretActions.Edit,
ProjectPermissionSecretActions.Delete
],
ProjectPermissionSub.Secrets
);
can(
[
ProjectPermissionDynamicSecretActions.ReadRootCredential,
ProjectPermissionDynamicSecretActions.EditRootCredential,
ProjectPermissionDynamicSecretActions.CreateRootCredential,
ProjectPermissionDynamicSecretActions.DeleteRootCredential,
ProjectPermissionDynamicSecretActions.Lease
],
ProjectPermissionSub.DynamicSecrets
);
can([ProjectPermissionActions.Edit, ProjectPermissionActions.Delete], ProjectPermissionSub.Project);
can([ProjectPermissionActions.Read, ProjectPermissionActions.Create], ProjectPermissionSub.SecretRollback);
can([ProjectPermissionActions.Edit], ProjectPermissionSub.Kms);
can(
[
ProjectPermissionCmekActions.Create,
ProjectPermissionCmekActions.Edit,
ProjectPermissionCmekActions.Delete,
ProjectPermissionCmekActions.Read,
ProjectPermissionCmekActions.Encrypt,
ProjectPermissionCmekActions.Decrypt,
ProjectPermissionCmekActions.Sign,
ProjectPermissionCmekActions.Verify
],
ProjectPermissionSub.Cmek
);
can(
[
ProjectPermissionSecretSyncActions.Create,
ProjectPermissionSecretSyncActions.Edit,
ProjectPermissionSecretSyncActions.Delete,
ProjectPermissionSecretSyncActions.Read,
ProjectPermissionSecretSyncActions.SyncSecrets,
ProjectPermissionSecretSyncActions.ImportSecrets,
ProjectPermissionSecretSyncActions.RemoveSecrets
],
ProjectPermissionSub.SecretSyncs
);
can(
[
ProjectPermissionKmipActions.CreateClients,
ProjectPermissionKmipActions.UpdateClients,
ProjectPermissionKmipActions.DeleteClients,
ProjectPermissionKmipActions.ReadClients,
ProjectPermissionKmipActions.GenerateClientCertificates
],
ProjectPermissionSub.Kmip
);
can(
[
ProjectPermissionSecretRotationActions.Create,
ProjectPermissionSecretRotationActions.Edit,
ProjectPermissionSecretRotationActions.Delete,
ProjectPermissionSecretRotationActions.Read,
ProjectPermissionSecretRotationActions.ReadGeneratedCredentials,
ProjectPermissionSecretRotationActions.RotateSecrets
],
ProjectPermissionSub.SecretRotation
);
return rules;
};
const buildMemberPermissionRules = () => {
const { can, rules } = new AbilityBuilder<MongoAbility<ProjectPermissionSet>>(createMongoAbility);
can(
[
ProjectPermissionSecretActions.DescribeAndReadValue,
ProjectPermissionSecretActions.DescribeSecret,
ProjectPermissionSecretActions.ReadValue,
ProjectPermissionSecretActions.Edit,
ProjectPermissionSecretActions.Create,
ProjectPermissionSecretActions.Delete
],
ProjectPermissionSub.Secrets
);
can(
[
ProjectPermissionActions.Read,
ProjectPermissionActions.Edit,
ProjectPermissionActions.Create,
ProjectPermissionActions.Delete
],
ProjectPermissionSub.SecretFolders
);
can(
[
ProjectPermissionDynamicSecretActions.ReadRootCredential,
ProjectPermissionDynamicSecretActions.EditRootCredential,
ProjectPermissionDynamicSecretActions.CreateRootCredential,
ProjectPermissionDynamicSecretActions.DeleteRootCredential,
ProjectPermissionDynamicSecretActions.Lease
],
ProjectPermissionSub.DynamicSecrets
);
can(
[
ProjectPermissionActions.Read,
ProjectPermissionActions.Edit,
ProjectPermissionActions.Create,
ProjectPermissionActions.Delete
],
ProjectPermissionSub.SecretImports
);
can([ProjectPermissionActions.Read], ProjectPermissionSub.SecretApproval);
can([ProjectPermissionSecretRotationActions.Read], ProjectPermissionSub.SecretRotation);
can([ProjectPermissionActions.Read, ProjectPermissionActions.Create], ProjectPermissionSub.SecretRollback);
can([ProjectPermissionMemberActions.Read, ProjectPermissionMemberActions.Create], ProjectPermissionSub.Member);
can([ProjectPermissionGroupActions.Read], ProjectPermissionSub.Groups);
can(
[
ProjectPermissionActions.Read,
ProjectPermissionActions.Edit,
ProjectPermissionActions.Create,
ProjectPermissionActions.Delete
],
ProjectPermissionSub.Integrations
);
can(
[
ProjectPermissionActions.Read,
ProjectPermissionActions.Edit,
ProjectPermissionActions.Create,
ProjectPermissionActions.Delete
],
ProjectPermissionSub.Webhooks
);
can(
[
ProjectPermissionIdentityActions.Read,
ProjectPermissionIdentityActions.Edit,
ProjectPermissionIdentityActions.Create,
ProjectPermissionIdentityActions.Delete
],
ProjectPermissionSub.Identity
);
can(
[
ProjectPermissionActions.Read,
ProjectPermissionActions.Edit,
ProjectPermissionActions.Create,
ProjectPermissionActions.Delete
],
ProjectPermissionSub.ServiceTokens
);
can(
[
ProjectPermissionActions.Read,
ProjectPermissionActions.Edit,
ProjectPermissionActions.Create,
ProjectPermissionActions.Delete
],
ProjectPermissionSub.Settings
);
can(
[
ProjectPermissionActions.Read,
ProjectPermissionActions.Edit,
ProjectPermissionActions.Create,
ProjectPermissionActions.Delete
],
ProjectPermissionSub.Environments
);
can(
[
ProjectPermissionActions.Read,
ProjectPermissionActions.Edit,
ProjectPermissionActions.Create,
ProjectPermissionActions.Delete
],
ProjectPermissionSub.Tags
);
can([ProjectPermissionActions.Read], ProjectPermissionSub.Role);
can([ProjectPermissionActions.Read], ProjectPermissionSub.AuditLogs);
can([ProjectPermissionActions.Read], ProjectPermissionSub.IpAllowList);
// double check if all CRUD are needed for CA and Certificates
can([ProjectPermissionActions.Read], ProjectPermissionSub.CertificateAuthorities);
can(
[
ProjectPermissionCertificateActions.Read,
ProjectPermissionCertificateActions.Edit,
ProjectPermissionCertificateActions.Create,
ProjectPermissionCertificateActions.Delete
],
ProjectPermissionSub.Certificates
);
can([ProjectPermissionActions.Read], ProjectPermissionSub.CertificateTemplates);
can([ProjectPermissionActions.Read], ProjectPermissionSub.PkiAlerts);
can([ProjectPermissionActions.Read], ProjectPermissionSub.PkiCollections);
can([ProjectPermissionActions.Read], ProjectPermissionSub.SshCertificates);
can([ProjectPermissionActions.Create], ProjectPermissionSub.SshCertificates);
can([ProjectPermissionActions.Read], ProjectPermissionSub.SshCertificateTemplates);
can([ProjectPermissionSshHostActions.Read], ProjectPermissionSub.SshHosts);
can(
[
ProjectPermissionCmekActions.Create,
ProjectPermissionCmekActions.Edit,
ProjectPermissionCmekActions.Delete,
ProjectPermissionCmekActions.Read,
ProjectPermissionCmekActions.Encrypt,
ProjectPermissionCmekActions.Decrypt,
ProjectPermissionCmekActions.Sign,
ProjectPermissionCmekActions.Verify
],
ProjectPermissionSub.Cmek
);
can(
[
ProjectPermissionSecretSyncActions.Create,
ProjectPermissionSecretSyncActions.Edit,
ProjectPermissionSecretSyncActions.Delete,
ProjectPermissionSecretSyncActions.Read,
ProjectPermissionSecretSyncActions.SyncSecrets,
ProjectPermissionSecretSyncActions.ImportSecrets,
ProjectPermissionSecretSyncActions.RemoveSecrets
],
ProjectPermissionSub.SecretSyncs
);
return rules;
};
const buildViewerPermissionRules = () => {
const { can, rules } = new AbilityBuilder<MongoAbility<ProjectPermissionSet>>(createMongoAbility);
can(ProjectPermissionSecretActions.DescribeAndReadValue, ProjectPermissionSub.Secrets);
can(ProjectPermissionSecretActions.DescribeSecret, ProjectPermissionSub.Secrets);
can(ProjectPermissionSecretActions.ReadValue, ProjectPermissionSub.Secrets);
can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretFolders);
can(ProjectPermissionDynamicSecretActions.ReadRootCredential, ProjectPermissionSub.DynamicSecrets);
can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretImports);
can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretApproval);
can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
can(ProjectPermissionSecretRotationActions.Read, ProjectPermissionSub.SecretRotation);
can(ProjectPermissionMemberActions.Read, ProjectPermissionSub.Member);
can(ProjectPermissionGroupActions.Read, ProjectPermissionSub.Groups);
can(ProjectPermissionActions.Read, ProjectPermissionSub.Role);
can(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
can(ProjectPermissionActions.Read, ProjectPermissionSub.Webhooks);
can(ProjectPermissionIdentityActions.Read, ProjectPermissionSub.Identity);
can(ProjectPermissionActions.Read, ProjectPermissionSub.ServiceTokens);
can(ProjectPermissionActions.Read, ProjectPermissionSub.Settings);
can(ProjectPermissionActions.Read, ProjectPermissionSub.Environments);
can(ProjectPermissionActions.Read, ProjectPermissionSub.Tags);
can(ProjectPermissionActions.Read, ProjectPermissionSub.AuditLogs);
can(ProjectPermissionActions.Read, ProjectPermissionSub.IpAllowList);
can(ProjectPermissionActions.Read, ProjectPermissionSub.CertificateAuthorities);
can(ProjectPermissionCertificateActions.Read, ProjectPermissionSub.Certificates);
can(ProjectPermissionCmekActions.Read, ProjectPermissionSub.Cmek);
can(ProjectPermissionActions.Read, ProjectPermissionSub.SshCertificates);
can(ProjectPermissionActions.Read, ProjectPermissionSub.SshCertificateTemplates);
can(ProjectPermissionSecretSyncActions.Read, ProjectPermissionSub.SecretSyncs);
return rules;
};
const buildNoAccessProjectPermission = () => {
const { rules } = new AbilityBuilder<MongoAbility<ProjectPermissionSet>>(createMongoAbility);
return rules;
};
const buildSshHostBootstrapPermissionRules = () => {
const { can, rules } = new AbilityBuilder<MongoAbility<ProjectPermissionSet>>(createMongoAbility);
can(
[ProjectPermissionSshHostActions.Create, ProjectPermissionSshHostActions.IssueHostCert],
ProjectPermissionSub.SshHosts
);
return rules;
};
const buildCryptographicOperatorPermissionRules = () => {
const { can, rules } = new AbilityBuilder<MongoAbility<ProjectPermissionSet>>(createMongoAbility);
can(
[
ProjectPermissionCmekActions.Encrypt,
ProjectPermissionCmekActions.Decrypt,
ProjectPermissionCmekActions.Sign,
ProjectPermissionCmekActions.Verify
],
ProjectPermissionSub.Cmek
);
return rules;
};
// General
export const projectAdminPermissions = buildAdminPermissionRules();
export const projectMemberPermissions = buildMemberPermissionRules();
export const projectViewerPermission = buildViewerPermissionRules();
export const projectNoAccessPermissions = buildNoAccessProjectPermission();
// SSH
export const sshHostBootstrapPermissions = buildSshHostBootstrapPermissionRules();
// KMS
export const cryptographicOperatorPermissions = buildCryptographicOperatorPermissionRules();

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