mirror of
https://gitcode.com/ageerle/ruoyi-ai.git
synced 2026-11-15 07:20:40 +00:00
feat: enhance coding harness, model security and system features
This commit is contained in:
@@ -65,7 +65,12 @@ public class DefaultTraceStreamSpan implements TraceStreamSpan {
|
||||
traceRecordService.finishNode(traceId, nodeId, status, errorMessage, outputPayload,
|
||||
new Date(), System.currentTimeMillis() - startMillis);
|
||||
} catch (Exception e) {
|
||||
log.warn("结束 trace stream span 失败,traceId={}, nodeId={}", traceId, nodeId, e);
|
||||
log.warn("trace_persistence operation=FINISH_STREAM_NODE status=FAILED traceId={} nodeId={} errorType={}",
|
||||
traceId, nodeId, errorType(e));
|
||||
}
|
||||
}
|
||||
|
||||
private static String errorType(Throwable error) {
|
||||
return error == null ? "unknown" : error.getClass().getName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,9 +37,14 @@ public final class TracePayloadUtils {
|
||||
if (throwable == null) {
|
||||
return null;
|
||||
}
|
||||
int maxLength = properties == null ? 1000 : properties.getPayload().getMaxErrorLength();
|
||||
String message = throwable.getClass().getSimpleName() + ": " + (throwable.getMessage() == null ? "" : throwable.getMessage());
|
||||
return truncate(message, maxLength);
|
||||
int maxLength = properties == null || properties.getPayload() == null
|
||||
? 1000 : properties.getPayload().getMaxErrorLength();
|
||||
// Trace payloads are durable, operator-visible records. Provider exception messages can
|
||||
// carry prompts, credentials, SQL, file-system paths, or response bodies, so this boundary
|
||||
// must never read or retain Throwable#getMessage(). The exception type is sufficient for
|
||||
// classification and remains useful without persisting untrusted content.
|
||||
String summary = "TRACE_FAILURE errorType=" + throwable.getClass().getName();
|
||||
return truncate(summary, maxLength);
|
||||
}
|
||||
|
||||
public static String toJson(Object value) {
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package org.ruoyi.common.trace.core;
|
||||
|
||||
import ch.qos.logback.classic.Logger;
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.read.ListAppender;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
@@ -9,11 +13,14 @@ import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.ruoyi.common.trace.config.TraceProperties;
|
||||
import org.ruoyi.common.trace.constant.TraceConstants;
|
||||
import org.ruoyi.common.trace.service.TraceRecordService;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
@@ -23,6 +30,7 @@ import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@Tag("dev")
|
||||
class DefaultTraceStreamSpanTest {
|
||||
|
||||
@Mock
|
||||
@@ -45,17 +53,18 @@ class DefaultTraceStreamSpanTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void finishErrorShouldRecordTruncatedError() {
|
||||
void finishErrorShouldRecordOnlyBoundedExceptionType() {
|
||||
TraceProperties properties = new TraceProperties();
|
||||
properties.getPayload().setMaxErrorLength(8);
|
||||
properties.getPayload().setMaxErrorLength(200);
|
||||
DefaultTraceStreamSpan span = new DefaultTraceStreamSpan(traceRecordService, properties, "trace-1", "node-1", System.currentTimeMillis());
|
||||
|
||||
span.finishError(new IllegalStateException("abcdef"));
|
||||
span.finishError(new IllegalStateException("provider-credential-path-canary"));
|
||||
|
||||
ArgumentCaptor<String> errorCaptor = ArgumentCaptor.forClass(String.class);
|
||||
verify(traceRecordService).finishNode(eq("trace-1"), eq("node-1"), eq(TraceConstants.STATUS_ERROR),
|
||||
errorCaptor.capture(), isNull(), any(Date.class), anyLong());
|
||||
assertEquals("IllegalS", errorCaptor.getValue());
|
||||
assertEquals("TRACE_FAILURE errorType=java.lang.IllegalStateException", errorCaptor.getValue());
|
||||
assertFalse(errorCaptor.getValue().contains("provider-credential-path-canary"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -72,12 +81,38 @@ class DefaultTraceStreamSpanTest {
|
||||
|
||||
@Test
|
||||
void writeFailureShouldNotEscape() {
|
||||
doThrow(new IllegalStateException("db down")).when(traceRecordService)
|
||||
Logger logger = (Logger) LoggerFactory.getLogger(DefaultTraceStreamSpan.class);
|
||||
ListAppender<ILoggingEvent> appender = attach(logger);
|
||||
doThrow(new IllegalStateException("trace-storage-credential-canary")).when(traceRecordService)
|
||||
.finishNode(eq("trace-1"), eq("node-1"), eq(TraceConstants.STATUS_SUCCESS), isNull(), isNull(), any(Date.class), anyLong());
|
||||
DefaultTraceStreamSpan span = new DefaultTraceStreamSpan(traceRecordService, new TraceProperties(), "trace-1", "node-1", System.currentTimeMillis());
|
||||
|
||||
span.finishSuccess();
|
||||
try {
|
||||
span.finishSuccess();
|
||||
|
||||
assertNull(TraceContext.currentNodeId());
|
||||
String logs = formattedLogs(appender);
|
||||
assertNull(TraceContext.currentNodeId());
|
||||
assertFalse(logs.contains("trace-storage-credential-canary"));
|
||||
assertTrue(logs.contains("java.lang.IllegalStateException"));
|
||||
} finally {
|
||||
detach(logger, appender);
|
||||
}
|
||||
}
|
||||
|
||||
private static ListAppender<ILoggingEvent> attach(Logger logger) {
|
||||
ListAppender<ILoggingEvent> appender = new ListAppender<>();
|
||||
appender.start();
|
||||
logger.addAppender(appender);
|
||||
return appender;
|
||||
}
|
||||
|
||||
private static void detach(Logger logger, ListAppender<ILoggingEvent> appender) {
|
||||
logger.detachAppender(appender);
|
||||
appender.stop();
|
||||
}
|
||||
|
||||
private static String formattedLogs(ListAppender<ILoggingEvent> appender) {
|
||||
return appender.list.stream().map(ILoggingEvent::getFormattedMessage)
|
||||
.reduce("", (left, right) -> left + "\n" + right);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
package org.ruoyi.common.trace.util;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.ruoyi.common.trace.config.TraceProperties;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@Tag("dev")
|
||||
class TracePayloadUtilsTest {
|
||||
|
||||
@Test
|
||||
@@ -25,4 +30,25 @@ class TracePayloadUtilsTest {
|
||||
String json = TracePayloadUtils.toJson(Map.of("count", 2));
|
||||
assertTrue(json.contains("\"count\":2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void errorShouldPersistOnlyTypeWithoutReadingThrowableMessage() {
|
||||
AtomicBoolean messageRead = new AtomicBoolean();
|
||||
Throwable failure = new IllegalStateException() {
|
||||
@Override
|
||||
public String getMessage() {
|
||||
messageRead.set(true);
|
||||
return "provider-credential-path-canary";
|
||||
}
|
||||
};
|
||||
|
||||
String summary = TracePayloadUtils.error(failure, new TraceProperties());
|
||||
TraceProperties missingPayloadPolicy = new TraceProperties();
|
||||
missingPayloadPolicy.setPayload(null);
|
||||
|
||||
assertFalse(messageRead.get());
|
||||
assertEquals("TRACE_FAILURE errorType=" + failure.getClass().getName(), summary);
|
||||
assertEquals(summary, TracePayloadUtils.error(failure, missingPayloadPolicy));
|
||||
assertFalse(summary.contains("provider-credential-path-canary"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user