Skip to content

Commit bcf5a0a

Browse files
SashaMITcursoragent
andcommitted
ci(vz-backend): Phase 1.1 polish — Linux verification + protected-paths gate
Closes the two verified gaps surfaced in the Phase 1 self-review: • Caveat #1: elastos-vz's Linux build path was unverified (dev work happened entirely on macOS). The existing ci.yml runs the full workspace check/clippy/test on ubuntu-latest but only on `main`, so Phase 1 commits on `sash/local-test` never hit it. • Caveat #2: scripts/check-linux-untouched.sh existed as a script anyone *could* run, not a gate anything *must* pass. Phase 2/3 commits could theoretically modify a protected crate without anyone noticing until manual review. Changes: • .github/workflows/ci.yml — extend push triggers to also include `sash/**` and `vz/**` so the existing check/clippy/test/build matrix runs on Vz-backend working branches. PR-to-main trigger unchanged. Modification is two new branch patterns; no job semantics changed. • .github/workflows/linux-untouched.yml — new dedicated workflow that runs scripts/check-linux-untouched.sh against the Phase 0 baseline commit (a65dad3). Triggers on push to Vz branches and on PRs to main. Uses fetch-depth: 0 so `git merge-base` can resolve against the baseline. • Local cargo fmt fixes applied to elastos-vz/{config,lib,provider, vm,tests/smoke}.rs that surfaced when running the same `cargo fmt --all -- --check` the CI workflow uses. No semantic changes. Verification (all green on macOS dev host): • cargo fmt --all -- --check ✅ • cargo clippy --workspace --all-targets ✅ (with -D warnings) • cargo test -p elastos-vz ✅ 37/37 • Linux-untouched gate vs a65dad3 ✅ Linux behaviour: still byte-equivalent to pre-Vz commit (workflow changes don't touch source). Mac behaviour: unchanged. Pending verifications (deferred to first CI run after push): • Linux build of elastos-vz + workspace • Linux test pass of elastos-vz + workspace • Linux-untouched gate run in GitHub Actions context Caveats #3 (mac-vz-feature-check stub) and #4 (pre-existing darwin-arm64 setup.rs failures inherited from Pre-Work 9fc4a7e) are intentionally not addressed here: #3 will be exercised by Phase 2's Vz API work; #4 is a separate non-blocking fix-up. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent dcbde90 commit bcf5a0a

7 files changed

Lines changed: 79 additions & 34 deletions

File tree

.github/workflows/ci.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ name: CI
22

33
on:
44
push:
5-
branches: [main]
5+
# Run on main and on Vz-backend working branches so Phase 1+ commits
6+
# get verified on Linux without waiting for a PR. The `sash/**`
7+
# pattern covers the current Vz development branch
8+
# (`sash/local-test`) and any future Vz sub-branches.
9+
branches: [main, "sash/**", "vz/**"]
610
pull_request:
711
branches: [main]
812

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: Linux-untouched gate (Vz backend)
2+
3+
# Enforces the Linux-untouched guarantee from docs/vz-backend/PLAN.md:
4+
# Phase 1+ Vz-backend commits must not modify the four protected crates
5+
# (elastos-crosvm, elastos-runtime, elastos-common, elastos-compute).
6+
#
7+
# Runs `scripts/check-linux-untouched.sh` against the Phase 0 baseline
8+
# (commit a65dad3 — the last commit before Vz work began). The script
9+
# itself documents how to adjust the base ref locally.
10+
#
11+
# Anchors:
12+
# - docs/vz-backend/PLAN.md → "Linux-untouched: explicit guarantees"
13+
# - PRINCIPLES.md #10 "One Canonical Path"
14+
# - scripts/check-linux-untouched.sh
15+
16+
on:
17+
push:
18+
branches: ["sash/**", "vz/**"]
19+
pull_request:
20+
branches: [main]
21+
22+
jobs:
23+
linux-untouched:
24+
name: Protected crates not modified vs Vz baseline
25+
runs-on: ubuntu-latest
26+
steps:
27+
- uses: actions/checkout@v4
28+
with:
29+
# Full history needed for `git merge-base` to find the
30+
# divergence point against the baseline commit.
31+
fetch-depth: 0
32+
33+
- name: Run protected-paths gate
34+
env:
35+
# Phase 0 baseline commit — last commit on sash/local-test
36+
# before Vz-backend Phase 1 work started. Update this only
37+
# if the project decides to re-baseline (e.g., after rebase
38+
# onto a newer upstream main). See docs/vz-backend/PLAN.md.
39+
VZ_BACKEND_BASELINE: a65dad3
40+
run: |
41+
set -euo pipefail
42+
# Make sure the baseline commit is reachable in the checkout.
43+
# Shallow clones don't always have it; `fetch-depth: 0` above
44+
# asks for the full history but defend against any quirks.
45+
if ! git cat-file -e "${VZ_BACKEND_BASELINE}^{commit}" 2>/dev/null; then
46+
git fetch origin "${VZ_BACKEND_BASELINE}" || true
47+
fi
48+
chmod +x scripts/check-linux-untouched.sh
49+
scripts/check-linux-untouched.sh "${VZ_BACKEND_BASELINE}"

elastos/crates/elastos-vz/src/config.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -251,10 +251,8 @@ impl VmConfig {
251251
// Default boot args use the Vz console device. The supervisor
252252
// may pass crosvm-style args through manifest overrides; the
253253
// `vz_boot_args` accessor rewrites them at construction time.
254-
let default_boot_args = format!(
255-
"console={} reboot=k panic=1 init=/init",
256-
VZ_CONSOLE_DEVICE
257-
);
254+
let default_boot_args =
255+
format!("console={} reboot=k panic=1 init=/init", VZ_CONSOLE_DEVICE);
258256
let base_boot_args = microvm
259257
.map(|m| rewrite_console_for_vz(&m.boot_args))
260258
.unwrap_or(default_boot_args);
@@ -437,7 +435,9 @@ mod tests {
437435
std::path::Path::new("/k/vmlinux"),
438436
);
439437
// Empty boot_args triggers the default branch.
440-
assert!(config.boot_args.contains("console=hvc0") || config.boot_args.contains("init=/init"));
438+
assert!(
439+
config.boot_args.contains("console=hvc0") || config.boot_args.contains("init=/init")
440+
);
441441
}
442442

443443
#[test]
@@ -450,7 +450,9 @@ mod tests {
450450
)
451451
.with_session("abc12345", "http://127.0.0.1:3000");
452452
assert!(config.boot_args.contains("elastos.token=abc12345"));
453-
assert!(config.boot_args.contains("elastos.api=http://127.0.0.1:3000"));
453+
assert!(config
454+
.boot_args
455+
.contains("elastos.api=http://127.0.0.1:3000"));
454456
}
455457

456458
#[test]

elastos/crates/elastos-vz/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,10 @@ mod tests {
128128

129129
// Off-mac platforms must always return false.
130130
#[cfg(not(all(target_os = "macos", target_arch = "aarch64")))]
131-
assert!(!supported, "is_supported() must be false outside macOS arm64");
131+
assert!(
132+
!supported,
133+
"is_supported() must be false outside macOS arm64"
134+
);
132135
}
133136

134137
#[test]

elastos/crates/elastos-vz/src/provider.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -179,11 +179,7 @@ impl VzProvider {
179179

180180
/// Append boot arguments to a VM before start. Fails closed in
181181
/// Phase 1.
182-
pub async fn append_boot_args_for_vm(
183-
&self,
184-
capsule_id: &CapsuleId,
185-
_args: &str,
186-
) -> Result<()> {
182+
pub async fn append_boot_args_for_vm(&self, capsule_id: &CapsuleId, _args: &str) -> Result<()> {
187183
Err(ElastosError::Compute(format!(
188184
"{} (append_boot_args_for_vm: capsule='{}')",
189185
PHASE_1_STUB_MESSAGE, capsule_id.0

elastos/crates/elastos-vz/src/vm.rs

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,8 @@ mod tests {
122122
#[test]
123123
fn running_vm_new_captures_config_and_starts_stopped() {
124124
let m = manifest();
125-
let config = VmConfig::from_manifest(
126-
&m,
127-
std::path::Path::new("/c"),
128-
std::path::Path::new("/k"),
129-
);
125+
let config =
126+
VmConfig::from_manifest(&m, std::path::Path::new("/c"), std::path::Path::new("/k"));
130127
let vm = RunningVm::new(config, m, PathBuf::from("/tmp/vm.sock"));
131128
assert!(matches!(vm.status, CapsuleStatus::Stopped));
132129
assert!(!vm.is_running());
@@ -135,11 +132,8 @@ mod tests {
135132
#[tokio::test]
136133
async fn running_vm_start_fails_closed_with_phase_1_stub() {
137134
let m = manifest();
138-
let config = VmConfig::from_manifest(
139-
&m,
140-
std::path::Path::new("/c"),
141-
std::path::Path::new("/k"),
142-
);
135+
let config =
136+
VmConfig::from_manifest(&m, std::path::Path::new("/c"), std::path::Path::new("/k"));
143137
let mut vm = RunningVm::new(config, m, PathBuf::from("/tmp/vm.sock"));
144138

145139
let err = vm.start().await.unwrap_err();
@@ -149,11 +143,8 @@ mod tests {
149143
#[tokio::test]
150144
async fn running_vm_stop_is_idempotent_in_phase_1() {
151145
let m = manifest();
152-
let config = VmConfig::from_manifest(
153-
&m,
154-
std::path::Path::new("/c"),
155-
std::path::Path::new("/k"),
156-
);
146+
let config =
147+
VmConfig::from_manifest(&m, std::path::Path::new("/c"), std::path::Path::new("/k"));
157148
let mut vm = RunningVm::new(config, m, PathBuf::from("/tmp/vm.sock"));
158149

159150
// Calling stop on a never-started VM must not error — same
@@ -165,11 +156,8 @@ mod tests {
165156
#[test]
166157
fn running_vm_http_port_passes_through_from_config() {
167158
let m = manifest();
168-
let config = VmConfig::from_manifest(
169-
&m,
170-
std::path::Path::new("/c"),
171-
std::path::Path::new("/k"),
172-
);
159+
let config =
160+
VmConfig::from_manifest(&m, std::path::Path::new("/c"), std::path::Path::new("/k"));
173161
let vm = RunningVm::new(config, m, PathBuf::from("/tmp/vm.sock"));
174162
assert_eq!(vm.http_port(), Some(4100));
175163
}

elastos/crates/elastos-vz/tests/smoke.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,10 @@ async fn vz_provider_load_for_microvm_fails_closed_with_phase_marker() {
107107
.unwrap_err();
108108

109109
let msg = err.to_string();
110-
assert!(msg.contains("Phase 2"), "expected Phase-2 marker, got: {msg}");
110+
assert!(
111+
msg.contains("Phase 2"),
112+
"expected Phase-2 marker, got: {msg}"
113+
);
111114
assert!(msg.contains("docs/vz-backend/PLAN.md"));
112115
}
113116

0 commit comments

Comments
 (0)