* Copyright (c) 2026 Huawei Technologies Co., Ltd.
* openFuyao is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package openscap
import (
"testing"
compliancev1alpha1 "gitcode.com/openFuyao/compliance-operator/api/v1alpha1"
"gitcode.com/openFuyao/compliance-operator/pkg/unified"
)
func TestParser_Parse(t *testing.T) {
tests := []struct {
name string
rawOutput string
wantCount int
wantErr bool
checkResult *compliancev1alpha1.UnifiedCheckResult
}{
{
name: "valid openscap output with markers",
rawOutput: `Some logs before
===COMPLIANCE_RESULT_START===
<?xml version="1.0" encoding="UTF-8"?>
<TestResult xmlns="http://checklists.nist.gov/xccdf/1.2">
<rule-result idref="xccdf_mil.disa.stig_rule_SV-242376r960759_rule" severity="medium">
<result>pass</result>
</rule-result>
<rule-result idref="xccdf_mil.disa.stig_rule_SV-242379r960759_rule" severity="high">
<result>fail</result>
</rule-result>
</TestResult>
===COMPLIANCE_RESULT_END===
Some logs after`,
wantCount: 2,
wantErr: false,
checkResult: &compliancev1alpha1.UnifiedCheckResult{
ID: "V-242376",
Status: unified.StatusPass,
ActualValue: "pass",
ExpectedValue: "pass",
},
},
{
name: "valid openscap output without markers",
rawOutput: `<?xml version="1.0" encoding="UTF-8"?>
<TestResult xmlns="http://checklists.nist.gov/xccdf/1.2">
<rule-result idref="xccdf_mil.disa.stig_rule_SV-242376r960759_rule" severity="medium">
<result>pass</result>
</rule-result>
</TestResult>`,
wantCount: 1,
wantErr: false,
checkResult: &compliancev1alpha1.UnifiedCheckResult{
ID: "V-242376",
Status: unified.StatusPass,
ActualValue: "pass",
ExpectedValue: "pass",
},
},
{
name: "invalid XML",
rawOutput: `===COMPLIANCE_RESULT_START===invalid xml===COMPLIANCE_RESULT_END===`,
wantCount: 0,
wantErr: true,
},
{
name: "empty output",
rawOutput: "",
wantCount: 0,
wantErr: true,
},
{
name: "Benchmark root format (OpenSCAP full output)",
rawOutput: `--- Starting Evaluation ---
Title Some rule
Result fail
===COMPLIANCE_RESULT_START===
<?xml version="1.0" encoding="UTF-8"?>
<Benchmark xmlns="http://checklists.nist.gov/xccdf/1.2" id="xccdf_mil.disa.stig_benchmark_Kubernetes_STIG">
<status date="2025-11-20">accepted</status>
<title>Kubernetes STIG</title>
<TestResult id="xccdf_org.open-scap_testresult" start-time="2026-06-05T08:57:24+00:00" end-time="2026-06-05T08:57:25+00:00">
<benchmark href="/scap-content/scap-rule.xml" id="xccdf_mil.disa.stig_benchmark_Kubernetes_STIG"/>
<profile idref="xccdf_mil.disa.stig_profile_MAC-1_Classified"/>
<target>master01</target>
<rule-result idref="xccdf_mil.disa.stig_rule_SV-242376r960759_rule" severity="medium" version="CNTR-K8-000150">
<result>fail</result>
</rule-result>
<rule-result idref="xccdf_mil.disa.stig_rule_SV-242381r1043176_rule" severity="high" version="CNTR-K8-000220">
<result>pass</result>
</rule-result>
<rule-result idref="xccdf_mil.disa.stig_rule_SV-242393r1137639_rule" severity="medium" version="CNTR-K8-000400">
<result>notapplicable</result>
</rule-result>
<score system="urn:xccdf:scoring:default" maximum="100.000000">71.186440</score>
</TestResult>
</Benchmark>
===COMPLIANCE_RESULT_END===`,
wantCount: 3,
wantErr: false,
checkResult: &compliancev1alpha1.UnifiedCheckResult{
ID: "V-242376",
Status: unified.StatusFail,
ActualValue: "fail",
ExpectedValue: "pass",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
p := NewParser()
results, err := p.Parse(tt.rawOutput)
if (err != nil) != tt.wantErr {
t.Errorf("Parser.Parse() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr {
if len(results) != tt.wantCount {
t.Errorf("Parser.Parse() got %d results, want %d", len(results), tt.wantCount)
}
if tt.checkResult != nil && len(results) > 0 {
got := results[0]
if got.ID != tt.checkResult.ID {
t.Errorf("Parser.Parse() ID = %s, want %s", got.ID, tt.checkResult.ID)
}
if got.Status != tt.checkResult.Status {
t.Errorf("Parser.Parse() Status = %s, want %s", got.Status, tt.checkResult.Status)
}
if got.ActualValue != tt.checkResult.ActualValue {
t.Errorf("Parser.Parse() ActualValue = %s, want %s", got.ActualValue, tt.checkResult.ActualValue)
}
if got.ExpectedValue != tt.checkResult.ExpectedValue {
t.Errorf("Parser.Parse() ExpectedValue = %s, want %s", got.ExpectedValue, tt.checkResult.ExpectedValue)
}
}
}
})
}
}
func TestExtractVulnID(t *testing.T) {
tests := []struct {
idref string
want string
}{
{"xccdf_mil.disa.stig_rule_SV-242376r960759_rule", "V-242376"},
{"xccdf_mil.disa.stig_rule_SV-245544r960759_rule", "V-245544"},
{"invalid-idref", ""},
}
for _, tt := range tests {
t.Run(tt.idref, func(t *testing.T) {
got := extractVulnID(tt.idref)
if got != tt.want {
t.Errorf("extractVulnID(%s) = %s, want %s", tt.idref, got, tt.want)
}
})
}
}
func TestMapOpenSCAPStatus(t *testing.T) {
tests := []struct {
result string
want string
}{
{"pass", unified.StatusPass},
{"fail", unified.StatusFail},
{"error", unified.StatusError},
{"unknown", unified.StatusWarn},
{"notapplicable", unified.StatusNotApplicable},
{"notchecked", unified.StatusNotChecked},
{"informational", unified.StatusInfo},
{"notselected", ""},
{"UNKNOWN", unified.StatusWarn},
}
for _, tt := range tests {
t.Run(tt.result, func(t *testing.T) {
got := mapOpenSCAPStatus(tt.result)
if got != tt.want {
t.Errorf("mapOpenSCAPStatus(%s) = %s, want %s", tt.result, got, tt.want)
}
})
}
}