adacam/scripts/build/build-artifact-from-existing.py
Kayos ed7ae5ba57 docs+scripts: project status, build scripts, patched usb-updater v5
- PROJECT_STATUS.md: full project log (hardware, partitions, artifacts, lessons learned, next steps)
- scripts/build/build-artifact-from-existing.py: rebuild artifact from existing data tar with new header
- scripts/build/build-v5-patched-updater.sh: patch system.img usb-updater + build artifact
- recovery/usb-updater-v5-patched: patched usb-updater with SSH recovery prepended

adacam-ssh-fix-v5.mender: 403MB, SHA256 acfbd16db9620f23785f8b103ffaeff6aed780f383273a61a23c8002f2bf0980
Status: PENDING TEST on replacement Bee (192.168.0.10)
2026-03-16 09:58:45 -07:00

104 lines
3.7 KiB
Python

import tarfile, hashlib, io, os
EXISTING = '/workspace/projects/adacam/recovery/adacam-ssh-fix.mender'
OUT = '/workspace/projects/adacam/recovery/adacam-ssh-fix-v4.mender'
SSH_FIX = b"""#!/bin/bash
# Debug: write status to USB so we can see if this actually ran
USB_LOG=/mnt/usb/hivemapper_update/state_script.log
echo "STATE SCRIPT RAN at $(date)" > $USB_LOG 2>/dev/null || true
cat > /etc/ssh/sshd_config << 'SSHEOF'
PermitRootLogin yes
AuthorizedKeysFile .ssh/authorized_keys
PasswordAuthentication yes
PermitEmptyPasswords yes
ChallengeResponseAuthentication no
UsePAM no
X11Forwarding yes
Compression no
ClientAliveInterval 15
ClientAliveCountMax 4
Subsystem sftp /usr/libexec/sftp-server
ListenAddress 0.0.0.0
SSHEOF
mkdir -p /home/root/.ssh
cat > /home/root/.ssh/authorized_keys << 'KEYS'
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK87jxvlXvo60pxwdtyJsXeFsb4KsAiFx4FnyXz81kh7 cobb@adacam
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOQxwJU91TCxds34P18D3xRbu7rxlrgTUoml/H8nxeDK kayos@openclaw
KEYS
chmod 700 /home/root/.ssh
chmod 600 /home/root/.ssh/authorized_keys
systemctl restart sshd 2>/dev/null || kill -HUP $(pgrep -x sshd | head -1) 2>/dev/null
echo "SSHD RESTARTED at $(date)" >> $USB_LOG 2>/dev/null || true
echo "overlay path: $(ls -la /data/overlay/current/ssh/ 2>&1)" >> $USB_LOG 2>/dev/null || true
echo "sshd_config written: $(cat /etc/ssh/sshd_config 2>/dev/null | head -3)" >> $USB_LOG 2>/dev/null || true
exit 0
"""
def sha256b(b):
return hashlib.sha256(b).hexdigest()
def sha256f(p):
h = hashlib.sha256()
with open(p,'rb') as f:
while True:
c = f.read(1024*1024)
if not c: break
h.update(c)
return h.hexdigest()
print('Extracting existing artifact...')
with tarfile.open(EXISTING,'r:') as art:
version_data = art.extractfile('version').read()
os.makedirs('/tmp/aw2/data',exist_ok=True)
art.extract(art.getmember('data/0000.tar.gz'),'/tmp/aw2/')
dtp = '/tmp/aw2/data/0000.tar.gz'
print(f'data tar: {os.path.getsize(dtp)/1024/1024:.0f}MB')
print('Hashing files in data tar...')
file_hashes = {}
with tarfile.open(dtp,'r:gz') as dt:
for m in dt.getmembers():
f = dt.extractfile(m)
if not f: continue
h = hashlib.sha256()
while True:
c = f.read(1024*1024)
if not c: break
h.update(c)
file_hashes[m.name] = h.hexdigest()
print(f' {m.name}: {h.hexdigest()[:16]}...')
print('Building header...')
hdr_buf = io.BytesIO()
with tarfile.open(fileobj=hdr_buf, mode='w:gz') as hdr:
for name,data in [
('header-info', b'{"payloads":[{"type":"dm-verity-update"}],"artifact_provides":{"artifact_name":"adacam-ssh-fix-v2"},"artifact_depends":{"device_type":["keembay"]}}'),
('headers/0000/type-info', b'{"type":"dm-verity-update"}'),
('headers/0000/meta-data', b'{}'),
]:
ti = tarfile.TarInfo(name=name); ti.size=len(data)
hdr.addfile(ti, io.BytesIO(data))
ti = tarfile.TarInfo(name='scripts/ArtifactInstall_Enter_00')
ti.size=len(SSH_FIX); ti.mode=0o755
hdr.addfile(ti, io.BytesIO(SSH_FIX))
hdr_bytes = hdr_buf.getvalue()
manifest = '\n'.join([
f'{file_hashes["system.img"]} data/0000/system.img',
f'{file_hashes["syshash.img"]} data/0000/syshash.img',
f'{file_hashes["boot.img"]} data/0000/boot.img',
f'{sha256b(hdr_bytes)} header.tar.gz',
f'{sha256b(version_data)} version',
]).encode()+b'\n'
print('Building artifact...')
with tarfile.open(OUT,'w:') as art:
for name,data in [('version',version_data),('manifest',manifest),('header.tar.gz',hdr_bytes)]:
ti=tarfile.TarInfo(name=name); ti.size=len(data)
art.addfile(ti,io.BytesIO(data))
art.add(dtp,arcname='data/0000.tar.gz')
print(f'DONE: {os.path.getsize(OUT)/1024/1024:.1f}MB')