runspec-linux 0.16.0__tar.gz → 0.18.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/CHANGELOG.md +34 -0
  2. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/PKG-INFO +3 -3
  3. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/README.md +1 -1
  4. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/pyproject.toml +3 -2
  5. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/packages.py +12 -1
  6. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/runspec.toml +31 -4
  7. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/venvs.py +2 -0
  8. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/.gitignore +0 -0
  9. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/__init__.py +0 -0
  10. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/_escalation.py +0 -0
  11. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/commands.py +0 -0
  12. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/containers.py +0 -0
  13. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/cron.py +0 -0
  14. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/files.py +0 -0
  15. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/fs/__init__.py +0 -0
  16. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/fs/_dispatch.py +0 -0
  17. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/fs/_worker.py +0 -0
  18. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/fs/cli.py +0 -0
  19. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/investigate.py +0 -0
  20. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/logs.py +0 -0
  21. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/nc_command.py +0 -0
  22. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/network.py +0 -0
  23. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/perf.py +0 -0
  24. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/power.py +0 -0
  25. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/security.py +0 -0
  26. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/services.py +0 -0
  27. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/sudoers.py +0 -0
  28. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/system_info.py +0 -0
  29. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/webops.py +0 -0
  30. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/tests/__init__.py +0 -0
  31. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/tests/test_escalation.py +0 -0
  32. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/tests/test_files.py +0 -0
  33. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/tests/test_fs.py +0 -0
  34. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/tests/test_inventory.py +0 -0
  35. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/tests/test_nc_send.py +0 -0
  36. {runspec_linux-0.16.0 → runspec_linux-0.18.0}/tests/test_webops.py +0 -0
@@ -1,5 +1,39 @@
1
1
  # runspec-linux Changelog
2
2
 
3
+ ## [0.18.0] — 2026-09-29
4
+
5
+ ### Added
6
+
7
+ - **`create-venv` sets up the logs inbox** (`logs/inbox`, `01777`, owned by the
8
+ venv's owner). Operators' and root's runs of the venv's runnables then reach
9
+ its history with no group admin (runspec >= 0.66). `logs/` is owner-only
10
+ (`0755`) unless `--group` is given. `--no-inbox` keeps the pre-inbox `2775`
11
+ layout and writes a `.no-inbox` opt-out marker.
12
+ - **`share-venv-logs` sets up the logs inbox** on an existing venv (run it with
13
+ `--run-as <owner>`). `--group` still adds the `2775` setgid group share, and
14
+ `--no-inbox` does only the group share, as before.
15
+
16
+ ### Changed
17
+
18
+ - **`install-into-venv` keeps `logs/`'s mode** instead of forcing `2775`.
19
+ - Requires `runspec-linux-core >= 0.12.0`.
20
+
21
+ ## [0.17.0] — 2026-09-26
22
+
23
+ ### Added
24
+
25
+ - **`list-autoremovable`** (autonomous, no root) previews what
26
+ `autoremove-packages` would remove, so an agent can check the list without an
27
+ approval prompt. `--purge` previews a purge. Not supported on yum.
28
+ - **`list-packages --reason`** says whether each package was installed by name
29
+ (`manual`) or as a dependency (`auto`). Autoremove only removes `auto`
30
+ packages, so this answers "why isn't this old kernel an autoremove
31
+ candidate?" instead of leaving it to a guess.
32
+
33
+ ### Changed
34
+
35
+ - Requires `runspec-linux-core >= 0.11.0`.
36
+
3
37
  ## [0.16.0] — 2026-09-26
4
38
 
5
39
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: runspec-linux
3
- Version: 0.16.0
3
+ Version: 0.18.0
4
4
  Summary: Linux system admin runnables for runspec
5
5
  Project-URL: Documentation, https://runspec.app/
6
6
  Project-URL: Source, https://github.com/jasonfinestone/runspec/tree/main/packages/python/runspec-linux
@@ -9,7 +9,7 @@ Project-URL: Issues, https://github.com/jasonfinestone/runspec/issues
9
9
  Keywords: linux,ops,runnable,runspec,ssh,sysadmin,venv
10
10
  Requires-Python: >=3.10
11
11
  Requires-Dist: runspec-fs-core>=0.5.0
12
- Requires-Dist: runspec-linux-core>=0.10.0
12
+ Requires-Dist: runspec-linux-core>=0.12.0
13
13
  Requires-Dist: runspec-webops-core>=0.3.0
14
14
  Requires-Dist: runspec>=0.50.1
15
15
  Provides-Extra: dev
@@ -51,7 +51,7 @@ pip install runspec-linux
51
51
  | Files | `find-large-files`, `backup-files`, `owning-package` |
52
52
  | Sessions | `last-logins`, `who` |
53
53
  | Containers | `list-containers`, `container-logs`, `restart-container` |
54
- | Packages | `list-packages`, `list-upgrades`, `upgrade-packages`, `install-package`, `remove-package`, `autoremove-packages` |
54
+ | Packages | `list-packages`, `list-upgrades`, `upgrade-packages`, `install-package`, `remove-package`, `autoremove-packages`, `list-autoremovable` |
55
55
  | Power | `reboot-host` |
56
56
  | Sudo bootstrap | `enable-passwordless-sudo` |
57
57
  | Python venvs | `create-venv`, `install-into-venv`, `configure-pip` |
@@ -31,7 +31,7 @@ pip install runspec-linux
31
31
  | Files | `find-large-files`, `backup-files`, `owning-package` |
32
32
  | Sessions | `last-logins`, `who` |
33
33
  | Containers | `list-containers`, `container-logs`, `restart-container` |
34
- | Packages | `list-packages`, `list-upgrades`, `upgrade-packages`, `install-package`, `remove-package`, `autoremove-packages` |
34
+ | Packages | `list-packages`, `list-upgrades`, `upgrade-packages`, `install-package`, `remove-package`, `autoremove-packages`, `list-autoremovable` |
35
35
  | Power | `reboot-host` |
36
36
  | Sudo bootstrap | `enable-passwordless-sudo` |
37
37
  | Python venvs | `create-venv`, `install-into-venv`, `configure-pip` |
@@ -4,14 +4,14 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "runspec-linux"
7
- version = "0.16.0"
7
+ version = "0.18.0"
8
8
  requires-python = ">=3.10"
9
9
  description = "Linux system admin runnables for runspec"
10
10
  readme = "README.md"
11
11
  keywords = ["runspec", "runnable", "linux", "sysadmin", "ops", "ssh", "venv"]
12
12
  dependencies = [
13
13
  "runspec>=0.50.1",
14
- "runspec-linux-core>=0.10.0",
14
+ "runspec-linux-core>=0.12.0",
15
15
  "runspec-webops-core>=0.3.0",
16
16
  "runspec-fs-core>=0.5.0",
17
17
  ]
@@ -63,6 +63,7 @@ upgrade-packages = "runspec_linux.packages:main_upgrade_packages"
63
63
  install-package = "runspec_linux.packages:main_install_package"
64
64
  remove-package = "runspec_linux.packages:main_remove_package"
65
65
  autoremove-packages = "runspec_linux.packages:main_autoremove_packages"
66
+ list-autoremovable = "runspec_linux.packages:main_list_autoremovable"
66
67
  reboot-host = "runspec_linux.power:main_reboot_host"
67
68
  enable-passwordless-sudo = "runspec_linux.sudoers:main_enable_passwordless_sudo"
68
69
  create-venv = "runspec_linux.venvs:main_create_venv"
@@ -5,6 +5,7 @@ import runspec as rs
5
5
  from runspec_linux_core import (
6
6
  autoremove_packages,
7
7
  install_package,
8
+ list_autoremovable,
8
9
  list_packages,
9
10
  list_upgrades,
10
11
  remove_package,
@@ -18,7 +19,7 @@ def main_list_packages() -> None:
18
19
  name_filter = spec.filter.value
19
20
  limit = spec.limit.value
20
21
  try:
21
- print(json.dumps(list_packages(name_filter, limit)))
22
+ print(json.dumps(list_packages(name_filter, limit, reason=spec.reason.value)))
22
23
  except Exception as e:
23
24
  # Includes ToolNotFoundError (no package manager) and CommandError.
24
25
  print(json.dumps({"error": str(e)}))
@@ -75,6 +76,16 @@ def main_remove_package() -> None:
75
76
  sys.exit(1)
76
77
 
77
78
 
79
+ def main_list_autoremovable() -> None:
80
+ spec = rs.parse("list-autoremovable")
81
+ try:
82
+ print(json.dumps(list_autoremovable(purge=spec.purge.value)))
83
+ except Exception as e:
84
+ # Includes CommandError (yum, failed listing) and ToolNotFoundError.
85
+ print(json.dumps({"error": str(e)}))
86
+ sys.exit(1)
87
+
88
+
78
89
  def main_autoremove_packages() -> None:
79
90
  spec = rs.parse("autoremove-packages")
80
91
  try:
@@ -483,6 +483,11 @@ short = "-n"
483
483
  description = "Maximum number of packages to return (sorted by name)"
484
484
  default = 100
485
485
 
486
+ [list-packages.args.reason]
487
+ type = "flag"
488
+ description = "Also say whether each package was installed by name (manual) or as a dependency (auto) — autoremove only ever removes auto packages"
489
+ default = false
490
+
486
491
  [list-upgrades]
487
492
  serve = ["local"]
488
493
  description = "List packages with an available upgrade (refreshes the package index first)"
@@ -531,6 +536,17 @@ type = "flag"
531
536
  description = "Also delete the packages' configuration files (apt purge / pacman -Rn; a plain remove on dnf/yum/zypper)"
532
537
  default = false
533
538
 
539
+ [list-autoremovable]
540
+ serve = ["local"]
541
+ description = "List the packages autoremove-packages would remove (read-only preview; not supported on yum)"
542
+ autonomy = "autonomous"
543
+ output = "json"
544
+
545
+ [list-autoremovable.args.purge]
546
+ type = "flag"
547
+ description = "Preview a purge (apt shows config files would go too)"
548
+ default = false
549
+
534
550
  [autoremove-packages]
535
551
  serve = ["local"]
536
552
  description = "Remove packages nothing depends on any more, e.g. old kernels (apt autoremove and equivalents; needs root)"
@@ -545,7 +561,7 @@ default = false
545
561
 
546
562
  [autoremove-packages.args.dry-run]
547
563
  type = "flag"
548
- description = "Only list what would be removed; remove nothing (not supported on yum)"
564
+ description = "Only list what would be removed; remove nothing (not supported on yum). list-autoremovable does the same without needing approval"
549
565
  default = false
550
566
 
551
567
  # ── Power ─────────────────────────────────────────────────────────────────────
@@ -664,7 +680,7 @@ required = false
664
680
 
665
681
  [create-venv]
666
682
  serve = ["local"]
667
- description = "Create a Python virtualenv (always --symlinks) from a specific interpreter, optionally as a service account, with a shared 2775 logs/ dir"
683
+ description = "Create a Python virtualenv (always --symlinks) from a specific interpreter, optionally as a service account, with a logs inbox so every account's runs reach its history"
668
684
  autonomy = "confirm"
669
685
  output = "json"
670
686
 
@@ -695,6 +711,11 @@ short = "-g"
695
711
  description = "Optional shared group to chgrp the venv to (e.g. consoles), so every connected console can read/write"
696
712
  required = false
697
713
 
714
+ [create-venv.args.no-inbox]
715
+ type = "flag"
716
+ description = "Don't set up the logs inbox (logs/inbox, 01777) — keep the pre-inbox layout (logs/ 2775) and write a logs/.no-inbox opt-out marker. Default: the inbox is created, so operators' and root's runs reach this venv's history with no group admin (runspec >= 0.66)"
717
+ default = false
718
+
698
719
  [create-venv.args.system-site-packages]
699
720
  type = "flag"
700
721
  description = "Give the venv access to the system site-packages"
@@ -846,12 +867,13 @@ description = "How to escalate to run-as: sudo (passwordless, -n) or su"
846
867
 
847
868
  [share-venv-logs]
848
869
  serve = ["local"]
849
- description = "Make an existing venv's logs/ dir shared (2775 + setgid, optional chgrp) so the per-venv runs DB and audit logs are writable across a console group — the repair for a venv not built with create-venv --group"
870
+ description = "Make an existing venv's logs shared: set up the logs inbox (logs/inbox, 01777) so every account's runs reach its history — plus, with --group, the 2775 setgid group share. Run as the venv owner (--run-as)"
850
871
  autonomy = "confirm"
851
872
  output = "json"
852
873
 
853
874
  examples = [
854
- {cmd = "share-venv-logs --venv /opt/venvs/app", description = "Make /opt/venvs/app/logs group-writable + setgid (keeps its current group)"},
875
+ {cmd = "share-venv-logs --venv /opt/venvs/app --run-as svc", description = "Set up the logs inbox as the venv's owner — the recommended setup"},
876
+ {cmd = "share-venv-logs --venv /opt/venvs/app --no-inbox", description = "The pre-inbox group share only: logs/ group-writable + setgid"},
855
877
  {cmd = "share-venv-logs --venv /opt/venvs/app --group consoles", description = "...and chgrp the logs dir to the shared 'consoles' group"},
856
878
  {cmd = "share-venv-logs --venv /opt/venvs/app --group consoles --run-as svc", description = "Run as the service account that owns the venv (via sudo -n -u)"},
857
879
  ]
@@ -868,6 +890,11 @@ short = "-g"
868
890
  description = "Optional shared group to chgrp the logs/ dir to (e.g. consoles), so every connected console can read/write. Omit to keep the current group"
869
891
  required = false
870
892
 
893
+ [share-venv-logs.args.no-inbox]
894
+ type = "flag"
895
+ description = "Skip the logs inbox — only the group share (logs/ 2775 setgid, optional chgrp)"
896
+ default = false
897
+
871
898
  [share-venv-logs.args.run-as]
872
899
  type = "str"
873
900
  short = "-u"
@@ -19,6 +19,7 @@ def main_create_venv() -> None:
19
19
  upgrade_deps=spec.upgrade_deps.value,
20
20
  clear=spec.clear.value,
21
21
  prompt=spec.prompt.value or None,
22
+ inbox=not spec.no_inbox.value,
22
23
  )
23
24
  print(json.dumps(result))
24
25
  except CommandError as e:
@@ -62,6 +63,7 @@ def main_share_venv_logs() -> None:
62
63
  group=spec.group.value or None,
63
64
  run_as=spec.run_as.value or None,
64
65
  become_method=spec.become_method.value,
66
+ inbox=not spec.no_inbox.value,
65
67
  )
66
68
  print(json.dumps(result))
67
69
  except CommandError as e: