feat(security-audit): allow Qwen3Guard auxiliary fields

This commit is contained in:
spongehah
2026-07-27 17:40:11 +08:00
parent 59ce11c780
commit fc495e087d
2 changed files with 19 additions and 13 deletions
@@ -86,19 +86,13 @@ func NormalizeCategory(value string) string {
}
func ParseQwen3Guard(content string, enabledScanners []string) (*NormalizedResult, error) {
lines := make([]string, 0, 2)
for _, line := range strings.Split(strings.ReplaceAll(content, "\r\n", "\n"), "\n") {
line = strings.TrimSpace(line)
if line != "" {
lines = append(lines, line)
}
}
if len(lines) != 2 {
return nil, &GuardError{Code: ErrorCodeInvalidResponse, Retryable: false}
}
var safety string
var categoryLine string
for _, line := range lines {
for _, line := range strings.Split(strings.ReplaceAll(content, "\r\n", "\n"), "\n") {
line = strings.TrimSpace(line)
if line == "" {
continue
}
lower := strings.ToLower(line)
switch {
case strings.HasPrefix(lower, "safety:"):
@@ -112,7 +106,7 @@ func ParseQwen3Guard(content string, enabledScanners []string) (*NormalizedResul
}
categoryLine = strings.TrimSpace(line[len("categories:"):])
default:
return nil, &GuardError{Code: ErrorCodeInvalidResponse}
// Auxiliary Guard fields, such as Refusal, do not affect audit decisions.
}
}
switch strings.ToLower(safety) {
@@ -22,7 +22,7 @@ func TestParseQwen3GuardStrictAndPolicy(t *testing.T) {
{"unsafe", "Safety: Unsafe\nCategories: Jailbreak", AllScannerIDs, EventCritical, ActionBlock, false},
{"unknown unsafe", "Safety: Unsafe\nCategories: Future Risk", AllScannerIDs, EventCritical, ActionBlock, false},
{"disabled unsafe warns", "Safety: Unsafe\nCategories: Violent", []string{"PII"}, EventFlag, ActionWarn, false},
{"extra explanation", "Safety: Safe\nCategories: None\nThis is safe", AllScannerIDs, "", "", true},
{"extra explanation", "Safety: Safe\nCategories: None\nThis is safe", AllScannerIDs, EventPass, ActionAllow, false},
{"duplicate", "Safety: Safe\nSafety: Safe", AllScannerIDs, "", "", true},
{"duplicate categories", "Safety: Safe\nCategories: None\nCategories: PII", AllScannerIDs, "", "", true},
{"missing categories", "Safety: Safe\n", AllScannerIDs, "", "", true},
@@ -42,6 +42,18 @@ func TestParseQwen3GuardStrictAndPolicy(t *testing.T) {
}
}
func TestParseQwen3GuardIgnoresAuxiliaryResponseFields(t *testing.T) {
result, err := ParseQwen3Guard("Safety: Unsafe\nCategories: Jailbreak\nRefusal: No", AllScannerIDs)
require.NoError(t, err)
require.Equal(t, "Unsafe", result.Safety)
require.Equal(t, []string{"jailbreak"}, result.Categories)
serialized, err := json.Marshal(result)
require.NoError(t, err)
require.NotContains(t, string(serialized), "Refusal")
require.NotContains(t, string(serialized), "No")
}
func TestQwen3GuardOfficialCategoriesAliasesAndUnknownAreStable(t *testing.T) {
official := "Violent, Non-violent Illegal Acts, Sexual Content or Sexual Acts, PII, Suicide & Self-Harm, Unethical Acts, Politically Sensitive Topics, Copyright Violation, Jailbreak"
result, err := ParseQwen3Guard("Safety: Unsafe\nCategories: "+official, AllScannerIDs)