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
Conversation
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.
…(aleph-vm#1001-#1010)
…24/24 on the testnet)
…-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
left a comment
There was a problem hiding this comment.
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
left a comment
There was a problem hiding this comment.
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
left a comment
There was a problem hiding this comment.
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.
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.shnow writesALEPH_VM_SUPERVISOR_IMPL(defaultrust, overridable from the environment) intosupervisor.envon every CRN.Pins
0.11.0(+ Kubov0.43.0as the release ships it)0.17.00.2.0(V-PROGRAM scheduling, aleph-vm-scheduler#193)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 inscripts/vprogram-artifacts.sh).What the run covers
test_confidential(SEV instance),test_vprograms(SEV-SNP V-PROGRAM exec + attested call),test_vprogram_compose(SEV-SNPaleph.compose/1).Not covered here:
test_vm_upgradeonly runs fromupgrade-check.yml(push tood/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.