Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apps/api/src/pkg/keys/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,9 +277,9 @@ export class KeyService {
* through a role.
*/
const permissions = new Set<string>([
...dbRes.permissions.filter((p) => p.permission).map((p) => p.permission.name),
...dbRes.permissions.filter((p) => p.permission).map((p) => p.permission.slug),
...dbRes.roles.flatMap((r) =>
r.role.permissions.filter((p) => p.permission).map((p) => p.permission.name),
r.role.permissions.filter((p) => p.permission).map((p) => p.permission.slug),
),
]);

Expand Down
4 changes: 2 additions & 2 deletions apps/api/src/routes/v1_apis_listKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,8 @@ export const registerV1ApisListKeys = (app: App) =>
return {
keys: keySpace.keys.map((k) => {
const permissions = new Set<string>([
...k.permissions.map((p) => p.permission.name),
...k.roles.flatMap((r) => r.role.permissions.map((p) => p.permission.name)),
...k.permissions.map((p) => p.permission.slug),
...k.roles.flatMap((r) => r.role.permissions.map((p) => p.permission.slug)),
]);
return {
...k,
Expand Down
5 changes: 3 additions & 2 deletions apps/api/src/routes/v1_keys_removePermissions.happy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ test("removes permission by name", async (t) => {

const { keyId } = await h.createKey();

const slug = randomUUID();
const permission = {
id: newId("test"),
name: randomUUID(),
slug: randomUUID(),
name: slug,
slug: slug,
workspaceId: h.resources.userWorkspace.id,
};

Expand Down
14 changes: 11 additions & 3 deletions apps/api/src/routes/v1_keys_removePermissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,16 @@ const route = createRoute({
z.object({
id: z.string().min(3).optional().openapi({
description:
"The id of the permission. Provide either `id` or `name`. If both are provided `id` is used.",
"The id of the permission. Provide either `id` or `slug`. If both are provided `id` is used.",
}),
name: z.string().min(1).optional().openapi({
deprecated: true,
description:
"Identify the permission via its name. Provide either `id` or `name`. If both are provided `id` is used.",
"This field is deprecated and will be removed in a future release. please use `slug` instead.",
}),
slug: z.string().min(1).optional().openapi({
description:
"Identify the permission via its slug. Provide either `id` or `slug`. If both are provided `id` is used.",
}),
}),
)
Expand Down Expand Up @@ -113,8 +118,11 @@ export const registerV1KeysRemovePermissions = (app: App) =>
if ("id" in deleteRequest) {
return cr.permissionId === deleteRequest.id;
}
if ("slug" in deleteRequest) {
return cr.permission.slug === deleteRequest.slug;
}
if ("name" in deleteRequest) {
return cr.permission.name === deleteRequest.name;
return cr.permission.slug === deleteRequest.name;
}
}
});
Expand Down
42 changes: 26 additions & 16 deletions apps/api/src/routes/v1_keys_setPermissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,13 @@ const route = createRoute({
"The id of the permission. Provide either `id` or `name`. If both are provided `id` is used.",
}),
name: z.string().min(1).optional().openapi({
deprecated: true,
description:
"Identify the permission via its name. Provide either `id` or `name`. If both are provided `id` is used.",
"This field is deprecated and will be removed in a future release. please use `slug` instead.",
}),
slug: z.string().min(1).optional().openapi({
description:
"Identify the permission via its slug. Provide either `id` or `slug`. If both are provided `id` is used.",
}),
create: z
.boolean()
Expand Down Expand Up @@ -118,15 +123,16 @@ export async function setPermissions(
requested: Array<{
id?: string;
name?: string;
slug?: string;
create?: boolean;
}>,
): Promise<Array<{ id: string; name: string }>> {
const { db, cache, rbac } = c.get("services");

const requestedIds = requested.filter(({ id }) => !!id).map(({ id }) => id!);
const requestedNames = requested
.filter(({ name }) => !!name)
.map(({ name, create }) => ({ name: name!, create: create! }));
const requestedSlugs = requested
.filter(({ name, slug }) => !!name || !!slug)
.map(({ name, slug, create }) => ({ slug: slug ?? name!, create: create! }));

const [key, existingPermissions, connectedPermissions] = await Promise.all([
db.primary.query.keys.findFirst({
Expand All @@ -143,10 +149,10 @@ export async function setPermissions(
eq(table.workspaceId, auth.authorizedWorkspaceId),
or(
requestedIds.length > 0 ? inArray(table.id, requestedIds) : undefined,
requestedNames.length > 0
requestedSlugs.length > 0
? inArray(
table.name,
requestedNames.map((n) => n.name),
table.slug,
requestedSlugs.map((r) => r.slug),
)
: undefined,
),
Expand All @@ -159,6 +165,7 @@ export async function setPermissions(
permission: {
columns: {
name: true,
slug: true,
},
},
},
Expand All @@ -176,7 +183,10 @@ export async function setPermissions(
if (requestedIds.includes(r.permissionId)) {
return false;
}
if (requestedNames.some(({ name }) => name === r.permission.name)) {
if (requestedSlugs.some(({ slug }) => slug === r.permission.slug)) {
return false;
}
if (!r.permission.slug && !r.permission.name) {
return false;
}
return true;
Expand Down Expand Up @@ -212,7 +222,7 @@ export async function setPermissions(
);
}

const missingPermissionNames: string[] = [];
const missingPermissionSlugs: string[] = [];
for (const id of requestedIds) {
if (!existingPermissions.some((r) => r.id === id)) {
throw new UnkeyApiError({
Expand All @@ -221,23 +231,23 @@ export async function setPermissions(
});
}
}
for (const { create, name } of requestedNames) {
if (!existingPermissions.some((r) => r.name === name)) {
for (const { create, slug } of requestedSlugs) {
if (!existingPermissions.some((r) => r.slug === slug)) {
if (!create) {
throw new UnkeyApiError({
code: "NOT_FOUND",
message: `permission ${name} not found and not allowed to create`,
message: `permission ${slug} not found and not allowed to create`,
});
}
missingPermissionNames.push(name);
missingPermissionSlugs.push(slug);
}
}

const createPermissions = missingPermissionNames.map((name) => ({
const createPermissions = missingPermissionSlugs.map((slug) => ({
id: newId("permission"),
workspaceId: auth.authorizedWorkspaceId,
name,
slug: name,
name: slug,
slug: slug,
}));
if (createPermissions.length > 0) {
const rbacResp = rbac.evaluatePermissions(
Expand Down
14 changes: 7 additions & 7 deletions apps/dashboard/lib/trpc/routers/rbac.ts
Original file line number Diff line number Diff line change
Expand Up @@ -796,22 +796,22 @@ export const rbacRouter = t.router({
export async function upsertPermissions(
ctx: Context,
workspaceId: string,
names: string[],
slugs: string[],
): Promise<{
permissions: Permission[];
auditLogs: UnkeyAuditLog[];
}> {
return await db.transaction(async (tx) => {
const existingPermissions = await tx.query.permissions.findMany({
where: (table, { inArray, and, eq }) =>
and(eq(table.workspaceId, workspaceId), inArray(table.name, names)),
and(eq(table.workspaceId, workspaceId), inArray(table.slug, slugs)),
});

const newPermissions: InsertPermission[] = [];
const auditLogs: UnkeyAuditLog[] = [];

const permissions = names.map((name) => {
const existingPermission = existingPermissions.find((p) => p.name === name);
const permissions = slugs.map((slug) => {
const existingPermission = existingPermissions.find((p) => p.slug === slug);

if (existingPermission) {
return existingPermission;
Expand All @@ -820,8 +820,8 @@ export async function upsertPermissions(
const permission: Permission = {
id: newId("permission"),
workspaceId,
name,
slug: name,
name: slug,
slug: slug,
description: null,
updatedAtM: null,
createdAtM: Date.now(),
Expand All @@ -837,7 +837,7 @@ export async function upsertPermissions(
{
type: "permission",
id: permission.id,
name: permission.name,
name: permission.slug,
},
],
context: {
Expand Down
2 changes: 0 additions & 2 deletions go/pkg/tls/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,4 @@
// - Loading TLS certificates and keys from files
// - Configuring HTTPS servers with sensible security defaults
// - Enabling HTTPS in command-line applications
//
// The package enforces secure defaults such as requiring TLS 1.2 or higher.
package tls
2 changes: 1 addition & 1 deletion go/pkg/tls/tls.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func New(certPEMBlock, keyPEMBlock []byte) (*tls.Config, error) {
// The keyFile parameter should be the path to a PEM-encoded private key file.
//
// The function reads both files, verifies their content, and creates a properly
// configured TLS configuration with secure defaults (TLS 1.2+).
// configured TLS configuration with secure defaults (TLS 1.3+).
//
// If the files cannot be read or contain invalid certificate/key data, the function
// returns a descriptive error. Common error cases include non-existent files, permission
Expand Down
8 changes: 4 additions & 4 deletions go/pkg/tls/tls_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ func TestNewWithValidCertificateAndKey(t *testing.T) {
require.NoError(t, err)
// A valid TLS config should have certificates
require.NotEmpty(t, tlsConfig.Certificates)
// Check TLS version is at least 1.2
require.Equal(t, uint16(0x0303), tlsConfig.MinVersion) // TLS 1.2
// Check TLS version is at least 1.3
require.Equal(t, uint16(0x0304), tlsConfig.MinVersion) // TLS 1.3
}

// TestNewWithEmptyCertificate verifies that the New function returns an appropriate
Expand Down Expand Up @@ -177,8 +177,8 @@ func TestNewFromFilesWithValidFiles(t *testing.T) {
require.NoError(t, err)
// A valid TLS config should have certificates
require.NotEmpty(t, tlsConfig.Certificates)
// Check TLS version is at least 1.2
require.Equal(t, uint16(0x0303), tlsConfig.MinVersion) // TLS 1.2
// Check TLS version is at least 1.3
require.Equal(t, uint16(0x0304), tlsConfig.MinVersion) // TLS 1.3
}

// TestNewFromFilesWithNonExistentCertificate verifies that the NewFromFiles function
Expand Down
3 changes: 1 addition & 2 deletions internal/db/src/schema/rbac.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@ export const permissions = mysqlTable(
id: varchar("id", { length: 256 }).primaryKey(),
workspaceId: varchar("workspace_id", { length: 256 }).notNull(),
name: varchar("name", { length: 512 }).notNull(),
slug: varchar("slug", { length: 128 }),
slug: varchar("slug", { length: 128 }).notNull(),
description: varchar("description", { length: 512 }),

createdAtM: bigint("created_at_m", { mode: "number" })
.notNull()
.default(0)
Expand Down
Loading