mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-07 08:26:51 +00:00
Record audit logs when the default parameters change (#22)
* Prepare for more endpoints that write logs * Record audit logs when the default parameters change
This commit is contained in:
parent
2a8ab9dacb
commit
9b40f322df
4 changed files with 166 additions and 62 deletions
55
src/actions/apiUtils.ts
Normal file
55
src/actions/apiUtils.ts
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
import { auth } from '@clerk/nextjs/server';
|
||||
import { logger } from '@/lib/server/logger';
|
||||
|
||||
export type ApiResponse = {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
error?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Validates user authentication and organization membership
|
||||
* @returns User and organization IDs if authenticated, or error response if not
|
||||
*/
|
||||
export async function validateAuth(): Promise<
|
||||
{ userId: string; orgId: string } | ApiResponse
|
||||
> {
|
||||
const { userId, orgId } = await auth();
|
||||
if (!userId) {
|
||||
return {
|
||||
success: false,
|
||||
error: 'Unauthorized: User required',
|
||||
};
|
||||
}
|
||||
if (!orgId) {
|
||||
return {
|
||||
success: false,
|
||||
error: 'Unauthorized: Organization required',
|
||||
};
|
||||
}
|
||||
return { userId, orgId };
|
||||
}
|
||||
|
||||
export function isAuthSuccess(
|
||||
result: { userId: string; orgId: string } | ApiResponse,
|
||||
): result is { userId: string; orgId: string } {
|
||||
return !('error' in result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic error handler for all operations
|
||||
* @param error The caught error
|
||||
* @param eventPrefix Prefix for logging events
|
||||
* @returns Error response
|
||||
*/
|
||||
export function handleError(error: unknown, eventPrefix: string): ApiResponse {
|
||||
logger.error({
|
||||
event: `${eventPrefix}_update_error`,
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
});
|
||||
return {
|
||||
success: false,
|
||||
error:
|
||||
error instanceof Error ? error.message : 'An unexpected error occurred',
|
||||
};
|
||||
}
|
||||
82
src/actions/defaultParameters.ts
Normal file
82
src/actions/defaultParameters.ts
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
'use server';
|
||||
|
||||
import { z } from 'zod';
|
||||
|
||||
import { AuditLogTargetType } from '@/db/schema';
|
||||
import { createAuditLog } from '@/lib/server/auditLogs';
|
||||
import {
|
||||
handleError,
|
||||
isAuthSuccess,
|
||||
validateAuth,
|
||||
type ApiResponse,
|
||||
} from './apiUtils';
|
||||
|
||||
const defaultParametersSchema = z.object({
|
||||
experimentalPowerSteering: z.boolean().optional(),
|
||||
terminalOutputLimit: z.number().int().nonnegative().optional(),
|
||||
compressProgressBar: z.boolean().optional(),
|
||||
inheritEnvVars: z.boolean().optional(),
|
||||
disableShellIntegration: z.boolean().optional(),
|
||||
shellIntegrationTimeout: z.number().int().nonnegative().optional(),
|
||||
commandDelay: z.number().int().nonnegative().optional(),
|
||||
enablePowerShellCounter: z.boolean().optional(),
|
||||
clearZshEol: z.boolean().optional(),
|
||||
enableOhMyZsh: z.boolean().optional(),
|
||||
enablePowerlevel10k: z.boolean().optional(),
|
||||
openTabsLimit: z.number().int().nonnegative().optional(),
|
||||
workspaceFilesLimit: z.number().int().nonnegative().optional(),
|
||||
showRooignoreFiles: z.boolean().optional(),
|
||||
fileReadThreshold: z.number().int().optional(),
|
||||
alwaysReadEntireFile: z.boolean().optional(),
|
||||
enableAutoCheckpoints: z.boolean().optional(),
|
||||
useCustomTemperature: z.boolean().optional(),
|
||||
temperature: z.number().nonnegative().optional(),
|
||||
rateLimit: z.number().nonnegative().optional(),
|
||||
enableEditingThroughDiffs: z.boolean().optional(),
|
||||
matchPrecision: z.number().int().min(50).max(100).optional(),
|
||||
});
|
||||
|
||||
type DefaultParametersRequest = z.infer<typeof defaultParametersSchema>;
|
||||
|
||||
/**
|
||||
* Updates default parameters and creates an audit log entry
|
||||
* @param data The default parameters data to update
|
||||
* @returns API response indicating success or failure
|
||||
*/
|
||||
export async function updateDefaultParameters(
|
||||
data: DefaultParametersRequest,
|
||||
): Promise<ApiResponse> {
|
||||
try {
|
||||
const authResult = await validateAuth();
|
||||
if (!isAuthSuccess(authResult)) return authResult;
|
||||
const { userId, orgId } = authResult;
|
||||
|
||||
const result = defaultParametersSchema.safeParse(data);
|
||||
if (!result.success) {
|
||||
return {
|
||||
success: false,
|
||||
error: 'Invalid request data',
|
||||
};
|
||||
}
|
||||
const validatedData = result.data;
|
||||
|
||||
// TODO: persist data to the database
|
||||
|
||||
// TODO: audit log description should contain more granular information on what changed
|
||||
await createAuditLog({
|
||||
userId,
|
||||
organizationId: orgId,
|
||||
targetType: AuditLogTargetType.DEFAULT_PARAMETERS,
|
||||
targetId: 'default-parameters',
|
||||
newValue: validatedData,
|
||||
description: 'Updated default parameters',
|
||||
});
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: 'Default parameters updated successfully',
|
||||
};
|
||||
} catch (error) {
|
||||
return handleError(error, 'default_parameters');
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +1,15 @@
|
|||
'use server';
|
||||
|
||||
import { auth } from '@clerk/nextjs/server';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { AuditLogTargetType } from '@/db/schema';
|
||||
import { logger } from '@/lib/server/logger';
|
||||
import { createAuditLog } from '@/lib/server/auditLogs';
|
||||
|
||||
type ApiResponse = {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
error?: string;
|
||||
};
|
||||
import {
|
||||
handleError,
|
||||
isAuthSuccess,
|
||||
validateAuth,
|
||||
type ApiResponse,
|
||||
} from './apiUtils';
|
||||
|
||||
const allowAllProvidersSchema = z.object({
|
||||
allowAllProviders: z.boolean(),
|
||||
|
|
@ -35,53 +33,8 @@ type AllowAllProvidersRequest = z.infer<typeof allowAllProvidersSchema>;
|
|||
type ProviderToggleRequest = z.infer<typeof providerToggleSchema>;
|
||||
type ModelToggleRequest = z.infer<typeof modelToggleSchema>;
|
||||
|
||||
/**
|
||||
* Validates user authentication and organization membership
|
||||
* @returns User and organization IDs if authenticated, or error response if not
|
||||
*/
|
||||
async function validateAuth(): Promise<
|
||||
{ userId: string; orgId: string } | ApiResponse
|
||||
> {
|
||||
const { userId, orgId } = await auth();
|
||||
if (!userId) {
|
||||
return {
|
||||
success: false,
|
||||
error: 'Unauthorized: User required',
|
||||
};
|
||||
}
|
||||
if (!orgId) {
|
||||
return {
|
||||
success: false,
|
||||
error: 'Unauthorized: Organization required',
|
||||
};
|
||||
}
|
||||
return { userId, orgId };
|
||||
}
|
||||
|
||||
function isAuthSuccess(
|
||||
result: { userId: string; orgId: string } | ApiResponse,
|
||||
): result is { userId: string; orgId: string } {
|
||||
return !('error' in result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic error handler for all operations
|
||||
* @param error The caught error
|
||||
* @param eventPrefix Prefix for logging events
|
||||
* @returns Error response
|
||||
*/
|
||||
function handleError(error: unknown, eventPrefix: string): ApiResponse {
|
||||
logger.error({
|
||||
event: `${eventPrefix}_update_error`,
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
});
|
||||
return {
|
||||
success: false,
|
||||
error:
|
||||
error instanceof Error ? error.message : 'An unexpected error occurred',
|
||||
};
|
||||
}
|
||||
|
||||
// Note: I haven't thought much about this API; this is a temporary stub to get audit logs working.
|
||||
// Feel free to refactor when implementing actual data writes.
|
||||
export async function updateAllowAllProviders(
|
||||
data: AllowAllProvidersRequest,
|
||||
): Promise<ApiResponse> {
|
||||
|
|
@ -119,6 +72,8 @@ export async function updateAllowAllProviders(
|
|||
}
|
||||
}
|
||||
|
||||
// Note: I haven't thought much about this API; this is a temporary stub to get audit logs working.
|
||||
// Feel free to refactor when implementing actual data writes.
|
||||
export async function updateProviderStatus(
|
||||
data: ProviderToggleRequest,
|
||||
): Promise<ApiResponse> {
|
||||
|
|
@ -156,6 +111,8 @@ export async function updateProviderStatus(
|
|||
}
|
||||
}
|
||||
|
||||
// Note: I haven't thought much about this API; this is a temporary stub to get audit logs working.
|
||||
// Feel free to refactor when implementing actual data writes.
|
||||
export async function updateModelStatus(
|
||||
data: ModelToggleRequest,
|
||||
): Promise<ApiResponse> {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { useState } from 'react';
|
|||
import { useForm } from 'react-hook-form';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
import { updateDefaultParameters } from '@/actions/defaultParameters';
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
|
|
@ -77,17 +78,26 @@ const DefaultParametersPage = () => {
|
|||
},
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const onSubmit = (_data: DefaultParamsFormValues) => {
|
||||
const onSubmit = async (data: DefaultParamsFormValues) => {
|
||||
setIsSaving(true);
|
||||
|
||||
setTimeout(() => {
|
||||
toast('Settings saved', {
|
||||
description: 'Default parameters have been updated successfully.',
|
||||
try {
|
||||
const result = await updateDefaultParameters(data);
|
||||
if (result.success) {
|
||||
toast('Settings saved', {
|
||||
description: 'Default parameters have been updated successfully.',
|
||||
});
|
||||
} else {
|
||||
throw new Error(result.error || 'An unexpected error occurred.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to update default parameters:', error);
|
||||
toast.error('Error saving settings', {
|
||||
description: 'Failed to update default parameters. Please try again.',
|
||||
});
|
||||
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}, 1000);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue