fix: expose param override audits for sensitive message fields (#4974)
This commit is contained in:
parent
146dd77b83
commit
0d4b25795a
@ -26,13 +26,20 @@ const (
|
||||
|
||||
var errSourceHeaderNotFound = errors.New("source header does not exist")
|
||||
|
||||
var paramOverrideKeyAuditPaths = map[string]struct{}{
|
||||
"model": {},
|
||||
"original_model": {},
|
||||
"upstream_model": {},
|
||||
"service_tier": {},
|
||||
"inference_geo": {},
|
||||
"speed": {},
|
||||
var paramOverrideSensitivePathPrefixes = []string{
|
||||
"model",
|
||||
"original_model",
|
||||
"upstream_model",
|
||||
"service_tier",
|
||||
"inference_geo",
|
||||
"speed",
|
||||
"messages",
|
||||
"input",
|
||||
"instructions",
|
||||
"system",
|
||||
"contents",
|
||||
"systemInstruction",
|
||||
"system_instruction",
|
||||
}
|
||||
|
||||
type paramOverrideAuditRecorder struct {
|
||||
@ -206,6 +213,7 @@ func shouldEnableParamOverrideAudit(paramOverride map[string]interface{}) bool {
|
||||
if operations, ok := tryParseOperations(paramOverride); ok {
|
||||
for _, operation := range operations {
|
||||
if shouldAuditParamPath(strings.TrimSpace(operation.Path)) ||
|
||||
shouldAuditParamPath(strings.TrimSpace(operation.From)) ||
|
||||
shouldAuditParamPath(strings.TrimSpace(operation.To)) {
|
||||
return true
|
||||
}
|
||||
@ -255,15 +263,19 @@ func shouldAuditParamPath(path string) bool {
|
||||
if common.DebugEnabled {
|
||||
return true
|
||||
}
|
||||
_, ok := paramOverrideKeyAuditPaths[path]
|
||||
return ok
|
||||
for _, prefix := range paramOverrideSensitivePathPrefixes {
|
||||
if path == prefix || strings.HasPrefix(path, prefix+".") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func shouldAuditOperation(mode, path, from, to string) bool {
|
||||
if common.DebugEnabled {
|
||||
return true
|
||||
}
|
||||
for _, candidate := range []string{path, to} {
|
||||
for _, candidate := range []string{path, from, to} {
|
||||
if shouldAuditParamPath(candidate) {
|
||||
return true
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ import (
|
||||
"github.com/QuantumNous/new-api/dto"
|
||||
"github.com/QuantumNous/new-api/setting/model_setting"
|
||||
"github.com/samber/lo"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestApplyParamOverrideTrimPrefix(t *testing.T) {
|
||||
@ -2184,6 +2185,95 @@ func TestApplyParamOverrideWithRelayInfoRecordsOnlyKeyOperationsWhenDebugDisable
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyParamOverrideWithRelayInfoRecordsConversationBodyOperationsWhenDebugDisabled(t *testing.T) {
|
||||
originalDebugEnabled := common2.DebugEnabled
|
||||
common2.DebugEnabled = false
|
||||
t.Cleanup(func() {
|
||||
common2.DebugEnabled = originalDebugEnabled
|
||||
})
|
||||
|
||||
info := &RelayInfo{
|
||||
ChannelMeta: &ChannelMeta{
|
||||
ParamOverride: map[string]interface{}{
|
||||
"operations": []interface{}{
|
||||
map[string]interface{}{
|
||||
"mode": "replace",
|
||||
"path": "messages.0.content",
|
||||
"from": "hello",
|
||||
"to": "hi",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"mode": "set",
|
||||
"path": "input.0.content.0.text",
|
||||
"value": "rewritten response input",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"mode": "set",
|
||||
"path": "instructions",
|
||||
"value": "new instruction",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"mode": "append",
|
||||
"path": "contents.0.parts",
|
||||
"value": map[string]interface{}{"text": "new gemini part"},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"mode": "copy",
|
||||
"from": "system",
|
||||
"to": "metadata.system_copy",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"mode": "set",
|
||||
"path": "temperature",
|
||||
"value": 0.1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
out, err := ApplyParamOverrideWithRelayInfo([]byte(`{
|
||||
"messages":[{"role":"user","content":"hello world"}],
|
||||
"input":[{"role":"user","content":[{"type":"input_text","text":"original response input"}]}],
|
||||
"instructions":"old instruction",
|
||||
"system":"old system",
|
||||
"contents":[{"role":"user","parts":[{"text":"hello gemini"}]}],
|
||||
"temperature":0.7
|
||||
}`), info)
|
||||
require.NoError(t, err)
|
||||
assertJSONEqual(t, `{
|
||||
"messages":[{"role":"user","content":"hi world"}],
|
||||
"input":[{"role":"user","content":[{"type":"input_text","text":"rewritten response input"}]}],
|
||||
"instructions":"new instruction",
|
||||
"system":"old system",
|
||||
"contents":[{"role":"user","parts":[{"text":"hello gemini"},{"text":"new gemini part"}]}],
|
||||
"temperature":0.1,
|
||||
"metadata":{"system_copy":"old system"}
|
||||
}`, string(out))
|
||||
|
||||
require.Equal(t, []string{
|
||||
"replace messages.0.content from hello to hi",
|
||||
"set input.0.content.0.text = rewritten response input",
|
||||
"set instructions = new instruction",
|
||||
"append contents.0.parts with {\"text\":\"new gemini part\"}",
|
||||
"copy system -> metadata.system_copy",
|
||||
}, info.ParamOverrideAudit)
|
||||
}
|
||||
|
||||
func TestShouldAuditParamPathUsesFieldBoundaryPrefixMatching(t *testing.T) {
|
||||
originalDebugEnabled := common2.DebugEnabled
|
||||
common2.DebugEnabled = false
|
||||
t.Cleanup(func() {
|
||||
common2.DebugEnabled = originalDebugEnabled
|
||||
})
|
||||
|
||||
require.True(t, shouldAuditParamPath("messages"))
|
||||
require.True(t, shouldAuditParamPath("messages.0.content"))
|
||||
require.True(t, shouldAuditParamPath("systemInstruction.parts.0.text"))
|
||||
require.False(t, shouldAuditParamPath("model_name"))
|
||||
require.False(t, shouldAuditParamPath("message"))
|
||||
}
|
||||
|
||||
func assertJSONEqual(t *testing.T, want, got string) {
|
||||
t.Helper()
|
||||
|
||||
|
||||
@ -985,9 +985,8 @@ export function DetailsDialog(props: DetailsDialogProps) {
|
||||
</DetailSection>
|
||||
)}
|
||||
|
||||
{/* Param override (admin only) */}
|
||||
{props.isAdmin &&
|
||||
other?.po &&
|
||||
{/* Param override */}
|
||||
{other?.po &&
|
||||
Array.isArray(other.po) &&
|
||||
other.po.length > 0 && (
|
||||
<DetailSection
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user