From f1072ee67ec41818dd8d8d1344e8386b184f66fb Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Mon, 20 Oct 2025 13:41:17 +0400 Subject: [PATCH 1/6] Update kubernetes-injector.mdx --- .../platforms/kubernetes-injector.mdx | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/docs/integrations/platforms/kubernetes-injector.mdx b/docs/integrations/platforms/kubernetes-injector.mdx index d5d48598b..40fea2635 100644 --- a/docs/integrations/platforms/kubernetes-injector.mdx +++ b/docs/integrations/platforms/kubernetes-injector.mdx @@ -51,6 +51,27 @@ $ kubectl logs deployment/infisical-agent-injector 2025/05/19 14:20:06 Successfully updated webhook configuration with CA bundle ``` +## Windows support + +The Infisical Agent Injector supports both running on Windows-based pods, and injecting the agent into Windows-based pods. + +To run the agent injector on a Windows pod, it's important that you add the `nodeSelector.kubernetes.io/os` label to the pod's deployment with the value `windows`. +This can be done by changing the helm values.yaml by adding the following: + +```yaml values.yaml +nodeSelector: + kubernetes.io/os: windows +``` + +By default the agent injector will run on Linux-based pods, unless you specify otherwise like in the example above. +No extra configuration is needed to inject into Windows-based pods, as the agent injector will detect and handle the injection automatically. + +The Agent Injector will only run and inject into Windows-based pods that are running on the supported Windows versions: +- **Windows Server 2022** + +We're looking to add support for other Windows versions in the future. If you're using a different Windows version, please let us know by opening [an issue](https://github.com/Infisical/infisical-agent-injector/issues/new), and we'll look into adding support for your desired version as soon as possible. + + ## Supported annotations The Infisical Agent Injector supports the following annotations: From a3e8e5433f9ccb805940e1b0c97648fddc9f8a2c Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Tue, 4 Nov 2025 04:46:09 +0400 Subject: [PATCH 2/6] docs: pkcs11 requirements --- .../platform/kms/hsm-integration.mdx | 89 ++++++++++++++++++- 1 file changed, 86 insertions(+), 3 deletions(-) diff --git a/docs/documentation/platform/kms/hsm-integration.mdx b/docs/documentation/platform/kms/hsm-integration.mdx index 7a8d15fe5..ea3918ae3 100644 --- a/docs/documentation/platform/kms/hsm-integration.mdx +++ b/docs/documentation/platform/kms/hsm-integration.mdx @@ -30,13 +30,96 @@ Using a hardware security module comes with the added benefit of having a secure Enabling HSM encryption has a set of key benefits: 1. **Root Key Wrapping**: The root KMS encryption key that is used to secure your Infisical instance will be encrypted using the HSM device rather than the standard software-protected key. + #### Caveats - **Performance**: Using an HSM device can have a performance impact on your Infisical instance. This is due to the additional latency introduced by the HSM device. This is however only noticeable when your instance(s) start up or when the encryption strategy is changed. - **Key Recovery**: If the HSM device is lost or destroyed, you will no longer be able to decrypt your data stored within Infisical. Most HSM providers offer recovery options, which you should consider when setting up an HSM device. -### Requirements -- An Infisical instance with a version number that is equal to or greater than `v0.91.0`. -- An HSM device from a provider such as [Thales Luna HSM](https://cpl.thalesgroup.com/encryption/data-protection-on-demand/services/luna-cloud-hsm), [AWS CloudHSM](https://aws.amazon.com/cloudhsm/), [Fortanix HSM](https://www.fortanix.com/platform/data-security-manager), or others. +## Requirements +- An HSM device _(PKCS#11 compatible library)_ from a compatible provider such as [Thales Luna HSM](https://cpl.thalesgroup.com/encryption/data-protection-on-demand/services/luna-cloud-hsm), [AWS CloudHSM](https://aws.amazon.com/cloudhsm/), [Fortanix HSM](https://www.fortanix.com/platform/data-security-manager), or others. + Infisical is validated to work with PKCS#11 2.40 and later. If your HSM device doesn't follow the >=2.40 PKCS#11 standard you may see degraded performance. + + +## Environment Variable Configuration +To configure your Infisical instance to use an HSM, you must set the required environment variables. Below you'll find an example of the required environment variables. +For further instructions on how to configure the HSM device for your Infisical instance, please see the [Setup Instructions](#setup-instructions) section. + + +```dotenv +HSM_LIB_PATH=/usr/local/lib/cloudhsm/cloudhsm.so +HSM_SLOT=1 +HSM_KEY_LABEL=infisical-key +HSM_PIN=your:pin +``` + +- `HSM_LIB_PATH`: The path to the PKCS#11 library provided by the HSM provider. This usually comes in the form of a `.so` for Linux and MacOS, or a `.dll` file for Windows. For Docker, you need to mount the library path as a volume. Further instructions can be found below. If you are using Docker, make sure to set the HSM_LIB_PATH environment variable to the path where the library is mounted in the container. +- `HSM_PIN`: The PKCS#11 PIN to use for authentication with the HSM device. +- `HSM_SLOT`: The slot number to use for the HSM device. This is typically between `0` and `5` for most HSM devices. +- `HSM_KEY_LABEL`: The label of the key to use for encryption. **Please note that if no key is found with the provided label, the HSM will create a new key with the provided label.** + +You can read more about the [default instance configurations](/self-hosting/configuration/envars) here. + +## PKCS#11 Key Attributes + +If no AES key or HMAC key already exists with the label you defined on the `HSM_KEY_LABEL` environment variable, then Infisical will create one for you automatically using the label specified on `HSM_KEY_LABEL`. +Below you'll find a list of the attributes each key will be created with. + +### AES Key + + + If you bring your own AES key and don't let Infisical create it for you it must have at least the following attributes: + + * `CKA_CLASS`: `CKO_PRIVATE_KEY` — Defines the key class _(secret key)_. + * `CKA_KEY_TYPE`: `CKO_AES` — Defines the key type _(AES key)_. + * `CKA_VALUE_LEN`: `32` — 256-bit key size. + * `CKA_ENCRYPT`: `true` — Encryption capabilities enabled. + * `CKA_DECRYPT`: `true` — Decryption capabilities enabled. + * `CKA_TOKEN`: `true` — The key material will persist in your HSM so it can be reused. + + + Note that for security reasons it is highly recommended to create an AES key with the full set of key attributes seen below if you're going to bring your own key. + + + +* `CKA_CLASS`: `CKO_PRIVATE_KEY` — Defines the key class _(secret key)_. +* `CKA_KEY_TYPE`: `CKO_AES` — Defines the key type _(AES key)_. +* `CKA_VALUE_LEN`: `32` — 256-bit key size. +* `CKA_LABEL`: Your specified label in the `HSM_KEY_LABEL` environment variable. +* `CKA_ENCRYPT`: `true` — Encryption capabilities enabled. +* `CKA_DECRYPT`: `true` — Decryption capabilities enabled. +* `CKA_TOKEN`: `true` — The key material will persist in your HSM so it can be reused. +* `CKA_EXTRACTABLE`: `false` — The key material is not extractable from the HSM. +* `CKA_SENSITIVE`: `true` — The key material is marked as sensitive. +* `CKA_PRIVATE`: `true` — The key material is marked as private to the slot and can't be accessed from other slots. + +### HMAC Key + + + If you bring your own AES key and don't let Infisical create it for you it must have at least the following attributes: + + * `CKA_CLASS`: `CKO_PRIVATE_KEY` — Defines the key class _(secret key)_. + * `CKA_KEY_TYPE`: `CKO_GENERIC_SECRET` — Defines the key class _(generic secret key)_. + * `CKA_VALUE_LEN`: `32` — 256-bit key size + * `CKA_SIGN`: `true` — Signing capabilities enabled + * `CKA_VERIFY`: `true` — Verifying capabilities enabled. + * `CKA_TOKEN`: `true` — The key material will persist in your HSM so it can be reused. + + + Note that for security reasons it is highly recommended to create an HMAC key with the full set of key attributes seen below if you're going to bring your own key. + + + +* `CKA_CLASS`: `CKO_PRIVATE_KEY` — Defines the key class _(secret key)_. +* `CKA_KEY_TYPE`: `CKO_GENERIC_SECRET` — Defines the key class _(generic secret key)_. +* `CKA_VALUE_LEN`: `32` — 256-bit key size. +* `CKA_LABEL`: Your specified label in the `HSM_KEY_LABEL` environment variable, suffixed with `_HMAC`. If you specify `infisical-key-v1`, then the HMAC key label will become `infisical-key-v1_HMAC`. +* `CKA_SIGN`: `true` — Signing capabilities enabled +* `CKA_VERIFY`: `true` — Verifying capabilities enabled. +* `CKA_TOKEN`: `true` — The key material will persist in your HSM so it can be reused. +* `CKA_EXTRACTABLE`: `false` — The key material is not extractable from the HSM. +* `CKA_SENSITIVE`: `true` — The key material is marked as sensitive. +* `CKA_PRIVATE`: `true` — The key material is marked as private to the slot and can't be accessed from other slots. + ## Setup Instructions From dab4c35ec9fd5056930d908f8926f34e4009dce7 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Tue, 4 Nov 2025 04:57:52 +0400 Subject: [PATCH 3/6] Update hsm-integration.mdx --- docs/documentation/platform/kms/hsm-integration.mdx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/documentation/platform/kms/hsm-integration.mdx b/docs/documentation/platform/kms/hsm-integration.mdx index ea3918ae3..a2e2dce16 100644 --- a/docs/documentation/platform/kms/hsm-integration.mdx +++ b/docs/documentation/platform/kms/hsm-integration.mdx @@ -37,7 +37,7 @@ Enabling HSM encryption has a set of key benefits: ## Requirements - An HSM device _(PKCS#11 compatible library)_ from a compatible provider such as [Thales Luna HSM](https://cpl.thalesgroup.com/encryption/data-protection-on-demand/services/luna-cloud-hsm), [AWS CloudHSM](https://aws.amazon.com/cloudhsm/), [Fortanix HSM](https://www.fortanix.com/platform/data-security-manager), or others. - Infisical is validated to work with PKCS#11 2.40 and later. If your HSM device doesn't follow the >=2.40 PKCS#11 standard you may see degraded performance. + Infisical is validated to work with PKCS#11 2.30 and newer. If your HSM device doesn't follow the >=2.30 PKCS#11 standard you may see degraded performance. ## Environment Variable Configuration @@ -69,7 +69,7 @@ Below you'll find a list of the attributes each key will be created with. If you bring your own AES key and don't let Infisical create it for you it must have at least the following attributes: - * `CKA_CLASS`: `CKO_PRIVATE_KEY` — Defines the key class _(secret key)_. + * `CKA_CLASS`: `CKO_SECRET_KEY` — Defines the key class _(secret key)_. * `CKA_KEY_TYPE`: `CKO_AES` — Defines the key type _(AES key)_. * `CKA_VALUE_LEN`: `32` — 256-bit key size. * `CKA_ENCRYPT`: `true` — Encryption capabilities enabled. @@ -81,7 +81,7 @@ Below you'll find a list of the attributes each key will be created with. -* `CKA_CLASS`: `CKO_PRIVATE_KEY` — Defines the key class _(secret key)_. +* `CKA_CLASS`: `CKO_SECRET_KEY` — Defines the key class _(secret key)_. * `CKA_KEY_TYPE`: `CKO_AES` — Defines the key type _(AES key)_. * `CKA_VALUE_LEN`: `32` — 256-bit key size. * `CKA_LABEL`: Your specified label in the `HSM_KEY_LABEL` environment variable. @@ -95,9 +95,9 @@ Below you'll find a list of the attributes each key will be created with. ### HMAC Key - If you bring your own AES key and don't let Infisical create it for you it must have at least the following attributes: + If you bring your own HMAC key and don't let Infisical create it for you it must have at least the following attributes: - * `CKA_CLASS`: `CKO_PRIVATE_KEY` — Defines the key class _(secret key)_. + * `CKA_CLASS`: `CKO_SECRET_KEY` — Defines the key class _(secret key)_. * `CKA_KEY_TYPE`: `CKO_GENERIC_SECRET` — Defines the key class _(generic secret key)_. * `CKA_VALUE_LEN`: `32` — 256-bit key size * `CKA_SIGN`: `true` — Signing capabilities enabled @@ -109,7 +109,7 @@ Below you'll find a list of the attributes each key will be created with. -* `CKA_CLASS`: `CKO_PRIVATE_KEY` — Defines the key class _(secret key)_. +* `CKA_CLASS`: `CKO_SECRET_KEY` — Defines the key class _(secret key)_. * `CKA_KEY_TYPE`: `CKO_GENERIC_SECRET` — Defines the key class _(generic secret key)_. * `CKA_VALUE_LEN`: `32` — 256-bit key size. * `CKA_LABEL`: Your specified label in the `HSM_KEY_LABEL` environment variable, suffixed with `_HMAC`. If you specify `infisical-key-v1`, then the HMAC key label will become `infisical-key-v1_HMAC`. From 27ac81ef5cc7b78f63f4c0f2c2330c152b99a79c Mon Sep 17 00:00:00 2001 From: Scott Wilson Date: Wed, 5 Nov 2025 16:55:41 -0800 Subject: [PATCH 4/6] fix: handle group memberships in secret versions history and fix secret versions query to always return all versions --- backend/src/server/routes/sanitizedSchemas.ts | 3 +- .../secret-v2-bridge/secret-v2-bridge-fns.ts | 4 +- .../secret-v2-bridge/secret-version-dal.ts | 23 ++++---- frontend/src/hooks/api/secrets/types.ts | 1 + .../GroupMembersSection/GroupMembersTable.tsx | 19 ++++++- .../route-secret-manager.tsx | 7 +++ .../SecretListView/SecretVersionItem.tsx | 53 ++++++++++++++++--- 7 files changed, 90 insertions(+), 20 deletions(-) diff --git a/backend/src/server/routes/sanitizedSchemas.ts b/backend/src/server/routes/sanitizedSchemas.ts index 47fbb0e07..17cfcb5ce 100644 --- a/backend/src/server/routes/sanitizedSchemas.ts +++ b/backend/src/server/routes/sanitizedSchemas.ts @@ -141,7 +141,8 @@ export const secretRawSchema = z.object({ actorId: z.string().nullable().optional(), actorType: z.string().nullable().optional(), name: z.string().nullable().optional(), - membershipId: z.string().nullable().optional() + membershipId: z.string().nullable().optional(), + groupId: z.string().nullable().optional() }) .optional() .nullable(), diff --git a/backend/src/services/secret-v2-bridge/secret-v2-bridge-fns.ts b/backend/src/services/secret-v2-bridge/secret-v2-bridge-fns.ts index 6b284ddee..01a7f6210 100644 --- a/backend/src/services/secret-v2-bridge/secret-v2-bridge-fns.ts +++ b/backend/src/services/secret-v2-bridge/secret-v2-bridge-fns.ts @@ -793,6 +793,7 @@ export const reshapeBridgeSecret = ( userActorId?: string | null; identityActorId?: string | null; membershipId?: string | null; + groupId?: string | null; actorType?: string | null; tags?: { id: string; @@ -823,7 +824,8 @@ export const reshapeBridgeSecret = ( actorType: secret.actorType, actorId: secret.userActorId || secret.identityActorId, name: secret.identityActorName || secret.userActorName, - membershipId: secret.membershipId + membershipId: secret.membershipId, + groupId: secret.groupId } : undefined, tags: secret.tags, diff --git a/backend/src/services/secret-v2-bridge/secret-version-dal.ts b/backend/src/services/secret-v2-bridge/secret-version-dal.ts index 7d25dac86..33ac43d09 100644 --- a/backend/src/services/secret-v2-bridge/secret-version-dal.ts +++ b/backend/src/services/secret-v2-bridge/secret-version-dal.ts @@ -182,7 +182,6 @@ export const secretVersionV2BridgeDALFactory = (db: TDbClient) => { const findVersionsBySecretIdWithActors = async ({ secretId, - projectId, secretVersions, findOpt = {}, tx @@ -196,11 +195,19 @@ export const secretVersionV2BridgeDALFactory = (db: TDbClient) => { try { const { offset, limit, sort = [["createdAt", "desc"]] } = findOpt; const query = (tx || db.replicaNode())(TableName.SecretVersionV2) + .leftJoin(TableName.SecretFolder, `${TableName.SecretFolder}.id`, `${TableName.SecretVersionV2}.folderId`) + .leftJoin(TableName.Environment, `${TableName.Environment}.id`, `${TableName.SecretFolder}.envId`) .leftJoin(TableName.Users, `${TableName.Users}.id`, `${TableName.SecretVersionV2}.userActorId`) + .leftJoin(TableName.UserGroupMembership, `${TableName.UserGroupMembership}.userId`, `${TableName.Users}.id`) .leftJoin(TableName.Membership, (qb) => { void qb - .on(`${TableName.Membership}.actorUserId`, `${TableName.SecretVersionV2}.userActorId`) - .andOn(`${TableName.Membership}.scope`, db.raw("?", [AccessScope.Project])); + .on(`${TableName.Membership}.scope`, db.raw("?", [AccessScope.Project])) + .andOn(`${TableName.Membership}.scopeProjectId`, `${TableName.Environment}.projectId`) + .andOn((sqb) => { + void sqb + .on(`${TableName.Membership}.actorUserId`, `${TableName.SecretVersionV2}.userActorId`) + .orOn(`${TableName.Membership}.actorGroupId`, `${TableName.UserGroupMembership}.groupId`); + }); }) .leftJoin(TableName.Identity, `${TableName.Identity}.id`, `${TableName.SecretVersionV2}.identityActorId`) .leftJoin(TableName.SecretV2, `${TableName.SecretVersionV2}.secretId`, `${TableName.SecretV2}.id`) @@ -216,12 +223,6 @@ export const secretVersionV2BridgeDALFactory = (db: TDbClient) => { ) .where((qb) => { void qb.where(`${TableName.SecretVersionV2}.secretId`, secretId); - void qb.where(`${TableName.Membership}.scopeProjectId`, projectId); - if (secretVersions?.length) void qb.whereIn(`${TableName.SecretVersionV2}.version`, secretVersions); - }) - .orWhere((qb) => { - void qb.where(`${TableName.SecretVersionV2}.secretId`, secretId); - void qb.whereNull(`${TableName.Membership}.scopeProjectId`); if (secretVersions?.length) void qb.whereIn(`${TableName.SecretVersionV2}.version`, secretVersions); }) .select( @@ -229,6 +230,7 @@ export const secretVersionV2BridgeDALFactory = (db: TDbClient) => { db.ref("username").withSchema(TableName.Users).as("userActorName"), db.ref("name").withSchema(TableName.Identity).as("identityActorName"), db.ref("id").withSchema(TableName.Membership).as("membershipId"), + db.ref("actorGroupId").withSchema(TableName.Membership).as("groupId"), db.ref("id").withSchema(TableName.SecretTag).as("tagId"), db.ref("color").withSchema(TableName.SecretTag).as("tagColor"), db.ref("slug").withSchema(TableName.SecretTag).as("tagSlug") @@ -256,7 +258,8 @@ export const secretVersionV2BridgeDALFactory = (db: TDbClient) => { ...SecretVersionsV2Schema.parse(el), userActorName: el.userActorName, identityActorName: el.identityActorName, - membershipId: el.membershipId + membershipId: el.membershipId, + groupId: el.groupId }), childrenMapper: [ { diff --git a/frontend/src/hooks/api/secrets/types.ts b/frontend/src/hooks/api/secrets/types.ts index 4f912fad2..f4bf2da98 100644 --- a/frontend/src/hooks/api/secrets/types.ts +++ b/frontend/src/hooks/api/secrets/types.ts @@ -109,6 +109,7 @@ export type SecretVersions = { actorType?: string | null; name?: string | null; membershipId?: string | null; + groupId?: string | null; } | null; }; diff --git a/frontend/src/pages/project/GroupDetailsByIDPage/components/GroupMembersSection/GroupMembersTable.tsx b/frontend/src/pages/project/GroupDetailsByIDPage/components/GroupMembersSection/GroupMembersTable.tsx index 1df989602..7ced08534 100644 --- a/frontend/src/pages/project/GroupDetailsByIDPage/components/GroupMembersSection/GroupMembersTable.tsx +++ b/frontend/src/pages/project/GroupDetailsByIDPage/components/GroupMembersSection/GroupMembersTable.tsx @@ -1,4 +1,4 @@ -import { useMemo } from "react"; +import { useEffect, useMemo } from "react"; import { faArrowDown, faArrowUp, @@ -7,6 +7,7 @@ import { faSearch } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { useNavigate, useSearch } from "@tanstack/react-router"; import { createNotification } from "@app/components/notifications"; import { @@ -48,6 +49,7 @@ enum GroupMembersOrderBy { } export const GroupMembersTable = ({ groupMembership }: Props) => { + const navigate = useNavigate(); const { search, setSearch, @@ -62,6 +64,21 @@ export const GroupMembersTable = ({ groupMembership }: Props) => { initPerPage: getUserTablePreference("projectGroupMembersTable", PreferenceKey.PerPage, 20) }); + // this handles links from secret versions when the actor is in a group membership + const { username, ...restSearch } = useSearch({ + strict: false + }); + useEffect(() => { + if (username) { + setSearch(username); + navigate({ + to: ".", + replace: true, + search: restSearch + }); + } + }, [username]); + const { handlePopUpToggle, popUp, handlePopUpOpen } = usePopUp(["assumePrivileges"] as const); const handlePerPageChange = (newPerPage: number) => { diff --git a/frontend/src/pages/project/GroupDetailsByIDPage/route-secret-manager.tsx b/frontend/src/pages/project/GroupDetailsByIDPage/route-secret-manager.tsx index 01349a83b..c7c1e6e85 100644 --- a/frontend/src/pages/project/GroupDetailsByIDPage/route-secret-manager.tsx +++ b/frontend/src/pages/project/GroupDetailsByIDPage/route-secret-manager.tsx @@ -1,4 +1,6 @@ import { createFileRoute, linkOptions } from "@tanstack/react-router"; +import { zodValidator } from "@tanstack/zod-adapter"; +import { z } from "zod"; import { ProjectAccessControlTabs } from "@app/types/project"; @@ -8,6 +10,11 @@ export const Route = createFileRoute( "/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/groups/$groupId" )({ component: GroupDetailsByIDPage, + validateSearch: zodValidator( + z.object({ + username: z.string().optional().catch(undefined) + }) + ), beforeLoad: ({ context, params }) => { return { breadcrumbs: [ diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretVersionItem.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretVersionItem.tsx index a2c25b13a..b6b7175c6 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretVersionItem.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretVersionItem.tsx @@ -2,6 +2,7 @@ import { useState } from "react"; import { faEye } from "@fortawesome/free-regular-svg-icons"; import { faArrowRotateRight, + faBan, faDesktop, faEyeSlash, faServer, @@ -68,10 +69,14 @@ export const SecretVersionItem = ({ const getLinkToModifyHistoryEntity = ( actorId: string, actorType: string, - membershipId: string | null = "" + membershipId: string | null = "", + groupId: string | null = "", + actorName: string | null = "" ) => { switch (actorType) { case ActorType.USER: + if (groupId) + return `/projects/secret-management/${currentProject.id}/groups/${groupId}?username=${actorName}`; return `/projects/secret-management/${currentProject.id}/members/${membershipId}`; case ActorType.IDENTITY: return `/projects/secret-management/${currentProject.id}/identities/${actorId}`; @@ -83,10 +88,26 @@ export const SecretVersionItem = ({ const onModifyHistoryClick = ( actorId: string | undefined | null, actorType: string | undefined | null, - membershipId: string | undefined | null + membershipId: string | undefined | null, + groupId: string | undefined | null, + actorName: string | undefined | null ) => { + if (!membershipId) { + createNotification({ + type: "info", + text: `This ${actorType === ActorType.USER ? "user" : "identity"} is no longer a member of this project.` + }); + return; + } + if (actorType && actorId && actorType !== ActorType.PLATFORM) { - const redirectLink = getLinkToModifyHistoryEntity(actorId, actorType, membershipId); + const redirectLink = getLinkToModifyHistoryEntity( + actorId, + actorType, + membershipId, + groupId, + actorName + ); if (redirectLink) { navigate({ to: redirectLink }); } @@ -157,15 +178,33 @@ export const SecretVersionItem = ({
Modified by: - + {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
- onModifyHistoryClick(actor.actorId, actor.actorType, actor.membershipId) + onClick={ + actor.membershipId + ? () => + onModifyHistoryClick( + actor.actorId, + actor.actorType, + actor.membershipId, + actor.groupId, + actor.name + ) + : undefined } - className="cursor-pointer" + className={actor.membershipId ? "cursor-pointer" : undefined} > + {!actor.membershipId && ( + + )}
From 44e9edcccaaa11d35c4a91136de1050fbbf6a30c Mon Sep 17 00:00:00 2001 From: Carlos Monastyrski Date: Thu, 6 Nov 2025 14:29:17 -0300 Subject: [PATCH 5/6] Delete PKI templates on project removal to avoid blocking users from removing PKI projects --- ...delete-pki-templates-on-project-removal.ts | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 backend/src/db/migrations/20251106172316_delete-pki-templates-on-project-removal.ts diff --git a/backend/src/db/migrations/20251106172316_delete-pki-templates-on-project-removal.ts b/backend/src/db/migrations/20251106172316_delete-pki-templates-on-project-removal.ts new file mode 100644 index 000000000..4d98f8af4 --- /dev/null +++ b/backend/src/db/migrations/20251106172316_delete-pki-templates-on-project-removal.ts @@ -0,0 +1,21 @@ +import { Knex } from "knex"; + +import { TableName } from "../schemas"; + +export async function up(knex: Knex): Promise { + if (await knex.schema.hasTable(TableName.PkiCertificateTemplateV2)) { + await knex.schema.alterTable(TableName.PkiCertificateTemplateV2, (t) => { + t.dropForeign(["projectId"]); + t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE"); + }); + } +} + +export async function down(knex: Knex): Promise { + if (await knex.schema.hasTable(TableName.PkiCertificateTemplateV2)) { + await knex.schema.alterTable(TableName.PkiCertificateTemplateV2, (t) => { + t.dropForeign(["projectId"]); + t.foreign("projectId").references("id").inTable(TableName.Project); + }); + } +} From c076bdd80271aa4132451d8e37a542744acff3c7 Mon Sep 17 00:00:00 2001 From: Scott Wilson Date: Thu, 6 Nov 2025 10:14:25 -0800 Subject: [PATCH 6/6] fix: address feedback concerns --- .../src/services/secret-v2-bridge/secret-version-dal.ts | 3 ++- .../components/SecretListView/SecretVersionItem.tsx | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/backend/src/services/secret-v2-bridge/secret-version-dal.ts b/backend/src/services/secret-v2-bridge/secret-version-dal.ts index 33ac43d09..a7f0eb565 100644 --- a/backend/src/services/secret-v2-bridge/secret-version-dal.ts +++ b/backend/src/services/secret-v2-bridge/secret-version-dal.ts @@ -198,6 +198,7 @@ export const secretVersionV2BridgeDALFactory = (db: TDbClient) => { .leftJoin(TableName.SecretFolder, `${TableName.SecretFolder}.id`, `${TableName.SecretVersionV2}.folderId`) .leftJoin(TableName.Environment, `${TableName.Environment}.id`, `${TableName.SecretFolder}.envId`) .leftJoin(TableName.Users, `${TableName.Users}.id`, `${TableName.SecretVersionV2}.userActorId`) + .leftJoin(TableName.Identity, `${TableName.Identity}.id`, `${TableName.SecretVersionV2}.identityActorId`) .leftJoin(TableName.UserGroupMembership, `${TableName.UserGroupMembership}.userId`, `${TableName.Users}.id`) .leftJoin(TableName.Membership, (qb) => { void qb @@ -206,10 +207,10 @@ export const secretVersionV2BridgeDALFactory = (db: TDbClient) => { .andOn((sqb) => { void sqb .on(`${TableName.Membership}.actorUserId`, `${TableName.SecretVersionV2}.userActorId`) + .orOn(`${TableName.Membership}.actorIdentityId`, `${TableName.SecretVersionV2}.identityActorId`) .orOn(`${TableName.Membership}.actorGroupId`, `${TableName.UserGroupMembership}.groupId`); }); }) - .leftJoin(TableName.Identity, `${TableName.Identity}.id`, `${TableName.SecretVersionV2}.identityActorId`) .leftJoin(TableName.SecretV2, `${TableName.SecretVersionV2}.secretId`, `${TableName.SecretV2}.id`) .leftJoin( TableName.SecretVersionV2Tag, diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretVersionItem.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretVersionItem.tsx index b6b7175c6..525b54444 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretVersionItem.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretVersionItem.tsx @@ -202,9 +202,11 @@ export const SecretVersionItem = ({ className={actor.membershipId ? "cursor-pointer" : undefined} > - {!actor.membershipId && ( - - )} + {!actor.membershipId && + actor.actorType && + [ActorType.USER, ActorType.IDENTITY].includes( + actor.actorType as ActorType + ) && }