fix: add ethtool, lsmod, lspci, modinfo, dkms to read-only command allowlist
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
ci / web (push) Has been cancelled
Desktop App / Build Linux (amd64) (push) Has been cancelled
Desktop App / Attach to Release (push) Has been cancelled

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:
2026-08-12 13:27:33 +02:00
parent 7ecf720166
commit 53823595de
2 changed files with 10 additions and 0 deletions

View File

@@ -46,6 +46,12 @@ func TestClassifyCommand_ReadOnly(t *testing.T) {
"sudo pct exec 121 -- systemctl status caddy",
// qm guest exec on a VM, read-only inner.
"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 {
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 +
// 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'",
// 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 {
if got := ClassifyCommand(c, ""); got != RiskReadOnly {