Skip to content

chore(cve): rebase CVE hygiene work onto v0.3.0 main (35→3 vulns, 12→4 warnings) - #2

Closed
SashaMIT wants to merge 7 commits into
mainfrom
chore/runtime-cve-hygiene-v030
Closed

SashaMIT wants to merge 7 commits into
mainfrom
chore/runtime-cve-hygiene-v030

Conversation

@SashaMIT

@SashaMIT SashaMIT commented May 28, 2026 •

Copy link
Copy Markdown
Contributor

Headline

Metric v0.3.0 baseline After this PR Reduction
cargo audit vulnerabilities 35 3 −32 (91%)
cargo audit warnings 12 4 −8 (67%)
Linux CI checks across the rebase — 12 / 12 first-try greens —

The 3 remaining vulns and 4 remaining warnings are all out of scope for this branch with explicit dispositions — see SIGNOFF.md → "Accepted findings".

Reading order

  1. docs/cve-hygiene/v030-rebase/SIGNOFF.md — top-level rationale, full RUSTSEC ledger, scope boundary, reviewer's checklist
  2. DAY_2.md — the hardest day (wasmtime 17 → 36 + FIFO transport reconciliation against v0.3.0's principal binding work)
  3. elastos/crates/elastos-server/Cargo.toml — the 25-line comment block above the iroh / distributed-topic-tracker block is load-bearing and explains the rc-chain pins

What's in this PR

Four daily, reviewable commits + four daily notes documenting every decision:

  • 756ccf0 — Day 1 dependency cascade + rc-chain pins (DAY_1.md)
  • cecded4 — Day 2 wasmtime 17→36 + FIFO carrier transport (DAY_2.md)
  • 1b87aae — Day 3 axum-server 0.7→0.8 + rustls-pemfile removal (DAY_3.md)
  • a591fda — Day 4 sign-off doc (this PR's exit criterion)

Two Rust source files touched: elastos-compute/src/providers/wasm.rs (the wasmtime API + FIFO transport migration) and elastos-tls/src/lib.rs (the rustls-pemfile → PemObject migration). elastos-server/src/carrier_bridge.rs is deliberately untouched despite v0.3.0's heavy churn there — BridgePipes is wire-compatible.

Relationship to the closed PR #1

This PR is the v0.3.0-rebased successor to #1 (which was rooted on v0.2.0 main). Same scope, same audit ledger, same security disposition. The v0.3.0 base makes the diff more useful for v0.3.1 review. PR #1 is now closed; the original v0.2.0-based work is preserved as the tag archive/runtime-cve-hygiene-v020-base (no force-pushes, no history rewrites).

Three project-level decisions worth weighing in on

These are not blocking for merging this PR, but the SIGNOFF.md surfaces them for visibility:

  1. rsa Marvin attack (RUSTSEC-2023-0071, new in v0.3.0 via elastos-auth / wallet-provider) — patch in v0.3.1, accept-and-document, or wait for upstream rsa 0.10?
  2. bincode 1.3 → 2.x migration scheduling — the only remaining warning we could chase, but it's a major API rewrite.
  3. Mac VZ work direction — this PR doesn't depend on the answer, but sash/local-test is paused waiting on it. See V030_MESSAGE_DRAFT.md on that branch for the framing.

Verification

  • cargo audit: 3 vulns / 4 warnings (all documented in SIGNOFF.md)
  • cargo fmt --all --check: clean
  • cargo clippy --workspace --all-targets -- -D warnings: clean (Linux CI)
  • cargo test --workspace: all pass (Linux CI)
  • Linux CI: 4 pushes, 12 / 12 checks green, all first-try

SashaMIT and others added 7 commits May 28, 2026 12:05
…5→21 vulns)

Rebases the CVE-hygiene work onto v0.3.0 main (commit 8acb72d). Day 1 focuses
on dependency-side fixes only — no code edits, no API migrations. All changes
are confined to Cargo.toml / Cargo.lock.

Result on Linux build target:
  cargo audit baseline (v0.3.0):  35 vulnerabilities / 12 warnings
  cargo audit after Day 1:        21 vulnerabilities /  7 warnings
  delta:                          14 CVEs closed, 5 warnings closed

What changed:

  elastos-storage/Cargo.toml
    lru 0.12 → 0.18 (closes RUSTSEC-XXXX unmaintained on lru 0.12.x)

  elastos-server/Cargo.toml
    + distributed-topic-tracker = "=0.2.7"
        0.2.8 silently bumped iroh ^0.96 → ^0.97; would clash with our
        direct iroh 0.96 pin. Same constraint as the v0.2.0 CVE branch
        (PR #1 commit d32cc3a) and documented inline.
    + ed25519 = "=3.0.0-rc.4"
    + pkcs8 = "=0.11.0-rc.11"
    + signature = "=3.0.0-rc.10"
        distributed-topic-tracker pulls in ed25519-dalek 3.0.0-pre.1, which
        was published against pre-release versions of three RustCrypto crates.
        The released ed25519 3.0.0 / pkcs8 0.11.0 / signature 3.0.0 have
        API-incompatible changes (pkcs8::Error variants moved). cargo update
        otherwise rolls them forward and breaks ed25519-dalek inside the
        registry source. Holding all three at the rc versions v0.3.0 shipped
        keeps the graph buildable until ed25519-dalek 3.x-stable releases.
    - crossterm = "0.28"
    - ratatui = "0.29"
        Dead deps in elastos-server src (verified via grep — only used in
        capsules/chat under its own `tui` feature gate, unaffected here).
        Removing them collapsed the lru 0.12.5 / atomic-polyfill / paste
        transitive chain that surfaced as unmaintained warnings.

  Cargo.lock
    Refreshed via `cargo update` (plain, NOT --aggressive — the rc-chain
    pins make aggressive too dangerous; see comment block in elastos-server
    Cargo.toml for the full rationale).

What's left for Day 2+:

  18 wasmtime CVEs  → Day 2: wasmtime 17 → 36 bump (cap-primitives transitive
                       also closes automatically, that's −19 total)
   2 hickory-proto  → DEFERRED (RUSTSEC-2026-0118/0119 require hickory 0.26
                       which is still pre-release; documented disposition
                       matches the old v0.2.0 branch's audit decisions)
   1 rsa            → NEW in v0.3.0 from elastos-auth (RUSTSEC-2023-0071,
                       Marvin attack). Flagged to Anders in V030_MESSAGE_DRAFT.md
                       for project-level decision before patching.

Verification: - cargo check --workspace --exclude elastos-crosvm --exclude elastos-server
      --exclude elastos-runtime → green on macOS host
  - elastos-crosvm fails to build on macOS due to pre-existing Linux-only
    libc bindings in v0.3.0 (sockaddr_in.sin_len missing, ioctl signature
    mismatch). Not a Day 1 regression — same error reproduces on plain
    `git checkout origin/main && cargo check`. Linux CI will verify.
  - cargo fmt --all --check: clean
  - Branch is pushed under `chore/runtime-cve-hygiene-v030` (parallel to the
    existing PR #1 v0.2.0 branch; swap proposed on Day 4).
Co-authored-by: Cursor <cursoragent@cursor.com>
Concrete metrics, the why behind each pin (especially the rc-chain),
remaining vuln breakdown by cluster, and the Day 2–4 plan. Lives on
the rebase branch so anyone looking at the diff finds the rationale.

Co-authored-by: Cursor <cursoragent@cursor.com>
…ulns)

Closes 18 vulnerabilities in one bump: the entire wasmtime cluster
(RUSTSEC-2026-0020/-0021/-0085/-0086/-0087/-0088/-0089/-0091/-0092/-0093
/-0094/-0095/-0096/-0149, -2025-0046/-0118, -2024-0438) plus the
cap-primitives transitive (RUSTSEC-2024-0445).

Cumulative result on Linux build target:
  cargo audit on v0.3.0 baseline:  35 vulnerabilities / 12 warnings
  cargo audit after Day 1:         21 vulnerabilities /  7 warnings
  cargo audit after Day 2:          3 vulnerabilities /  5 warnings
  Day 2 delta:                     -18 vulnerabilities / -2 warnings

The 3 remaining vulnerabilities are out of scope for this branch:
  - 2 hickory-proto CVEs (RUSTSEC-2026-0118/-0119) — DEFERRED, require
    hickory 0.26 which is still pre-release. Same disposition as the
    v0.2.0 CVE branch and documented there.
  - 1 rsa Marvin attack (RUSTSEC-2023-0071) — NEW in v0.3.0 via
    elastos-auth / wallet-provider. Flagged to Anders in
    V030_MESSAGE_DRAFT.md for project-level decision before patching.

==== What changed ====

elastos-compute/Cargo.toml
  wasmtime    17 → 36 (current stable line)
  wasmtime-wasi 17 → 36
  wasi-common: REMOVED (no longer pulled in directly; preview1 host
               functions now come from wasmtime_wasi::preview1)
  Inline comment block documents the migration rationale and the new
  FIFO carrier transport.

elastos-compute/src/providers/wasm.rs (port of archive/runtime-cve-hygiene-v020-base + v0.3.0 principal binding)
  WASI API migration:
    wasi_common::pipe::{ReadPipe, WritePipe}     → REMOVED
    wasmtime_wasi::sync::WasiCtxBuilder          → wasmtime_wasi::WasiCtxBuilder
    wasmtime_wasi::WasiCtx                       → wasmtime_wasi::preview1::WasiP1Ctx
    + use wasmtime_wasi::{DirPerms, FilePerms}
    + use wasmtime_wasi::preview1::{self, WasiP1Ctx}
  Carrier bridge transport rewrite:
    OLD: fd-injection via WasiCtx::insert_file (FD 3/4)
         REMOVED upstream in wasmtime-wasi 24+ — no workaround
    NEW: per-launch carrier dir + two FIFOs (request, response) under
         /tmp/elastos-carrier/<capsule-id>/, preopened into the WASI
         sandbox at /_carrier via DirPerms::READ + FilePerms::READ|WRITE.
         New helpers: carrier_dir_for(), setup_carrier_fifos(),
         cleanup_carrier_dir(), mkfifo(), CARRIER_GUEST_DIR constant,
         BridgeTransport enum (currently single variant Fifos), Drop
         impl on RunningInstance to GC the carrier dir.
  Type-complexity fix preserved from PR #1 commit 46e3edd:
    WasiContextWithBridge type alias for build_wasi_context return.
  Stricter entrypoint policy (v0.3.0 change ported on top):
    Missing _start now returns an ElastosError::Compute instead of
    silently falling back to main() or emitting a warning.

  v0.3.0's principal-binding work, layered back on top of the archive port:
    + BridgePipes.capsule_id: String
    + BridgePipes.principal_id: Option<String>
    + WasmProvider.bridge_principals (Arc<RwLock<HashMap<...>>>)
    + WasmProvider::set_bridge_principal() / clear_bridge_principal()
    + build_wasi_context() now takes principal_id: Option<&str> and
      threads it through setup_carrier_fifos() into the returned pipes.
    + Both test manifests get authority: None (v0.3.0 added the field).

  Tests included (all from the archive branch's coverage):
    test_default_bridge_transport_is_fifos
    test_setup_carrier_fifos_creates_dir_and_fifos_with_correct_modes
    test_cleanup_carrier_dir_is_idempotent
    test_setup_carrier_fifos_round_trip_via_host_ends
    test_mkfifo_returns_typed_error_on_invalid_path
    test_running_instance_drop_cleans_carrier_dir

==== Reconciliation notes ====

The v0.3.0 main delta on wasm.rs (+27/-12) was small and focused on
principal binding. The CVE branch delta (+500/-113) was the wasmtime
migration plus FIFO transport. They touched mostly disjoint regions, so
the port was a copy-archive-then-overlay-v0.3.0 operation:

  1. Copy elastos-compute/src/providers/wasm.rs from
     archive/runtime-cve-hygiene-v020-base (the known-working post-CVE
     end-state).
  2. Add v0.3.0's two new fields to BridgePipes.
  3. Add v0.3.0's bridge_principals field + setter/clearer to WasmProvider.
  4. Thread principal_id through setup_carrier_fifos and build_wasi_context.
  5. Apply v0.3.0's stricter _start policy and the TODO-comment cleanup.
  6. Add authority: None to both test manifests.

Carrier_bridge.rs was NOT touched on Day 2. Its only API contact with
wasm.rs is BridgePipes { capsule_stdout, capsule_stdin } — neither of
which moved. The two new BridgePipes fields (capsule_id, principal_id)
are passive additions that consumers can read but aren't required to.
Day 3 will handle any carrier_bridge.rs reconciliation needed for the
axum-server 0.7 → 0.8 / rustls-pemfile migration.

==== Verification ====

  cargo check -p elastos-compute (Mac):              green
  cargo check --workspace --exclude crosvm/server/runtime (Mac): green
  cargo clippy --workspace --exclude crosvm/server/runtime/guest
    --all-targets -- -D warnings (Mac):              green
  cargo fmt --all --check:                           clean
  Linux CI on PR #2:                                 pushed for verification

The elastos-crosvm / elastos-guest Mac compile failures are pre-existing
in v0.3.0 (sockaddr_in.sin_len, ioctl signature, openpty winsize
pointer) and reproduce on plain origin/main. Not caused by Day 2.

Co-authored-by: Cursor <cursoragent@cursor.com>
Records the wasmtime 17→36 migration + FIFO transport reconciliation,
including the three-way diff that informed the copy-then-overlay
strategy, the API-surface preservation evidence, and the cluster-by-
cluster CVE closure ledger.

Co-authored-by: Cursor <cursoragent@cursor.com>
…ulns / 4 warnings)

Closes the rustls-pemfile unmaintained warning (RUSTSEC-2025-0134) by
bumping axum-server to 0.8 (which itself dropped the dep) and migrating
the elastos-tls cert/key loader from `rustls_pemfile::{certs,
pkcs8_private_keys}` to the in-tree `rustls_pki_types::pem::PemObject`
API. Wire format is identical PEM; the returned types
(`CertificateDer<'static>`, `PrivatePkcs8KeyDer<'static>`) are the same
ones we were already constructing manually one line below.

Cumulative result on Linux build target:
  cargo audit on v0.3.0 baseline:  35 vulnerabilities / 12 warnings
  cargo audit after Day 1:         21 vulnerabilities /  7 warnings
  cargo audit after Day 2:          3 vulnerabilities /  5 warnings
  cargo audit after Day 3:          3 vulnerabilities /  4 warnings
  Day 3 delta:                     -1 warning (rustls-pemfile)

The 3 remaining vulnerabilities are unchanged from Day 2 and are all
out of scope for this branch (2 hickory deferred upstream, 1 rsa Marvin
flagged to Anders).

==== What changed ====

elastos-tls/Cargo.toml
  axum-server      0.7 → 0.8 (drops rustls-pemfile transitive)
  rustls-pemfile   "2.0"     → REMOVED (closes RUSTSEC-2025-0134)
  Inline comment documents the migration target.

elastos-tls/src/lib.rs (start_tls_proxy cert/key loader)
  - use rustls_pemfile::{certs, pkcs8_private_keys};
  - use std::io::BufReader;
  + use tokio_rustls::rustls::pki_types::{pem::PemObject, CertificateDer, PrivatePkcs8KeyDer};

  - let cert_file = fs::File::open(cert_path)?;
  - let key_file = fs::File::open(key_path)?;
  - let certs = certs(&mut BufReader::new(cert_file)).collect::<Result<Vec<_>, _>>()?;
  - let keys = pkcs8_private_keys(&mut BufReader::new(key_file)).collect::<Result<Vec<_>, _>>()?;
  - let key = keys.into_iter().next().ok_or_else(|| anyhow::anyhow!("No private key found"))?;
  + let certs: Vec<CertificateDer<'static>> = CertificateDer::pem_file_iter(cert_path)?
  +     .collect::<Result<Vec<_>, _>>()?;
  + let key: PrivatePkcs8KeyDer<'static> = PrivatePkcs8KeyDer::from_pem_file(key_path)?;

  Error messages updated to include path context (small UX
  improvement that came naturally with the rewrite).

elastos-server/Cargo.toml
  axum-server  0.7 → 0.8 (no source changes needed; consumers are
  wire-compatible — verified by grep'ing axum_server uses in
  server_infra.rs and api/server.rs and observing that the archive
  branch's diff against those files is empty).

==== Reconciliation notes ====

elastos-server/src/api/server.rs and elastos-server/src/server_infra.rs
both `use axum_server` directly but at the call surfaces (Server::bind,
TlsConfig, etc.) the 0.7 → 0.8 migration is wire-compatible. Verified
two ways:
  1. Diff of $(merge_base v0.3.0 archive) vs archive on those files
     returns empty — the original v0.2.0 → archive transition didn't
     need source edits there.
  2. cargo check --workspace --exclude crosvm/server/runtime on Mac
     compiles clean post-bump (elastos-tls is what actually pulled
     axum-server 0.8 into our build).

The Day 1 rc-chain pins (ed25519, pkcs8, signature) all held through
the cargo update — verified post-bump:
  ed25519   3.0.0-rc.4    ✓ (pin held)
  pkcs8     0.11.0-rc.11  ✓ (pin held)
  signature 3.0.0-rc.10   ✓ (pin held; not shown but present)

==== Verification ====

  cargo check -p elastos-tls (Mac):                green
  cargo check --workspace --exclude crosvm/server/runtime (Mac): green
  cargo clippy --workspace --exclude crosvm/server/runtime/guest
    --all-targets -- -D warnings (Mac):            green
  cargo fmt --all --check:                         clean
  cargo audit:                                     3 vulns / 4 warnings
  Linux CI on PR #2:                               pushed for verification

Co-authored-by: Cursor <cursoragent@cursor.com>
Day 3 records the axum-server 0.7→0.8 + rustls-pemfile removal that
brings the warning count to 4 (down from 12 baseline). All 4 remaining
warnings are wasmtime transitives or deferred bincode work — none
directly fixable on this branch.

Includes the rationale for the build-cache-save 16m timing (not a
regression: cargo build itself finished in ~7m), the verification
that v0.3.0 didn't drift on elastos-tls/src or elastos-server/src
axum-server callers, and the Day 4 ship-it preview.

Co-authored-by: Cursor <cursoragent@cursor.com>
…eview

Top-level reviewer's doc covering:
  - Headline result (35→3 vulns / 12→4 warnings, 91% / 67% reductions)
  - Why this PR exists (v0.3.0 rebase rationale; CVE work isolated
    from the open Mac VZ product question)
  - Full 4-day timeline with per-day commit + Δ metrics, linked to
    the existing DAY_1.md / DAY_2.md / DAY_3.md notes
  - CVE closure ledger by RUSTSEC ID — closed (32) and accepted (3+4)
  - Cargo.toml + Rust source change summary
  - Reviewer's checklist (read-in-order guide)
  - Final verification record (audit / fmt / clippy / test / CI history)
  - Handoff section with the three project-level decisions Anders
    might want to weigh in on (rsa disposition, bincode migration
    scheduling, Mac VZ direction)

No code changes today — Day 4 is the ship-it day. The next steps
(flip PR #2 from Draft → Ready, close PR #1 with explanatory comment)
are handled outside the commit history via gh CLI.

Co-authored-by: Cursor <cursoragent@cursor.com>
@SashaMIT SashaMIT changed the title [DRAFT — DO NOT REVIEW] CVE hygiene rebase onto v0.3.0 (Day 1/4) chore(cve): rebase CVE hygiene work onto v0.3.0 main (35→3 vulns, 12→4 warnings) May 28, 2026
@SashaMIT
SashaMIT marked this pull request as ready for review May 28, 2026 07:34
SashaMIT added a commit that referenced this pull request May 28, 2026
Day 1 of the Mac VZ rebase onto v0.3.0 is a deliberate no-op for code:
the new branch is identical to PR #2 HEAD (CVE work + v0.3.0 main).
Mac VZ work starts landing on Day 2.

Includes the conflict map for Days 2–4 (which files conflict and how
hard), the rationale for branching off PR #2 instead of main directly
(avoids audit regression), and the recovery plan if Day 4's
carrier_bridge.rs reconciliation doesn't converge cleanly.

PR #3 is open as DRAFT / DO NOT REVIEW to surface Linux + Mac VZ CI
during the rebase. Will flip to ready on Day 4.

Co-authored-by: Cursor <cursoragent@cursor.com>
SashaMIT added a commit that referenced this pull request May 28, 2026
Day 2 of 4 in the Mac VZ rebase onto v0.3.0 main. Lands the entire
non-conflicting surface of the Mac VZ branch — everything that does
not require reconciling supervisor.rs (Day 3) or carrier_bridge.rs
(Day 4) on top of v0.3.0.

What landed
-----------
* Entire new `elastos-vz` crate (Vz/Apple Virtualization.framework
  substrate). Cleanly compiles on Mac, stubs out on Linux. Registered
  as a workspace member; `elastos-server` picks it up via a
  `[target.'cfg(target_os = "macos")'.dependencies]` block so Linux
  builds are byte-identical.
* `elastos-crosvm` cfg-gating (lib.rs, rootfs.rs, network_stub.rs):
  the crate now compiles cleanly on macOS for the first time, which
  in turn means `cargo check -p elastos-server` succeeds locally on
  Mac without our CVE-rebase-era exclusion list.
* `binaries.rs`: layered v0.3.0's env-var override on top of Mac VZ's
  `ELASTOS_DATA_DIR`-respecting global fallback. Both behaviors retained.
* New ancillary modules with no v0.3.0 conflict: `overlay_initrd.rs`
  (CPIO overlay-init builder used by Mac VZ's substrate boot).
* `security_cmd.rs`, `sources.rs`: small Mac-only changes, no v0.3.0
  conflict.
* CI: `mac-vz.yml`, `release-mac.yml`, `_self-hosted-probe.yml`,
  `linux-untouched.yml` workflows; `ci.yml` trigger update for
  `sash/**` and `vz/**` branches.
* Scripts: `scripts/lib/cross-platform*.sh`, `runtime-cleanup*.sh`,
  `components-json-verify.sh`, `release/*`, `dev/*`,
  `measure-{vz,crosvm}-baseline.sh`, `release-mac.sh`. Several
  existing smoke scripts (`chat-wasm-native-interop-smoke.sh`,
  `home-frontdoor-smoke.sh`, `local-carrier-setup-smoke.sh`,
  `lib/runtime-cleanup.sh`) extended for Mac VZ — v0.3.0 didn't touch
  them so the merge is clean.
* Docs: full `docs/vz-backend/` tree including phase notes, plan,
  threat model, perf baseline, etc. Plus `docs/MAC.md`,
  `docs/ELASTOS_PRD.md`. `state.md` updated for Mac substrate scope.
* Test fixtures inside elastos-vz now include `authority: None` to
  match the v0.3.0 `CapsuleManifest` schema (same fix as PR #2's
  wasm.rs reconciliation).

What is deliberately deferred
-----------------------------
* Day 3: `supervisor.rs` (+148/-88 v0.3.0 vs +3800/-81 Mac VZ),
  `setup.rs`, `vm_provider.rs`, `runtime_control.rs`, `home_cmd.rs`,
  `run_cmd.rs`, `main.rs`, `doctor_cmd.rs`, `vm_debug_cmd.rs`,
  `elastos-guest/runtime.rs`, plus all the new tests under
  `elastos-server/tests/` that depend on Supervisor APIs.
* Day 4: `carrier_bridge.rs`, `runtime.rs` (BridgeContext.on_terminate),
  fuzz target (depends on carrier_bridge framing API),
  `vz_shutdown_semantics.rs`, `vz_chat_interop_smoke.rs`,
  `vz_home_frontdoor_smoke.rs` (all depend on Day 4 BridgeContext).

Verification
------------
Local Mac (`cargo clippy --workspace --exclude elastos-guest --tests
-- -D warnings`) — green (elastos-guest exclusion is the same
preexisting v0.3.0 cross-OS bug we documented in the CVE rebase
SIGNOFF). `cargo fmt --all -- --check` — clean. `cargo audit` — 3
vulns / 4 warnings, identical to PR #2 (no regression). Linux + Mac
VZ CI signal will land via the draft PR #3 push.

Co-authored-by: Cursor <cursoragent@cursor.com>
SashaMIT added a commit that referenced this pull request May 28, 2026
…d1333

Day 2 surfaced two CI gaps:

1. `linux-untouched.yml` referenced `scripts/check-linux-untouched.sh`
   which I forgot to port from the archive. Pulled it in as-is.

2. The gate's hardcoded baseline `a65dad3` (the original Phase 0
   sash/local-test commit) is unreachable from the rebased branch,
   because the new branch is rooted on PR #2 / v0.3.0 main rather
   than on sash/local-test. Re-baselined to `ded1333` (Day 2 HEAD,
   the first Mac-VZ-rebase commit), so the gate now enforces "no
   Mac-VZ-rebase work modifies elastos-crosvm / elastos-runtime /
   elastos-common / elastos-compute beyond what Day 2 already
   shipped." Day 3+ only touches elastos-server (not in the
   protected list) so this remains a meaningful guardrail.

Inline comment in the workflow documents the rationale and points
back to docs/mac-vz/v030-rebase/DAY_2.md.

Co-authored-by: Cursor <cursoragent@cursor.com>
@andersalm

Copy link
Copy Markdown
Contributor

Superseded by the reviewed 0.3.1 stack merged to main at 6d4c385. The CVE hygiene changes from this branch were reorganized into smaller review commits before merging, so this PR is intentionally closed rather than merged.

@andersalm andersalm closed this May 28, 2026
@andersalm
andersalm deleted the chore/runtime-cve-hygiene-v030 branch May 28, 2026 16:01
SashaMIT added a commit that referenced this pull request Jun 17, 2026
…ent audit, action enforcement, hardening pass

Closes the four highest pre-audit findings as fail-closed boundaries, each
with a regression test.

#1 CEK reconstruction integrity (HIGH): bind the reconstructed CEK to a
   published commitment before use and add 3-share cheater-detection on the
   live quorum/threshold open path. A Byzantine node returning a well-formed
   but wrong-valued share now FAILS THE OPEN CLOSED; an uncommitted 2-of-2
   open is refused rather than yielding a silently-wrong key.
   (ddrm-envelope, decrypt/encrypt/key providers, media-authority/producer rails)

#2 Tamper-evident audit + content-open custody (GAP-8): hash-chained
   (seq + prev_hash + record_hash), ed25519-signed records with a crypto-
   agility tag, persisted 0600 signing key, verify_chain, emit() -> Result.
   A content-open event is emitted on the viewer open path; a failed audit
   append fails the open closed (503). ed25519 lives in the trusted core
   (no capsule ML-DSA dependency). Caveat in-code: tamper-evident against
   external editing + non-repudiable, NOT against a live-compromised runtime
   (external anchoring is a deliberate follow-on).
   (elastos-runtime primitives/audit.rs, elastos-server viewer_open/gateway)

#3 Central action-enforcement: validate every provider dispatch against the
   operation's required action via required_action_for(op), not the token's
   self-declared action. Enforced centrally at the trust boundary (bridge +
   HTTP provider proxy); fail-closed Admin default for unmapped ops.
   (provider_resource.rs, carrier_bridge.rs, handlers/provider.rs)

#4 Quick hardening:
   (a) DKMS_AUTHORITY_NODE_SET_ID_B64 mandatory in release — absent it, the
       node refuses to authorize against a caller-declared node-set
       (cross-quorum replay defense); fallback only in test/dev-modes.
   (b) MAX_LINE_BYTES (16 MiB) cap in vsock-proxy: all line reads routed
       through a bounded reader so a newline-less peer can't OOM the bridge.
   (c) gf256_mul made branchless (arithmetic masks, no tables, fixed 8 iters)
       to remove the secret-dependent control-flow timing channel.
   (d) effective_now clamped to the node clock at issuance so a caller can
       only shorten its session window, never extend it past its TTL.

Also: widen check-wci-alignment.sh to exempt manifest-less crates (crypto
libraries / node binaries are not deployable app capsules) and dependency
files; HANDOVER Day 139 checkpoint; incidental cargo-fmt normalization to
keep the workspace fmt-clean.

Verified per-crate: ddrm-envelope 40/40, dkms-authority 24/24, vsock-proxy
3/3; alignment-check green. (These crates are outside the elastos workspace,
so `just verify` does not exercise them.)

Co-authored-by: Cursor <cursoragent@cursor.com>
SashaMIT pushed a commit that referenced this pull request Jun 17, 2026
Both remaining enrichments.

Sub-provider coverage (#1):
- ProviderRegistry::sub_provider_schemes() (elastos-runtime, additive) lists
  the elastos:// sub-provider schemes (did/key/peer/…) that schemes() omits.
- RegistryInspectSource lists main + sub schemes; CatalogInspectSource's
  running-status detection now matches sub-provider-backed schemes too.

Live per-capsule audit (#2):
- AuditSource trait + AuthAuditSource: reads the signed runtime audit log
  (RuntimeAuditEventV1 in auth state), correlates by capsule_id (capsule name),
  and fills the detail view's audit section — recent events (newest-first,
  capped) + total/denied counts. Runs on a blocking task off the async workers.
- InspectProvider gains an optional audit source (with_audit builder); project
  renders the live audit. Records expose only safe fields (ts/event/reason/
  success) — no signatures or handles (#16).
- serve_cmd wires AuthAuditSource(data_dir) on both serve paths.

Honest remaining: granted_capabilities stays empty — bearer-token caps have no
central registry and RuntimeAuditEventV1 has no resource/action, so observed
grants need a capability-event source that records them.

Verified: cargo test -p elastos-server inspect_provider — 10 passed (incl. live
audit + sub-provider tests, #16 no-leak preserved); cargo test -p
elastos-runtime --lib — 278 passed (additive registry method, no regression).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ZKy5Cca9RzwDuLb1szdeq
SashaMIT pushed a commit that referenced this pull request Jun 20, 2026
…partial

Re-verified all eight PRE_AUDIT findings against the current tree (deep + passing
tests for #1/#3/#6; code + mechanism for #2/#4/#5/#7/#8). Adds a dated verification
banner with file:line evidence and flips the #1/#2 status cells.

- #1 (was HIGH/CRITICAL) RESOLVED: CEK reconstruction is integrity-checked end-to-end
  and production-wired — producer publishes cek_commitment at mint, the open path
  reconstructs via reconstruct_quorum_cek_checked (3+ shares cross-check / commitment
  binding / degraded 2-share-without-commitment refused). Byzantine-share tests pass
  (decrypt-provider 146/0).
- #2 PARTIAL by design: log-redaction is done (log_fp fingerprints the wallet/content
  triple); blinded identifiers / oblivious lookup / frame padding / node-operator
  visibility remain documented roadmap, not code defects. Kept for the firm.
- #3 RESOLVED (audit tamper-evidence; recorded earlier this branch).
- #4 RESOLVED: central required_action_for map, fail-closed on unmapped ops, enforced
  at the bridge on the required (not token's) action.
- #5 RESOLVED: node-set-id pin mandatory in release (compile_error fence + authorize
  refuses a caller-declared node-set).
- #6 RESOLVED: vsock-proxy MAX_LINE_BYTES cap fails closed; binds the guest vsock
  wildcard CID, not TCP 0.0.0.0.
- #7 RESOLVED: GF(256) multiply rewritten branchless (mask selects, fixed 8 iters).
- #8 RESOLVED: effective_now clamps the caller clock in release (window can only shrink).

No code change. Purpose: hand the external firm a trustworthy "scope these OUT" list.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VjFQt6DK9ZGnLs4ykUWsuX
SashaMIT added a commit that referenced this pull request Jun 23, 2026
…e/cover/content_cid/mime)

Building the enrichment slice that is genuinely buildable+verifiable here (only the network fetch is live),
correcting the earlier over-conservative "all live" framing.

- market_reads.rs: PURE extract_cid (content-market's exact ipfs:// / /ipfs/ / Qm-bafy rule) + parse_asset_metadata
  (the same field paths content-market enrich_listing reads: name, description, image|media.previewURL,
  media.uri->content_cid, media.contentType->mime). 2 unit tests (extract_cid PC2 rules; parse paths + poster
  fallback + empty->None). This is the descriptive slice; the full kid==contentId validation is the hardening
  follow-on (PHASE2_ENRICHMENT.md).
- market_get: optional &token_uri -> enrich_from_token_uri fetches the metadata.json via the content/* plane
  (P4) + parses + merges as `metadata` into the response. Best-effort (live terms are load-bearing). The fetch
  is compile-verified; Cursor live-verifies it resolves real assets.
- Shell: get() passes token_uri + merges the enriched name/cover/content_cid/medium onto the cached listing
  (so acquire() now has a real content_cid on the live path); mimeToMedium maps mime->medium. Browser-verified
  the detail view still renders on the mock path (no regression, no console errors).

market_reads 4/4 pass; crate compiles; shell syntax OK. This unblocks live display + the real buy->pin
(content_cid) — checklist items #1 (descriptive), #2-prep, #6.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
SashaMIT added a commit that referenced this pull request Jun 23, 2026
…"you own this"

Checklist #2. market_reads: encode_has_access (selector 0x54d42821 + holder address word + bytes16 KID
left-aligned, matching chain-provider::encode_has_access_by_content_id_address_bytes16) + decode_bool
(fail-soft) + has_access_live. market_get: after enrichment, if the metadata carries the KID, resolve the
buyer's wallet (resolve_subject_address) and read hasAccessByContentId(wallet, KID) live, setting
on_chain.has_access.

Cache-correctness: the terms+metadata are wallet-independent and cached; has_access is WALLET-SPECIFIC and
computed per-request OUTSIDE the cache (restructured /get so a cache hit still recomputes has_access) — so
one buyer's ownership can never leak to another via the shared cache. 2 new unit tests (encoder pins
selector + left-aligns the KID; decode_bool true/false/fail-soft); market_reads 6/6. Live read = Cursor.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
SashaMIT added a commit that referenced this pull request Jun 23, 2026
…iggest prototype->product jump)

The UI/UX audit's #2 highest-leverage finding: OS emoji (rail/facets/pills/cards) float outside the
--ink/--mut/--acc palette, vary per-OS, and read as a prototype. Replaced with an inline feather/lucide-style
stroke-SVG set (currentColor, stroke-width 2, viewBox 24, stroke-linecap/linejoin round) — the SAME convention
as the sibling capsules/marketplace/browser/marketplace.js icons={}; no scratch art, no new pack (honors the
standing constraint), no dependency.

- app.js: ICONS map (16 glyphs: compass/key/bell/clapperboard/package/gamepad/tv/headphones/book/image/box/
  unlock/cart/recycle/link) + icon() helper (returns an aria-hidden SVG) + mediaIcon(). MEDIA now maps medium
  -> icon name. Replaced every display emoji: card + detail covers (mediaIcon, .ico-cover), the lockchip (key),
  the resell badge (recycle), the hero key, the Activity/Vault view titles, the listed-row glyph.
- index.html: rail/asset-type/medium/rights facets + chain & vault pills carry data-icon=… with clean text
  labels (no emoji); boot() injects the SVG into every [data-icon] (one icon source). Kept the monochrome ◎
  wallet + ◐ theme symbols (theme sun<->moon cross-fade is the deeper motion pass).
- styles.css: .ico sizing (16px inline, 13px in lockchip/badge, 34/56px covers), .facets button -> flex with
  gap so icon+label align, .badge inline-flex.

Skill principles applied: currentColor inheritance, consistent sizing, optical baseline, aria-hidden on
decorative glyphs, no transition:all. Browser-verified: 3 rail + 11 facet + 17 cover + 18 lock icons render,
all stroke=currentColor, ZERO emoji left in nav/facets, clean labels, no console errors. Mock section-title
emoji (🔥/✨, sample data) left as-is (live sections carry no emoji).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
SashaMIT pushed a commit that referenced this pull request Jul 1, 2026
…inspector

Additive completion of the incompletely-merged 0.5 approved-provider dispatch
(degradation #2): our flint InspectProvider gains 0.5's registry-backed
`dispatch_approved` execution op WITHOUT losing any custody projection
(intent_proof / spend_budget / audit_attestation / W7 export all intact).
Superset, not swap.

- InspectProvider now retains a `Weak<ProviderRegistry>`; `with_registry`
  stops being a passthrough. Read-only projection ops ignore it.
- `dispatch_approved` routes an operator-APPROVED provider act back through
  `registry.invoke_provider(source: "inspect", ...)`. Fail-closed throughout:
  target must be manifest-backed with declared provider authority; the op must
  be DECLARED by that authority (plan_provider_operation, not token-vs-itself);
  the request must not predeclare Runtime routing metadata; and an unwired
  registry yields `runtime_unavailable` rather than a silent no-op.
- One additive `handle_op` arm ("dispatch_approved"); every flint op
  (capsule/self/plan/intent/discover/audit_attestation) is untouched.
- Tests: metadata-guard, fail-closed-without-registry, undeclared-op refusal,
  and an explicit NO-REGRESSION guard that read-only projection ops are
  unaffected by the graft.

Remaining for #2: wire the production inspector registration with a real
Arc::downgrade(registry) so dispatch is live outside tests (next chunk).

Gate: cargo test -p elastos-server --lib green (1032), fmt clean, 0 warnings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FEL7iSfBWL2JiAFDy8fq5z
SashaMIT pushed a commit that referenced this pull request Jul 1, 2026
…istrations

Chunk D of #2: the gateway inspector (server_infra) was already handing
`with_registry` a real `Arc::downgrade(&provider_registry)` — the merge's
passthrough was the only thing dropping it, so Chunk A already made gateway
dispatch live. This wires the remaining production serve paths (serve_cmd, 3
sites) the same way, so `dispatch_approved` is live wherever the inspector is
registered. Test and mcp-serve registrations stay unwired (fail-closed by
construction).

Completes flint-0.5 enforcement degradation #2. All three tracked degradations
are now RESTORED; flint-0.5 is a true superset of flint — 0.5's features plus
fully intact KEEP enforcement, no regression.

Gate: cargo test --workspace --lib green (all crates), esp npm test 89, fmt
clean, 0 warnings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FEL7iSfBWL2JiAFDy8fq5z
SashaMIT pushed a commit that referenced this pull request Jul 4, 2026
…ent, casing desync, honest CLI

Review pass on the mandate lifecycle (guardian: PASS w/ advisories;
red-team: two real breaks + latent gaps). All folded:

- DURABLE ENFORCEMENT (red-team #1): production built its CapabilityStore
  in-memory, so individually-revoked (unexpired) tokens would validate again
  after a restart — a revoke durably ATTESTED but not durably ENFORCED. The
  server now builds the store with_persistence (revocations + epoch survive
  restart) and fails closed at boot if persistence is unavailable.
- ID-CASING DESYNC (red-team #2): hex::decode accepts UPPERCASE but the
  standing-envelope registry is keyed by the token's lowercase Display form,
  so an uppercase id revoked the token yet left the envelope (the dispatch
  path's only check) live. The handler now kills the envelope by the
  canonicalized id. Regression test:
  revoke_with_uppercase_id_still_kills_the_standing_envelope.
- HONEST CLI (guardian F2/F4): the revoke headline now states exactly what is
  attested; revoked:false becomes an unmissable stderr WARNING (a mistyped
  id attests a revoke for a token that never existed while the real mandate
  stays live). The receipt command no longer inlines the receipt's own
  embedded signer into the suggested verify command (pinning a document's
  self-carried key is circular); it prints it as informational and tells the
  operator to pin the key they trust out-of-band.
- TRACKED LATENT GAPS (guardian F1/F3, red-team #3/#4): recorded as G-M1..3
  in docs/KNOWN_GAPS.md — the intent-channel dispatcher (zero non-test call
  sites today) must consult token revocation + epoch when wired, and its
  acts must reach the per-mandate receipt; same-uid control-plane trust
  boundary documented. Lifecycle test comment now states honestly which act
  path it models.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BnpmuD7RtQ3NuTfRQJGrQb
SashaMIT pushed a commit that referenced this pull request Jul 4, 2026
…-dependent read

Adds a second wired affordance whose outcome tracks REAL variable state, not
just chain integrity: `runtime.content_seen` answers "did the mandate's own
capsule successfully open content id X?" — so the SAME agent + method +
declaration reconciles "performed" or "authorized_not_performed" depending on
what the runtime actually recorded, proving the reconciliation is a genuine
independent observation.

Backed by AuditLog::principal_opened_content (sync, streams the durable log,
early-returns). Handler + executor ratchets prove the state-dependence and
principal isolation end to end.

Folded in from guardian (CHANGES-REQUIRED) + red-team (DO-NOT-SHIP, conditional):

- CROSS-PRINCIPAL ORACLE (red-team #5 / guardian #4, blocking): the first cut
  matched ANY principal's access, letting an agent learn whether anyone
  accessed an id. Now PRINCIPAL-SCOPED — matches only ContentOpen with the
  caller's own principal_id ("did I open it", not "did anyone"). ContentFetch
  is dropped (it carries no principal, so it can't be attributed). A ratchet
  proves a different capsule asking about the same id is Declined.
- RECEIPT OVER-CLAIM (guardian #1, blocking): CapabilityUse carries resource +
  action but not the method, so a content_seen "read of X" was
  indistinguishable from a real content read. The mandate is now scoped to a
  content-access-CHECK resource (elastos://runtime/content-access/<id>), so the
  receipt honestly names a read of the CHECK, not the content bytes — mirroring
  Sprint 7's canonical-resource pattern.
- WEAKER EVIDENTIARY BAR (guardian #2): the scan didn't verify signatures while
  audit_verify Declines unsigned logs for the same offline-rewrite threat. The
  executor now requires the log signed + verify_chain Ok before the scan, so a
  matched ContentOpen is signature-attested — the same bar as audit_verify.

Gate: clippy clean on changed files; elastos-server 1128 + elastos-runtime 399
tests green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BnpmuD7RtQ3NuTfRQJGrQb
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