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.
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/CHANGELOG.md +34 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/PKG-INFO +3 -3
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/README.md +1 -1
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/pyproject.toml +3 -2
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/packages.py +12 -1
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/runspec.toml +31 -4
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/venvs.py +2 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/.gitignore +0 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/__init__.py +0 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/_escalation.py +0 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/commands.py +0 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/containers.py +0 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/cron.py +0 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/files.py +0 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/fs/__init__.py +0 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/fs/_dispatch.py +0 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/fs/_worker.py +0 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/fs/cli.py +0 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/investigate.py +0 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/logs.py +0 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/nc_command.py +0 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/network.py +0 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/perf.py +0 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/power.py +0 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/security.py +0 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/services.py +0 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/sudoers.py +0 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/system_info.py +0 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/runspec_linux/webops.py +0 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/tests/__init__.py +0 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/tests/test_escalation.py +0 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/tests/test_files.py +0 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/tests/test_fs.py +0 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/tests/test_inventory.py +0 -0
- {runspec_linux-0.16.0 → runspec_linux-0.18.0}/tests/test_nc_send.py +0 -0
- {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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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",
|
|
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:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|