From 66ca1153303c9522c3389178f16398913097d13f Mon Sep 17 00:00:00 2001 From: hushen <190065939+918154429@users.noreply.github.com> Date: Mon, 14 Sep 2026 23:40:28 +0800 Subject: [PATCH 1/4] fix(brain): align Ubuntu-only descriptions with action fences --- CHANGELOG.md | 6 + .../src/planning_tools/propose_plan.rs | 127 ++++++++++-------- 2 files changed, 79 insertions(+), 54 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26c93daa..489dab5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,12 @@ Releases before `0.2.5` predate the public launch; their notes live in the ## [Unreleased] +### Fixed + +- Align planner action descriptions with the Ubuntu execution fence, including + Ufw and the other tool families moved to shared or Debian-family support. + Guard both directions of the description/fence relationship (#416). + ## [0.15.0] — 2026-09-10 ### Changed diff --git a/crates/sysknife-brain/src/planning_tools/propose_plan.rs b/crates/sysknife-brain/src/planning_tools/propose_plan.rs index 2da06882..d51521e9 100644 --- a/crates/sysknife-brain/src/planning_tools/propose_plan.rs +++ b/crates/sysknife-brain/src/planning_tools/propose_plan.rs @@ -192,11 +192,11 @@ this is runtime status, NOT the saved configuration; on Ubuntu the saved config "disable a swap file, remove it, and drop its /etc/fstab entry — param: file* (must already be a swap file per /proc/swaps or /etc/fstab, and not a symlink); High risk"), // apt pinning (preferences.d) — Ubuntu/Debian only ("GetAptPins", - "show apt pin priorities (apt-cache policy) — param: package (optional); Ubuntu only; read-only"), + "show apt pin priorities (apt-cache policy) — param: package (optional); read-only"), ("SetAptPin", - "pin a package to a version/release via /etc/apt/preferences.d — params: name*, package* (glob), pin* (e.g. 'version 1.24.*' or 'release a=noble-security'), priority* (int -1..1000); Ubuntu only; Medium risk"), + "pin a package to a version/release via /etc/apt/preferences.d — params: name*, package* (glob), pin* (e.g. 'version 1.24.*' or 'release a=noble-security'), priority* (int -1..1000); Medium risk"), ("RemoveAptPin", - "remove a SysKnife-managed apt pin — param: name*; Ubuntu only; Medium risk"), + "remove a SysKnife-managed apt pin — param: name*; Medium risk"), // Scoped sudoers.d ("GetSudoGrants", "list SysKnife-managed sudoers.d drop-ins — no params; read-only"), @@ -294,33 +294,33 @@ this is runtime status, NOT the saved configuration; on Ubuntu the saved config "show SysKnife's own job log — optional params: limit (int), status_filter, action_filter, since_hours (int)"), // ── Ubuntu / apt — package management ──────────────────────────────────── ("AptUpdate", - "refresh apt package index (apt-get update) — no params; Ubuntu only"), + "refresh apt package index (apt-get update) — no params"), ("AptUpgrade", - "upgrade all installed packages via dist-upgrade — no params; Ubuntu only; High risk"), + "upgrade all installed packages via dist-upgrade — no params; High risk"), ("AptInstall", - "install a package — param: package* (string, e.g. nginx); Ubuntu only"), + "install a package — param: package* (string, e.g. nginx)"), ("AptRemove", - "remove a package, keep config files — param: package*; Ubuntu only"), + "remove a package, keep config files — param: package*"), ("AptPurge", - "remove a package AND its config files — param: package*; Ubuntu only"), + "remove a package AND its config files — param: package*"), ("AptAutoremove", - "remove automatically-installed packages no longer needed — no params; Ubuntu only"), + "remove automatically-installed packages no longer needed — no params"), ("AptHold", - "pin a package at its current version (apt-mark hold) — param: package*; Ubuntu only"), + "pin a package at its current version (apt-mark hold) — param: package*"), ("AptUnhold", - "unpin a package to allow upgrades (apt-mark unhold) — param: package*; Ubuntu only"), + "unpin a package to allow upgrades (apt-mark unhold) — param: package*"), ("AptSearch", - "search apt repos for packages — param: term*; Ubuntu only; read-only"), + "search apt repos for packages — param: term*; read-only"), ("AptListInstalled", - "list all installed packages (dpkg -l) — no params; Ubuntu only; read-only"), + "list all installed packages (dpkg -l) — no params; read-only"), ("AptShow", - "show package details (version, deps, description) — param: package*; Ubuntu only; read-only"), + "show package details (version, deps, description) — param: package*; read-only"), ("AptListUpgradable", - "list packages with available upgrades — no params; Ubuntu only; read-only. Use for 'are there pending updates?' or 'what updates are available?'"), + "list packages with available upgrades — no params; read-only. Use for 'are there pending updates?' or 'what updates are available?'"), ("AptHistoryList", - "show recent apt transaction history — no params; Ubuntu only; read-only"), + "show recent apt transaction history — no params; read-only"), ("ConfigureUnattendedUpgrades", - "enable or disable automatic security updates (unattended-upgrades) — param: enabled* (bool); Ubuntu only; High risk"), + "enable or disable automatic security updates (unattended-upgrades) — param: enabled* (bool); High risk"), // ── Ubuntu / ppa — Launchpad PPAs ───────────────────────────────────────── ("AddPpa", "add a Launchpad PPA — param: name* in / format (e.g. 'deadsnakes/ppa'); Ubuntu only; requires software-properties-common"), @@ -328,55 +328,55 @@ this is runtime status, NOT the saved configuration; on Ubuntu the saved config "remove a Launchpad PPA — param: name* in / format; Ubuntu only"), // ── Ubuntu / snap ───────────────────────────────────────────────────────── ("SnapInstall", - "install a snap (auto-holds to prevent auto-refresh) — params: name*; optional: channel (default stable), auto_update (bool, default false); Ubuntu only"), + "install a snap (auto-holds to prevent auto-refresh) — params: name*; optional: channel (default stable), auto_update (bool, default false)"), ("SnapRemove", - "remove a snap — param: name*; Ubuntu only"), + "remove a snap — param: name*"), ("SnapRefresh", - "update a snap or all snaps — param: name (optional, omit for all); Ubuntu only"), + "update a snap or all snaps — param: name (optional, omit for all)"), ("SnapHold", - "pin a snap at its current version (snap refresh --hold) — param: name*; Ubuntu only"), + "pin a snap at its current version (snap refresh --hold) — param: name*"), ("SnapUnhold", - "allow a held snap to auto-refresh again — param: name*; Ubuntu only"), + "allow a held snap to auto-refresh again — param: name*"), ("SnapList", - "list installed snaps — no params; Ubuntu only; read-only"), + "list installed snaps — no params; read-only"), ("SnapInfo", - "show snap details (version, channel, description) — param: name*; Ubuntu only; read-only"), + "show snap details (version, channel, description) — param: name*; read-only"), ("SnapRevert", - "revert a snap to its previous revision — param: name*; Ubuntu only"), + "revert a snap to its previous revision — param: name*"), ("SnapClassicInstall", - "install a snap with classic confinement (full system access) — param: name*; Ubuntu only"), + "install a snap with classic confinement (full system access) — param: name*"), // ── Ubuntu / ufw — firewall ─────────────────────────────────────────────── ("UfwEnable", - "enable the ufw firewall — no params; Ubuntu only; High risk"), + "enable the ufw firewall — no params; High risk"), ("UfwDisable", - "disable the ufw firewall — no params; Ubuntu only; High risk"), + "disable the ufw firewall — no params; High risk"), ("UfwAllow", - "allow inbound traffic on a port or service — param: port_or_service* (e.g. 22, 22/tcp, OpenSSH); Ubuntu only; High risk"), + "allow inbound traffic on a port or service — param: port_or_service* (e.g. 22, 22/tcp, OpenSSH); High risk"), ("UfwDeny", - "deny inbound traffic on a port or service — param: port_or_service*; Ubuntu only; High risk"), + "deny inbound traffic on a port or service — param: port_or_service*; High risk"), ("UfwReset", - "reset ufw to defaults, removing all rules — no params; Ubuntu only; High risk; irreversible"), + "reset ufw to defaults, removing all rules — no params; High risk; irreversible"), ("UfwStatus", "show current ufw status and rules — optional param: numbered (boolean, default false); true runs ufw status numbered and exposes rule_number values for UfwDeleteRule, false keeps verbose status; read-only"), // ── Ubuntu / distrobox — container environment ──────────────────────────── ("DistroboxList", - "list distrobox containers — no params; Ubuntu only; read-only"), + "list distrobox containers — no params; read-only"), ("DistroboxCreate", - "create a distrobox container — params: name*, image* (e.g. ubuntu:24.04, fedora:41); Ubuntu only"), + "create a distrobox container — params: name*, image* (e.g. ubuntu:24.04, fedora:41)"), ("DistroboxRemove", - "remove a distrobox container — param: name*; Ubuntu only"), + "remove a distrobox container — param: name*"), // ── Ubuntu / netplan — server network config ────────────────────────────── ("NetplanGetConfig", - "read the SAVED network configuration: the netplan YAML in /etc/netplan/ — no params; Ubuntu only; \ + "read the SAVED network configuration: the netplan YAML in /etc/netplan/ — no params; \ read-only; on Ubuntu this is what \"the network config\" means, as opposed to GetNetworkStatus which \ reports live interface state"), ("NetplanApply", - "apply netplan network configuration immediately — no params; Ubuntu only; High risk; can disconnect SSH"), + "apply netplan network configuration immediately — no params; High risk; can disconnect SSH"), // ── Ubuntu / grub — kernel arguments ───────────────────────────────────── ("GrubGetKargs", - "read current GRUB_CMDLINE_LINUX from /etc/default/grub — no params; Ubuntu only; read-only"), + "read current GRUB_CMDLINE_LINUX from /etc/default/grub — no params; read-only"), ("GrubSetKargs", - "modify GRUB kernel arguments and run update-grub — params: append (list), delete (list), bare tokens only (no '='); both lists are screened for boot-security downgrades; Ubuntu only; High risk; requires reboot"), + "modify GRUB kernel arguments and run update-grub — params: append (list), delete (list), bare tokens only (no '='); both lists are screened for boot-security downgrades; High risk; requires reboot"), // ── Ubuntu / reboot ─────────────────────────────────────────────────────── ("CheckPendingReboot", "check whether a reboot is pending (/var/run/reboot-required) — no params; Ubuntu only; read-only"), @@ -387,32 +387,32 @@ reports live interface state"), "set DNS servers for a network interface — params: interface* (e.g. eth0), servers* (string[]); cross-distro; High risk"), // ── Ubuntu / AppArmor ───────────────────────────────────────────────────── ("AppArmorStatus", - "show status of all loaded AppArmor profiles (aa-status) — no params; Ubuntu only; read-only"), + "show status of all loaded AppArmor profiles (aa-status) — no params; read-only"), ("AppArmorEnforce", - "put an AppArmor profile into enforce mode (aa-enforce) — param: profile_path* (e.g. /etc/apparmor.d/usr.bin.firefox); Ubuntu only; High risk"), + "put an AppArmor profile into enforce mode (aa-enforce) — param: profile_path* (e.g. /etc/apparmor.d/usr.bin.firefox); High risk"), ("AppArmorComplain", - "put an AppArmor profile into complain/learning mode (aa-complain) — param: profile_path*; Ubuntu only; High risk (disables MAC enforcement for the profile)"), + "put an AppArmor profile into complain/learning mode (aa-complain) — param: profile_path*; High risk (disables MAC enforcement for the profile)"), // ── Ubuntu / cloud-init ─────────────────────────────────────────────────── ("CloudInitStatus", - "show cloud-init provisioning status (cloud-init status --long) — no params; Ubuntu only; read-only"), + "show cloud-init provisioning status (cloud-init status --long) — no params; read-only"), // ── Ubuntu / Flatpak (Ubuntu-specific routing) ──────────────────────────── ("UbuntuInstallFlatpak", - "install a Flatpak app on Ubuntu — params: username*, app_id*, remote* (e.g. flathub); Ubuntu only; Medium risk"), + "install a Flatpak app — params: username*, app_id*, remote* (e.g. flathub); Medium risk"), ("UbuntuRemoveFlatpak", - "remove a Flatpak app on Ubuntu — params: username*, app_id*; Ubuntu only; Medium risk"), + "remove a Flatpak app — params: username*, app_id*; Medium risk"), ("UbuntuUpdateFlatpak", - "update Flatpak app(s) on Ubuntu — param: username*; optional: app_id (omit for all); Ubuntu only; Medium risk"), + "update Flatpak app(s) — param: username*; optional: app_id (omit for all); Medium risk"), ("UbuntuListFlatpaks", - "list installed Flatpak apps on Ubuntu — param: username*; Ubuntu only; read-only"), + "list installed Flatpak apps — param: username*; read-only"), // ── Ubuntu / fail2ban ───────────────────────────────────────────────────── ("Fail2banStatus", - "show fail2ban jail status — optional param: jail (omit for all jails); Ubuntu only; read-only"), + "show fail2ban jail status — optional param: jail (omit for all jails); read-only"), ("Fail2banBanIp", - "ban an IP address in a fail2ban jail — params: jail* (string), ip* (IPv4 or IPv6); Ubuntu only; High risk"), + "ban an IP address in a fail2ban jail — params: jail* (string), ip* (IPv4 or IPv6); High risk"), ("Fail2banUnbanIp", - "unban an IP address from a fail2ban jail — params: jail*, ip*; Ubuntu only; Medium risk"), + "unban an IP address from a fail2ban jail — params: jail*, ip*; Medium risk"), ("ConfigureFail2banJail", - "write a fail2ban jail override (/etc/fail2ban/jail.d/) — params: name*, plus at least one of enabled (bool), maxretry (1-100), bantime/findtime (seconds 0-2592000); Ubuntu only; High risk; needs fail2ban installed"), + "write a fail2ban jail override (/etc/fail2ban/jail.d/) — params: name*, plus at least one of enabled (bool), maxretry (1-100), bantime/findtime (seconds 0-2592000); High risk; needs fail2ban installed"), // ── auditd file-watch rules (cross-distro) ─────────────────────────────── ("GetAuditRules", "list loaded audit rules (auditctl -l) — no params; read-only; needs auditd installed"), @@ -429,14 +429,14 @@ reports live interface state"), "renew due certbot certificates (certbot renew) — no params; Medium risk; needs certbot + network"), // ── Ubuntu / Tier 3 — netplan extensions ───────────────────────────────── ("NetplanSet", - "set a single netplan key to a value — params: key* (e.g. 'ethernets.eth0.dhcp4'), value*; Ubuntu only; High risk; run NetplanApply to activate"), + "set a single netplan key to a value — params: key* (e.g. 'ethernets.eth0.dhcp4'), value*; High risk; run NetplanApply to activate"), ("NetplanGenerate", - "regenerate netplan backend config without applying — no params; Ubuntu only; Medium risk; dry-run before NetplanApply"), + "regenerate netplan backend config without applying — no params; Medium risk; dry-run before NetplanApply"), // ── Ubuntu / Tier 3 — ufw extensions ───────────────────────────────────── ("UfwDeleteRule", "delete a ufw rule by number — param: rule_number* (positive integer from query_ufw_rules or UfwStatus with numbered=true); never guess a rule number, and refresh after rule changes; High risk"), ("UfwLimit", - "add rate-limiting rule on a port/service (>6 connections/30s blocked) — param: target* (e.g. '22' or 'ssh'); Ubuntu only; High risk; use for SSH brute-force mitigation"), + "add rate-limiting rule on a port/service (>6 connections/30s blocked) — param: target* (e.g. '22' or 'ssh'); High risk; use for SSH brute-force mitigation"), // ── Ubuntu / Tier 3 — release upgrade ──────────────────────────────────── ("UbuntuReleaseUpgrade", "upgrade to the next Ubuntu release (do-release-upgrade) — no params; Ubuntu only; High risk; takes 20–45 min; requires reboot; only for explicit distribution upgrade requests"), @@ -456,7 +456,7 @@ reports live interface state"), "show Canonical Livepatch kernel-patch status — no params; Ubuntu only; read-only; requires canonical-livepatch installed and Ubuntu Pro"), // ── Ubuntu / Tier 3 — Multipass ────────────────────────────────────────── ("MultipassList", - "list Multipass VMs and their state — no params; Ubuntu only; read-only"), + "list Multipass VMs and their state — no params; read-only"), ]; /// Should `action` be offered on the detected distribution? @@ -724,6 +724,25 @@ pub fn parse_proposed_plan(intent: &str, input: &serde_json::Value) -> Result) -> ToolDefinition { let hint = family.map(|family| sysknife_types::DistroHint { id: if family == DISTRO_FAMILY_DEBIAN { From fc53c7298b5783c9ab7dfc5f17dfaa8b7644d68a Mon Sep 17 00:00:00 2001 From: hushen <190065939+918154429@users.noreply.github.com> Date: Mon, 14 Sep 2026 23:51:45 +0800 Subject: [PATCH 2/4] docs: regenerate action reference from corrected descriptions --- docs/action-reference.md | 108 +++++++++++++++++++-------------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/docs/action-reference.md b/docs/action-reference.md index 59df9200..90186aa6 100644 --- a/docs/action-reference.md +++ b/docs/action-reference.md @@ -56,10 +56,10 @@ Every row is derived from the live code: the command from each action's `ActionS | `RemoveFlatpakRemote` | `sudo runuser -u testuser -- flatpak remote-delete --user remote` | Medium | All | – | – | remove a Flatpak remote — params: username\*, remote\* (name) | | `GetFlatpakAppInfo` | `sudo runuser -u testuser -- flatpak info --user app-id` | Low | All | – | – | show metadata for an installed Flatpak — params: username\*, app_id\* | | `UpdateFlatpak` | `sudo runuser -u testuser -- flatpak update --user -y com.example.App` | Medium | All | – | – | update Flatpak apps — params: username\* (required); app_id (optional — omit to update all) | -| `UbuntuInstallFlatpak` | `sudo runuser -u testuser -- flatpak install --user -y flathub app-id` | Medium | Ubuntu | – | – | install a Flatpak app on Ubuntu — params: username\*, app_id\*, remote\* (e.g. flathub); Ubuntu only; Medium risk | -| `UbuntuRemoveFlatpak` | `sudo runuser -u testuser -- flatpak uninstall --user -y app-id` | Medium | Ubuntu | – | – | remove a Flatpak app on Ubuntu — params: username\*, app_id\*; Ubuntu only; Medium risk | -| `UbuntuUpdateFlatpak` | `sudo runuser -u testuser -- flatpak update --user -y com.example.App` | Medium | Ubuntu | – | – | update Flatpak app(s) on Ubuntu — param: username\*; optional: app_id (omit for all); Ubuntu only; Medium risk | -| `UbuntuListFlatpaks` | `sudo runuser -u testuser -- flatpak list --user --app --columns=application,name,version,origin` | Low | Ubuntu | – | – | list installed Flatpak apps on Ubuntu — param: username\*; Ubuntu only; read-only | +| `UbuntuInstallFlatpak` | `sudo runuser -u testuser -- flatpak install --user -y flathub app-id` | Medium | Ubuntu | – | – | install a Flatpak app — params: username\*, app_id\*, remote\* (e.g. flathub); Medium risk | +| `UbuntuRemoveFlatpak` | `sudo runuser -u testuser -- flatpak uninstall --user -y app-id` | Medium | Ubuntu | – | – | remove a Flatpak app — params: username\*, app_id\*; Medium risk | +| `UbuntuUpdateFlatpak` | `sudo runuser -u testuser -- flatpak update --user -y com.example.App` | Medium | Ubuntu | – | – | update Flatpak app(s) — param: username\*; optional: app_id (omit for all); Medium risk | +| `UbuntuListFlatpaks` | `sudo runuser -u testuser -- flatpak list --user --app --columns=application,name,version,origin` | Low | Ubuntu | – | – | list installed Flatpak apps — param: username\*; read-only | ## Toolbox @@ -262,51 +262,51 @@ Every row is derived from the live code: the command from each action's `ActionS | Action | Command | Risk | Distro | Rb | Ro | Description | |---|---|---|---|---|---|---| -| `AppArmorStatus` | `sudo aa-status` | Low | Ubuntu | – | – | show status of all loaded AppArmor profiles (aa-status) — no params; Ubuntu only; read-only | -| `AppArmorEnforce` | `sudo aa-enforce /etc/apparmor.d/usr.bin.firefox` | High | Ubuntu | – | – | put an AppArmor profile into enforce mode (aa-enforce) — param: profile_path\* (e.g. /etc/apparmor.d/usr.bin.firefox); Ubuntu only; High risk | -| `AppArmorComplain` | `sudo aa-complain /etc/apparmor.d/usr.bin.firefox` | High | Ubuntu | – | – | put an AppArmor profile into complain/learning mode (aa-complain) — param: profile_path\*; Ubuntu only; High risk (disables MAC enforcement for the profile) | +| `AppArmorStatus` | `sudo aa-status` | Low | Ubuntu | – | – | show status of all loaded AppArmor profiles (aa-status) — no params; read-only | +| `AppArmorEnforce` | `sudo aa-enforce /etc/apparmor.d/usr.bin.firefox` | High | Ubuntu | – | – | put an AppArmor profile into enforce mode (aa-enforce) — param: profile_path\* (e.g. /etc/apparmor.d/usr.bin.firefox); High risk | +| `AppArmorComplain` | `sudo aa-complain /etc/apparmor.d/usr.bin.firefox` | High | Ubuntu | – | – | put an AppArmor profile into complain/learning mode (aa-complain) — param: profile_path\*; High risk (disables MAC enforcement for the profile) | ## cloud-init | Action | Command | Risk | Distro | Rb | Ro | Description | |---|---|---|---|---|---|---| -| `CloudInitStatus` | `cloud-init status --long` | Low | Ubuntu | – | – | show cloud-init provisioning status (cloud-init status --long) — no params; Ubuntu only; read-only | +| `CloudInitStatus` | `cloud-init status --long` | Low | Ubuntu | – | – | show cloud-init provisioning status (cloud-init status --long) — no params; read-only | ## fail2ban | Action | Command | Risk | Distro | Rb | Ro | Description | |---|---|---|---|---|---|---| -| `Fail2banStatus` | `sudo fail2ban-client status` | Low | Ubuntu | – | – | show fail2ban jail status — optional param: jail (omit for all jails); Ubuntu only; read-only | -| `Fail2banBanIp` | `sudo fail2ban-client set sshd banip 192.0.2.1` | High | Ubuntu | – | – | ban an IP address in a fail2ban jail — params: jail\* (string), ip\* (IPv4 or IPv6); Ubuntu only; High risk | -| `Fail2banUnbanIp` | `sudo fail2ban-client set sshd unbanip 192.0.2.1` | Medium | Ubuntu | – | – | unban an IP address from a fail2ban jail — params: jail\*, ip\*; Ubuntu only; Medium risk | -| `ConfigureFail2banJail` | `sudo /usr/lib/sysknife/fail2ban-jail-edit --name sshd --maxretry 3` | High | Ubuntu | – | – | write a fail2ban jail override (/etc/fail2ban/jail.d/) — params: name\*, plus at least one of enabled (bool), maxretry (1-100), bantime/findtime (seconds 0-2592000); Ubuntu only; High risk; needs fail2ban installed | +| `Fail2banStatus` | `sudo fail2ban-client status` | Low | Ubuntu | – | – | show fail2ban jail status — optional param: jail (omit for all jails); read-only | +| `Fail2banBanIp` | `sudo fail2ban-client set sshd banip 192.0.2.1` | High | Ubuntu | – | – | ban an IP address in a fail2ban jail — params: jail\* (string), ip\* (IPv4 or IPv6); High risk | +| `Fail2banUnbanIp` | `sudo fail2ban-client set sshd unbanip 192.0.2.1` | Medium | Ubuntu | – | – | unban an IP address from a fail2ban jail — params: jail\*, ip\*; Medium risk | +| `ConfigureFail2banJail` | `sudo /usr/lib/sysknife/fail2ban-jail-edit --name sshd --maxretry 3` | High | Ubuntu | – | – | write a fail2ban jail override (/etc/fail2ban/jail.d/) — params: name\*, plus at least one of enabled (bool), maxretry (1-100), bantime/findtime (seconds 0-2592000); High risk; needs fail2ban installed | ## apt | Action | Command | Risk | Distro | Rb | Ro | Description | |---|---|---|---|---|---|---| -| `AptUpdate` | `sudo env DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a /usr/bin/apt-get update` | Low | Ubuntu | – | – | refresh apt package index (apt-get update) — no params; Ubuntu only | -| `AptUpgrade` | `sudo env DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a /usr/bin/apt-get dist-upgrade -y` | High | Ubuntu | – | – | upgrade all installed packages via dist-upgrade — no params; Ubuntu only; High risk | -| `AptInstall` | `sudo env DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a /usr/bin/apt-get install -y curl` | Medium | Ubuntu | – | – | install a package — param: package\* (string, e.g. nginx); Ubuntu only | -| `AptRemove` | `sudo env DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a /usr/bin/apt-get remove -y curl` | Medium | Ubuntu | – | – | remove a package, keep config files — param: package\*; Ubuntu only | -| `AptPurge` | `sudo env DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a /usr/bin/apt-get purge -y curl` | Medium | Ubuntu | – | – | remove a package AND its config files — param: package\*; Ubuntu only | -| `AptAutoremove` | `sudo env DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a /usr/bin/apt-get autoremove -y` | Medium | Ubuntu | – | – | remove automatically-installed packages no longer needed — no params; Ubuntu only | -| `AptHold` | `sudo apt-mark hold curl` | Medium | Ubuntu | – | – | pin a package at its current version (apt-mark hold) — param: package\*; Ubuntu only | -| `AptUnhold` | `sudo apt-mark unhold curl` | Medium | Ubuntu | – | – | unpin a package to allow upgrades (apt-mark unhold) — param: package\*; Ubuntu only | -| `AptSearch` | `apt-cache search curl` | Low | Ubuntu | – | – | search apt repos for packages — param: term\*; Ubuntu only; read-only | -| `AptListInstalled` | `dpkg -l` | Low | Ubuntu | – | – | list all installed packages (dpkg -l) — no params; Ubuntu only; read-only | -| `AptShow` | `apt-cache show curl` | Low | Ubuntu | – | – | show package details (version, deps, description) — param: package\*; Ubuntu only; read-only | -| `AptListUpgradable` | `bash -c "apt list --upgradable 2>/dev/null"` | Low | Ubuntu | – | – | list packages with available upgrades — no params; Ubuntu only; read-only. Use for 'are there pending updates?' or 'what updates are available?' | -| `AptHistoryList` | `bash -c "grep -A 4 '^Start-Date' /var/log/apt/history.log \| tail -n 80"` | Low | Ubuntu | – | – | show recent apt transaction history — no params; Ubuntu only; read-only | -| `ConfigureUnattendedUpgrades` | `sudo /usr/lib/sysknife/unattended-upgrades-edit --enable` | High | Ubuntu | – | – | enable or disable automatic security updates (unattended-upgrades) — param: enabled\* (bool); Ubuntu only; High risk | +| `AptUpdate` | `sudo env DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a /usr/bin/apt-get update` | Low | Ubuntu | – | – | refresh apt package index (apt-get update) — no params | +| `AptUpgrade` | `sudo env DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a /usr/bin/apt-get dist-upgrade -y` | High | Ubuntu | – | – | upgrade all installed packages via dist-upgrade — no params; High risk | +| `AptInstall` | `sudo env DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a /usr/bin/apt-get install -y curl` | Medium | Ubuntu | – | – | install a package — param: package\* (string, e.g. nginx) | +| `AptRemove` | `sudo env DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a /usr/bin/apt-get remove -y curl` | Medium | Ubuntu | – | – | remove a package, keep config files — param: package\* | +| `AptPurge` | `sudo env DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a /usr/bin/apt-get purge -y curl` | Medium | Ubuntu | – | – | remove a package AND its config files — param: package\* | +| `AptAutoremove` | `sudo env DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a /usr/bin/apt-get autoremove -y` | Medium | Ubuntu | – | – | remove automatically-installed packages no longer needed — no params | +| `AptHold` | `sudo apt-mark hold curl` | Medium | Ubuntu | – | – | pin a package at its current version (apt-mark hold) — param: package\* | +| `AptUnhold` | `sudo apt-mark unhold curl` | Medium | Ubuntu | – | – | unpin a package to allow upgrades (apt-mark unhold) — param: package\* | +| `AptSearch` | `apt-cache search curl` | Low | Ubuntu | – | – | search apt repos for packages — param: term\*; read-only | +| `AptListInstalled` | `dpkg -l` | Low | Ubuntu | – | – | list all installed packages (dpkg -l) — no params; read-only | +| `AptShow` | `apt-cache show curl` | Low | Ubuntu | – | – | show package details (version, deps, description) — param: package\*; read-only | +| `AptListUpgradable` | `bash -c "apt list --upgradable 2>/dev/null"` | Low | Ubuntu | – | – | list packages with available upgrades — no params; read-only. Use for 'are there pending updates?' or 'what updates are available?' | +| `AptHistoryList` | `bash -c "grep -A 4 '^Start-Date' /var/log/apt/history.log \| tail -n 80"` | Low | Ubuntu | – | – | show recent apt transaction history — no params; read-only | +| `ConfigureUnattendedUpgrades` | `sudo /usr/lib/sysknife/unattended-upgrades-edit --enable` | High | Ubuntu | – | – | enable or disable automatic security updates (unattended-upgrades) — param: enabled\* (bool); High risk | ## apt preferences / pinning | Action | Command | Risk | Distro | Rb | Ro | Description | |---|---|---|---|---|---|---| -| `GetAptPins` | `apt-cache policy` | Low | Ubuntu | – | – | show apt pin priorities (apt-cache policy) — param: package (optional); Ubuntu only; read-only | -| `SetAptPin` | `sudo /usr/lib/sysknife/apt-pin-edit --op set --name hold-nginx --package nginx --pin "version 1.24.*" --priority 990` | Medium | Ubuntu | – | – | pin a package to a version/release via /etc/apt/preferences.d — params: name\*, package\* (glob), pin\* (e.g. 'version 1.24.\*' or 'release a=noble-security'), priority\* (int -1..1000); Ubuntu only; Medium risk | -| `RemoveAptPin` | `sudo /usr/lib/sysknife/apt-pin-edit --op remove --name hold-nginx` | Medium | Ubuntu | – | – | remove a SysKnife-managed apt pin — param: name\*; Ubuntu only; Medium risk | +| `GetAptPins` | `apt-cache policy` | Low | Ubuntu | – | – | show apt pin priorities (apt-cache policy) — param: package (optional); read-only | +| `SetAptPin` | `sudo /usr/lib/sysknife/apt-pin-edit --op set --name hold-nginx --package nginx --pin "version 1.24.*" --priority 990` | Medium | Ubuntu | – | – | pin a package to a version/release via /etc/apt/preferences.d — params: name\*, package\* (glob), pin\* (e.g. 'version 1.24.\*' or 'release a=noble-security'), priority\* (int -1..1000); Medium risk | +| `RemoveAptPin` | `sudo /usr/lib/sysknife/apt-pin-edit --op remove --name hold-nginx` | Medium | Ubuntu | – | – | remove a SysKnife-managed apt pin — param: name\*; Medium risk | ## PPA @@ -319,52 +319,52 @@ Every row is derived from the live code: the command from each action's `ActionS | Action | Command | Risk | Distro | Rb | Ro | Description | |---|---|---|---|---|---|---| -| `SnapInstall` | `sudo sh -c "snap install --channel=stable firefox && snap refresh --hold firefox"` | Medium | Ubuntu | – | – | install a snap (auto-holds to prevent auto-refresh) — params: name\*; optional: channel (default stable), auto_update (bool, default false); Ubuntu only | -| `SnapRemove` | `sudo snap remove firefox` | Medium | Ubuntu | – | – | remove a snap — param: name\*; Ubuntu only | -| `SnapRefresh` | `sudo snap refresh firefox` | Medium | Ubuntu | – | – | update a snap or all snaps — param: name (optional, omit for all); Ubuntu only | -| `SnapHold` | `sudo snap refresh --hold firefox` | Medium | Ubuntu | – | – | pin a snap at its current version (snap refresh --hold) — param: name\*; Ubuntu only | -| `SnapUnhold` | `sudo snap refresh --unhold firefox` | Medium | Ubuntu | – | – | allow a held snap to auto-refresh again — param: name\*; Ubuntu only | -| `SnapList` | `snap list` | Low | Ubuntu | – | – | list installed snaps — no params; Ubuntu only; read-only | -| `SnapInfo` | `snap info firefox` | Low | Ubuntu | – | – | show snap details (version, channel, description) — param: name\*; Ubuntu only; read-only | -| `SnapRevert` | `sudo snap revert firefox` | Medium | Ubuntu | – | – | revert a snap to its previous revision — param: name\*; Ubuntu only | -| `SnapClassicInstall` | `sudo snap install --classic code` | Medium | Ubuntu | – | – | install a snap with classic confinement (full system access) — param: name\*; Ubuntu only | +| `SnapInstall` | `sudo sh -c "snap install --channel=stable firefox && snap refresh --hold firefox"` | Medium | Ubuntu | – | – | install a snap (auto-holds to prevent auto-refresh) — params: name\*; optional: channel (default stable), auto_update (bool, default false) | +| `SnapRemove` | `sudo snap remove firefox` | Medium | Ubuntu | – | – | remove a snap — param: name\* | +| `SnapRefresh` | `sudo snap refresh firefox` | Medium | Ubuntu | – | – | update a snap or all snaps — param: name (optional, omit for all) | +| `SnapHold` | `sudo snap refresh --hold firefox` | Medium | Ubuntu | – | – | pin a snap at its current version (snap refresh --hold) — param: name\* | +| `SnapUnhold` | `sudo snap refresh --unhold firefox` | Medium | Ubuntu | – | – | allow a held snap to auto-refresh again — param: name\* | +| `SnapList` | `snap list` | Low | Ubuntu | – | – | list installed snaps — no params; read-only | +| `SnapInfo` | `snap info firefox` | Low | Ubuntu | – | – | show snap details (version, channel, description) — param: name\*; read-only | +| `SnapRevert` | `sudo snap revert firefox` | Medium | Ubuntu | – | – | revert a snap to its previous revision — param: name\* | +| `SnapClassicInstall` | `sudo snap install --classic code` | Medium | Ubuntu | – | – | install a snap with classic confinement (full system access) — param: name\* | ## ufw | Action | Command | Risk | Distro | Rb | Ro | Description | |---|---|---|---|---|---|---| -| `UfwEnable` | `sudo ufw --force enable` | High | Ubuntu | – | – | enable the ufw firewall — no params; Ubuntu only; High risk | -| `UfwDisable` | `sudo ufw disable` | High | Ubuntu | – | – | disable the ufw firewall — no params; Ubuntu only; High risk | -| `UfwAllow` | `sudo ufw allow 22` | High | Ubuntu | – | – | allow inbound traffic on a port or service — param: port_or_service\* (e.g. 22, 22/tcp, OpenSSH); Ubuntu only; High risk | -| `UfwDeny` | `sudo ufw deny 23` | High | Ubuntu | – | – | deny inbound traffic on a port or service — param: port_or_service\*; Ubuntu only; High risk | -| `UfwReset` | `sudo ufw --force reset` | High | Ubuntu | – | – | reset ufw to defaults, removing all rules — no params; Ubuntu only; High risk; irreversible | +| `UfwEnable` | `sudo ufw --force enable` | High | Ubuntu | – | – | enable the ufw firewall — no params; High risk | +| `UfwDisable` | `sudo ufw disable` | High | Ubuntu | – | – | disable the ufw firewall — no params; High risk | +| `UfwAllow` | `sudo ufw allow 22` | High | Ubuntu | – | – | allow inbound traffic on a port or service — param: port_or_service\* (e.g. 22, 22/tcp, OpenSSH); High risk | +| `UfwDeny` | `sudo ufw deny 23` | High | Ubuntu | – | – | deny inbound traffic on a port or service — param: port_or_service\*; High risk | +| `UfwReset` | `sudo ufw --force reset` | High | Ubuntu | – | – | reset ufw to defaults, removing all rules — no params; High risk; irreversible | | `UfwStatus` | `sudo ufw status verbose` | Low | Ubuntu | – | – | show current ufw status and rules — optional param: numbered (boolean, default false); true runs ufw status numbered and exposes rule_number values for UfwDeleteRule, false keeps verbose status; read-only | | `UfwDeleteRule` | `sudo ufw --force delete 1` | High | Ubuntu | – | – | delete a ufw rule by number — param: rule_number\* (positive integer from query_ufw_rules or UfwStatus with numbered=true); never guess a rule number, and refresh after rule changes; High risk | -| `UfwLimit` | `sudo ufw limit 22` | High | Ubuntu | – | – | add rate-limiting rule on a port/service (>6 connections/30s blocked) — param: target\* (e.g. '22' or 'ssh'); Ubuntu only; High risk; use for SSH brute-force mitigation | +| `UfwLimit` | `sudo ufw limit 22` | High | Ubuntu | – | – | add rate-limiting rule on a port/service (>6 connections/30s blocked) — param: target\* (e.g. '22' or 'ssh'); High risk; use for SSH brute-force mitigation | ## netplan | Action | Command | Risk | Distro | Rb | Ro | Description | |---|---|---|---|---|---|---| -| `NetplanGetConfig` | `find /etc/netplan -maxdepth 1 -name *.yaml -print -exec cat {} +` | Low | Ubuntu | – | – | read the SAVED network configuration: the netplan YAML in /etc/netplan/ — no params; Ubuntu only; read-only; on Ubuntu this is what "the network config" means, as opposed to GetNetworkStatus which reports live interface state | -| `NetplanApply` | `sudo netplan apply` | High | Ubuntu | – | – | apply netplan network configuration immediately — no params; Ubuntu only; High risk; can disconnect SSH | -| `NetplanSet` | `sudo netplan set ethernets.eth0.dhcp4=true` | High | Ubuntu | – | – | set a single netplan key to a value — params: key\* (e.g. 'ethernets.eth0.dhcp4'), value\*; Ubuntu only; High risk; run NetplanApply to activate | -| `NetplanGenerate` | `sudo netplan generate` | Medium | Ubuntu | – | – | regenerate netplan backend config without applying — no params; Ubuntu only; Medium risk; dry-run before NetplanApply | +| `NetplanGetConfig` | `find /etc/netplan -maxdepth 1 -name *.yaml -print -exec cat {} +` | Low | Ubuntu | – | – | read the SAVED network configuration: the netplan YAML in /etc/netplan/ — no params; read-only; on Ubuntu this is what "the network config" means, as opposed to GetNetworkStatus which reports live interface state | +| `NetplanApply` | `sudo netplan apply` | High | Ubuntu | – | – | apply netplan network configuration immediately — no params; High risk; can disconnect SSH | +| `NetplanSet` | `sudo netplan set ethernets.eth0.dhcp4=true` | High | Ubuntu | – | – | set a single netplan key to a value — params: key\* (e.g. 'ethernets.eth0.dhcp4'), value\*; High risk; run NetplanApply to activate | +| `NetplanGenerate` | `sudo netplan generate` | Medium | Ubuntu | – | – | regenerate netplan backend config without applying — no params; Medium risk; dry-run before NetplanApply | ## distrobox | Action | Command | Risk | Distro | Rb | Ro | Description | |---|---|---|---|---|---|---| -| `DistroboxList` | `distrobox list` | Low | Ubuntu | – | – | list distrobox containers — no params; Ubuntu only; read-only | -| `DistroboxCreate` | `distrobox create --yes --name dev --image ubuntu:24.04` | Medium | Ubuntu | – | – | create a distrobox container — params: name\*, image\* (e.g. ubuntu:24.04, fedora:41); Ubuntu only | -| `DistroboxRemove` | `distrobox rm --force dev` | Medium | Ubuntu | – | – | remove a distrobox container — param: name\*; Ubuntu only | +| `DistroboxList` | `distrobox list` | Low | Ubuntu | – | – | list distrobox containers — no params; read-only | +| `DistroboxCreate` | `distrobox create --yes --name dev --image ubuntu:24.04` | Medium | Ubuntu | – | – | create a distrobox container — params: name\*, image\* (e.g. ubuntu:24.04, fedora:41) | +| `DistroboxRemove` | `distrobox rm --force dev` | Medium | Ubuntu | – | – | remove a distrobox container — param: name\* | ## GRUB | Action | Command | Risk | Distro | Rb | Ro | Description | |---|---|---|---|---|---|---| -| `GrubGetKargs` | `grep -E ^GRUB_CMDLINE_LINUX /etc/default/grub` | Low | Ubuntu | – | – | read current GRUB_CMDLINE_LINUX from /etc/default/grub — no params; Ubuntu only; read-only | -| `GrubSetKargs` | `sudo /usr/lib/sysknife/grub-kargs-edit --append quiet --delete splash` | High | Ubuntu | ✓ | – | modify GRUB kernel arguments and run update-grub — params: append (list), delete (list), bare tokens only (no '='); both lists are screened for boot-security downgrades; Ubuntu only; High risk; requires reboot | +| `GrubGetKargs` | `grep -E ^GRUB_CMDLINE_LINUX /etc/default/grub` | Low | Ubuntu | – | – | read current GRUB_CMDLINE_LINUX from /etc/default/grub — no params; read-only | +| `GrubSetKargs` | `sudo /usr/lib/sysknife/grub-kargs-edit --append quiet --delete splash` | High | Ubuntu | ✓ | – | modify GRUB kernel arguments and run update-grub — params: append (list), delete (list), bare tokens only (no '='); both lists are screened for boot-security downgrades; High risk; requires reboot | ## Ubuntu release upgrade @@ -392,7 +392,7 @@ Every row is derived from the live code: the command from each action's `ActionS | Action | Command | Risk | Distro | Rb | Ro | Description | |---|---|---|---|---|---|---| -| `MultipassList` | `multipass list` | Low | Ubuntu | – | – | list Multipass VMs and their state — no params; Ubuntu only; read-only | +| `MultipassList` | `multipass list` | Low | Ubuntu | – | – | list Multipass VMs and their state — no params; read-only | --- From 581fbaa4640fac376da5e386aae8a1df29c61ff3 Mon Sep 17 00:00:00 2001 From: hushen <190065939+918154429@users.noreply.github.com> Date: Tue, 15 Sep 2026 00:04:52 +0800 Subject: [PATCH 3/4] test: record Linux CI measured workspace baseline --- README.md | 2 +- docs/distro-support.md | 2 +- docs/introduction.md | 2 +- tests/evidence/workspace-tests.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a381ad8e..4f187be2 100644 --- a/README.md +++ b/README.md @@ -314,7 +314,7 @@ milestone. | **Every Ubuntu LTS validated** — 22.04, 24.04 and 26.04 all at 79/79, each with a replay twin that reproduces it | ✅ | | Telegram approval interface | 📋 roadmap | -**1,852 Rust tests and 72 frontend tests** form the current deterministic +**1,853 Rust tests and 72 frontend tests** form the current deterministic release baseline. ## Configure your LLM diff --git a/docs/distro-support.md b/docs/distro-support.md index a622c644..0578df7f 100644 --- a/docs/distro-support.md +++ b/docs/distro-support.md @@ -91,7 +91,7 @@ family and the atomic story family are implemented and covered by the workspace suite. What is missing is a way to put the helpers somewhere the daemon's own grants already point. -The deterministic workspace baseline is 1,852 Rust tests plus 72 frontend +The deterministic workspace baseline is 1,853 Rust tests plus 72 frontend tests. Those tests verify action construction, policy, approval, storage, and UI behavior, but they do not replace a real distribution VM run. diff --git a/docs/introduction.md b/docs/introduction.md index 2b0c7c76..25bd9d63 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -141,7 +141,7 @@ flow. ## Status -190 typed actions · 1,852 Rust tests + 72 frontend tests · MIT +190 typed actions · 1,853 Rust tests + 72 frontend tests · MIT SysKnife is the reference implementation of the [LACS specification](https://github.com/lacs-project/specification) — a diff --git a/tests/evidence/workspace-tests.json b/tests/evidence/workspace-tests.json index f40c3476..e175f7b4 100644 --- a/tests/evidence/workspace-tests.json +++ b/tests/evidence/workspace-tests.json @@ -4,6 +4,6 @@ "tests": "cargo nextest run --workspace --locked" }, "frontend_tests": 72, - "tests": 1852, + "tests": 1853, "version": 2 } From 33285c61bae7f87e059d6a2092dbcfc44f7cb696 Mon Sep 17 00:00:00 2001 From: hushen <190065939+918154429@users.noreply.github.com> Date: Tue, 15 Sep 2026 00:18:00 +0800 Subject: [PATCH 4/4] fix: upgrade rustls for RUSTSEC-2026-0285 --- Cargo.lock | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 83cebc79..acd832f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -242,9 +242,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-lc-rs" -version = "1.16.3" +version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ec6fb3fe69024a75fa7e1bfb48aa6cf59706a101658ea01bfd33b2b248a038f" +checksum = "b281d307588d634de920874890732659e2e7672f72b5e10e81badc1a8a83621e" dependencies = [ "aws-lc-sys", "zeroize", @@ -252,14 +252,15 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.40.0" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f50037ee5e1e41e7b8f9d161680a725bd1626cb6f8c7e901f91f942850852fe7" +checksum = "9bff6c3b54fad79a2e60b8102caf565819711497c1f5f092f49508e2f5c31b27" dependencies = [ "cc", "cmake", "dunce", "fs_extra", + "pkg-config", ] [[package]] @@ -4010,9 +4011,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.39" +version = "0.23.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c2c118cb077cca2822033836dfb1b975355dfb784b5e8da48f7b6c5db74e60e" +checksum = "0d41d731c7d2f962d1ccc364cec258de3c0e93b38c2fb3ba97ac74513048d634" dependencies = [ "aws-lc-rs", "once_cell", @@ -4074,9 +4075,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.103.13" +version = "0.103.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2" dependencies = [ "aws-lc-rs", "ring",