fix(portal): keep technical health out of security view
This commit is contained in:
@@ -2240,33 +2240,30 @@ fn agent_quality_explain(quality: &AgentQuality) -> AgentQualityExplain {
|
|||||||
|
|
||||||
fn command_json_source(name: &str, command: &str, timeout: Duration) -> SourceStatus {
|
fn command_json_source(name: &str, command: &str, timeout: Duration) -> SourceStatus {
|
||||||
match run_shell(command, timeout) {
|
match run_shell(command, timeout) {
|
||||||
Ok((stdout, stderr, success)) => {
|
Ok((stdout, stderr, success)) => match serde_json::from_str::<Value>(&stdout) {
|
||||||
if !success {
|
Ok(payload) => SourceStatus {
|
||||||
return SourceStatus {
|
ok: payload_bool(&payload, "/ok").unwrap_or(true),
|
||||||
ok: false,
|
status: status_from_payload(&payload),
|
||||||
status: "FAIL".to_string(),
|
summary: source_summary(name, &payload),
|
||||||
summary: format!("{name} command returned non-zero status"),
|
error: if success || stderr.trim().is_empty() {
|
||||||
error: Some(stderr.trim().to_string()),
|
None
|
||||||
payload: None,
|
} else {
|
||||||
};
|
Some(stderr.trim().to_string())
|
||||||
}
|
|
||||||
match serde_json::from_str::<Value>(&stdout) {
|
|
||||||
Ok(payload) => SourceStatus {
|
|
||||||
ok: payload_bool(&payload, "/ok").unwrap_or(true),
|
|
||||||
status: status_from_payload(&payload),
|
|
||||||
summary: source_summary(name, &payload),
|
|
||||||
error: None,
|
|
||||||
payload: Some(payload),
|
|
||||||
},
|
},
|
||||||
Err(err) => SourceStatus {
|
payload: Some(payload),
|
||||||
ok: false,
|
},
|
||||||
status: "FAIL".to_string(),
|
Err(err) => SourceStatus {
|
||||||
summary: format!("{name} returned invalid JSON"),
|
ok: false,
|
||||||
error: Some(err.to_string()),
|
status: "FAIL".to_string(),
|
||||||
payload: None,
|
summary: if success {
|
||||||
|
format!("{name} returned invalid JSON")
|
||||||
|
} else {
|
||||||
|
format!("{name} command returned non-zero status")
|
||||||
},
|
},
|
||||||
}
|
error: Some(err.to_string()),
|
||||||
}
|
payload: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
Err(err) => SourceStatus {
|
Err(err) => SourceStatus {
|
||||||
ok: false,
|
ok: false,
|
||||||
status: "FAIL".to_string(),
|
status: "FAIL".to_string(),
|
||||||
@@ -9352,6 +9349,19 @@ mod tests {
|
|||||||
assert!(err.to_string().contains("command timed out"));
|
assert!(err.to_string().contains("command timed out"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn command_json_source_accepts_valid_json_with_nonzero_exit() {
|
||||||
|
let source = command_json_source(
|
||||||
|
"detmir_status",
|
||||||
|
"printf '%s' '{\"severity\":\"OK\",\"ok_for_operator\":false}'; exit 2",
|
||||||
|
Duration::from_secs(1),
|
||||||
|
);
|
||||||
|
assert!(source.ok);
|
||||||
|
assert_eq!(source.status, "OK");
|
||||||
|
assert!(source.payload.is_some());
|
||||||
|
assert!(!source.summary.contains("command returned non-zero"));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn agent_quality_history_counts_seven_ok_days() {
|
fn agent_quality_history_counts_seven_ok_days() {
|
||||||
let (_dir, path) = write_history(
|
let (_dir, path) = write_history(
|
||||||
|
|||||||
@@ -1214,7 +1214,7 @@ function renderSecurityView(data, report, extras = {}) {
|
|||||||
${renderInvestigationPacks(report?.risk_incident_candidates)}
|
${renderInvestigationPacks(report?.risk_incident_candidates)}
|
||||||
<section class="dashboard-band security-band">
|
<section class="dashboard-band security-band">
|
||||||
<div class="band-head"><h3>Расследования</h3><span class="muted">ручная проверка, решения и материалы</span></div>
|
<div class="band-head"><h3>Расследования</h3><span class="muted">ручная проверка, решения и материалы</span></div>
|
||||||
${renderIncidentsList(extras.incidents || data.incidents || [])}
|
${renderDlpIncidentsList(extras.incidents || data.incidents || [])}
|
||||||
</section>
|
</section>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -289,6 +289,14 @@ async function main() {
|
|||||||
"Связь рисков и активности",
|
"Связь рисков и активности",
|
||||||
].every((marker) => containsText(securityText, marker)),
|
].every((marker) => containsText(securityText, marker)),
|
||||||
});
|
});
|
||||||
|
checks.push({
|
||||||
|
name: "security_role_hides_technical_health_sources",
|
||||||
|
ok:
|
||||||
|
!containsText(securityText, "detmir_check")
|
||||||
|
&& !containsText(securityText, "detmir_status")
|
||||||
|
&& !containsText(securityText, "command failed")
|
||||||
|
&& !containsText(securityText, "command returned non-zero"),
|
||||||
|
});
|
||||||
checks.push({
|
checks.push({
|
||||||
name: "security_events_security_text",
|
name: "security_events_security_text",
|
||||||
ok: !expectedSecurityText || containsText(securityText, expectedSecurityText),
|
ok: !expectedSecurityText || containsText(securityText, expectedSecurityText),
|
||||||
|
|||||||
Reference in New Issue
Block a user