Add groups to ssh hosts allowed principals bot improvements

This commit is contained in:
carlosmonastyrski
2025-05-02 13:36:05 -03:00
parent 36916704be
commit 7d0574087c
3 changed files with 24 additions and 26 deletions
+1 -5
View File
@@ -160,11 +160,7 @@ export const groupDALFactory = (db: TDbClient) => {
const findGroupsByProjectId = async (projectId: string, tx?: Knex) => { const findGroupsByProjectId = async (projectId: string, tx?: Knex) => {
try { try {
const docs = await (tx || db.replicaNode())(TableName.Groups) const docs = await (tx || db.replicaNode())(TableName.Groups)
.leftJoin( .join(TableName.GroupProjectMembership, `${TableName.Groups}.id`, `${TableName.GroupProjectMembership}.groupId`)
TableName.GroupProjectMembership,
`${TableName.Groups}.id`,
`${TableName.GroupProjectMembership}.groupId`
)
.where(`${TableName.GroupProjectMembership}.projectId`, projectId) .where(`${TableName.GroupProjectMembership}.projectId`, projectId)
.select(selectAllTableCols(TableName.Groups)); .select(selectAllTableCols(TableName.Groups));
return docs; return docs;
@@ -262,16 +262,15 @@ export const sshHostServiceFactory = ({
} }
if (allowedPrincipals.groups && allowedPrincipals.groups.length > 0) { if (allowedPrincipals.groups && allowedPrincipals.groups.length > 0) {
const groups = await groupDAL.findGroupsByProjectId(projectId); const projectGroups = await groupDAL.findGroupsByProjectId(projectId);
const groups = projectGroups.filter((g) => allowedPrincipals.groups?.includes(g.slug));
const foundGroupSlugs = new Set(groups.map((g) => g.slug)); if (groups.length !== allowedPrincipals.groups?.length) {
throw new BadRequestError({
for (const slug of allowedPrincipals.groups) { message: `Invalid group slugs: ${allowedPrincipals.groups
if (!foundGroupSlugs.has(slug)) { .filter((g) => !projectGroups.some((pg) => pg.slug === g))
throw new BadRequestError({ .join(", ")}`
message: `Invalid group slug: ${slug}` });
});
}
} }
for await (const group of groups) { for await (const group of groups) {
@@ -49,11 +49,11 @@ const schema = z
loginMappings: z loginMappings: z
.object({ .object({
loginUser: z.string().trim().min(1), loginUser: z.string().trim().min(1),
principals: z allowedPrincipals: z
.array( .array(
z.object({ z.object({
type: z.enum(["user", "group"]), type: z.enum(["user", "group"]),
value: z.string().trim() value: z.string().trim().min(1)
}) })
) )
.default([]) .default([])
@@ -110,7 +110,7 @@ export const SshHostModal = ({ popUp, handlePopUpToggle }: Props) => {
userCertTtl: sshHost.userCertTtl, userCertTtl: sshHost.userCertTtl,
loginMappings: sshHost.loginMappings.map(({ loginUser, allowedPrincipals }) => ({ loginMappings: sshHost.loginMappings.map(({ loginUser, allowedPrincipals }) => ({
loginUser, loginUser,
principals: [ allowedPrincipals: [
...(allowedPrincipals.usernames || []).map((username) => ({ ...(allowedPrincipals.usernames || []).map((username) => ({
type: "user" as const, type: "user" as const,
value: username value: username
@@ -169,10 +169,14 @@ export const SshHostModal = ({ popUp, handlePopUpToggle }: Props) => {
} }
} }
const transformedLoginMappings = loginMappings.map(({ loginUser, principals }) => { const transformedLoginMappings = loginMappings.map(({ loginUser, allowedPrincipals }) => {
const usernames = principals.filter((p) => p.type === "user").map((p) => p.value); const usernames = allowedPrincipals
.filter((p) => p.type === "user" && p.value)
.map((p) => p.value);
const groupNames = principals.filter((p) => p.type === "group").map((p) => p.value); const groupNames = allowedPrincipals
.filter((p) => p.type === "group" && p.value)
.map((p) => p.value);
return { return {
loginUser, loginUser,
@@ -182,7 +186,6 @@ export const SshHostModal = ({ popUp, handlePopUpToggle }: Props) => {
} }
}; };
}); });
console.log(transformedLoginMappings);
if (sshHost) { if (sshHost) {
await updateMutateAsync({ await updateMutateAsync({
@@ -230,7 +233,7 @@ export const SshHostModal = ({ popUp, handlePopUpToggle }: Props) => {
principalType: string, principalType: string,
principalValue: string principalValue: string
) => { ) => {
const principals = getValues(`loginMappings.${mappingIndex}.principals`) || []; const principals = getValues(`loginMappings.${mappingIndex}.allowedPrincipals`) || [];
return principals.some((p) => p.type === principalType && p.value === principalValue); return principals.some((p) => p.type === principalType && p.value === principalValue);
}; };
@@ -297,7 +300,7 @@ export const SshHostModal = ({ popUp, handlePopUpToggle }: Props) => {
variant="outline_bg" variant="outline_bg"
onClick={() => { onClick={() => {
const newIndex = loginMappingsFormFields.fields.length; const newIndex = loginMappingsFormFields.fields.length;
loginMappingsFormFields.append({ loginUser: "", principals: [] }); loginMappingsFormFields.append({ loginUser: "", allowedPrincipals: [] });
setExpandedMappings((prev) => ({ setExpandedMappings((prev) => ({
...prev, ...prev,
[newIndex]: true [newIndex]: true
@@ -392,8 +395,8 @@ export const SshHostModal = ({ popUp, handlePopUpToggle }: Props) => {
size="xs" size="xs"
variant="outline_bg" variant="outline_bg"
onClick={() => { onClick={() => {
const current = getValues(`loginMappings.${i}.principals`) ?? []; const current = getValues(`loginMappings.${i}.allowedPrincipals`) ?? [];
setValue(`loginMappings.${i}.principals`, [ setValue(`loginMappings.${i}.allowedPrincipals`, [
...current, ...current,
{ type: "user", value: "" } { type: "user", value: "" }
]); ]);
@@ -404,7 +407,7 @@ export const SshHostModal = ({ popUp, handlePopUpToggle }: Props) => {
</div> </div>
<Controller <Controller
control={control} control={control}
name={`loginMappings.${i}.principals`} name={`loginMappings.${i}.allowedPrincipals`}
render={({ field: { value = [], onChange }, fieldState: { error } }) => ( render={({ field: { value = [], onChange }, fieldState: { error } }) => (
<div className="flex flex-col space-y-2"> <div className="flex flex-col space-y-2">
{value.map((principal, principalIndex) => ( {value.map((principal, principalIndex) => (