Skip to content

test: whole suite on the Rust supervisor with pyaleph 0.11.0, aleph-cli 0.17.0, scheduler 0.2.0, aleph-vm #1168 - #37

Open
odesenfans wants to merge 63 commits into
mainfrom
od/snp-rust-supervisor-validation
Open

test: whole suite on the Rust supervisor with pyaleph 0.11.0, aleph-cli 0.17.0, scheduler 0.2.0, aleph-vm #1168#37
odesenfans wants to merge 63 commits into
mainfrom
od/snp-rust-supervisor-validation

Conversation

@odesenfans

Copy link
Copy Markdown
Contributor

Why

Only the confidential TEE server ran ALEPH_VM_SUPERVISOR_IMPL=rust; the DigitalOcean CRNs took the launcher's python default, so every non-confidential test on this testnet (instances, programs, migration, backups, port forwards, IPv6) still validated the Python supervisor. crn-up.sh now writes ALEPH_VM_SUPERVISOR_IMPL (default rust, overridable from the environment) into supervisor.env on every CRN.

Pins

  • pyaleph 0.11.0 (+ Kubo v0.43.0 as the release ships it)
  • aleph-cli 0.17.0
  • scheduler-rs / scheduler-api 0.2.0 (V-PROGRAM scheduling, aleph-vm-scheduler#193)
  • aleph-vm from od/drop-attest-cli (aleph-vm#1168 deb). aleph-vm#1169 is stacked on it and targets that branch, so the deb workflow never ran for it; its only change is the nix guest kernel, which is not in the deb (guest images come from the pinned fixtures in scripts/vprogram-artifacts.sh).

What the run covers

  • DO CRN 0/1 on the Rust supervisor + Rust controller: full regular suite.
  • Static TEE server on Rust: test_confidential (SEV instance), test_vprograms (SEV-SNP V-PROGRAM exec + attested call), test_vprogram_compose (SEV-SNP aleph.compose/1).

Not covered here: test_vm_upgrade only runs from upgrade-check.yml (push to od/upgrade-check-1.15-to-dev), and the V-PROGRAM fixtures are still the 2026-08-20 build (aleph-vm ba690c65), so the #1168 init/agent changes and the #1169 kernel are not in the measured guest yet.

odesenfans added 30 commits July 3, 2026 13:09
Point the CRN deployment at the aleph-vm dev-accelerate branch (PR #977:
gRPC supervisor rework, integration suite, directory-based VM migration)
so the testnet migration test exercises it end to end before merge.

crn-up.sh fetches aleph-vm.debian-12.deb from the branch's CI build
(build-deb-package-and-integration-tests.yml); the latest dev-accelerate
run is green and produces that artifact.

Revert to version: 1.13.0 once aleph-vm#977 lands.
scheduler 0.1.2 (#188) makes node_watcher poll the v2 executions endpoint,
so a gracefully-stopping VM stays observed (present as STOPPED) instead of
dropping out of the v1 running-only list and being reported 'missing' for the
~34s graceful-shutdown window. That is what broke test_instance_stop_start
on the dev-accelerate aleph-vm (whose stop is a graceful guest shutdown vs
the old near-instant teardown). Pairs with aleph-vm's stop=stop_vm change,
which keeps the stopped VM in the pool so v2 still lists it.
aleph-vm#977 (supervisor rework) merged into dev, so the temporary
dev-accelerate branch pin is obsolete (that branch will be deleted).
Point at dev to keep the migration and graceful-stop tests running
against the merged code until it reaches main and a release is cut.
Scheduler stays at 0.1.2 (graceful-stop tolerance).
Validate Phase 2 (gRPC wire + two-service packaging) on testnet. Phase 1 (#980)
has merged to dev; phase2 carries it plus the Phase 2 changes.
The static AMD SEV-SNP server runs Ubuntu 24.04 (Python 3.12), but the branch
path deployed the debian-12 .deb (cp311), so its vendored pydantic_core native
extension failed to import there and the supervisor crash-looped (confidential
test: :4020 connection refused). Provision CRN droplets as ubuntu-24.04 (CCN
already is) and fetch/deploy the ubuntu-24.04 branch .deb so the Python ABI
matches on every host including the TEE server.
Diagnosing the confidential create/registration on the SEV box: in the
two-service split the agent serves /control/* and /v2/about/executions/list, so
the confidential allocation result and the awaiting_confidential_init state live
in its journal, not the supervisor daemon's. Also switch the TEE journals from
-n 5000 to --since: the supervisor crash-loops during the static-server
reinstall and blew the line budget before the test window.
Validate PR-1 of the agent/supervisor boundary split (contract layer +
import-linter, behavior-neutral) on testnet.
…re origin

The test_confidential init-session 'VM not found' failure reproduced 2x on
#986 (od/agent-supervisor-contract), whose confidential-path code is import-only
vs dev. Run against dev to determine if the breakage is pre-existing (#984/#985)
rather than caused by #986. Will revert the pin afterwards.
…l failure is pre-existing on dev

Isolation run (manifesto pinned to dev) failed test_confidential identically
(VM not found at init-session), proving the breakage is pre-existing on dev
(#984/#985), not caused by #986. Restoring the pin to the PR-1 branch.
…#990)

Validate the complete combined stack (tip branch builds a .deb with all four
PRs) on testnet integration. Combined-stack GitHub CI is green (PR #991).
Known: the confidential SSH test is a pre-existing dev failure (needs the
.deb-selection fix + SEV hw); the other 23 are expected to pass.
The generated supervisor.env omitted ALEPH_VM_SUPERVISOR_GRPC_SOCKET, so the
agent ran its own in-process VmPool and never dialed the supervisor daemon. The
daemon ran idle alongside it. Every prior green #27 validated the in-process
path, not the two-process gRPC connector the boundary work is for.

Set the socket so the agent talks to the daemon over gRPC. Expect split-mode
gaps to surface (endpoints that still reach the in-process pool: backups,
restore, confidential, migration, network recreation, GPU reservation,
persistent programs).
The manifesto pinned od/fix-confidential-reconcile-teardown, deleted after #987
merged, so crn-up.sh could not fetch a build. dev now carries the full boundary
stack + the firecracker Configuration vm_id fix, and crn-up.sh sets the gRPC
socket. Deploy dev to exercise the two-process connector end-to-end for the
first time.
…-accelerate

# Conflicts:
#	.github/workflows/pr-tests.yml
#	scripts/crn-up.sh
Point every component at its V-PROGRAM-capable pre-release so the full
flow (CLI create/show/call with RA-TLS attestation) can be validated on
the testnet:

- pyaleph 0.10.3-rc7: first pinned release with the V-PROGRAM message
  handler, vms DB migration and cost model.
- aleph-cli 0.17.0-rc1: vprogram command set (create/show/call with
  RA-TLS attestation verification). Subsumes the pin from PR #32.
- scheduler-rs / scheduler-api vprogram-rc1: one-off images built from
  od/vprogram-scheduling (scheduler#193), adding V-PROGRAM ingestion,
  SEV-SNP capability matching and the v_programs allocation bucket.
- aleph-vm od/vprogram-integration: dev (gRPC split) plus the full
  vprogram stack (#1050..#1079) including the SNP launch path, measured
  workload volumes and the attestation port host mapping.
Adds the first genuine end-to-end attestation test: deploy the fib-service
measured workload with the Rust CLI, wait for scheduler placement on the
SEV-SNP TEE server, then exercise vprogram call, which only returns a body
after the AMD report chain verifies, the TLS key is bound to the report,
and the launch measurement matches the ones the CLI pinned at create time.
A wrong --expected-measurement must fail without printing any body.

Pieces:
- scripts/vprogram-artifacts.sh: fetch the prebuilt fixtures (runtime
  bundle, manifest template, fib-workload.ext4) from the
  vprogram-fixtures-1 release, sha256-pinned. The fixtures are
  nix-reproducible builds of aleph-vm od/vprogram-integration rev
  de9ed350; rebuild instructions in the release notes.
- conftest: vprogram_dir + vprogram_runtime_hash fixtures. The bundle is
  uploaded per run (fresh CCN each time); the manifest template's zeroed
  bundle.ref is patched with the run's STORE hash before upload.
- local-up.sh: export ALEPH_TESTNET_VPROGRAM_DIR when the fixtures dir
  exists; the test skips otherwise.
- pr-tests.yml: fetch fixtures on the CCN + install cryptsetup-bin there
  (vprogram create runs veritysetup locally to hash the workload).
… sample

First live run (31373843773) taught two things:

- vprogram create --json emits a submission receipt (type: V-PROGRAM,
  item_hash, message_status) rather than a full message envelope; match
  on the type field instead of content.verification.
- The rc1 CLI resolves the attested endpoint exactly once at readiness,
  before the CRN maps the attestation port (the mapping happens only
  after the SNP guest's measured boot: aleph-vm agent/run.py
  reconcile_vprogram_port_forwards runs post-_wait_until_running). Poll
  vprogram show as a fallback so the attestation path still gets
  exercised; drop the fallback once aleph-rs#318 ships in the pinned
  CLI.
Round-2 run (31378982391) launched the V-PROGRAM but the guest never
started: the agent created the VM then hit 'did not reach RUNNING within
120.0s' twice, and no aleph-vm-controller@ unit ever appeared for it.

Root cause: the aleph-vm deb ships both supervisor daemon
implementations behind ALEPH_VM_SUPERVISOR_IMPL (default python), and
the V-PROGRAM SNP auto-launch only exists in the Rust daemon
(lifecycle.rs: session-dir derivation, verity sidecar force-insert,
measured cmdline with workload_roothash; none of it exists in the
python daemon). The python daemon parks the AlephQemuConfidentialInstance
execution waiting for the operator session dance that classic
confidential instances perform and V-PROGRAMs never do.

Set ALEPH_VM_SUPERVISOR_IMPL=rust on the confidential CRN only (the
TEE server, the sole node that can run V-PROGRAMs). The Rust daemon
also implements the classic CVM session flow (confidential.rs), so
test_confidential stays covered; DO CRNs keep the default python
daemon that PR #27 has been validating.

Also stop + reset-failed all aleph-vm-controller@ units in tee-reset.sh:
the state wipe deletes controller.json files but left the units
restart-looping (observed at restart counter 844k), flooding the journal
and drowning the CI log capture.
Round 3 (31382627461) got the full chain working: measured SNP boot
under the Rust daemon, attestation port mapped, endpoint resolved on
the TEE server, and the guest's aleph-attest-agent bound :8443 with an
attested TLS identity - 3 seconds AFTER the test's first call. The CRN
maps the port at RUNNING (qemu up), a few seconds before guest
userspace finishes starting, so the first connection can land in that
gap.

Retry transport-level failures ('error sending request') for up to two
minutes; attestation verification failures still fail immediately.
Round 4 (31385362211): the SNP guest boots, aleph-attest-agent binds
0.0.0.0:8443, the DNAT host port is allocated and surfaced via the
executions list, yet external connections to it fail for minutes
(the CLI only sees 'error sending request'). The confidential
instance's SSH forward works on the same host, so the failure is
specific to the V-PROGRAM mapping.

Capture the host-level view after tests: nft ruleset, interfaces,
routes, listeners, plus two live probes: TEE host -> guest :8443
directly (guest reachability) and runner -> public host port (full
DNAT path). Their combination localizes the break.
Round 5's diagnostics only probed the first dnat-to-:8443 rule, which
turned out to be a STALE mapping from an earlier run (nft rules survive
tee-reset): port 24006 answered 200 while the run's own port 24008 went
unprobed. Loop over all rules so each mapping gets a host->guest and a
runner->DNAT probe, with compact status-code output.
…ails

Rounds 4-6 all show the identical signature: the guest's attest agent is
up and listening, the run's own DNAT rule exists through the failure
window (round 5's diagnostics listed it), a stale sibling rule to the
same guest IP serves curl 200, yet vprogram call fails with 'error
sending request' for the full retry window. Everything points at the
CLI's RA-TLS verifier rejecting the handshake (most plausibly a launch
measurement mismatch), which reqwest hides behind a transport-looking
error until aleph-rs#319 ships.

Capture ground truth at failure time: on the first failed call, curl the
same endpoint with no verification and carry the HTTP status into the
final assertion message. 200 there + CLI failure = verifier rejection,
beyond doubt.
rc2 carries aleph-rs#318 (create --wait polls for the attested endpoint
within the wait budget) and #319 (attestation rejections are named
instead of hiding behind 'error sending request').

- manifesto: aleph-cli 0.17.0-rc1 -> 0.17.0-rc2.
- test: remove the show-polling fallback; the ready payload's
  attested_endpoint is the CLI contract again. The warm-up retry stays
  (the port maps a few seconds before the guest binds), but with #319 a
  verification failure no longer matches the transient predicate, so it
  fails fast with the actual reason.
…6 on the CCN droplet

The new runtime (aleph-vm rev d9e0c5c6, #1125) waits out link-local DAD
before the guest's DHCPv6 solicit, the root cause of run 32147657203's
unreachable guest IPv6. Platform roothash is unchanged (initrd-only
change); the launch measurement moves to c632109e... and is computed by
the CLI at create time as usual. Also give the CCN droplet --enable-ipv6
like the CRN droplets: the previous run showed it has no v6 default
route, so the test's external v6 probe had no valid vantage point.
Probe stays warn-not-fail for this first post-fix run; promote to an
assertion once green.
The DAD wait alone did not restore guest IPv6: udhcpc's startup deconfig
was flushing the link-local away (aleph-vm#1126, root-caused and
verified in a local qemu boot). Pin the rebuilt bundle + manifest.
Run 32169787438: the guest now leases and serves its IPv6 (host-side
probe 200 after aleph-vm#1126), but the external path still times out.
ndppd runs with the correct iface-mode rule; the Scaleway experiments
validated kernel proxy-NDP end to end on this host. Add a proxy entry
for the guest during diagnostics and re-probe from the droplet: a 200
with the entry in place convicts ndppd.
Established: Scaleway routes the /64 to the host (no NDP needed; live
capture showed external SYNs arriving), the ip6 forward chains are open,
and dnsmasq's RA carries router lifetime 1800s (netns-verified with the
exact production flags). Replace the kernel-proxy A/B (moot under routed
delivery) with simultaneous tcpdumps on the uplink and the tap during a
droplet probe: the segment where the SYN or SYN-ACK vanishes names the
culprit (host forward, guest reply, or fabric egress).
Root cause of the external v6 timeout, established with on-host
captures: Scaleway's NATIVE /64 is inbound-routed but egress-filtered to
the registered primary address, so VM-sourced replies egress the NIC and
are silently dropped by the fabric; the attached flexible-IP /64 uses
the on-link NDP model (which the daemon's ndppd serves) and its egress
is open. Verified end to end on the host: a netns emulating a VM behind
a /124 + an NDP proxy entry answers external HTTP over the fip /64.
crn-up.sh gains STATIC_CRN_IPV6_POOL to override the (broken) derived
native pool for static CRNs; the workflow sets it to the TEE server's
fip 2001:bc8:702:32d::/64.
Run 32184087567 was fully green: droplet -> internet -> Scaleway ->
ndppd -> host -> tap -> guest at [fip::61]:8443 answered 200 over the
complete designed chain (DHCPv6 single-address lease, RA default route,
iface-mode NDP proxying, dual-stack attest agent). Promote the probe
from warn to a hard assertion so the v6 path is a regression gate from
here on.
Full-stack refresh for the new validation session:

- aleph-vm deb from od/snp-inst-4-agent (#1131 tip ba690c65: dev with the
  merged compose runtime plus the SNP-instances stack)
- aleph-cli 0.17.0-rc10 (vprogram create --compose, liveness nonce,
  KDS CRL revocation, measurement/policy pins)
- pyaleph 0.10.3-rc8
- runtime fixtures repinned to the 2026.08.20 bundle + manifest
  (measurement 04729caf..., platform roothash unchanged); the fib
  workload now comes from mainnet storage (2026-08-18 nix rebuild)
  instead of the vprogram-fixtures-1 GitHub prerelease
…rt map)

Run 32361553700: the V-PROGRAM booted and went ready but the CLI resolved
no attested endpoint. od/snp-inst-4-agent is missing the four
validation-only commits that lived on od/vprogram-integration-2 (notably
aleph-vm#1079, the attestation port map). od/vprogram-integration-3
(aleph-vm#1142) is #1131 plus those four cherry-picks.
Adds the compose leg on top of the 2026.08.20 repin:

- fixtures: the compose runtime bundle (297 MB, fetched from mainnet IPFS
  by CID, sha256-pinned like everything else) and its manifest template
- conftest: vprogram_compose_runtime_hash uploads both to the testnet;
  the forced native storage engine works past the CLI's 100 MiB default
  cutoff because the CCN config raises max_file_size to 4 GiB
- test: vprogram create --compose with a single traefik/whoami service
  (network_mode host, --port 8080), wait ready on the TEE server, then
  an attested / call must return the container's whoami dump

Requires aleph-cli 0.17.0-rc10 (vprogram create --compose, aleph-rs#344)
and the aleph.compose/1 runtime published 2026-08-20 (aleph-vm#1132
runtime flavor, bundle a30b27cc..., manifest 3f7e5a25...).
Run 32372006187: the compose VM booted, attested (nonce freshness
verified) and the call reached the guest, but the whoami container was
not up yet; the attest agent answered with an upstream-unreachable 502
body while the CLI exited 0, so the retry loop took the first sample as
final. Retry on that body too, with a 240s budget for the in-guest
podman load + compose up, and keep transport failures retried as
before.
Root cause of runs 32372006187/32375910277, reproduced in a local qemu
boot of the compose runtime: rc10's docker fallback saves the archive
from the digest-pinned ref, and docker save name@sha256:... writes
RepoTags: null, so the guest's podman load imports a bare image ID that
podman-compose cannot match against the pinned image: string (short-name
resolution fails without a registries.conf, fail-closed poweroff).

Supply the archive ourselves with a TAGGED docker save and
--image-archive, which the CLI maps verbatim: podman load restores the
tag and compose resolves it from local storage (whoami verified up on
:8080 in the local boot). Archive bytes stay verity-measured either way.
Drop once the CLI saves archives under a podman-matchable reference.

Also raise the job timeout to 75 min: two SNP boots per run pushed the
suite past 60 (run 32375910277 was killed at the limit).
…shed aleph-vm aggregation

All three registers-schema adopters (pyaleph 0.10.3-rc9, aleph-cli
0.17.0-rc11, aleph-vm od/vprogram-integration-3 rebuilt on dev 2df8d87e)
move together; scheduler images bumped to the vprogram-rc2 build.
Run 32416035775 attempt 2 lost the documented nodestatus-balances race:
the confidential rootfs upload still saw 'Insufficient balance' after
180s while the same upload passed on attempt 1 and every earlier run of
the day. Give the asynchronous funding more room; real cost shortfalls
still fail, just later.
The validation aggregation branch is fully merged (aleph-vm #1131,
#1147, #1148); dev's tree matches the branch that passed run
32426136992.
scheduler-rs/scheduler-api move to the 2026-08-24 vprogram-rc3 build.
aleph-vm stays pinned to dev, which gained the measured-CPU SNP launch
(#1145), agent-owned VM disks (#1149) and the SNP vCPU probe retry
(#1150) since the last green run.
dev gained agent-side backups with supervisor guest quiescence (#1151),
disk admission before resource download (#1153), the dead proto
reservation cleanup (#1154) and FAILED reporting for dead controller
units (#1152) since the last green run.
The Siena/Zen4c TEE host reports x86 microcode 0x0AA0021C (SPL 28) since
its 2026-08-24 reboot, above rc11's Zen4c EntrySign floor of 25, so the
--min-tcb microcode=21 --accept-outdated-tcb override the V-PROGRAM tests
carried since 2026-08-17 is obsolete. Dropping it also makes the runs
exercise the real TCB gate again instead of lowering every silicon line's
floor (which is what the CLI's 'accepting a TCB below the network floor'
warning was about).
Throwaway harness for the 2.0 release readiness call: install the 1.15.0
release deb, boot a QEMU instance with a disk marker and an extra port
forward, upgrade the CRN in place to the dev branch's CI deb via the new
crn-up.sh --upgrade, and assert the instance survived untouched: same
controller unit main PID and start time, exactly one QEMU process (no
double boot), same vm_index in the controller config, same rootfs inode,
listed by the new supervisor/agent, no adoption errors in the journals,
port forward kept, marker readable, stop/start still working and coming
back on the same rootfs file. A second scenario flips
ALEPH_VM_SUPERVISOR_IMPL python -> rust -> python on the upgraded node
with the same checks.

Ported from od/aleph-vm-upgrade-checks onto the validated dev-era stack
(pyaleph rc9, scheduler vprogram-rc3, cli rc11), without the TEE host
steps: the static SNP server is on mainnet and must not be touched.
…st poll lands on a serving node

Run 33010889646: --register restarted the supervisor right after staking,
the scheduler's node watcher polled during the restart window, marked the
node Unreachable, and the first instance message stayed unscheduled for
5 min (no reschedule trigger on recovery), past the dispatch timeout.
Set ALEPH_VM_NODE_HASH, restart, wait for :4020, then link.

Scenario B now fails fast with a clear message when the node was never
upgraded (no supervisor-launcher), instead of blaming the rust swap.
… live on the TEE server

The TEE server joins as static confidential CRN index 1 (baseline 1.15.0
installed on it too). Scenario A now creates a plain instance and an SEV
instance (init-session + measured start + secret injection), upgrades
every CRN in one pass (UPGRADE_STATIC=1 opts the static server in), and
asserts both survived untouched; the SEV VM additionally has to report
SEV active and a dm-crypt root after the upgrade, and to come back on the
same rootfs after stop, start, re-init-session and secret injection.
Scenario B gains an SEV variant: python -> rust -> python swap with the
confidential VM live, stop/start under the Rust daemon.

Host commands honour the per-CRN ssh-user (the TEE server is non-root
with passwordless sudo), like crn-up.sh.
…17.0 / 0.2.0 releases

Until now only the confidential TEE server ran ALEPH_VM_SUPERVISOR_IMPL=rust;
the DigitalOcean CRNs took the launcher's python default, so every
non-confidential test (instances, programs, migration, backups, port
forwards, IPv6) on this testnet still validated the Python supervisor.
crn-up.sh now writes ALEPH_VM_SUPERVISOR_IMPL (default rust, overridable
from the environment) into supervisor.env on every CRN.

Version pins: pyaleph 0.11.0 (with its Kubo v0.43.0), aleph-cli 0.17.0,
scheduler-rs/api 0.2.0 (V-PROGRAM scheduling, aleph-vm-scheduler#193),
aleph-vm from od/drop-attest-cli (PR #1168; #1169 is stacked on it and
has no deb build, its kernel change is not part of the deb anyway).

@foxpatch-aleph foxpatch-aleph left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well-structured PR that switches all CRNs to the Rust supervisor, adds V-PROGRAM end-to-end tests, and introduces an in-place upgrade test harness. The code is thorough with excellent diagnostic logging and well-documented race condition mitigations. The main concern is a file-read-during-write bug in the TEE network diagnostics step, plus a few minor observations.

.github/workflows/pr-tests.yml (line 403): The uplink and tap variables are obtained by grepping tee-network.txt from within the same { ... } > tee-network.txt 2>&1 block that is actively writing to that file. Since the shell opens the file for writing (truncation) before the block executes, and stdio output to the file may not be flushed by the time grep reads it, these variables will likely be empty, silently skipping the dual-capture diagnostic. Consider writing the static diagnostic output to a temporary variable or file first, then grep from that, before redirecting everything into tee-network.txt.

.github/workflows/pr-tests.yml (line 424): The DNAT-rule probing loop at the end (grep -E \"dnat.*:8443\" tee-network.txt | while ...) reads tee-network.txt after the { } block has closed, so the file is fully written at that point. However, the while read loop appends to tee-network.txt with >>, which is fine. One concern: if the earlier IPv6 section's { } block has already closed, the file content is complete, but the DNAT probe results are appended after the closing done of the outer block — this works but the appended content won't be visible if the file is later read by the upload step (it will be, since >> flushes). This is OK.

scripts/crn-up.sh (line 80): With the manifesto now using branch: instead of version: for aleph-vm, read_vm_version() will throw a KeyError if ever called without ALEPH_VM_VERSION set. Currently this path is unreachable because read_vm_branch() returns the manifesto branch first, but it's a latent fragility. Consider using m['components']['aleph-vm'].get('version') or adding a guard that errors with a clear message when neither version: nor ALEPH_VM_VERSION is available.

tests/test_vm_upgrade.py (line 150): The vm_hash is interpolated directly into a pgrep -f pattern: f\"pgrep -f '[q]emu-system-x86_64.*{vm_hash}' || true\". While vm_hash comes from the aleph CLI's JSON output (a hex hash), this pattern is injectable if the hash were ever malformed. Consider quoting or validating the hash format before interpolating it into remote shell commands.

tests/test_vm_upgrade.py (line 76): The _crn_run default timeout is 60 seconds. Some commands invoked through this helper (e.g., journalctl with large log volumes, or apt-get operations) may exceed 60s. The callers that need more time should pass an explicit timeout= — most do, but a few (like _supervisor_exe at line 126 calling readlink -f /proc/{pid}/exe) use the default, which is fine for that case. Just something to be aware of as new callers are added.

tests/test_vprograms.py (line 162): Neither test_vprogram_deploy_and_attested_call nor test_vprogram_compose_deploy_and_attested_call clean up (delete) the V-PROGRAM after the test. This is fine for CI (fresh testnet each run + tee-reset.sh wipes VM state), but adding a try/finally with aleph_cli(\"vprogram\", \"delete\", item_hash, ...) would be good hygiene for local dev runs and matches the pattern used in test_vm_upgrade.py.

tests/test_vm_upgrade.py (line 408): The confidential fixture has scope=\"module\" but catches pytest.skip.Exception. If the underlying fixtures (e.g., confidential_crn_host) are scope=\"session\", requesting them from a module-scoped fixture is fine, but the skip exception class check (pytest.skip.Exception) is an internal pytest API that may change between versions. Consider using pytest.skip.Exception via except Exception with a check for isinstance(e, pytest.skip.Exception) or simply catching pytest.skip.Exception — which is what's done here. This works but is fragile across pytest versions.

Kubo v0.43.0 refuses to start when the config still carries the pre-0.42
Reprovider.* keys ("deprecated configuration detected. Manually migrate
'Reprovider' fields to 'Provide'"), so pyaleph never got its IPFS daemon
and the CCN failed its readiness wait on the first run of #37.

@foxpatch-aleph foxpatch-aleph left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well-structured PR that pins new component versions, forces the Rust supervisor on all CRNs, adds V-PROGRAM and in-place upgrade test suites, and fixes the Kubo config key for v0.43.0. The code is generally correct with thorough comments explaining non-obvious decisions (scheduler race conditions, IPv6 egress filtering, fixture provenance). The main observations are: a hardcoded IPv6 pool in the workflow (acceptable for testnet but fragile if infrastructure changes), docker pull/save in test_vprogram_compose.py using check=True which produces a raw traceback instead of a pytest failure message, and the very long inline TEE diagnostics block in pr-tests.yml that could be a script file for maintainability. None of these are blocking.

.github/workflows/pr-tests.yml (line 277): STATIC_CRN_IPV6_POOL=2001:bc8:702:32d::/64 is hardcoded. If the Scaleway flexible-IP /64 ever changes, this will silently break V-PROGRAM IPv6 reachability tests with no obvious error pointing here. Consider sourcing it from a secret or documenting the dependency more visibly.

tests/test_vprogram_compose.py (line 58): docker pull/save use check=True, which raises CalledProcessError on failure (a raw traceback) instead of pytest.fail (a clean message). The test still fails, but the diagnostics are worse. Consider check=False + an assert with the stderr tail, matching the pattern used for aleph_cli calls in the same test.

.github/workflows/pr-tests.yml (line 335): The TEE network diagnostics step is ~100 lines of inline bash. Consider extracting it to scripts/tee-diagnostics.sh for readability and reuse — the upgrade-check.yml workflow would benefit from the same diagnostics.

tests/test_vm_upgrade.py (line 154): The nested python3 -c command with escaped double quotes inside the SSH command string is correct but fragile to modify. A comment with an example of the expanded command would help future maintainers.

tests/test_vprogram_compose.py (line 108): The retry loop references root after the loop exits (line 131 asserts on root.stdout). If the loop were to exit without the break (e.g., due to an unexpected exception path), root would be the last assigned value, which might be a non-successful result. The current logic is correct since the only break is on success, but the coupling between loop control and the variable is implicit.

Run 2 of #37 (33112723550) ran the whole suite on the Rust supervisor:
28/31 green including the SEV instance; the three failures were harness
drift, not supervisor behaviour:

- aleph-cli 0.17.0 made the V-PROGRAM name a mandatory positional
  (aleph-rs#361); both vprogram create calls pass one, ahead of the
  optional-valued --wait.
- tests/test_vm_upgrade.py ran under pr-tests without GH_TOKEN and with
  the deleted `dev` branch as candidate. It is opt-in now: the module
  skips unless ALEPH_VM_UPGRADE_BRANCH is set, which only
  upgrade-check.yml does, and that workflow's candidate is `main`.
- aleph-vm deb from `main`: #1168 merged, everything dev carried is on
  main now.

@foxpatch-aleph foxpatch-aleph left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well-structured PR that switches the full test suite to the Rust supervisor, pins pyaleph 0.11.0 / aleph-cli 0.17.0 / scheduler 0.2.0, adds V-PROGRAM and V-PROGRAM compose end-to-end tests, and introduces a thorough in-place upgrade validation workflow. The test coverage is excellent (controller snapshots, QEMU PID tracking, rootfs inode checks, adoption error detection, supervisor impl swap tests). Comments are detailed and explain non-obvious decisions well. The concerns noted (unsanitized variables in remote shell commands, deb cache reuse, missing V-PROGRAM cleanup) are minor and non-blocking — the controlled CI environment and existing cleanup mechanisms (tee-reset.sh) mitigate them in practice.

tests/test_vm_upgrade.py (line 194): The pattern and since_ts are interpolated into a remote shell grep -iE command. since_ts comes from a controlled date format so this is safe today, but consider using printf '%q' or adding a comment noting the format constraint, to prevent future format changes from silently breaking the remote command.

scripts/crn-up.sh (line 793): The cached upgrade deb (aleph-vm-upgrade.${deb_variant}.deb) persists across calls. If --upgrade is invoked twice with different targets (branch A then branch B), the second call reuses the stale cached deb from the first because the filename doesn't encode the branch/version. Consider removing the cached file at the end of upgrade_crn or including the branch in the filename.

tests/test_vprogram_compose.py (line 51): The V-PROGRAM testnet-whoami is never deleted after the test. While tee-reset.sh wipes execution state, the on-chain message persists. If the test is re-run against the same testnet, vprogram create testnet-whoami may fail on the duplicate name. Consider adding a try/finally with vprogram delete or using a unique name.

tests/test_vprograms.py (line 36): Same as the compose test — the V-PROGRAM testnet-fib is never deleted. Consider adding cleanup in a try/finally block.

.github/workflows/pr-tests.yml (line 403): The diagnostic step greps tee-network.txt while the enclosing redirect is still writing to it. This works because earlier output is flushed sequentially, but it is fragile — if output ordering changes, the grep patterns may miss. A comment noting this dependency on sequential flush would help future maintainers.

deploy/001-update-ipfs-config.sh (line 6): The config key rename from Reprovider.Strategy to Provide.Strategy has no version guard. If this script ever runs against a pre-0.42 Kubo, it will fail. Since the manifesto pins v0.43.0 this is safe, but a comment noting the minimum Kubo version would be helpful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants