Retain locked isolation recipe and verified dependency closure

This commit is contained in:
codex 2026-10-19 14:59:04 +02:00
parent 8e67cfbb49
commit 04797021fd
36 changed files with 6732 additions and 0 deletions

View file

@ -0,0 +1,127 @@
# CUST73 interactive launch revision 3: locked source recipe
Same proposal/trial as r1/r2; original directories remain unchanged. All live
entry scripts have an unconditional refusal before mutation. No import,
distribution startup, package installation, sudo, authentication, listener,
firewall, service or production change was executed. Removing a source lock is
a new exact revision requiring supervisor disposition before execution.
## Fixed inputs and verified evidence
Target: new WSL2 distro `custodian-codex` on `bnt-lap001`, account/group
`custodian-codex` UID/GID1001, private home `/home/custodian-codex`, SSH alias
`custodian-codex-workstation`, candidate loopback TCP22273. A UID/GID collision,
existing distro/storage location or occupied endpoint refuses execution.
Local Windows store is `$env:LOCALAPPDATA\Custodian\WSL\custodian-codex`.
The actual Windows owner/ACL and loopback reachability must be checked, not
inferred from a path. No global `.wslconfig` or existing distro is modified.
Pinned rootfs: Ubuntu24.04.5 AMD64 `.wsl` from
[official release](https://releases.ubuntu.com/24.04.5/), SHA256
`bb415d824822c4b878125729af451a5d18fb13d1cf5cbed9a7393ad64ac6039e`.
Fetched checksum list and detached signature are retained. `gpgv` verified the
signature with installed Ubuntu cloudimage/archive keyrings, signer
`843938DF228D22F7B3742BC0D94AA3F0EFE21092`. Image bytes were not downloaded;
verify their digest before import. `rootfs.json` records provenance. Ubuntu's
manifest is retained as package information, not independently signed package
closure evidence. It contains Python3 and systemd, but **not openssh-server or
nftables**. Do not claim this image alone can run the recipe.
Pinned installed Codex candidate: 0.163.0, SHA256
`399ff69c431c066e40de318fba45c2b07f45a76b19939d247ee4828fc70c4215`.
`codex-candidate.json` records current user-owned installed binary; publisher
signature/provenance is not established. A trusted artifact must be installed
root-owned at `/usr/local/bin/codex` only after source/transport review. No
operator auth or `.codex` contents are copied. Desktop remote connection may
manage its own executable: confirm which binary it actually launches and bind
that digest; this candidate must not be misrepresented as enforced remotely.
## Files and intended execution sequence after later approval
1. `import-disabled.ps1`: refuses today. Reviewed body validates image SHA and
absent distro/store, then imports only the new name with WSL2. Before enabling,
add exact preflight receipts for Windows owner ACL, free space >=5GiB,
TCP22273 availability, verified WSL version, and native handoff UI support.
Rootfs import is distinct from first boot; no active session is migrated here.
2. Separate package/bootstrap preparation: verify signed Ubuntu apt metadata and
resolve openssh-server/nftables plus dependency closure against this rootfs;
retain exact package names/versions/SHAs and service-install behavior. Package
installation must suppress automatic service startup with a temporary
root-owned `policy-rc.d` returning101, removed only after verified staging.
This closure is an explicit missing input; no unpinned `apt install` is hidden
in the locked script. Transfer reviewed bundle through operator-owned stdin
or artifact channel, not a drive mount made available to the agent.
3. `guest-stage.sh`: refuses today. Intended body verifies root and exact distro,
refuses existing target account/UID/GID, requires dependencies, creates only
UID/GID1001/private home/state, installs wsl/SSH/systemd/nft source. It creates
no key/authentication/launch-approval marker and starts no service. Stage a
fresh root-owned machine identity and pin it in the supervisor receipt.
4. Stop/restart only this new distribution to activate `wsl.conf`; never invoke
global `wsl --shutdown`. Verify effective disabled interop/automount, no shared
host mounts/sockets, and namespace scope before loading any nft rules. WSL
distributions' actual network relationship must be observed: do not apply an
output UID rule if it could affect UID1001 in another guest/network namespace.
5. SSH service source hides host/shared paths for its process tree, retains
native stdio sessions, and uses loopback only. The nft initial policy blocks
new account egress; service requires a root-owned launch approval marker and
separately authorized public key. No agent edits those files. Run `sshd -t`
and `sshd -T`, `nft --check -f`, systemd unit verification, and boot-denial
canaries in the new guest before enabling. These checks were NOT run live.
6. Model/Hub egress remains closed. Resolve exact endpoints and constrain required
outgoing connections without admitting host/admin/private network control
planes; this requires a reviewed egress amendment and credential route. Do
not remove the firewall to make inference work. Login with closed egress is
transport preparation, never completed assignment admission.
7. Install scoped Codex authentication and clean checkout, then operator's native
existing-chat handoff. The [Codex remote connection guide](https://learn.chatgpt.com/docs/remote-connections)
specifies SSH startup and existing-chat handoff; the actual UI availability
answer is pending. Preserve [native approvals](https://learn.chatgpt.com/docs/app-server).
Bind actual tool process identity, chat association and approved/denied action
proofs plus original CUST73 negative checks before declaring isolation.
`verify-guest.py` is deliberately partial: checks identity, group/home/state,
configuration and visible Windows paths only. Its success does not certify
network policy, root sudo policy, other mount paths, cgroup restrictions,
host identity, connector capability scope or assignment admission. Machine-ID
plus UID probe from r2 remains relevant; root-owned marker is not attestation.
## Source-backed design
[Microsoft WSL configuration](https://learn.microsoft.com/en-us/windows/wsl/wsl-config)
documents per-distribution systemd, automount and interop settings. Settings
require restart; disabled automount does not prevent a privileged manual mount.
[Import guide](https://learn.microsoft.com/en-us/windows/wsl/use-custom-distro)
documents named WSL2 import and default root entry. This is why account/boot
controls precede any chat attachment. The SSH service's systemd source adds a
restricted mount view but still needs guest validation, especially Codex's
nested sandbox and foreground app-server lifetime. If it breaks the runtime,
revise exact controls and test; do not disable them silently.
## Approval, estimates and recovery
Expected result of staging: new dormant dedicated guest with reviewed source,
private account and closed egress. Expected result is NOT a working authenticated
Codex assignment. Runtime transport and admission are separately verified steps.
Estimated incremental infrastructure cost EUR0; no model requests in staging.
Budget proposal: <=5GiB initial local storage (image around371MiB), SSH process
tree MemoryMax2GiB/CPUQuota100%/TasksMax256, operator30–60minutes. Actual available
disk/RAM are unverified; package downloads and inference would be separately
bounded. Cost/risk numbers are estimates requiring supervisor acceptance.
Estimated failure recovery30minutes; privileged workstation configuration risk
moderate, production risk low because no production change is proposed. The
main risks are Windows/WSL host escape surfaces, shared networking scope,
unproven runtime compatibility, auth leakage and accidental old-session use.
Rollback: stop work/disconnect the destination, retain receipts, and terminate
only `custodian-codex` after explicit confirmation of its identity. Preserve guest
storage for inspection; never unregister/delete it automatically. Do not resume
assignment tools under old UID1000. Original workstation distro and production
k3s remain unaffected by the proposed target choice. If an existing distribution
or namespace would be modified, stop; the approved scope would no longer match.
Remaining hard inputs before executable approval: UI answer; signed package
closure; trusted actual runtime binary; rootfs byte hash; Windows ACL/disk/port;
namespace/firewall compatibility; scoped auth and egress; full admission tests.
This revision replaces null design choices with concrete files/pins, and leaves
unverified facts explicit rather than filling them with guessed success.

View file

@ -0,0 +1,16 @@
83bc3f93733671818100ccb5dd7b4c512445b967d24f913c0baf722cf27d4b50 PROPOSAL.md
a2d332239ecb1ae4e5343ab580e21fce6e0588a3f603a0719e53a79cbcc9ac1e closed-egress.nft
d97a19841db6f25eadb3aa38f3f5cd3e3562dcd95d99c5ff8ae88d6e8ca6532a codex-candidate.json
ecbf50d94009d951b3f8ca577e2abb7676beebcabe92ae556c9b28178193a39c cust73-network.service
29ff4a7ac6130403d5689de759eb6c132fd4f644e1513ca210d47ff764600f55 cust73-sshd.service
15d6db145f3b44605ed118eb794527bffb43aa1e4981be974de50b12158f604b guest-stage.sh
dbe735fb8251f4cb9df14df9feb778f01bf92f2e812b8b6e9ffe5da16664af5b import-disabled.ps1
6a420bc04fb5a5eacb38539b6e130e28a254c90194103539b60aba29a2de002d rootfs.json
6fe4fc37f892daed9ef3c9c25624cbe247962053f08adb50957dcba046e0e880 sshd_config
5b44effbca14afd8efb40ccf160bf5a2d24b2b8037a787a146effd2ffc3aa779 test_recipe.py
728064ecf411f4ab702d9c3ca0a938ce672771424c028a1b52b2449f7eb5a068 ubuntu-SHA256SUMS
f9be4b4a527b63f14dde0387edcb7a02ba3ac43d537b1674a5aeae19c6f23827 ubuntu-SHA256SUMS.gpg
5bb19729f514a7f1fe42d29f91afcf4cbcd8489f2740e5c0ccbd8832d4aaec81 ubuntu-rootfs.manifest
fbc27b9572abb198eb78223679a0a5912e2f3b11737c8c0724dc24f1d6d9b9fb validation.json
77335cc839457967de4bcb3ee3589ea262b2a52f41017d4caa5934030fd81702 verify-guest.py
e94ba4d9527947ebc84dc1cfc6bc9f4ee861f345ecee7ae03a3917b722e4799f wsl.conf

View file

@ -0,0 +1,9 @@
# Account UID is fixed by guest-stage.sh; no rule for another distro is authorized.
# New outgoing connections fail closed. This does not enable model inference.
table inet cust73_initial {
chain output {
type filter hook output priority -10; policy accept;
meta skuid 1001 ct state established,related accept
meta skuid 1001 counter reject
}
}

View file

@ -0,0 +1,9 @@
{
"observed_version_directory": "0.163.0-x86_64-unknown-linux-musl",
"source_path": "/home/worsch/.codex/packages/app-server-daemon/releases/0.163.0-x86_64-unknown-linux-musl/bin/codex",
"sha256": "399ff69c431c066e40de318fba45c2b07f45a76b19939d247ee4828fc70c4215",
"source_owner_uid": 1000,
"origin_signature_verified": false,
"install_destination": "/usr/local/bin/codex",
"capture_utc": "2026-10-19T12:49:35.583050+00:00"
}

View file

@ -0,0 +1,11 @@
[Unit]
Description=Initial closed egress for Custodian account
Before=cust73-sshd.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/sbin/nft -f /etc/cust73/closed-egress.nft
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,30 @@
[Unit]
Description=Dedicated Custodian Codex SSH transport (not assignment admission)
Requires=cust73-network.service
After=network.target cust73-network.service
ConditionPathExists=/etc/cust73/authorized_keys
ConditionPathExists=/etc/cust73/launch-approved
[Service]
Type=simple
ExecStartPre=/usr/local/lib/cust73/verify-guest.py
ExecStartPre=/usr/sbin/sshd -t -f /etc/cust73/sshd_config
ExecStart=/usr/sbin/sshd -D -e -f /etc/cust73/sshd_config
Restart=no
UMask=0077
NoNewPrivileges=yes
PrivateTmp=yes
PrivateMounts=yes
ProtectSystem=strict
ReadWritePaths=/home/custodian-codex /run
ProtectHome=read-only
InaccessiblePaths=/root /mnt /media -/run/WSL -/run/docker.sock -/run/podman -/run/user/1000
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
MemoryMax=2G
TasksMax=256
CPUQuota=100%
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,41 @@
#!/bin/bash
set -euo pipefail
# Mandatory source-review lock. Removing this line changes the proposal digest.
# This revision is never a live execution authorization, even with sudo.
printf '%s\n' 'REFUSED: CUST73 revision 3 is preparation-only; execution disabled.' >&2
exit 78
# Reviewed staging body for a newly imported named guest only. NOT EXECUTED.
test "$(id -u)" = 0
test "${WSL_DISTRO_NAME:-}" = custodian-codex
test "$(uname -m)" = x86_64
test ! -e /etc/cust73/staged
test ! -e /home/worsch
! getent passwd custodian-codex >/dev/null
! getent passwd 1001 >/dev/null
! getent group 1001 >/dev/null
bundle_dir=/root/cust73-source
test -d "$bundle_dir"
# Dependencies must have been separately staged and verified; never apt-install
# or start services implicitly from a recipe that claims exact package pins.
for exe in /usr/sbin/sshd /usr/sbin/nft /usr/bin/python3 /usr/bin/systemctl; do
test -x "$exe"
done
groupadd --gid 1001 custodian-codex
useradd --uid 1001 --gid 1001 --create-home --shell /bin/bash custodian-codex
passwd --lock custodian-codex
chmod 0700 /home/custodian-codex
install -d -o 1001 -g 1001 -m 0700 /home/custodian-codex/.codex /home/custodian-codex/work
install -d -o root -g root -m 0700 /etc/cust73
install -d -o root -g root -m 0755 /usr/local/lib/cust73 /run/sshd
install -o root -g root -m 0644 "$bundle_dir/wsl.conf" /etc/wsl.conf
install -o root -g root -m 0600 "$bundle_dir/sshd_config" /etc/cust73/sshd_config
install -o root -g root -m 0600 "$bundle_dir/closed-egress.nft" /etc/cust73/closed-egress.nft
install -o root -g root -m 0755 "$bundle_dir/verify-guest.py" /usr/local/lib/cust73/verify-guest.py
install -o root -g root -m 0644 "$bundle_dir/cust73-sshd.service" /etc/systemd/system/cust73-sshd.service
install -o root -g root -m 0644 "$bundle_dir/cust73-network.service" /etc/systemd/system/cust73-network.service
install -o root -g root -m 0600 /dev/null /etc/cust73/staged
printf '%s\n' custodian-codex > /etc/cust73/distribution-name
chmod 0600 /etc/cust73/distribution-name
# No authorized key, Codex auth, listener approval marker, daemon start or enable.
# Dedicated guest must first be stopped/restarted to apply wsl.conf.

View file

@ -0,0 +1,20 @@
# Preparation-only: the import body cannot execute in this revision.
throw 'REFUSED: CUST73 revision 3 has no distribution-creation authorization.'
$ErrorActionPreference = 'Stop'
$DistroName = 'custodian-codex'
$Image = Join-Path $PSScriptRoot 'ubuntu-24.04.5-wsl-amd64.wsl'
$Expected = 'bb415d824822c4b878125729af451a5d18fb13d1cf5cbed9a7393ad64ac6039e'
$Store = Join-Path $env:LOCALAPPDATA 'Custodian\WSL\custodian-codex'
if ((Get-FileHash -Algorithm SHA256 -LiteralPath $Image).Hash.ToLower() -ne $Expected) {
throw 'Rootfs digest mismatch'
}
$Existing = (& wsl.exe --list --quiet) -replace "`0", ''
if ($LASTEXITCODE -ne 0) { throw 'WSL inventory unavailable' }
if ($Existing.Trim() -contains $DistroName) { throw 'Distribution already exists' }
if (Test-Path -LiteralPath $Store) { throw 'Destination already exists' }
# ACL/rootfs/signature/free-space checks in PROPOSAL.md must precede this body.
# --import does not copy the operator home; no existing distro is exported.
& wsl.exe --import $DistroName $Store $Image --version 2
if ($LASTEXITCODE -ne 0) { throw 'Import failed; retain evidence, do not unregister' }
# Do not start a guest, clone a repo, copy credentials or install Codex here.

View file

@ -0,0 +1,12 @@
{
"distribution": "Ubuntu",
"version": "24.04.5",
"architecture": "amd64",
"url": "https://releases.ubuntu.com/24.04.5/ubuntu-24.04.5-wsl-amd64.wsl",
"sha256": "bb415d824822c4b878125729af451a5d18fb13d1cf5cbed9a7393ad64ac6039e",
"checksums_url": "https://releases.ubuntu.com/24.04.5/SHA256SUMS",
"capture_utc": "2026-10-19T12:47:10.334895+00:00",
"rootfs_downloaded": false,
"signature_verified": true,
"signer_fingerprint": "843938DF228D22F7B3742BC0D94AA3F0EFE21092"
}

View file

@ -0,0 +1,28 @@
Port 22273
ListenAddress 127.0.0.1
AddressFamily inet
HostKey /etc/ssh/ssh_host_ed25519_key
PidFile /run/cust73-sshd.pid
AllowUsers custodian-codex
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
AuthenticationMethods publickey
AuthorizedKeysFile /etc/cust73/authorized_keys
StrictModes yes
UsePAM yes
PermitEmptyPasswords no
PermitUserEnvironment no
PermitUserRC no
AllowAgentForwarding no
AllowTcpForwarding no
AllowStreamLocalForwarding no
GatewayPorts no
X11Forwarding no
PermitTunnel no
MaxAuthTries 3
MaxSessions 4
LoginGraceTime 30
LogLevel INFO
Subsystem sftp internal-sftp

View file

@ -0,0 +1,44 @@
import importlib.util
from pathlib import Path
import subprocess
import unittest
BASE = Path(__file__).parent
spec = importlib.util.spec_from_file_location('verify_guest', BASE/'verify-guest.py')
m = importlib.util.module_from_spec(spec); spec.loader.exec_module(m)
class RecipeTests(unittest.TestCase):
def good(self):
return dict(distro='custodian-codex',uid=1001,gid=1001,home_mode=0o700,
state_mode=0o700,home_uid=1001,state_uid=1001,groups=[1001],
interop='false',automount='false',mount_fstab='false',
windows_mount=False,operator_home=False,interop_handler=False)
def test_partial_pass_is_never_admission(self):
r=m.check_snapshot(self.good())
self.assertTrue(r['partial_preflight_passed']); self.assertFalse(r['assignment_admitted'])
def test_each_missing_boundary_blocks(self):
for key,bad in dict(distro='Ubuntu-24.04',uid=1000,gid=0,home_mode=0o755,
state_mode=0o755,home_uid=0,state_uid=0,groups=[1001,27],
interop='true',automount='true',mount_fstab='true',
windows_mount=True,operator_home=True,interop_handler=True).items():
with self.subTest(key=key):
s=self.good();s[key]=bad
self.assertFalse(m.check_snapshot(s)['partial_preflight_passed'])
def test_script_lock_refuses_without_privileges(self):
r=subprocess.run(['bash',str(BASE/'guest-stage.sh')],capture_output=True,text=True)
self.assertEqual(r.returncode,78);self.assertIn('execution disabled',r.stderr)
def test_shell_syntax(self):
subprocess.run(['bash','-n',str(BASE/'guest-stage.sh')],check=True)
def test_import_remains_locked(self):
lines=[x for x in (BASE/'import-disabled.ps1').read_text().splitlines() if x and not x.startswith('#')]
self.assertTrue(lines[0].startswith("throw 'REFUSED:"))
if __name__ == '__main__':
unittest.main()

View file

@ -0,0 +1,9 @@
faabcf33ae53976d2b8207a001ff32f4e5daae013505ac7188c9ea63988f8328 *ubuntu-24.04.3-desktop-amd64.iso
c3514bf0056180d09376462a7a1b4f213c1d6e8ea67fae5c25099c6fd3d8274b *ubuntu-24.04.3-live-server-amd64.iso
c74833a55e525b1e99e1541509c566bb3e32bdb53bf27ea3347174364a57f47c *ubuntu-24.04.3-wsl-amd64.wsl
3a4c9877b483ab46d7c3fbe165a0db275e1ae3cfe56a5657e5a47c2f99a99d1e *ubuntu-24.04.4-desktop-amd64.iso
e907d92eeec9df64163a7e454cbc8d7755e8ddc7ed42f99dbc80c40f1a138433 *ubuntu-24.04.4-live-server-amd64.iso
9b2f7730dc68227dd04a9f3e5eab86ad85caf556b8606ad94f1f29ff5c4fd3f5 *ubuntu-24.04.4-wsl-amd64.wsl
97f3d7ffb032c3eb3b23d2c8be9cc76e60c2c1f2c0146ba5ba9fe01cafae0fd8 *ubuntu-24.04.5-live-server-amd64.iso
bb415d824822c4b878125729af451a5d18fb13d1cf5cbed9a7393ad64ac6039e *ubuntu-24.04.5-wsl-amd64.wsl
4da4a0c9035da8e68a59a838674f403f0a54472c78a83b4fb7f78d03588f85a7 *ubuntu-24.04.5.1-desktop-amd64.iso

View file

@ -0,0 +1,16 @@
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEhDk43yKNIvezdCvA2Uqj8O/iEJIFAmqpmFAACgkQ2Uqj8O/i
EJKEexAAoVl86jh5vDagkPiBmkOYJWh2w1cW87bV+IEBC+7nw/r2CNC47XHqYaZe
9h2IwcQpo5JG0Ld4H2+AaX2ldQ263eBFsMLkaTChYqo9E4LQnK/4CWg80lNi+mTL
Uu0+soknJK/MyyYpkd8QF9I4C+0YzTUHv/GkoEDdrTwVHWwUkYhCqIONfj2Un1BI
AYdJuAd5czSAzIbVqEySHMQ+ELVDsyopTYn4v8YJXUQ4ChFok4fOBsvb77FWA2Dh
jzAYv3DmW/UW9RT/1VFfeg8s7aq1cfpwAoFm/blRI795d9PK95W5dlEGDhQ3Fegp
PSdlw4zUpv3K38uAj8BYrfYRhXRgZ6s1viFxsztqVwVO1jJruRZC4oTZ2jGWHSbo
v5ZFqhpjqNCtlEIea8UiKd0kSkaiiPunCghBG74H8h+EhrBsisNQVbI0Ok199b6S
4evE6T+y+Kbdrr3jO6OIArV3NIQoNIhMy6hfi3O1pto5WC7GyCj5kGgwTQ8HEfdb
y7Rygkga7RMXqjw/W76jrlx3r5RToU65LpOQ4EiIao2xHXepYL7Oi2GZQK31ZcvW
M3rz6Ehv4/Kd0KL5niQwkEHsUESlXV37/1YJdtcLEMfcC0+8meWDrpELclSmM0SV
KpqUZDcRSheRAton/AnaTJFPnSuVT+9VjqXDBloTc5nur6/IfR8=
=iUg8
-----END PGP SIGNATURE-----

View file

@ -0,0 +1,523 @@
adduser 3.137ubuntu1
adwaita-icon-theme 46.0-1
apparmor 4.0.1really4.0.1-0ubuntu0.24.04.7
apport 2.28.3-0ubuntu0.1
apport-core-dump-handler 2.28.3-0ubuntu0.1
apport-symptoms 0.25
appstream 1.0.2-1build6
apt 2.8.3
apt-utils 2.8.3
at-spi2-common 2.52.0-1build1
at-spi2-core 2.52.0-1build1
base-files 13ubuntu10.5
base-passwd 3.6.3build1
bash 5.2.21-2ubuntu4
bash-completion 1:2.11-8
bc 1.07.1-3ubuntu4
binutils 2.42-4ubuntu2.10
binutils-common:amd64 2.42-4ubuntu2.10
binutils-x86-64-linux-gnu 2.42-4ubuntu2.10
bsdextrautils 2.39.3-9ubuntu6.6
bsdutils 1:2.39.3-9ubuntu6.6
byobu 6.11-0ubuntu1.1
ca-certificates 20260601~24.04.1
cloud-guest-utils 0.33-1
cloud-init 26.1-0ubuntu1~24.04.1
command-not-found 23.04.0
console-setup 1.226ubuntu1.1
console-setup-linux 1.226ubuntu1.1
coreutils 9.4-3ubuntu6.3
cron 3.0pl1-184ubuntu2
cron-daemon-common 3.0pl1-184ubuntu2
curl 8.5.0-2ubuntu10.13
dash 0.5.12-6ubuntu5
dbus 1.14.10-4ubuntu4.1
dbus-bin 1.14.10-4ubuntu4.1
dbus-daemon 1.14.10-4ubuntu4.1
dbus-session-bus-common 1.14.10-4ubuntu4.1
dbus-system-bus-common 1.14.10-4ubuntu4.1
dbus-user-session 1.14.10-4ubuntu4.1
dbus-x11 1.14.10-4ubuntu4.1
dconf-gsettings-backend:amd64 0.40.0-4ubuntu0.1
dconf-service 0.40.0-4ubuntu0.1
debconf 1.5.86ubuntu1
debconf-i18n 1.5.86ubuntu1
debianutils 5.17build1
dhcpcd-base 1:10.0.6-1ubuntu3.2
diffutils 1:3.10-1ubuntu0.1
dirmngr 2.4.4-2ubuntu17.6
distro-info 1.7build1
distro-info-data 0.72-0ubuntu0.24.04.1
dmsetup 2:1.02.185-3ubuntu3.2
dpkg 1.22.6ubuntu6.6
e2fsprogs 1.47.0-2.4~exp1ubuntu4.1
e2fsprogs-l10n 1.47.0-2.4~exp1ubuntu4.1
eatmydata 131-1ubuntu1
ed 1.20.1-1
eject 2.39.3-9ubuntu6.6
ethtool 1:6.7-1build1
fdisk 2.39.3-9ubuntu6.6
file 1:5.45-3build1
findutils 4.9.0-5build1
fontconfig 2.15.0-1.1ubuntu2
fontconfig-config 2.15.0-1.1ubuntu2
fonts-dejavu-core 2.37-8
fonts-dejavu-mono 2.37-8
fonts-ubuntu 0.869+git20240321-0ubuntu1
fuse3 3.14.0-5build1
gawk 1:5.2.1-2ubuntu0.1
gcc-14-base:amd64 14.2.0-4ubuntu2~24.04.1
gdisk 1.0.10-1build1
gettext-base 0.21-14ubuntu2
gir1.2-girepository-2.0:amd64 1.80.1-1
gir1.2-glib-2.0:amd64 2.80.0-6ubuntu3.8
gir1.2-packagekitglib-1.0 1.2.8-2ubuntu1.5
git 1:2.43.0-1ubuntu7.3
git-man 1:2.43.0-1ubuntu7.3
gnupg 2.4.4-2ubuntu17.6
gnupg-l10n 2.4.4-2ubuntu17.6
gnupg-utils 2.4.4-2ubuntu17.6
gpg 2.4.4-2ubuntu17.6
gpg-agent 2.4.4-2ubuntu17.6
gpg-wks-client 2.4.4-2ubuntu17.6
gpgconf 2.4.4-2ubuntu17.6
gpgsm 2.4.4-2ubuntu17.6
gpgv 2.4.4-2ubuntu17.6
grep 3.11-4build1
groff-base 1.23.0-3build2
gsettings-desktop-schemas 46.1-0ubuntu1
gtk-update-icon-cache 3.24.41-4ubuntu1.3
gzip 1.12-1ubuntu3.2
hicolor-icon-theme 0.17-2
hostname 3.23+nmu2ubuntu2
humanity-icon-theme 0.6.16
info 7.1-3build2
init 1.66ubuntu1
init-system-helpers 1.66ubuntu1
install-info 7.1-3build2
iproute2 6.1.0-1ubuntu6.4
iputils-ping 3:20240117-1ubuntu0.1
iso-codes 4.16.0-1
kbd 2.6.4-2ubuntu2
keyboard-configuration 1.226ubuntu1.1
keyboxd 2.4.4-2ubuntu17.6
kmod 31+20240202-2ubuntu7.2
krb5-locales 1.20.1-6ubuntu2.8
landscape-client 24.02-0ubuntu5.7
landscape-common 24.02-0ubuntu5.7
less 590-2ubuntu2.1
libacl1:amd64 2.3.2-1build1.1
libapparmor1:amd64 4.0.1really4.0.1-0ubuntu0.24.04.7
libappstream5:amd64 1.0.2-1build6
libapt-pkg6.0t64:amd64 2.8.3
libargon2-1:amd64 0~20190702+dfsg-4build1
libassuan0:amd64 2.5.6-1build1
libatk-bridge2.0-0t64:amd64 2.52.0-1build1
libatk1.0-0t64:amd64 2.52.0-1build1
libatm1t64:amd64 1:2.5.1-5.1build1
libatspi2.0-0t64:amd64 2.52.0-1build1
libattr1:amd64 1:2.5.2-1ubuntu0.1
libaudit-common 1:3.1.2-2.1build1.1
libaudit1:amd64 1:3.1.2-2.1build1.1
libavahi-client3:amd64 0.8-13ubuntu6.2
libavahi-common-data:amd64 0.8-13ubuntu6.2
libavahi-common3:amd64 0.8-13ubuntu6.2
libbinutils:amd64 2.42-4ubuntu2.10
libblkid1:amd64 2.39.3-9ubuntu6.6
libbpf1:amd64 1:1.3.0-2build2
libbrotli1:amd64 1.1.0-2build2
libbsd0:amd64 0.12.1-1build1.1
libbz2-1.0:amd64 1.0.8-5.1ubuntu0.1
libc-bin 2.39-0ubuntu8.8
libc6:amd64 2.39-0ubuntu8.8
libcairo-gobject2:amd64 1.18.0-3build1
libcairo2:amd64 1.18.0-3build1
libcap-ng0:amd64 0.8.4-2build2
libcap2:amd64 1:2.66-5ubuntu2.4
libcap2-bin 1:2.66-5ubuntu2.4
libcbor0.10:amd64 0.10.2-1.2ubuntu2
libcolord2:amd64 1.4.7-1build2
libcom-err2:amd64 1.47.0-2.4~exp1ubuntu4.1
libcrypt1:amd64 1:4.4.36-4build1
libcryptsetup12:amd64 2:2.7.0-1ubuntu4.2
libctf-nobfd0:amd64 2.42-4ubuntu2.10
libctf0:amd64 2.42-4ubuntu2.10
libcups2t64:amd64 2.4.7-1.2ubuntu7.14
libcurl3t64-gnutls:amd64 8.5.0-2ubuntu10.13
libcurl4t64:amd64 8.5.0-2ubuntu10.13
libdatrie1:amd64 0.2.13-3build1
libdb5.3t64:amd64 5.3.28+dfsg2-7
libdbus-1-3:amd64 1.14.10-4ubuntu4.1
libdconf1:amd64 0.40.0-4ubuntu0.1
libdebconfclient0:amd64 0.271ubuntu3
libdeflate0:amd64 1.19-1build1.1
libdevmapper1.02.1:amd64 2:1.02.185-3ubuntu3.2
libdrm-amdgpu1:amd64 2.4.125-1ubuntu0.1~24.04.2
libdrm-common 2.4.125-1ubuntu0.1~24.04.2
libdrm-intel1:amd64 2.4.125-1ubuntu0.1~24.04.2
libdrm2:amd64 2.4.125-1ubuntu0.1~24.04.2
libduktape207:amd64 2.7.0+tests-0ubuntu3
libdw1t64:amd64 0.190-1.1ubuntu0.1
libeatmydata1:amd64 131-1ubuntu1
libedit2:amd64 3.1-20230828-1build1
libegl-mesa0:amd64 25.2.8-0ubuntu0.24.04.2
libegl1:amd64 1.7.0-1build1
libelf1t64:amd64 0.190-1.1ubuntu0.1
libepoxy0:amd64 1.5.10-1build1
liberror-perl 0.17029-2
libestr0:amd64 0.1.11-1build1
libevent-core-2.1-7t64:amd64 2.1.12-stable-9ubuntu2.1
libexpat1:amd64 2.6.1-2ubuntu0.4
libext2fs2t64:amd64 1.47.0-2.4~exp1ubuntu4.1
libfastjson4:amd64 1.2304.0-1build1
libfdisk1:amd64 2.39.3-9ubuntu6.6
libffi8:amd64 3.4.6-1build1
libfido2-1:amd64 1.14.0-1build3
libfontconfig1:amd64 2.15.0-1.1ubuntu2
libfreetype6:amd64 2.13.2+dfsg-1ubuntu0.1
libfribidi0:amd64 1.0.13-3build1
libfuse3-3:amd64 3.14.0-5build1
libgbm1:amd64 25.2.8-0ubuntu0.24.04.2
libgcc-s1:amd64 14.2.0-4ubuntu2~24.04.1
libgcrypt20:amd64 1.10.3-2ubuntu0.2
libgdbm-compat4t64:amd64 1.23-5.1build1
libgdbm6t64:amd64 1.23-5.1build1
libgdk-pixbuf-2.0-0:amd64 2.42.10+dfsg-3ubuntu3.3
libgdk-pixbuf2.0-bin 2.42.10+dfsg-3ubuntu3.3
libgdk-pixbuf2.0-common 2.42.10+dfsg-3ubuntu3.3
libgirepository-1.0-1:amd64 1.80.1-1
libgl1:amd64 1.7.0-1build1
libgl1-mesa-dri:amd64 25.2.8-0ubuntu0.24.04.2
libglib2.0-0t64:amd64 2.80.0-6ubuntu3.8
libglib2.0-bin 2.80.0-6ubuntu3.8
libglib2.0-data 2.80.0-6ubuntu3.8
libglvnd0:amd64 1.7.0-1build1
libglx-mesa0:amd64 25.2.8-0ubuntu0.24.04.2
libglx0:amd64 1.7.0-1build1
libgmp10:amd64 2:6.3.0+dfsg-2ubuntu6.1
libgnutls30t64:amd64 3.8.3-1.1ubuntu3.6
libgpg-error-l10n 1.47-3build2.1
libgpg-error0:amd64 1.47-3build2.1
libgpm2:amd64 1.20.7-11
libgprofng0:amd64 2.42-4ubuntu2.10
libgraphite2-3:amd64 1.3.14-2ubuntu0.24.04.1
libgssapi-krb5-2:amd64 1.20.1-6ubuntu2.8
libgstreamer1.0-0:amd64 1.24.2-1ubuntu0.1
libgtk-3-0t64:amd64 3.24.41-4ubuntu1.3
libgtk-3-bin 3.24.41-4ubuntu1.3
libgtk-3-common 3.24.41-4ubuntu1.3
libharfbuzz0b:amd64 8.3.0-2build2
libhogweed6t64:amd64 3.9.1-2.2build1.1
libicu74:amd64 74.2-1ubuntu3.1
libidn2-0:amd64 2.3.7-2build1.1
libjansson4:amd64 2.14-2build2
libjbig0:amd64 2.1-6.1ubuntu2
libjpeg-turbo8:amd64 2.1.5-2ubuntu2
libjpeg8:amd64 8c-2ubuntu11
libjson-c5:amd64 0.17-1build1
libk5crypto3:amd64 1.20.1-6ubuntu2.8
libkeyutils1:amd64 1.6.3-3build1
libkmod2:amd64 31+20240202-2ubuntu7.2
libkrb5-3:amd64 1.20.1-6ubuntu2.8
libkrb5support0:amd64 1.20.1-6ubuntu2.8
libksba8:amd64 1.6.6-1build1
liblcms2-2:amd64 2.14-2ubuntu0.1
libldap-common 2.6.10+dfsg-0ubuntu0.24.04.1
libldap2:amd64 2.6.10+dfsg-0ubuntu0.24.04.1
liblerc4:amd64 4.0.0+ds-4ubuntu2
libllvm20:amd64 1:20.1.2-0ubuntu1~24.04.3
liblocale-gettext-perl 1.07-6ubuntu5
liblz4-1:amd64 1.9.4-1build1.1
liblzma5:amd64 5.6.1+really5.4.5-1ubuntu0.3
liblzo2-2:amd64 2.10-2build4
libmagic-mgc 1:5.45-3build1
libmagic1t64:amd64 1:5.45-3build1
libmd0:amd64 1.1.0-2build1.1
libmnl0:amd64 1.0.5-2build1
libmount1:amd64 2.39.3-9ubuntu6.6
libmpfr6:amd64 4.2.1-1build1.1
libncursesw6:amd64 6.4+20240113-1ubuntu2.2
libnetplan1:amd64 1.1.2-8ubuntu1~24.04.2
libnettle8t64:amd64 3.9.1-2.2build1.1
libnewt0.52:amd64 0.52.24-2ubuntu2
libnghttp2-14:amd64 1.59.0-1ubuntu0.4
libnpth0t64:amd64 1.6-3.1build1
libnss-systemd:amd64 255.4-1ubuntu8.17
libp11-kit0:amd64 0.25.3-4ubuntu2.2
libpackagekit-glib2-18:amd64 1.2.8-2ubuntu1.5
libpam-cap:amd64 1:2.66-5ubuntu2.4
libpam-modules:amd64 1.5.3-5ubuntu5.7
libpam-modules-bin 1.5.3-5ubuntu5.7
libpam-runtime 1.5.3-5ubuntu5.7
libpam-systemd:amd64 255.4-1ubuntu8.17
libpam0g:amd64 1.5.3-5ubuntu5.7
libpango-1.0-0:amd64 1.52.1+ds-1build1
libpangocairo-1.0-0:amd64 1.52.1+ds-1build1
libpangoft2-1.0-0:amd64 1.52.1+ds-1build1
libpciaccess0:amd64 0.17-3ubuntu0.24.04.2
libpcre2-8-0:amd64 10.42-4ubuntu2.1
libperl5.38t64:amd64 5.38.2-3.2ubuntu0.4
libpipeline1:amd64 1.5.7-2
libpixman-1-0:amd64 0.42.2-1build1
libpng16-16t64:amd64 1.6.43-5ubuntu0.6
libpolkit-agent-1-0:amd64 124-2ubuntu1.24.04.3
libpolkit-gobject-1-0:amd64 124-2ubuntu1.24.04.3
libpopt0:amd64 1.19+dfsg-1build1
libproc2-0:amd64 2:4.0.4-4ubuntu3.3
libpsl5t64:amd64 0.21.2-1.1build1
libpython3-stdlib:amd64 3.12.3-0ubuntu2.1
libpython3.12-minimal:amd64 3.12.3-1ubuntu0.16
libpython3.12-stdlib:amd64 3.12.3-1ubuntu0.16
libpython3.12t64:amd64 3.12.3-1ubuntu0.16
libreadline8t64:amd64 8.2-4build1
librsvg2-2:amd64 2.58.0+dfsg-1build1
librsvg2-common:amd64 2.58.0+dfsg-1build1
librtmp1:amd64 2.4+20151223.gitfa8646d.1-2build7
libsasl2-2:amd64 2.1.28+dfsg1-5ubuntu3.1
libsasl2-modules:amd64 2.1.28+dfsg1-5ubuntu3.1
libsasl2-modules-db:amd64 2.1.28+dfsg1-5ubuntu3.1
libseccomp2:amd64 2.5.5-1ubuntu3.1
libselinux1:amd64 3.5-2ubuntu2.1
libsemanage-common 3.5-1build5
libsemanage2:amd64 3.5-1build5
libsensors-config 1:3.6.0-9build1
libsensors5:amd64 1:3.6.0-9build1
libsepol2:amd64 3.5-2build1
libsframe1:amd64 2.42-4ubuntu2.10
libsharpyuv0:amd64 1.3.2-0.4build3
libsigsegv2:amd64 2.14-1ubuntu2
libslang2:amd64 2.3.3-3build2
libsmartcols1:amd64 2.39.3-9ubuntu6.6
libsodium23:amd64 1.0.18-1ubuntu0.24.04.1
libsqlite3-0:amd64 3.45.1-1ubuntu2.7
libss2:amd64 1.47.0-2.4~exp1ubuntu4.1
libssh-4:amd64 0.10.6-2ubuntu0.5
libssl3t64:amd64 3.0.13-0ubuntu3.15
libstdc++6:amd64 14.2.0-4ubuntu2~24.04.1
libstemmer0d:amd64 2.2.0-4build1
libsystemd-shared:amd64 255.4-1ubuntu8.17
libsystemd0:amd64 255.4-1ubuntu8.17
libtasn1-6:amd64 4.19.0-3ubuntu0.24.04.2
libtext-charwidth-perl:amd64 0.04-11build3
libtext-iconv-perl:amd64 1.7-8build3
libtext-wrapi18n-perl 0.06-10
libthai-data 0.1.29-2build1
libthai0:amd64 0.1.29-2build1
libtiff6:amd64 4.5.1+git230720-4ubuntu2.5
libtinfo6:amd64 6.4+20240113-1ubuntu2.2
libtirpc-common 1.3.4+ds-1.1build1
libtirpc3t64:amd64 1.3.4+ds-1.1build1
libuchardet0:amd64 0.0.8-1build1
libudev1:amd64 255.4-1ubuntu8.17
libunistring5:amd64 1.1-2build1.1
libunwind8:amd64 1.6.2-3build1.1
libutempter0:amd64 1.2.1-3build1
libuuid1:amd64 2.39.3-9ubuntu6.6
libvulkan1:amd64 1.3.275.0-1build1
libwayland-client0:amd64 1.22.0-2.1build1
libwayland-cursor0:amd64 1.22.0-2.1build1
libwayland-egl1:amd64 1.22.0-2.1build1
libwebp7:amd64 1.3.2-0.4build3
libx11-6:amd64 2:1.8.7-1build1
libx11-data 2:1.8.7-1build1
libx11-xcb1:amd64 2:1.8.7-1build1
libxau6:amd64 1:1.0.9-1build6
libxcb-dri3-0:amd64 1.15-1ubuntu2
libxcb-glx0:amd64 1.15-1ubuntu2
libxcb-present0:amd64 1.15-1ubuntu2
libxcb-randr0:amd64 1.15-1ubuntu2
libxcb-render0:amd64 1.15-1ubuntu2
libxcb-shm0:amd64 1.15-1ubuntu2
libxcb-sync1:amd64 1.15-1ubuntu2
libxcb-xfixes0:amd64 1.15-1ubuntu2
libxcb1:amd64 1.15-1ubuntu2
libxcomposite1:amd64 1:0.4.5-1build3
libxcursor1:amd64 1:1.2.1-1build1
libxdamage1:amd64 1:1.1.6-1build1
libxdmcp6:amd64 1:1.1.3-0ubuntu6
libxext6:amd64 2:1.3.4-1build2
libxfixes3:amd64 1:6.0.0-2build1
libxi6:amd64 2:1.8.1-1build1
libxinerama1:amd64 2:1.1.4-3build1
libxkbcommon0:amd64 1.6.0-1build1
libxml2:amd64 2.9.14+dfsg-1.3ubuntu3.8
libxmlb2:amd64 0.3.24-1~ubuntu0.24.04.1
libxmuu1:amd64 2:1.1.3-3build2
libxrandr2:amd64 2:1.5.2-2build1
libxrender1:amd64 1:0.9.10-1.1build1
libxshmfence1:amd64 1.3-1build5
libxtables12:amd64 1.8.10-3ubuntu2
libxtst6:amd64 2:1.2.3-1.1build1
libxxf86vm1:amd64 1:1.1.4-1build4
libxxhash0:amd64 0.8.2-2build1
libyaml-0-2:amd64 0.2.5-1build1
libzstd1:amd64 1.5.5+dfsg2-2build1.1
locales 2.39-0ubuntu8.8
login 1:4.13+dfsg1-4ubuntu3.2
logrotate 3.21.0-2build1
logsave 1.47.0-2.4~exp1ubuntu4.1
lsb-release 12.0-2
lshw 02.19.git.2021.06.19.996aaad9c7-2ubuntu0.24.04.1
lsof 4.95.0-1build3
man-db 2.12.0-4build2
manpages 6.7-2
mawk 1.3.4.20240123-1build1
media-types 10.1.0
mesa-libgallium:amd64 25.2.8-0ubuntu0.24.04.2
mesa-vulkan-drivers:amd64 25.2.8-0ubuntu0.24.04.2
motd-news-config 13ubuntu10.5
mount 2.39.3-9ubuntu6.6
nano 7.2-2ubuntu0.2
ncurses-base 6.4+20240113-1ubuntu2.2
ncurses-bin 6.4+20240113-1ubuntu2.2
netbase 6.4
netcat-openbsd 1.226-1ubuntu2
netplan-generator 1.1.2-8ubuntu1~24.04.2
netplan.io 1.1.2-8ubuntu1~24.04.2
networkd-dispatcher 2.2.4-1
openssh-client 1:9.6p1-3ubuntu13.19
openssl 3.0.13-0ubuntu3.15
packagekit 1.2.8-2ubuntu1.5
packagekit-tools 1.2.8-2ubuntu1.5
passwd 1:4.13+dfsg1-4ubuntu3.2
pastebinit 1.6.2-1
patch 2.7.6-7build3
pci.ids 0.0~2024.03.31-1ubuntu0.1
perl 5.38.2-3.2ubuntu0.4
perl-base 5.38.2-3.2ubuntu0.4
perl-modules-5.38 5.38.2-3.2ubuntu0.4
pinentry-curses 1.2.1-3ubuntu5
polkitd 124-2ubuntu1.24.04.3
procps 2:4.0.4-4ubuntu3.3
psmisc 23.7-1build1
publicsuffix 20231001.0357-0.1
python-apt-common 2.7.7ubuntu5.3
python-babel-localedata 2.10.3-3build1
python3 3.12.3-0ubuntu2.1
python3-apport 2.28.3-0ubuntu0.1
python3-apt 2.7.7ubuntu5.3
python3-attr 23.2.0-2
python3-automat 22.10.0-2
python3-babel 2.10.3-3build1
python3-bcrypt 3.2.2-1build1
python3-blinker 1.7.0-1
python3-certifi 2023.11.17-1
python3-cffi-backend:amd64 1.16.0-2build1
python3-chardet 5.2.0+dfsg-1
python3-click 8.1.6-2
python3-colorama 0.4.6-4
python3-commandnotfound 23.04.0
python3-configobj 5.0.8-3
python3-constantly 23.10.4-1
python3-cryptography 41.0.7-4ubuntu0.4
python3-dbus 1.3.2-5build3
python3-debconf 1.5.86ubuntu1
python3-distro 1.9.0-1
python3-distro-info 1.7build1
python3-distupgrade 1:24.04.29
python3-gdbm:amd64 3.12.3-0ubuntu1
python3-gi 3.48.2-1
python3-hamcrest 2.1.0-1
python3-httplib2 0.20.4-3ubuntu0.1
python3-hyperlink 21.0.0-5
python3-idna 3.6-2ubuntu0.2
python3-incremental 22.10.0-1
python3-jinja2 3.1.2-1ubuntu1.3
python3-json-pointer 2.0-0ubuntu1
python3-jsonpatch 1.32-3
python3-jsonschema 4.10.3-2ubuntu1
python3-jwt 2.7.0-1ubuntu0.1
python3-launchpadlib 1.11.0-6
python3-lazr.restfulclient 0.14.6-1
python3-lazr.uri 1.0.6-3
python3-markdown-it 3.0.0-2
python3-markupsafe 2.1.5-1build2
python3-mdurl 0.1.2-1
python3-minimal 3.12.3-0ubuntu2.1
python3-netifaces:amd64 0.11.0-2build3
python3-netplan 1.1.2-8ubuntu1~24.04.2
python3-newt:amd64 0.52.24-2ubuntu2
python3-oauthlib 3.2.2-1
python3-openssl 23.2.0-1ubuntu0.1
python3-pkg-resources 68.1.2-2ubuntu1.2
python3-problem-report 2.28.3-0ubuntu0.1
python3-pyasn1 0.4.8-4ubuntu0.3
python3-pyasn1-modules 0.2.8-1
python3-pycurl 7.45.3-1build2
python3-pygments 2.17.2+dfsg-1
python3-pyparsing 3.1.1-1
python3-pyrsistent:amd64 0.20.0-1build2
python3-requests 2.31.0+dfsg-1ubuntu1.1
python3-rich 13.7.1-1
python3-serial 3.5-2
python3-service-identity 24.1.0-1
python3-setuptools 68.1.2-2ubuntu1.2
python3-six 1.16.0-4
python3-software-properties 0.99.49.4
python3-systemd 235-1build4
python3-twisted 24.3.0-1ubuntu0.2
python3-typing-extensions 4.10.0-1
python3-tz 2024.1-2
python3-update-manager 1:24.04.12
python3-urllib3 2.0.7-1ubuntu0.7
python3-wadllib 1.3.6-5
python3-yaml 6.0.1-2build2
python3-zope.interface 6.1-1build1
python3.12 3.12.3-1ubuntu0.16
python3.12-minimal 3.12.3-1ubuntu0.16
readline-common 8.2-4build1
rsync 3.2.7-1ubuntu1.5
rsyslog 8.2312.0-3ubuntu9.3
run-one 1.17-0ubuntu2
sed 4.9-2ubuntu0.24.04.1
sensible-utils 0.0.22
session-migration 0.3.9build1
sgml-base 1.31
shared-mime-info 2.4-4
show-motd 3.12
snapd 2.76.3+ubuntu24.04
software-properties-common 0.99.49.4
squashfs-tools 1:4.6.1-1build1
sudo 1.9.15p5-3ubuntu5.24.04.2
systemd 255.4-1ubuntu8.17
systemd-dev 255.4-1ubuntu8.17
systemd-hwe-hwdb 255.1.7
systemd-resolved 255.4-1ubuntu8.17
systemd-sysv 255.4-1ubuntu8.17
systemd-timesyncd 255.4-1ubuntu8.17
sysvinit-utils 3.08-6ubuntu3
tar 1.35+dfsg-3ubuntu0.4
time 1.9-0.2build1
tmux 3.4-1ubuntu0.1
tzdata 2026c-0ubuntu0.24.04.1
ubuntu-keyring 2023.11.28.1
ubuntu-minimal 1.539.2
ubuntu-mono 24.04-0ubuntu1
ubuntu-pro-client 37.2ubuntu~24.04.1
ubuntu-pro-client-l10n 37.2ubuntu~24.04.1
ubuntu-release-upgrader-core 1:24.04.29
ubuntu-wsl 1.539.2
ucf 3.0043+nmu1
udev 255.4-1ubuntu8.17
unattended-upgrades 2.9.1+nmu4ubuntu1
update-manager-core 1:24.04.12
update-motd 3.12
usb.ids 2024.03.18-1
util-linux 2.39.3-9ubuntu6.6
uuid-runtime 2.39.3-9ubuntu6.6
vim 2:9.1.0016-1ubuntu7.20
vim-common 2:9.1.0016-1ubuntu7.20
vim-runtime 2:9.1.0016-1ubuntu7.20
vim-tiny 2:9.1.0016-1ubuntu7.20
wget 1.21.4-1ubuntu4.5
whiptail 0.52.24-2ubuntu2
wsl-pro-service 0.1.18~24.04.3
wsl-setup 0.5.10~24.04.2
x11-common 1:7.7+23ubuntu3
xauth 1:1.1.2-1build1
xdg-user-dirs 0.18-1build1
xkb-data 2.41-2ubuntu1.1
xml-core 0.19
xxd 2:9.1.0016-1ubuntu7.20
xz-utils 5.6.1+really5.4.5-1ubuntu0.3
zlib1g:amd64 1:1.3.dfsg-3.1ubuntu2.2

View file

@ -0,0 +1,12 @@
{
"capture_utc": "2026-10-19T12:51:21.797227+00:00",
"tests_passed": 5,
"test_detail": "partial preflight predicates, 14 negative mutations, locked guest entry, bash syntax, locked PowerShell source",
"ubuntu_checksum_signature_verified": true,
"rootfs_downloaded": false,
"powershell_parser_run": false,
"guest_services_validated": false,
"distro_created": false,
"live_mutation": false,
"actual_assignment_admitted": false
}

View file

@ -0,0 +1,58 @@
#!/usr/bin/env python3
"""Read-only launch preflight; outputs predicates only, never file contents."""
import configparser
import json
import os
from pathlib import Path
import pwd
import sys
def check_snapshot(s):
checks = {
'dedicated_guest': s['distro'] == 'custodian-codex',
'account': s['uid'] == 1001 and s['gid'] == 1001,
'private_home': s['home_mode'] == 0o700,
'private_state': s['state_mode'] == 0o700,
'home_owner': s['home_uid'] == 1001 and s['state_uid'] == 1001,
'no_admin_groups': s['groups'] == [1001],
'interop_config_disabled': s['interop'] == 'false',
'automount_config_disabled': s['automount'] == 'false',
'fstab_config_disabled': s['mount_fstab'] == 'false',
'no_windows_mount': not s['windows_mount'],
'no_operator_home': not s['operator_home'],
'no_interop_handler': not s['interop_handler'],
}
return {'checks': checks, 'partial_preflight_passed': all(checks.values()),
'assignment_admitted': False}
def main():
try:
c = configparser.ConfigParser(); c.read('/etc/wsl.conf')
p = pwd.getpwnam('custodian-codex')
home = Path(p.pw_dir).stat(); state = (Path(p.pw_dir)/'.codex').stat()
result = check_snapshot({
# systemd services do not necessarily inherit WSL_DISTRO_NAME.
# Root-owned stage marker is partial local evidence, not host attestation.
'distro': Path('/etc/cust73/distribution-name').read_text().strip(),
'uid': p.pw_uid, 'gid': p.pw_gid,
'home_mode': home.st_mode & 0o777, 'state_mode': state.st_mode & 0o777,
'home_uid': home.st_uid, 'state_uid': state.st_uid,
'groups': sorted(os.getgrouplist(p.pw_name, p.pw_gid)),
'interop': c.get('interop','enabled'),
'automount': c.get('automount','enabled'),
'mount_fstab': c.get('automount','mountFsTab'),
'windows_mount': Path('/mnt/c/Windows').exists(),
'operator_home': Path('/home/worsch').exists(),
'interop_handler': Path('/proc/sys/fs/binfmt_misc/WSLInterop').exists(),
})
except Exception:
result = {'partial_preflight_passed': False, 'assignment_admitted': False,
'reason': 'preflight_refused'}
print(json.dumps(result, sort_keys=True))
return 0 if result['partial_preflight_passed'] else 1
if __name__ == '__main__':
sys.exit(main())

View file

@ -0,0 +1,16 @@
[boot]
systemd=true
[automount]
enabled=false
mountFsTab=false
[interop]
enabled=false
appendWindowsPath=false
[network]
hostname=custodian-codex
[user]
default=custodian-codex

View file

@ -0,0 +1,27 @@
422c895ed4e7887853ab3ae688e80441bdf85da76c85e22e1717fbeff04e2bfc README.md
d40c06f399718665d5541101a1e0dba811bd17aa1b2ae80e33f771db9ab81f67 apt.conf
fcaee001747a6adaa0cd9337fef437b3aa7a7a6d5246b62fbd4784d3d6a5009e archives/libnftables1_1.0.9-1ubuntu0.1_amd64.deb
e5bde5c9cbb95082700011f0b7ef2c0a41900b0a9fd7434f6e90448e2a7b4e50 archives/libnftnl11_1.2.6-2build1_amd64.deb
36118b862539868408ee056411d6e470068d14c46e5296b29bfb744770f5d2ce archives/libwrap0_7.6.q-33_amd64.deb
d648859fccde3c17b8b9b89993427564f91f394a39306db1f67bd5ea3ac42c6e archives/nftables_1.0.9-1ubuntu0.1_amd64.deb
5fb4429e9eff60a5b4ddb68ccf0c46ee67066b445794ede5fe181e64c4a8b795 archives/openssh-client_1%3a9.6p1-3ubuntu13.20_amd64.deb
5d0d5eb672ddc27601e2da4e8465c5736dc73375a21bc1cd1834fcb08fb155bf archives/openssh-server_1%3a9.6p1-3ubuntu13.20_amd64.deb
111fb22cab9abf220b681f97eefa195ccfacef7d85561772ecef22e88db2d7bb archives/openssh-sftp-server_1%3a9.6p1-3ubuntu13.20_amd64.deb
555e0ba60e95b18f8d482cdc6091c37bdda7377d4763ec400de2d91b571de201 download.txt
550c8f90c5cb35ce1d6ae37935b02ffef733b8d65890fd8b83073c4f7caad891 install-disabled.sh
05c2c50a69e01a09541b744202c5267e5cdf0392f9cc5e3668f6771236c9ebd1 lists/archive.ubuntu.com_ubuntu_dists_noble-updates_InRelease
12603c9c2691679fbf657cc6bf3f60a14affb37e3cf576e3042d980fe463c91f lists/archive.ubuntu.com_ubuntu_dists_noble-updates_main_binary-amd64_Packages
cdb2f31d809f589719a53c6ad15f255b27569c4059542ada282aaa21b8e164b0 lists/archive.ubuntu.com_ubuntu_dists_noble_InRelease
8f6f71ae839c8cba390a7643fcbbdacddb0bc7d12c1583a2dd80a1f8443a30e5 lists/archive.ubuntu.com_ubuntu_dists_noble_main_binary-amd64_Packages
ac9a742aef4fb5d0d52f43e5fd7631d9aaa0b643c45ab16ecfaf000b140be930 lists/security.ubuntu.com_ubuntu_dists_noble-security_InRelease
6b99baab015714c0f5fa3ca2a89e6b2ffb57a821ee99bddbc89316801eeb9dda lists/security.ubuntu.com_ubuntu_dists_noble-security_main_binary-amd64_Packages
c71c3b2a4cd64cd28649db25363a4edaa311ebe1ae9cba4633377e2647a3b9e4 package-pins.json
fdfabf32e3fb57f4dd2492a7b3086200c8be9c0db435c5beebdff7e1b8f350cc resolution.txt
ac8964b068fefc85db5205d35d9471c7c404da2a106aef99cf91201c302f6986 resolve.py
5de2ab566fe9a9ab2f4d1f544dc3a44d6d25ab40414f69451ceb0609245d72e5 rootfs-dpkg-status
bb415d824822c4b878125729af451a5d18fb13d1cf5cbed9a7393ad64ac6039e rootfs.wsl
55b96ea3ce06c828c7fbf9d5dbb177e3dc7544dbee7ea5c44aa10c42337e07d0 sources.list
0b3a20720d6fb3e0241cd624d4a08c1562a9ec9b585a8abe780352ffffdf1200 test_verification.py
a5ef2c5ca919a7f5caee65f3ba49d757f752d2afa909deb73d9cebd14013b168 validation.json
166905190ebbd255d95b0964b04486ea4eeb82beb9caf3faa66bd24694f2cc12 verification-manifest.json
bf68c471478a6f85acabee5edbeb40f4e7c28b9bbc438d47d6465c73323c9c8d verify_closure.py

View file

@ -0,0 +1,60 @@
# Verified Ubuntu dependency closure — CUST73 launch r3 addendum
Preparation-only receipt. Existing launch r3 stays unchanged. This directory
contains the verified rootfs, original installed package database, signed Ubuntu
repository snapshots, seven `.deb` files, exact package pins, solver output and
verification code. No rootfs was imported/booted and no package installed.
Rootfs Ubuntu24.04.5 AMD64: SHA256
`bb415d824822c4b878125729af451a5d18fb13d1cf5cbed9a7393ad64ac6039e`,
388,975,696bytes, from
`https://releases.ubuntu.com/24.04.5/ubuntu-24.04.5-wsl-amd64.wsl`.
The prior r3 Ubuntu detached checksum signature verification remains its trust
anchor. Image bytes were downloaded and hashed here; only the regular tar member
`var/lib/dpkg/status` was extracted to a file. No rootfs files were executed.
APT configuration redirects status, lists, caches, logs and extended state under
this directory, disables host config fragments and additional sources, and
requires authenticated repositories. Only Ubuntu noble/main, noble-updates/main
and noble-security/main are enabled. Recommends/suggests are off. `resolve.py`
requires the target status and uses simulation then **download-only**, never
dpkg installation. Initial extraction rejected the unrelated os-release symlink
before producing status; an exploratory simulation therefore saw an empty
status. It was discarded. The retained resolution was rerun only after regular
dpkg status extraction succeeded, and contains the correct seven-package result.
`verify_closure.py` independently checks every InRelease with the installed
Ubuntu archive keyring, then validates decompressed Packages bytes against its
signed SHA256 entry. Every `.deb` must match its signed index hash, size and
package/version/architecture, and the exact set must equal the solver plan.
It also rehashes the rootfs. `verification-manifest.json` records individual
package hashes/sizes/paths, suites/signers/dates and rootfs/status hashes.
APT's original index acquisition enforced freshness/signature policy. Retained
snapshots are an approval input, not a claim of indefinite package freshness;
do not refresh them silently after approval.
Exact closure: openssh-client, openssh-sftp-server and openssh-server
`1:9.6p1-3ubuntu13.20`; libwrap0 `7.6.q-33`; libnftnl11 `1.2.6-2build1`;
libnftables1 and nftables `1.0.9-1ubuntu0.1`. The SSH client is upgraded;
six other packages are newly installed. Dependencies already in the rootfs
remain bound by the verified rootfs/status. This is not a general distro upgrade.
For later operator review, `install-disabled.sh` contains the exact offline
installation body and an unconditional refusal before mutation. It checks the
new distro and exact original installed-state bytes, masks default SSH/nftables
services, suppresses maintainer-script service starts with policy-rc.d, and uses
only downloaded local packages with no downloads/removals. Failure preserves
the start suppression for inspection. No default service is unmasked or started.
Private root-owned staging and reviewed manifest verification must precede any
approved revision. Do not elevate this agent-writable `/tmp` bundle directly.
Verify again with `python3 verify_closure.py`; test rejection behavior with
`python3 -m unittest -v test_verification.py`. Tests alter only temporary copies
and exercise tampered archive/index, incomplete closure, and locked installer.
No tests require root, a guest or package installation.
This closes the r3 **package dependency choice/download/provenance** gate.
It does not close UI handoff, namespace/runtime compatibility, Windows endpoint,
authentication, network egress or actual assignment admission gates. New source
execution still needs a bound supervisor approval revision; locks are not removed
here. No additional infrastructure or model-call cost was incurred.

View file

@ -0,0 +1,11 @@
# Retention boundary
This directory retains the original reviewed source, manifests, signed release
metadata and solver/validation receipts. It is not the executable artifact bundle.
The complete verified bundle remains at `/tmp/cust73-ubuntu-dependencies-r1`,
including rootfs, Packages indexes, dpkg baseline and seven binary archives.
`ORIGINAL-SHA256SUMS` refers to that complete bundle, not just this Git snapshot.
Do not run the installer from this partial review copy or infer admission from
source checks. Reverify the complete artifact bundle before root-owned staging;
if it has expired or disappeared, reacquire exact pinned bytes and validate their
signed provenance before seeking an execution approval.

View file

@ -0,0 +1,17 @@
652ae1e9cd3c80a841c05b938464b45f6ce1d2fe6679913a9b4f1dda1e5daf7f ORIGINAL-SHA256SUMS
422c895ed4e7887853ab3ae688e80441bdf85da76c85e22e1717fbeff04e2bfc README.md
3036d9232191dfa6efc6ce50dc0c96236bd5e3afa13372ac91bba310dd2dd69b RETENTION.md
d40c06f399718665d5541101a1e0dba811bd17aa1b2ae80e33f771db9ab81f67 apt.conf
555e0ba60e95b18f8d482cdc6091c37bdda7377d4763ec400de2d91b571de201 download.txt
550c8f90c5cb35ce1d6ae37935b02ffef733b8d65890fd8b83073c4f7caad891 install-disabled.sh
c71c3b2a4cd64cd28649db25363a4edaa311ebe1ae9cba4633377e2647a3b9e4 package-pins.json
fdfabf32e3fb57f4dd2492a7b3086200c8be9c0db435c5beebdff7e1b8f350cc resolution.txt
ac8964b068fefc85db5205d35d9471c7c404da2a106aef99cf91201c302f6986 resolve.py
05c2c50a69e01a09541b744202c5267e5cdf0392f9cc5e3668f6771236c9ebd1 signed-metadata/archive.ubuntu.com_ubuntu_dists_noble-updates_InRelease
cdb2f31d809f589719a53c6ad15f255b27569c4059542ada282aaa21b8e164b0 signed-metadata/archive.ubuntu.com_ubuntu_dists_noble_InRelease
ac9a742aef4fb5d0d52f43e5fd7631d9aaa0b643c45ab16ecfaf000b140be930 signed-metadata/security.ubuntu.com_ubuntu_dists_noble-security_InRelease
55b96ea3ce06c828c7fbf9d5dbb177e3dc7544dbee7ea5c44aa10c42337e07d0 sources.list
0b3a20720d6fb3e0241cd624d4a08c1562a9ec9b585a8abe780352ffffdf1200 test_verification.py
a5ef2c5ca919a7f5caee65f3ba49d757f752d2afa909deb73d9cebd14013b168 validation.json
166905190ebbd255d95b0964b04486ea4eeb82beb9caf3faa66bd24694f2cc12 verification-manifest.json
bf68c471478a6f85acabee5edbeb40f4e7c28b9bbc438d47d6465c73323c9c8d verify_closure.py

View file

@ -0,0 +1,21 @@
Dir::Etc::main "-";
Dir::Etc::parts "-";
Dir::Etc::sourcelist "/tmp/cust73-ubuntu-dependencies-r1/sources.list";
Dir::Etc::sourceparts "-";
Dir::State::lists "/tmp/cust73-ubuntu-dependencies-r1/lists";
Dir::State::status "/tmp/cust73-ubuntu-dependencies-r1/rootfs-dpkg-status";
Dir::State::extended_states "/tmp/cust73-ubuntu-dependencies-r1/extended_states";
Dir::Cache::archives "/tmp/cust73-ubuntu-dependencies-r1/archives";
Dir::Cache::pkgcache "/tmp/cust73-ubuntu-dependencies-r1/pkgcache.bin";
Dir::Cache::srcpkgcache "/tmp/cust73-ubuntu-dependencies-r1/srcpkgcache.bin";
Dir::Log "/tmp/cust73-ubuntu-dependencies-r1/log";
APT::Architecture "amd64";
APT::Architectures { "amd64"; };
APT::Install-Recommends "false";
APT::Install-Suggests "false";
Acquire::Languages "none";
Acquire::AllowInsecureRepositories "false";
Acquire::AllowDowngradeToInsecureRepositories "false";
Acquire::Check-Valid-Until "true";
APT::Get::AllowUnauthenticated "false";
Debug::NoLocking "true";

View file

@ -0,0 +1,23 @@
Reading package lists...
Building dependency tree...
Suggested packages:
firewalld keychain libpam-ssh monkeysphere ssh-askpass molly-guard ufw
Recommended packages:
ncurses-term ssh-import-id
The following NEW packages will be installed:
libnftables1 libnftnl11 libwrap0 nftables openssh-server openssh-sftp-server
The following packages will be upgraded:
openssh-client
1 upgraded, 6 newly installed, 0 to remove and 74 not upgraded.
Need to get 2000 kB of archives.
After this operation, 3826 kB of additional disk space will be used.
Get:1 https://archive.ubuntu.com/ubuntu noble/main amd64 libwrap0 amd64 7.6.q-33 [47.9 kB]
Get:2 https://security.ubuntu.com/ubuntu noble-security/main amd64 openssh-client amd64 1:9.6p1-3ubuntu13.20 [909 kB]
Get:3 https://archive.ubuntu.com/ubuntu noble/main amd64 libnftnl11 amd64 1.2.6-2build1 [66.0 kB]
Get:4 https://archive.ubuntu.com/ubuntu noble-updates/main amd64 libnftables1 amd64 1.0.9-1ubuntu0.1 [359 kB]
Get:5 https://archive.ubuntu.com/ubuntu noble-updates/main amd64 nftables amd64 1.0.9-1ubuntu0.1 [69.8 kB]
Get:6 https://security.ubuntu.com/ubuntu noble-security/main amd64 openssh-sftp-server amd64 1:9.6p1-3ubuntu13.20 [37.4 kB]
Get:7 https://security.ubuntu.com/ubuntu noble-security/main amd64 openssh-server amd64 1:9.6p1-3ubuntu13.20 [512 kB]
Fetched 2000 kB in 0s (5076 kB/s)
Download complete and in download only mode
W: Unable to read /etc/apt/-/ - DirectoryExists (2: No such file or directory)

View file

@ -0,0 +1,31 @@
#!/bin/bash
set -euo pipefail
printf '%s\n' 'REFUSED: dependency receipt is preparation-only; install disabled.' >&2
exit 78
# Reviewed offline installation body; requires a NEW approved executable revision.
test "$(id -u)" = 0
test "${WSL_DISTRO_NAME:-}" = custodian-codex
bundle_dir=/root/cust73-deps
test -d "$bundle_dir"
test ! -e /usr/sbin/policy-rc.d
# Refuse any installed-state drift from the verified original rootfs.
cmp --silent /var/lib/dpkg/status "$bundle_dir/rootfs-dpkg-status"
# Operator must first verify bundle/deb hashes with the reviewed manifest and
# root-owned source in a private directory; do not run agent-writable code as root.
# Prevent both immediate package-service startup and subsequent default listeners.
systemctl mask ssh.service ssh.socket nftables.service
printf '#!/bin/sh\nexit 101\n' > /usr/sbin/policy-rc.d
chmod 0755 /usr/sbin/policy-rc.d
# Keep policy-rc.d on failure for safe investigation. Removal is success-only.
apt-get --yes --no-download --no-remove --no-install-recommends \
-o Dir::Etc::sourcelist=/dev/null -o Dir::Etc::sourceparts=- \
-o Dir::Cache::archives="$bundle_dir/archives" \
install "$bundle_dir"/archives/*.deb
python3 - <<'PY'
from pathlib import Path
p=Path('/usr/sbin/policy-rc.d')
assert p.read_bytes()==b'#!/bin/sh\nexit 101\n'
p.unlink()
PY
# Do not unmask/start default services. r3 dedicated cust73 service remains off.

View file

@ -0,0 +1,9 @@
[
"openssh-client=1:9.6p1-3ubuntu13.20",
"openssh-sftp-server=1:9.6p1-3ubuntu13.20",
"libwrap0=7.6.q-33",
"openssh-server=1:9.6p1-3ubuntu13.20",
"libnftnl11=1.2.6-2build1",
"libnftables1=1.0.9-1ubuntu0.1",
"nftables=1.0.9-1ubuntu0.1"
]

View file

@ -0,0 +1,32 @@
NOTE: This is only a simulation!
apt-get needs root privileges for real execution.
Keep also in mind that locking is deactivated,
so don't depend on the relevance to the real current situation!
Reading package lists...
Building dependency tree...
The following additional packages will be installed:
libnftables1 libnftnl11 libwrap0 openssh-client openssh-sftp-server
Suggested packages:
firewalld keychain libpam-ssh monkeysphere ssh-askpass molly-guard ufw
Recommended packages:
ncurses-term ssh-import-id
The following NEW packages will be installed:
libnftables1 libnftnl11 libwrap0 nftables openssh-server openssh-sftp-server
The following packages will be upgraded:
openssh-client
1 upgraded, 6 newly installed, 0 to remove and 74 not upgraded.
Inst openssh-client [1:9.6p1-3ubuntu13.19] (1:9.6p1-3ubuntu13.20 Ubuntu:24.04/noble-security [amd64])
Inst openssh-sftp-server (1:9.6p1-3ubuntu13.20 Ubuntu:24.04/noble-security [amd64])
Inst libwrap0 (7.6.q-33 Ubuntu:24.04/noble [amd64])
Inst openssh-server (1:9.6p1-3ubuntu13.20 Ubuntu:24.04/noble-security [amd64])
Inst libnftnl11 (1.2.6-2build1 Ubuntu:24.04/noble [amd64])
Inst libnftables1 (1.0.9-1ubuntu0.1 Ubuntu:24.04/noble-updates [amd64])
Inst nftables (1.0.9-1ubuntu0.1 Ubuntu:24.04/noble-updates [amd64])
Conf openssh-client (1:9.6p1-3ubuntu13.20 Ubuntu:24.04/noble-security [amd64])
Conf openssh-sftp-server (1:9.6p1-3ubuntu13.20 Ubuntu:24.04/noble-security [amd64])
Conf libwrap0 (7.6.q-33 Ubuntu:24.04/noble [amd64])
Conf openssh-server (1:9.6p1-3ubuntu13.20 Ubuntu:24.04/noble-security [amd64])
Conf libnftnl11 (1.2.6-2build1 Ubuntu:24.04/noble [amd64])
Conf libnftables1 (1.0.9-1ubuntu0.1 Ubuntu:24.04/noble-updates [amd64])
Conf nftables (1.0.9-1ubuntu0.1 Ubuntu:24.04/noble-updates [amd64])
W: Unable to read /etc/apt/-/ - DirectoryExists (2: No such file or directory)

View file

@ -0,0 +1,39 @@
#!/usr/bin/env python3
"""Download-only resolution against verified target status; never installs."""
from pathlib import Path
import hashlib
import json
import os
import re
import subprocess
BASE = Path(__file__).resolve().parent
ROOTFS_SHA = 'bb415d824822c4b878125729af451a5d18fb13d1cf5cbed9a7393ad64ac6039e'
def main():
status = BASE/'rootfs-dpkg-status'
if not status.is_file() or b'Package: base-files\n' not in status.read_bytes():
raise SystemExit('refuse absent/incomplete target dpkg status')
env = dict(os.environ, APT_CONFIG=str(BASE/'apt.conf'), LC_ALL='C')
r = subprocess.run(['apt-get','--simulate','--no-remove','install','openssh-server','nftables'],
env=env, capture_output=True, text=True, check=True)
(BASE/'resolution.txt').write_text(r.stdout+r.stderr)
if re.search(r'^Remv ',r.stdout,re.M): raise SystemExit('removal refused')
packages = []
for line in r.stdout.splitlines():
if line.startswith('Inst '):
m=re.match(r'Inst (\S+)(?: \[[^]]+\])? \((\S+)',line)
if not m: raise SystemExit('unparsed installation record')
packages.append(m[1]+'='+m[2])
if not packages: raise SystemExit('empty package plan')
(BASE/'package-pins.json').write_text(json.dumps(packages,indent=2)+'\n')
# Exact versions, target rootfs state, download-only flag: no dpkg invocation.
r=subprocess.run(['apt-get','--download-only','--yes','--no-remove','install',*packages],
env=env,capture_output=True,text=True)
(BASE/'download.txt').write_text(r.stdout+r.stderr)
r.check_returncode()
print(json.dumps({'downloaded_package_count':len(packages),'installed':False}))
if __name__=='__main__':main()

View file

@ -0,0 +1,3 @@
deb [arch=amd64 signed-by=/usr/share/keyrings/ubuntu-archive-keyring.gpg] https://archive.ubuntu.com/ubuntu noble main
deb [arch=amd64 signed-by=/usr/share/keyrings/ubuntu-archive-keyring.gpg] https://archive.ubuntu.com/ubuntu noble-updates main
deb [arch=amd64 signed-by=/usr/share/keyrings/ubuntu-archive-keyring.gpg] https://security.ubuntu.com/ubuntu noble-security main

View file

@ -0,0 +1,55 @@
import json
from pathlib import Path
import shutil
import subprocess
import tempfile
import unittest
import verify_closure
SOURCE=Path(__file__).parent
class VerificationTests(unittest.TestCase):
def fixture(self, p):
for d in ['lists','archives']:shutil.copytree(SOURCE/d,p/d)
shutil.copy2(SOURCE/'package-pins.json',p/'package-pins.json')
shutil.copy2(SOURCE/'rootfs-dpkg-status',p/'rootfs-dpkg-status')
(p/'rootfs.wsl').symlink_to(SOURCE/'rootfs.wsl')
def test_tampered_deb_rejected(self):
with tempfile.TemporaryDirectory(prefix='cust73-negative-') as d:
p=Path(d);self.fixture(p)
deb=next((p/'archives').glob('*.deb'))
with deb.open('ab') as f:f.write(b'tamper')
old=verify_closure.BASE;verify_closure.BASE=p
try:
with self.assertRaisesRegex(ValueError,'untrusted package'):verify_closure.verify()
finally:verify_closure.BASE=old
def test_incomplete_closure_rejected(self):
with tempfile.TemporaryDirectory(prefix='cust73-negative-') as d:
p=Path(d);self.fixture(p)
pins=json.loads((p/'package-pins.json').read_text())
(p/'package-pins.json').write_text(json.dumps(pins[:-1]))
old=verify_closure.BASE;verify_closure.BASE=p
try:
with self.assertRaisesRegex(ValueError,'closure differs'):verify_closure.verify()
finally:verify_closure.BASE=old
def test_tampered_index_rejected(self):
with tempfile.TemporaryDirectory(prefix='cust73-negative-') as d:
p=Path(d);self.fixture(p)
index=next((p/'lists').glob('*_Packages'))
with index.open('ab') as f:f.write(b'tamper')
old=verify_closure.BASE;verify_closure.BASE=p
try:
with self.assertRaisesRegex(ValueError,'index hash mismatch'):verify_closure.verify()
finally:verify_closure.BASE=old
def test_installer_refuses_and_has_valid_syntax(self):
subprocess.run(['bash','-n',str(SOURCE/'install-disabled.sh')],check=True)
r=subprocess.run(['bash',str(SOURCE/'install-disabled.sh')],capture_output=True)
self.assertEqual(r.returncode,78)
if __name__=='__main__':unittest.main()

View file

@ -0,0 +1,10 @@
{
"capture_utc": "2026-10-19T12:56:47.718874+00:00",
"source_tests_passed": 4,
"signed_repository_count": 3,
"verified_packages": 7,
"rootfs_downloaded_verified": true,
"distro_created": false,
"packages_installed": false,
"r3_modified": false
}

View file

@ -0,0 +1,129 @@
{
"capture_utc": "2026-10-19T12:54:55.399648+00:00",
"rootfs_sha256": "bb415d824822c4b878125729af451a5d18fb13d1cf5cbed9a7393ad64ac6039e",
"dpkg_status_sha256": "5de2ab566fe9a9ab2f4d1f544dc3a44d6d25ab40414f69451ceb0609245d72e5",
"repositories": [
{
"file": "archive.ubuntu.com_ubuntu_dists_noble-updates_InRelease",
"sha256": "05c2c50a69e01a09541b744202c5267e5cdf0392f9cc5e3668f6771236c9ebd1",
"suite": "noble-updates",
"date": "Sun, 18 Oct 2026 23:55:07 UTC",
"valid_until": null,
"signers": [
"F6ECB3762474EDA9D21B7022871920D1991BC93C"
],
"packages_sha256": "12603c9c2691679fbf657cc6bf3f60a14affb37e3cf576e3042d980fe463c91f"
},
{
"file": "archive.ubuntu.com_ubuntu_dists_noble_InRelease",
"sha256": "cdb2f31d809f589719a53c6ad15f255b27569c4059542ada282aaa21b8e164b0",
"suite": "noble",
"date": "Thu, 25 Apr 2024 15:10:33 UTC",
"valid_until": null,
"signers": [
"F6ECB3762474EDA9D21B7022871920D1991BC93C"
],
"packages_sha256": "8f6f71ae839c8cba390a7643fcbbdacddb0bc7d12c1583a2dd80a1f8443a30e5"
},
{
"file": "security.ubuntu.com_ubuntu_dists_noble-security_InRelease",
"sha256": "ac9a742aef4fb5d0d52f43e5fd7631d9aaa0b643c45ab16ecfaf000b140be930",
"suite": "noble-security",
"date": "Mon, 19 Oct 2026 11:38:32 UTC",
"valid_until": null,
"signers": [
"F6ECB3762474EDA9D21B7022871920D1991BC93C"
],
"packages_sha256": "6b99baab015714c0f5fa3ca2a89e6b2ffb57a821ee99bddbc89316801eeb9dda"
}
],
"packages": [
{
"package": "libnftables1",
"version": "1.0.9-1ubuntu0.1",
"architecture": "amd64",
"sha256": "fcaee001747a6adaa0cd9337fef437b3aa7a7a6d5246b62fbd4784d3d6a5009e",
"bytes": 358574,
"local_file": "archives/libnftables1_1.0.9-1ubuntu0.1_amd64.deb",
"repository_path": "pool/main/n/nftables/libnftables1_1.0.9-1ubuntu0.1_amd64.deb",
"signed_suites": [
"noble-updates"
]
},
{
"package": "libnftnl11",
"version": "1.2.6-2build1",
"architecture": "amd64",
"sha256": "e5bde5c9cbb95082700011f0b7ef2c0a41900b0a9fd7434f6e90448e2a7b4e50",
"bytes": 65986,
"local_file": "archives/libnftnl11_1.2.6-2build1_amd64.deb",
"repository_path": "pool/main/libn/libnftnl/libnftnl11_1.2.6-2build1_amd64.deb",
"signed_suites": [
"noble"
]
},
{
"package": "libwrap0",
"version": "7.6.q-33",
"architecture": "amd64",
"sha256": "36118b862539868408ee056411d6e470068d14c46e5296b29bfb744770f5d2ce",
"bytes": 47874,
"local_file": "archives/libwrap0_7.6.q-33_amd64.deb",
"repository_path": "pool/main/t/tcp-wrappers/libwrap0_7.6.q-33_amd64.deb",
"signed_suites": [
"noble"
]
},
{
"package": "nftables",
"version": "1.0.9-1ubuntu0.1",
"architecture": "amd64",
"sha256": "d648859fccde3c17b8b9b89993427564f91f394a39306db1f67bd5ea3ac42c6e",
"bytes": 69842,
"local_file": "archives/nftables_1.0.9-1ubuntu0.1_amd64.deb",
"repository_path": "pool/main/n/nftables/nftables_1.0.9-1ubuntu0.1_amd64.deb",
"signed_suites": [
"noble-updates"
]
},
{
"package": "openssh-client",
"version": "1:9.6p1-3ubuntu13.20",
"architecture": "amd64",
"sha256": "5fb4429e9eff60a5b4ddb68ccf0c46ee67066b445794ede5fe181e64c4a8b795",
"bytes": 908792,
"local_file": "archives/openssh-client_1%3a9.6p1-3ubuntu13.20_amd64.deb",
"repository_path": "pool/main/o/openssh/openssh-client_9.6p1-3ubuntu13.20_amd64.deb",
"signed_suites": [
"noble-security"
]
},
{
"package": "openssh-server",
"version": "1:9.6p1-3ubuntu13.20",
"architecture": "amd64",
"sha256": "5d0d5eb672ddc27601e2da4e8465c5736dc73375a21bc1cd1834fcb08fb155bf",
"bytes": 511546,
"local_file": "archives/openssh-server_1%3a9.6p1-3ubuntu13.20_amd64.deb",
"repository_path": "pool/main/o/openssh/openssh-server_9.6p1-3ubuntu13.20_amd64.deb",
"signed_suites": [
"noble-security"
]
},
{
"package": "openssh-sftp-server",
"version": "1:9.6p1-3ubuntu13.20",
"architecture": "amd64",
"sha256": "111fb22cab9abf220b681f97eefa195ccfacef7d85561772ecef22e88db2d7bb",
"bytes": 37350,
"local_file": "archives/openssh-sftp-server_1%3a9.6p1-3ubuntu13.20_amd64.deb",
"repository_path": "pool/main/o/openssh/openssh-sftp-server_9.6p1-3ubuntu13.20_amd64.deb",
"signed_suites": [
"noble-security"
]
}
],
"package_count": 7,
"package_download_bytes": 1999964,
"installed": false
}

View file

@ -0,0 +1,79 @@
#!/usr/bin/env python3
"""Verify InRelease -> Packages -> .deb hashes, plus exact solver closure."""
from pathlib import Path
import datetime
import hashlib
import json
import re
import subprocess
BASE=Path(__file__).resolve().parent
def paragraphs(text):
for paragraph in text.strip().split('\n\n'):
result={};key=None
for line in paragraph.splitlines():
if line.startswith(' '):
if key is None: raise ValueError('orphan continuation')
result[key]+='\n'+line[1:]
else:
key,value=line.split(':',1)
if key in result:raise ValueError('duplicate field')
result[key]=value.strip()
yield result
def sha(data):return hashlib.sha256(data).hexdigest()
def verify():
releases=[];records=[]
for release in sorted((BASE/'lists').glob('*_InRelease')):
p=subprocess.run(['gpgv','--keyring','/usr/share/keyrings/ubuntu-archive-keyring.gpg',
'--status-fd','2','--output','-',str(release)],capture_output=True,check=True)
status=p.stderr.decode()
fingerprints=re.findall(r'\[GNUPG:\] VALIDSIG ([A-F0-9]+)',status)
if not fingerprints:raise ValueError('missing valid signer')
fields=next(paragraphs(p.stdout.decode()))
hashes={l.split()[2]:(l.split()[0],int(l.split()[1]))
for l in fields['SHA256'].splitlines() if l.strip()}
index=release.with_name(release.name.removesuffix('InRelease')+'main_binary-amd64_Packages')
if not index.exists():index=index.with_name(index.name+'.lz4')
raw=subprocess.check_output(['/usr/lib/apt/apt-helper','cat-file',str(index)])
digest,size=hashes['main/binary-amd64/Packages']
if (sha(raw),len(raw))!=(digest,size):raise ValueError('package index hash mismatch')
for record in paragraphs(raw.decode()):
if 'SHA256' in record:record['_suite']=fields['Suite'];records.append(record)
releases.append({'file':release.name,'sha256':sha(release.read_bytes()),
'suite':fields['Suite'],'date':fields.get('Date'),
'valid_until':fields.get('Valid-Until'),
'signers':fingerprints,'packages_sha256':digest})
if len(releases)!=3:raise ValueError('expected all three signed suites')
pins=json.loads((BASE/'package-pins.json').read_text())
verified=[]
for deb in sorted((BASE/'archives').glob('*.deb')):
data=deb.read_bytes();digest=sha(data)
candidates=[r for r in records if r['SHA256']==digest and int(r['Size'])==len(data)]
if not candidates:raise ValueError('untrusted package bytes')
r=candidates[0]
identity=subprocess.check_output(['dpkg-deb','--show','--showformat=${Package}\t${Version}\t${Architecture}',str(deb)],text=True).split('\t')
if identity!=[r['Package'],r['Version'],r['Architecture']]:raise ValueError('identity mismatch')
verified.append({'package':r['Package'],'version':r['Version'],'architecture':r['Architecture'],
'sha256':digest,'bytes':len(data),'local_file':str(deb.relative_to(BASE)),
'repository_path':r['Filename'],'signed_suites':sorted({c['_suite'] for c in candidates})})
actual={r['package']+'='+r['version'] for r in verified}
expected={p.replace(':amd64=','=') for p in pins}
if actual!=expected or len(verified)!=len(expected):raise ValueError('download closure differs from plan')
rootfs=BASE/'rootfs.wsl'
h=hashlib.file_digest(rootfs.open('rb'),'sha256').hexdigest()
if h!='bb415d824822c4b878125729af451a5d18fb13d1cf5cbed9a7393ad64ac6039e':raise ValueError('rootfs mismatch')
return {'capture_utc':datetime.datetime.now(datetime.timezone.utc).isoformat(),
'rootfs_sha256':h,'dpkg_status_sha256':sha((BASE/'rootfs-dpkg-status').read_bytes()),
'repositories':releases,'packages':verified,'package_count':len(verified),
'package_download_bytes':sum(p['bytes'] for p in verified),'installed':False}
if __name__=='__main__':
receipt=verify();(BASE/'verification-manifest.json').write_text(json.dumps(receipt,indent=2)+'\n')
print(json.dumps({'verified_packages':receipt['package_count'],'installed':False}))