feat: add comprehensive permission tests and enhance permission checks in components

- Introduced new test files for permission checks, including `check-permission.test.ts`, `enterprise-only-resources.test.ts`, `resolve-permissions.test.ts`, and `service-access.test.ts`.
- Implemented permission checks in various components to ensure actions are gated by user permissions, including `ShowTraefikConfig`, `UpdateTraefikConfig`, `ShowVolumes`, `ShowDomains`, and others.
- Enhanced the logic for displaying UI elements based on user permissions, ensuring that only authorized users can access or modify resources.
This commit is contained in:
Mauricio Siu
2026-03-15 16:42:48 -06:00
parent 8eace173b9
commit 8127dc4536
118 changed files with 25020 additions and 5430 deletions
@@ -0,0 +1,94 @@
import { db } from "@dokploy/server/db";
import { auditLog } from "@dokploy/server/db/schema";
import type { AuditAction, AuditResourceType } from "@dokploy/server/db/schema";
import { hasValidLicense } from "@dokploy/server/services/proprietary/license-key";
import { and, desc, eq, gte, ilike, lte } from "drizzle-orm";
export type { AuditAction, AuditResourceType };
export interface CreateAuditLogInput {
organizationId: string;
userId: string;
userEmail: string;
userRole: string;
action: AuditAction;
resourceType: AuditResourceType;
resourceId?: string;
resourceName?: string;
metadata?: Record<string, unknown>;
}
/**
* Creates an audit log entry. Fire-and-forget safe — errors are swallowed
* so a logging failure never breaks the main operation.
*/
export const createAuditLog = async (input: CreateAuditLogInput) => {
try {
const licensed = await hasValidLicense(input.organizationId);
if (!licensed) return;
await db.insert(auditLog).values({
organizationId: input.organizationId,
userId: input.userId,
userEmail: input.userEmail,
userRole: input.userRole,
action: input.action,
resourceType: input.resourceType,
resourceId: input.resourceId,
resourceName: input.resourceName,
metadata: input.metadata ? JSON.stringify(input.metadata) : undefined,
});
} catch (err) {
console.error("[audit-log] Failed to create audit log entry:", err);
}
};
export interface GetAuditLogsInput {
organizationId: string;
userId?: string;
userEmail?: string;
resourceName?: string;
action?: AuditAction;
resourceType?: AuditResourceType;
from?: Date;
to?: Date;
limit?: number;
offset?: number;
}
export const getAuditLogs = async (input: GetAuditLogsInput) => {
const {
organizationId,
userId,
userEmail,
resourceName,
action,
resourceType,
from,
to,
limit = 50,
offset = 0,
} = input;
const conditions = [eq(auditLog.organizationId, organizationId)];
if (userId) conditions.push(eq(auditLog.userId, userId));
if (userEmail) conditions.push(ilike(auditLog.userEmail, `%${userEmail}%`));
if (resourceName) conditions.push(ilike(auditLog.resourceName, `%${resourceName}%`));
if (action) conditions.push(eq(auditLog.action, action));
if (resourceType) conditions.push(eq(auditLog.resourceType, resourceType));
if (from) conditions.push(gte(auditLog.createdAt, from));
if (to) conditions.push(lte(auditLog.createdAt, to));
const [logs, total] = await Promise.all([
db.query.auditLog.findMany({
where: and(...conditions),
orderBy: [desc(auditLog.createdAt)],
limit,
offset,
}),
db.$count(auditLog, and(...conditions)),
]);
return { logs, total };
};