Retain locked isolation recipe and verified dependency closure
This commit is contained in:
parent
8e67cfbb49
commit
04797021fd
36 changed files with 6732 additions and 0 deletions
127
docs/changes/CUST-WP-0073/interactive-launch-r3/PROPOSAL.md
Normal file
127
docs/changes/CUST-WP-0073/interactive-launch-r3/PROPOSAL.md
Normal 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.
|
||||
16
docs/changes/CUST-WP-0073/interactive-launch-r3/SHA256SUMS
Normal file
16
docs/changes/CUST-WP-0073/interactive-launch-r3/SHA256SUMS
Normal 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
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
|
|
@ -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.
|
||||
12
docs/changes/CUST-WP-0073/interactive-launch-r3/rootfs.json
Normal file
12
docs/changes/CUST-WP-0073/interactive-launch-r3/rootfs.json
Normal 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"
|
||||
}
|
||||
28
docs/changes/CUST-WP-0073/interactive-launch-r3/sshd_config
Normal file
28
docs/changes/CUST-WP-0073/interactive-launch-r3/sshd_config
Normal 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
|
||||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
|
@ -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-----
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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())
|
||||
16
docs/changes/CUST-WP-0073/interactive-launch-r3/wsl.conf
Normal file
16
docs/changes/CUST-WP-0073/interactive-launch-r3/wsl.conf
Normal 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
|
||||
|
|
@ -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
|
||||
60
docs/changes/CUST-WP-0073/ubuntu-dependencies-r1/README.md
Normal file
60
docs/changes/CUST-WP-0073/ubuntu-dependencies-r1/README.md
Normal 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.
|
||||
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
21
docs/changes/CUST-WP-0073/ubuntu-dependencies-r1/apt.conf
Normal file
21
docs/changes/CUST-WP-0073/ubuntu-dependencies-r1/apt.conf
Normal 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";
|
||||
|
|
@ -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)
|
||||
|
|
@ -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.
|
||||
|
|
@ -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"
|
||||
]
|
||||
|
|
@ -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)
|
||||
39
docs/changes/CUST-WP-0073/ubuntu-dependencies-r1/resolve.py
Normal file
39
docs/changes/CUST-WP-0073/ubuntu-dependencies-r1/resolve.py
Normal 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()
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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}))
|
||||
Loading…
Add table
Add a link
Reference in a new issue