fix: add ethtool, lsmod, lspci, modinfo, dkms to read-only command allowlist
Read-only diagnostic commands ethtool, lsmod, lspci, modinfo, and dkms were missing from the readOnlyLeadPattern in the command classifier, causing compound diagnostic commands (e.g. 'uname -r && ethtool -i eno1 && lsmod | grep r8169') to be misclassified as config_mutation instead of read_only. This forced operator approval for simple hardware/driver inspection during the 2026-08-12 hubris NIC cutover session. Added regression test with the exact compound command from that session.
This commit is contained in:
@@ -72,6 +72,7 @@ var readOnlyLeadPattern = regexp.MustCompile(
|
|||||||
`grep|egrep|fgrep|rg|wc|sort|uniq|cut|tr|tee|find|tree|locate|` +
|
`grep|egrep|fgrep|rg|wc|sort|uniq|cut|tr|tee|find|tree|locate|` +
|
||||||
`dpkg\s+(-l|-s|--list|--status)\b|apt\s+(list|search|show)\b|` +
|
`dpkg\s+(-l|-s|--list|--status)\b|apt\s+(list|search|show)\b|` +
|
||||||
`systemctl\s+(status|is-active|is-enabled|is-failed|list-units|list-unit-files|list-timers|show)\b|` +
|
`systemctl\s+(status|is-active|is-enabled|is-failed|list-units|list-unit-files|list-timers|show)\b|` +
|
||||||
|
`ethtool|lsmod|lspci|modinfo|dkms|` +
|
||||||
`timedatectl|hostnamectl|systemd-analyze|` +
|
`timedatectl|hostnamectl|systemd-analyze|` +
|
||||||
`docker\s+(ps|images|inspect|logs|version|info|stats)|` +
|
`docker\s+(ps|images|inspect|logs|version|info|stats)|` +
|
||||||
`docker\s+compose\s+(logs|ps|top|config|images|port|cp)\b|` +
|
`docker\s+compose\s+(logs|ps|top|config|images|port|cp)\b|` +
|
||||||
|
|||||||
@@ -46,6 +46,12 @@ func TestClassifyCommand_ReadOnly(t *testing.T) {
|
|||||||
"sudo pct exec 121 -- systemctl status caddy",
|
"sudo pct exec 121 -- systemctl status caddy",
|
||||||
// qm guest exec on a VM, read-only inner.
|
// qm guest exec on a VM, read-only inner.
|
||||||
"qm guest exec 100 -- systemctl status caddy",
|
"qm guest exec 100 -- systemctl status caddy",
|
||||||
|
// Hardware/driver diagnostic commands (F2 fix — 2026-08-12).
|
||||||
|
"ethtool -i eno1",
|
||||||
|
"lsmod",
|
||||||
|
"lspci",
|
||||||
|
"modinfo r8125",
|
||||||
|
"dkms status",
|
||||||
}
|
}
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
if got := ClassifyCommand(c, ""); got != RiskReadOnly {
|
if got := ClassifyCommand(c, ""); got != RiskReadOnly {
|
||||||
@@ -171,6 +177,9 @@ func TestClassifyCommand_CompoundReadOnly(t *testing.T) {
|
|||||||
// P4: the exact compound from session d0d562e0 — find + ls + tail +
|
// P4: the exact compound from session d0d562e0 — find + ls + tail +
|
||||||
// echo + journalctl, all read-only segments.
|
// echo + journalctl, all read-only segments.
|
||||||
"ls -lt /var/log/rclone-backup/ | head -20 && tail -3 /var/log/rclone-backup/runs.jsonl || echo \"not found\" && find /var/log/rclone-backup/ -name 'runs.jsonl'",
|
"ls -lt /var/log/rclone-backup/ | head -20 && tail -3 /var/log/rclone-backup/runs.jsonl || echo \"not found\" && find /var/log/rclone-backup/ -name 'runs.jsonl'",
|
||||||
|
// F2 fix: the exact compound diagnostic that was misclassified as
|
||||||
|
// config_mutation (2026-08-12 hubris NIC driver cutover session).
|
||||||
|
"uname -r && echo '---' && ethtool -i eno1 && echo '---' && lsmod | grep r8169 && echo '---' && ip link show eno1 && echo '---' && cat /etc/network/interfaces | head -30",
|
||||||
}
|
}
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
if got := ClassifyCommand(c, ""); got != RiskReadOnly {
|
if got := ClassifyCommand(c, ""); got != RiskReadOnly {
|
||||||
|
|||||||
Reference in New Issue
Block a user