Feature: MPEG-DASH/CENC compliance + DKMS hardening + creator flow#8
Closed
irzhywau wants to merge 218 commits into
Closed
Feature: MPEG-DASH/CENC compliance + DKMS hardening + creator flow#8irzhywau wants to merge 218 commits into
irzhywau wants to merge 218 commits into
Conversation
Add the Runtime provider registry and gateway proxy support needed for object/content provider invocation, stream sessions, progress/cancel metadata, and provider-backed viewer handoff. This is the transport/control-plane slice. Concrete Library, content, Spaces, and package surfaces are committed separately so reviewers can separate runtime plumbing from product behavior.
Replace the static Library capsule with a PC2-familiar file-manager surface backed by the Runtime object-provider API. This includes source-split Library UI code, icons, navigation, selection, upload/download, rename/create/delete/trash, publish/share/status/properties hooks, and object CID metadata. Add the standalone object-provider capsule and boundary tests while keeping publish/share availability authority separated through Runtime/content-provider coordination.
…0.4.0 plan Durable agent-facing alignment docs for the PC2 -> Runtime convergence: the capability/provider first-principles playbook, the finished-product PRD, and the current-week coordination plan with Anders' 0.4.0 line. Co-authored-by: Cursor <cursoragent@cursor.com>
… backend Day 1 of the dDRM convergence. Brings PC2's CENC/AES-128-CTR fMP4 decrypt engine (Elacity/pc2.net @ a0a910158) in-tree as a provider-internal module, behind the existing fail-closed contract (not yet wired into open_session/ render). CEK stays inside the boundary and is zeroized after use. Also fixes a pre-existing 0.4.0 drift: DecryptSessionRequestV1.release_receipt is now a typed ReleaseReceiptV1, so the validator/test fixture were updated to match. Adds aes/ctr/base64 deps. 14 tests pass incl. an end-to-end golden decrypt with a CEK-containment assertion. Co-authored-by: Cursor <cursoragent@cursor.com>
elastos-crosvm's guest-network module uses Linux-only TAP/ioctl + libc (SOCK_CLOEXEC, sockaddr_in.sin_len), which broke `cargo build -p elastos-server` on macOS and blocked local gateway/Home development. Gate the Linux network module to target_os="linux" and provide a non-Linux network_stub.rs that mirrors NetworkConfig's public surface and fails closed (microVM launch already fails closed via the /dev/kvm check in vm.rs::start()). Scope the mkfs.ext4 rootfs test to Linux. Linux paths are byte-for-byte unchanged (gate, not rewrite). This is the minimal Darwin slice extracted from the Mac VZ branch (sash/local-test-v030); crosvm is otherwise identical between the two. With this, elastos-server builds on macOS and `elastos gateway` serves the 0.4.0 Home UI at http://localhost:8090/apps/home/. 18 crosvm tests pass on macOS incl. fail-closed stub tests. Co-authored-by: Cursor <cursoragent@cursor.com>
…o decrypt-provider Day 3 surfaced that DecryptSessionRequestV1 carries authority+intent only (release_receipt attests release; no CEK, no ciphertext). End-to-end decrypt is blocked on an architecture decision: how the CEK (VM-sealed) and ciphertext reach the decrypt microVM. Documents Option A (material pushed in request) vs Option B (provider-chain capability calls), recommends A-for-decrypt composed with B-upstream, and lists questions for Anders. Contract-first: not inventing the security boundary unilaterally. Co-authored-by: Cursor <cursoragent@cursor.com>
…Abstraction) Introduces decrypt_session_segment (validated material -> cenc engine -> plaintext, CEK owned+zeroized by the engine) and scoped_session_response (containment-safe caller response). Not yet wired into open_session/render — the CEK+ciphertext transport rail is the open decision in DDRM_DECRYPT_RAIL.md (Hybrid chosen). Tier/rail-agnostic, pure Rust: ready to connect once the rail lands. Adds provider- boundary tests: golden decrypt through the seam, fail-closed on bad CEK, and an assertion that neither the CEK nor decrypted plaintext can cross to the caller. Co-authored-by: Cursor <cursoragent@cursor.com>
…hardening decrypt-provider's cenc engine is pure compute (ideal wasm workload, runs on macOS today, composes with the Hybrid rail). microVM stays the later max-isolation upgrade; same Rust code targets both. Security contract is tier-independent. Co-authored-by: Cursor <cursoragent@cursor.com>
cargo build --target wasm32-wasip1 succeeds with zero code changes; full decrypt path (cenc engine + elastos-common protected_content) is wasm-clean and all 17 host tests stay green. Hard evidence for the wasm-now tier recommendation. Co-authored-by: Cursor <cursoragent@cursor.com>
… execution decrypt-provider.wasm runs correctly under wasmtime 45.0.1: status advertises blocked raw authority, malformed ops + raw_plaintext output rejected, valid sessions fail closed (not_configured) until the rail lands. Adds reusable scripts/wasm-smoke.sh (CI-suitable) and records the evidence in DDRM_DECRYPT_RAIL.md. Co-authored-by: Cursor <cursoragent@cursor.com>
Fixes pre-existing 0.4.0 drift (KeyReleaseRequestV1 gained rights_receipt) and closes a fail-closed gap: key-provider now verifies the upstream rights decision (allowed + principal/session/object/right must match the request) before it would release a key. Adds 4 binding tests (9 total), confirms host + wasm32-wasip1 builds, and adds a WASI-sandbox smoke harness. CEK stays wrapped-only. Records rights->key->decrypt chain parity in DDRM_DECRYPT_RAIL.md. Co-authored-by: Cursor <cursoragent@cursor.com>
…ypt chain parity rights-provider already had the contract + 9 tests (incl. wire-level rejection of hidden chain/wallet/key fields). Brings it to the proven bar: confirms host + wasm32-wasip1 builds and adds scripts/wasm-smoke.sh (4/4 pass under wasmtime). All three dDRM chain links now compile to wasm, run under WASI, and are fail-closed end-to-end; only the CEK/ciphertext rail (Anders' call) remains. Updates the chain-parity table in DDRM_DECRYPT_RAIL.md. Co-authored-by: Cursor <cursoragent@cursor.com>
Brings the drm/open orchestrator to the proven bar: confirms host + wasm32-wasip1 builds, adds scripts/wasm-smoke.sh (4/4 pass), and adds chain_seam_tests proving the receipts compose across the chain — RightsDecisionReceiptV1 deserializes into the key request, ReleaseReceiptV1 into the decrypt request (12 host tests). All four dDRM links (drm/open -> rights -> key -> decrypt) now compile to wasm, run under WASI, are fail-closed, and have verified inter-provider handoffs. Updates chain-parity table in DDRM_DECRYPT_RAIL.md. Co-authored-by: Cursor <cursoragent@cursor.com>
Adds scripts/ddrm-chain-smoke.sh that runs all four provider WASI smokes (drm -> rights -> key -> decrypt) and emits one consolidated PASS/FAIL report — a single-command demo that the whole chain is fail-closed + wasm/WASI-proven. Adds docs/convergence/DDRM_STATUS.md: parity table, proven security properties, how-to-run, the one open rail decision, and commit inventory for review. Co-authored-by: Cursor <cursoragent@cursor.com>
Captures PC2 ddrm-decrypt's CEK-sealing envelope (P-256 ECDH unwrap, AES-256-CBC, v2/v3 layouts) as an executable, tested characterization spec in decrypt-provider (envelope.rs). All recovered material is held in Zeroizing; golden round-trips, truncation/wrong-key fail-closed cases, and a CEK-containment assertion pass on host and the crate stays wasm32-wasip1-clean. The module is intentionally NOT yet wired into live dispatch — it pins the rail's byte contract pending Anders' Option A + tier confirmation (contract-first). Adds docs/convergence/PC2_PLAYER_ALIGNMENT.md: validates the two viewer capsules (media: elacity-player; non-media: ddrm-viewer/wasm-renderer) and adopts Irzhy's two invariants as binding rules — CEK/KID generated in-wasm on encrypt; CEK recovery + content decryption colocated in one wasm boundary with zeroization on decrypt (CEK never crosses FFI). Adds docs/convergence/PUSH_PLAN.md for clean reinstatement (branch->PR order + per-PR test plans). Co-authored-by: Cursor <cursoragent@cursor.com>
…sules Characterization tests for the chain's downstream boundary: the scoped response carries metadata only (allow-listed keys), a forbidden-key check rejects any cek/iv/key/plaintext/... field for both the media (elacity-player) and non-media (ddrm-viewer) players, and a media-segment decrypt run asserts neither CEK nor decrypted bytes reach the player-facing output. Pins PC2 ddrm-decrypt's "public functions never return a CEK; only a handle" rule (Irzhy invariant #2 at the consumer edge). 25 host tests green; crate stays wasm32-wasip1-clean. Documents the consumer contract in PC2_PLAYER_ALIGNMENT.md. Co-authored-by: Cursor <cursoragent@cursor.com>
Adds docs/convergence/DDRM_SECURITY_MODEL.md — a self-contained trust-model walkthrough for the team (Irzhy/Anders): the two invariants, actor/boundary map, encrypt + decrypt mermaid flows, a threat model per boundary, and an invariant->enforcement table where every claimed property cites a passing test (envelope, cenc, consumer-contract, key-provider rights-binding, decrypt-provider opaque-id/output-kind/fail-closed). Records the inter-stage CEK transport decision (Irzhy's ECDH+DSA point): keep key/decrypt as separate boxes but seal the CEK to decrypt-provider's per-session key and unwrap+decrypt+zeroize in one boundary; strongest variant has the dKMS seal directly. Flags the PC2 (classical P-256) -> runtime PQ-hybrid (x25519+ml-kem-768, ml-dsa-65) reconciliation and sharpened questions for Anders. Co-authored-by: Cursor <cursoragent@cursor.com>
Consolidate the dDRM review package to current truth and de-risk the one rail-independent PQ piece ahead of the rail landing. - DDRM_STATUS.md: full +14 commit inventory, parity table (decrypt-provider now 25 host tests: cenc + envelope + consumer contract), both chain ends pinned (upstream envelope spec, downstream consumer contract), and the sharpened 3 open rail sub-questions for Anders/Irzhy. - Prove PQ-hybrid is viable inside the wasm boundary: ml-kem 0.2.3 (ML-KEM-768) and ml-dsa 0.0.4 (ML-DSA-65) both compile to wasm32-wasip1 on pinned 1.89.0. GO, with a pin-exact caveat (ml-dsa is 0.0.x). Recorded in both docs. Co-authored-by: Cursor <cursoragent@cursor.com>
… gap Closes the encrypt side of Irzhy's security invariants. Adds a fail-closed encrypt-provider capsule (the chain's producer end) with the boundary contract pinned by characterization tests, plus a precise gap analysis vs the PC2 reference. - encrypt-provider skeleton (microvm tier), self-contained (no elastos-common yet) to stay rebase-safe while 0.4.0 churns (Anders: ~20% on GitHub, commits being redone). Builds to wasm32-wasip1; 6 host tests pass. - Invariant #1 pinned: caller cannot supply a CEK on the wire (deny_unknown_fields + no key field); sealed output carries only ciphertext + wrapped_cek (never raw CEK); CEK zeroized; status blocks raw_cek + plaintext authority; fail-closed. - The one gap (CEK+KID generated in-boundary, not in the Node host as PC2 does today) is captured as an #[ignore]d test + DDRM_ENCRYPT_INVARIANT.md, with a scoped landing and reconcile-to-elastos-common plan. - Updated DDRM_SECURITY_MODEL.md (invariant #1 -> test rows, second open item) and DDRM_STATUS.md (encrypt-provider row, both-ends note, base-volatility note). Co-authored-by: Cursor <cursoragent@cursor.com>
… drift) Anders force-pushed origin/0.4.0 (redone commits, more to come). Reconcile without rebasing yet (base still in flux): - Verified elastos-common/protected_content.rs is byte-identical between this branch and the redone origin/0.4.0 — the contract converged, zero type drift. The redone base independently added the exact types our providers consume. - scripts/ddrm-drift-check.sh: guards every schema const, struct, and chain-binding field the dDRM chain depends on; fails loudly on a future 0.4.0 type move. Currently PASS. Lists encrypt-provider's reconcile-to-common items. - Recorded the rebase recipe + safety backup (backup/decrypt-provider-cenc-preD17) in PUSH_PLAN.md, and the reconciliation + 61 green provider tests in DDRM_STATUS.md. Co-authored-by: Cursor <cursoragent@cursor.com>
…context A new engineer/agent can start cold from HANDOVER.md with no blindspots: the 30-second picture, mission + priority stack, the capability/dDRM mental model, what's built (61 green provider tests), the ordered doc map, key people and their concerns, the hard constraints (GitHub suspended, 0.4.0 in flux, zero type drift), branch topology, open blockers, verify commands, the working method, the 10/10 daily-prompt methodology, a Day 1-17 log, and the next unblocked options. Also corrects the DDRM_STATUS commit-count note (17 ours; rev-list shows 19 vs the force-pushed base due to 2 orphaned old-upstream commits the rebase drops). Co-authored-by: Cursor <cursoragent@cursor.com>
…p flag
Join the two tested islands of the decrypt boundary — the upstream
CEK-sealing envelope unwrap (envelope::{parse,ecdh_unwrap,extract_cek}) and
the decrypt-step core (decrypt_session_segment) — into decrypt_sealed_segment,
the single in-boundary operation the Hybrid decrypt rail will invoke once the
CEK-transport rail is confirmed (DDRM_DECRYPT_RAIL.md).
Mirrors PC2 ddrm-decrypt::session::unwrap_envelope -> cenc decrypt: the CEK
materializes only after a correct ECDH unwrap against the session key, is held
in Zeroizing for its whole lifetime, is consumed + zeroized by the cenc engine,
and never reaches the scoped response. Pinned by two characterization tests
(end-to-end recover + containment; fail-closed on wrong session key) and proven
to build to wasm32-wasip1.
Gated behind the rail-prep Cargo feature (OFF by default, Parallel Change): the
live dispatch and the 25-test default suite are unchanged, so the live wiring is
a one-step swap into open_session/render once the rail + session-key
provisioning land. No behaviour change on the default path.
Co-authored-by: Cursor <cursoragent@cursor.com>
…y CEK+KID Vendor PC2 cenc-encrypt's AES-128-CTR cipher core (Elacity/pc2.net @ a0a910158) into encrypt-provider/src/cenc.rs — the symmetric counterpart of the AES-CTR core decrypt-provider vendored from cenc-decrypt — and add the in-boundary keygen PC2 lacks: - mint_cek_and_kid() mints a 16-byte CEK + 16-byte KID with a CSPRNG (getrandom -> WASI random_get on wasm32-wasip1). Generation is unconditional, takes no caller input, and never leaves the sandbox. This is the precise move that closes the gap: PC2 minted the CEK in the Node host (dashPackager.ts::generateCEK). - seal_segment_in_boundary() mints the key, CENC-encrypts the asset, scrubs the CEK on drop (Zeroizing<[u8;16]>), and returns SealedSegment — which has no CEK field, so invariant #1's output half is enforced by construction. The once-#[ignore]d cek_and_kid_generated_inside_boundary now passes; encrypt-provider goes 6(+1 ignored) -> 13 green, 0 ignored. Full chain: 68 green, drift PASS, builds clean to wasm32-wasip1. Scope held deliberately tight (one boundary at a time): cipher core only. PC2's fMP4 box surgery (mp4box) and Elacity PSSH injection were NOT vendored — PSSH embeds chain/Lit authority we must translate, not copy (ACL). Those + the actual CEK sealing are a later boundary sharing the decrypt rail dependency, so `seal` dispatch stays fail-closed, mirroring decrypt-provider's fail-closed open_session. No behaviour change on the live (fail-closed) dispatch path. Co-authored-by: Cursor <cursoragent@cursor.com>
…gen deps Lockfile byproduct of the Day-19 invariant-#1 closure (aes, ctr, getrandom + transitives). Keeps the committed tree consistent with Cargo.toml. Co-authored-by: Cursor <cursoragent@cursor.com>
…ope island) Add src/pq_envelope.rs — the post-quantum analogue of the classical envelope.rs, behind the pq-envelope feature (default OFF, Parallel Change), proving the runtime profile (elastos-pq-hybrid-threshold-v0) composes and recovers a CEK: - Hybrid KEM: x25519 DH || ML-KEM-768 (FIPS 203). The AES-256-GCM wrap key is derived (SHA-256 KDF, labelled + length-prefixed) from BOTH shared secrets, so confidentiality holds if EITHER primitive stays unbroken. - AEAD wrap is authenticated: wrong KEM secret / tampered blob fail closed (UnsealFailed), no plaintext on error. - Signature sits behind a CekSealVerifier abstraction so ml-dsa-65 (or a hybrid ECDSA+ml-dsa during PC2 migration) plugs in without touching the unwrap path. - CEK returned in Zeroizing; never present in the sealed bytes. Unwrap needs no RNG and no outbound authority — a pure in-VM transform, like the classical path. Pinned by 4 characterization tests (round-trip recover; wrong-session fail-closed; tampered-signature fail-closed; sealed blob has no raw CEK) and proven to build to wasm32-wasip1 under 1.89.0. Resolved versions: ml-kem 0.2.3, x25519-dalek 2, aes-gcm 0.10, sha2 0.10. cargo test --features pq-envelope: 29 green (25 default + 4 PQ). Default suite (25) and rail-prep (27) unchanged; the PQ crates are pulled only when the feature is enabled. This makes the PQ rail a known-good drop-in for the classical envelope the moment Anders confirms the transport + signature scheme. No behaviour change on the default path. Co-authored-by: Cursor <cursoragent@cursor.com>
Bind the three in-boundary engines into one cross-engine proof: decrypt_pq_sealed_segment (feature pq-rail-prep, default OFF, enables pq-envelope) chains hybrid_unwrap -> decrypt_session_segment — the PQ analogue of the Day-18 classical decrypt_sealed_segment. The PQ unwrap slots exactly where the classical ecdh_unwrap does (mirroring PC2 ddrm-decrypt::session::unwrap_envelope -> cenc), with the CEK in Zeroizing throughout, consumed + zeroized by the cenc engine, and never reaching the scoped response. Pinned by a cross-engine golden: PQ-seal a CEK and CENC-encrypt a segment with that SAME CEK, then prove the composed path recovers the plaintext while the CEK stays off the boundary (pq_sealed_segment_decrypts_end_to_end_and_keeps_cek_off_the_boundary), plus a wrong-session fail-closed case. Builds clean to wasm32-wasip1. cargo test --features pq-rail-prep: 31 green (29 + 2 cross-engine). Default (25), rail-prep (27) and pq-envelope (29) suites unchanged; no new dependencies. Full chain 68 green, drift PASS. This proves the entire PQ dDRM data path (sealed CEK in -> rendered bytes out, key contained) before the rail lands — the remaining work is the transport shim, not the crypto or the engines. Also refreshes DDRM_SECURITY_MODEL.md to current truth (Day-19 keygen closure + the PQ rows). No behaviour change on the default path. Co-authored-by: Cursor <cursoragent@cursor.com>
Add substrate-independent golden-vector fixtures (characterization/golden-file pattern) under tests/vectors/ that lock the dDRM decrypt data paths across refactor, rebase onto 0.4.0, and a future microVM port: - classical_cenc.json: P-256 ECDH envelope -> CENC AES-128-CTR, byte-compatible with PC2 ddrm-decrypt, so it doubles as a cross-impl conformance fixture. - pq_hybrid_cenc.json: x25519+ML-KEM-768 hybrid seal -> CENC; replay reconstructs the typed PqSealedEnvelope from flat bytes (ML-KEM dk/ct (de)serialization), exercising the wire-decode the live rail will need. Replay (recover CEK -> decrypt -> assert plaintext) and corrupted-input fail-closed tests run with no in-test sealing and no RNG (every consumer step is deterministic). Schema in src/vector_format.rs. Feature split: `vectors` (default OFF, enables pq-rail-prep) replays the committed fixtures; `gen-vectors` regenerates them. Base suites unchanged (25/27/29/31); `--features vectors` = 35 green. Builds clean to wasm32-wasip1. Co-authored-by: Cursor <cursoragent@cursor.com>
Add scripts/pc2-conformance.sh: decrypts the committed classical golden vector
(classical_cenc.json) using PC2 ddrm-decrypt's REAL code and asserts byte-for-byte
parity end to end:
- CEK transport: PC2 envelope::parse -> ecdh_unwrap -> extract_keys_blob recovers
the same 16-byte CEK from our sealed envelope.
- media: PC2 mp4box::parse_segment -> cenc::decrypt_samples decrypts our segment
to the same plaintext.
The harness compiles a small driver (scripts/pc2-conformance/driver.rs) against the
PC2 repo on demand via a temp crate, so no absolute path or PC2 coupling enters the
ElastOS build graph. Resolves PC2 via PC2_REPO (default local checkout); skips clean
(exit 0) when PC2 is absent so the default chain is never broken; fails (exit 1)
only on genuine divergence. Result against the live PC2 checkout: PASS.
No capsule code changed; base suites (25/27/29/31), vectors (35), chain (68), and
drift remain unchanged.
Co-authored-by: Cursor <cursoragent@cursor.com>
- Add scripts/ddrm-verify.sh: one-button pre-rebase/PR gate aggregating the contract drift check + PC2 cross-impl conformance (skips clean without PC2, fails non-zero on any genuine gate failure). - Widen the conformance driver to take multiple vectors and add a NEGATIVE case: for every vector it tampers the envelope and asserts PC2 fails closed too, so both implementations reject the same corruption identically. - Add a v2 fixed-IV classical golden vector (classical_cenc_v2.json) alongside the v3 random-IV one; the harness cross-checks both PC2-supported envelope versions. Add an in-repo v2 replay test (refactored the emit/replay into shared helpers). Base suites unchanged (25/27/29/31); vectors suite 35 -> 36 (+v2 replay); chain 68; drift PASS. Live PC2 result: PASS for v3 + v2, positive and negative. Co-authored-by: Cursor <cursoragent@cursor.com>
…n M1 verdict Commit 3 of the audit follow-up. Both items were traced to ground by read-only reachability passes before any code: A7 is a real availability bug (fixed); M1 is not exploitable (cleared + pinned). A7 (HIGH, reachable by every legitimate user on flaky Carrier transport): the quorum open retry loop re-sent the SAME wallet-signed grant on attempts 2-3. Each grant carries a single-use per-request nonce, so the dKMS node's process-global replay guard (correctly) rejected the retry as "access grant rejected: replayed" — turning transient sub-quorum transport loss on attempt 1 into a hard open failure. Fix: on retries, assemble a FRESH grant from the already-cached wallet-signed delegation (new request_nonce + timestamp, signed by the cached session key) — no MetaMask popup, and the SAME delegation signature so the forensic watermark anchor is unchanged. Attempt 1 still uses the up-front grant. Fail-soft: if no live session is cached or regeneration fails, fall back to the original (never worse than before). Regeneration runs inside the existing spawn_blocking (it shells the grant sidecar), so the async executor is never blocked. The decision is split into an I/O-free `pick_grant_for_attempt` so the per-attempt logic is unit-tested without the sidecar (4 new tests). This never weakens the gate: a retry sends a different LEGITIMATE nonce, it does not bypass the replay guard, and the on-chain hasAccessByContentId check still runs on every recover. M1 (cleared): ECDSA high-s malleability at the recover sites looked like it could bypass a replay/dedup gate. A full sweep confirms NO replay/dedup key in the tree is signature-keyed — the grant replay guard keys on explicit server nonces, recovered identities derive from the public key (malleability-invariant), and signature_hash fields are audit/equality values only. Safe-by-construction. Pinned in the PRINCIPLES_CONFORMANCE "do not re-churn" register, with a note that naive low-s normalization (without flipping recovery_id parity) would break owner recovery — so it is deliberately not applied to the crown-jewel path. Gate: cargo test -p elastos-server green — 774 + 95 passed, 0 failed (incl. the 4 new attempt tests). No CEK-path, served-byte, or wire-format change; client-side only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VjFQt6DK9ZGnLs4ykUWsuX
…resolved Chosen next target was "harden the audit/custody trail (PRE-3)". Traced to ground first (the H1/M1 discipline) — and, like H1 and M1, the finding is stale: the work is already done. No code change; this commit records the verdict so the audit docs match reality and a future pass does not re-implement an already-tamper-evident log. Ground truth (substantiated by passing tests, not assertion): - AuditLog::emit returns Result and writes a ChainedRecord — monotonic seq + prev_hash + record_hash over domain‖seq‖prev_hash‖event_json, ed25519-signed with a crypto-agility tag — flushed and sync_all'd to disk BEFORE the chain head advances (failed write retries the same seq: no gap, no silent loss); verify_chain walks it for tamper-evidence (primitives/audit.rs:461-535). - The dDRM open emits a FAIL-CLOSED content_open (viewer_open.rs:481): the open is refused (503) if the custody record can't durably commit, on the common path before object/media/quorum dispatch. Session-bound segment/byte serving is covered transitively (sessions are minted only by that handler). - The "no open event, only a comment at viewer_open.rs:1021" claim was a misread: :1021 is media-layout detection, not an open path. - Non-gaps confirmed: /api/provider/object/download/raw serves the principal's OWN library files (no decrypt/CEK/quorum; provider-effect audit is correct, and there are no chain rights to revoke on one's own files); the demo routes serve an operator-fixed sample, not attacker-selectable content. - Genuinely open (separate roadmap, not a present defect): external anchoring of the chain head against a live-compromised runtime that still holds the signing key. Test evidence: cargo test -p elastos-runtime audit — 17 passed, 0 failed, incl. dropping_a_record_breaks_the_chain, emit_chains_seq_and_a_clean_log_verifies, content_open_grant_digest_is_optional_and_chain_verifies, the_chain_resumes_across_reopen_and_stays_append_only. Also annotates PRE_AUDIT.md row 3 as RESOLVED with the implementing references. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VjFQt6DK9ZGnLs4ykUWsuX
…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
The List operation calls library_object() per directory entry, which for a file read the whole file and hashed it TWICE — once for the `revision` token (SHA-256) and again in raw_sha256_cid() for the `content_cid` (also SHA-256 over the same bytes, wrapped in a CIDv1 multihash). On a folder of N files that is N reads + 2N full SHA-256 passes on every listing — and listings are the file explorer's hottest path. Hash once and derive both: split raw_sha256_cid into sha256_digest_to_raw_cid(digest) and reuse the single digest for the revision hex + the CID. Byte-identical outputs (revision is a compare-and-swap token threaded through ~14 mutation ops via if_revision, so exactness matters) — pinned by a new test asserting the single-hash path equals the prior two-pass form across representative inputs. ~Halves per-file hashing on every directory listing; no behavior, API, or revision-value change. Test: cargo test -p elastos-server single_hash_listing — ok. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VjFQt6DK9ZGnLs4ykUWsuX
Re-listing a folder (navigation, refresh, polling — the file explorer's most frequent op) re-read and re-hashed every unchanged file each time, just to recompute display facts (revision token, content CID, size, thumbnail pointer). Add a bounded, process- global cache of those file-content facts keyed on (path, len, mtime), consulted ONLY on the LIST display path: a re-list of an unchanged directory now skips the full read + SHA-256 entirely. Safety: the cache is self-invalidating — any write bumps the file's mtime, so the key changes and a stale entry is never served. Critically, it is wired ONLY through library_object_listing_cached (the List loop); the CAS gate (check_revision) and every mutation keep using library_object (fresh), so a stale entry can at worst cause a benign false write-conflict, never a wrong overwrite. Bounded to 8192 entries (FIFO eviction); keys are principal-scoped (no cross-tenant leakage). Refactor: the file-facts computation is extracted into file_listing_facts (always fresh), wrapped by file_listing_facts_maybe_cached; library_object becomes a thin fresh wrapper over library_object_inner(.., use_list_cache=false). Tests (cargo test -p elastos-server, 777 pass): cas_path_does_not_consult_the_listing_ cache (CAS path never reads the cache), listing_cache_key_changes_with_len_and_mtime (self-invalidation), single_hash_listing_matches_two_pass_revision_and_cid. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VjFQt6DK9ZGnLs4ykUWsuX
…ct URLs The file-explorer cover cache (loadCover) was an unbounded Map of endpoint -> Promise<objectURL>. Over a long browse session it grew without limit, and because each entry holds an object URL (createObjectURL keeps the backing blob alive until revoked), the blob memory leaked too — capping alone wouldn't have freed it. Make it a bounded LRU (256 entries): touch on access (re-insert at the back) so a cover still on screen is never the one evicted, and on eviction revoke the object URL so the blob memory is actually released. Behavior-preserving — covers still load and cache, and re-renders stay cheap on a hit; an already-rendered (then-evicted) URL stays visible since revoke only blocks new resolutions. Gate: node --check api.js passes (no behavioral JS harness exists for this capsule). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VjFQt6DK9ZGnLs4ykUWsuX
The CI `check` job runs `cargo fmt --all --check` and `cargo clippy --workspace -D warnings` (RUSTFLAGS=-D warnings) from elastos/. Two gate failures from this branch's earlier commits, fixed here: - rustfmt: reflow a few lines in access_grant.rs / viewer_open.rs / library.rs to match rustfmt (whitespace only, no logic change). - clippy dead_code: the A/B list refactor left `raw_sha256_cid` (whole-buffer hash + CID) with no production caller — the list path now derives the CID from the already- computed digest via `sha256_digest_to_raw_cid`. It remains useful only as the independent reference the byte-identity test checks against, so gate it `#[cfg(test)]`. Verified locally from elastos/: `cargo fmt --all -- --check` clean, `cargo clippy --workspace --all-targets -- -D warnings` clean, `cargo test -p elastos-server library::` 63 pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VjFQt6DK9ZGnLs4ykUWsuX
…iewer authz Every media segment and object byte/page request ran is_viewer_capsule -> resolve_browser_capsule, which reads + JSON-parses the viewer capsule's manifest from disk (plus an entrypoint stat) — re-resolved from scratch on every fragment, hundreds of times per playback, for the same capsule. It is redundant on these paths: a media/object session is created ONLY by the open path, which resolved + validated the viewer capsule at creation and bound it into session.viewer. On a segment request that proof is already in hand — the home-launch token (verified fresh here, scoped to `viewer`; its DID load is memoized) plus the session.viewer match and the principal match are the authorization. So we drop the per-fragment manifest re-resolve and rely on the session binding. Trade-off (documented inline): an active playback/view keeps serving if the viewer capsule is uninstalled mid-stream, instead of 404-ing — the principal still owns the content and the token + session + principal gates are unchanged, so it stays fail-closed. A bogus viewer with no session now rejects via the token/session gate (401/404) rather than the capsule check (404) — still fail-closed. Gates (elastos workspace): cargo fmt --check clean, cargo clippy --workspace --all-targets -D warnings clean, cargo test -p elastos-server viewer 26 pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VjFQt6DK9ZGnLs4ykUWsuX
…et advance) The capability-conformance KNOWN_GAPS registry still described GAP-8 as "audit sink is best-effort and unsigned ... the log is not hash-chained/tamper-evident." That claim is now false: emit_best_effort routes through emit(), which builds a hash-chained, ed25519-signed, fsync'd ChainedRecord (PRE-3). A build-visible registry making a false claim about the code is exactly the docs-code drift the ratchet exists to prevent. - Rewrite GAP-8 to the TRUE residual (downgraded med -> low): capability grant/use/denial events emit best-effort, so a write failure drops the NON-custody event — a deliberate availability choice; custody opens are fail-closed. The log itself is tamper-evident. - Strengthen denial_is_audited from "log is non-empty" to assert the record is a CHAINED envelope (carries seq + prev_hash + record_hash), pinning the now-closed tamper-evidence half so a regression flips the ratchet red. Gate: cargo fmt --check clean; cargo test -p elastos-runtime --test capability_conformance 8 passed (denial_is_audited, gaps_registry_is_intact), 3 still-ignored open gaps. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VjFQt6DK9ZGnLs4ykUWsuX
…log redaction Docs-alignment was the lowest movable scorecard axis: the dDRM/dKMS verdicts (H1, M1, M3, A7, A1/A2, PRE-1..8) lived as PROSE in PRE_AUDIT.md / PRINCIPLES_CONFORMANCE.md with nothing failing if they drifted. This adds the DDRM counterpart of the capability side's KNOWN_GAPS ratchet. - New `elastos/crates/elastos-server/tests/ddrm_verdicts.rs`: a VERDICTS table pairing each verdict's load-bearing invariant with the test (or CI job / explicit structural reason) that pins it. `verdicts_registry_is_intact` keeps it honest — a settled security verdict must cite a real pin (test path / ci-job / structural), never bare prose or a todo. Runs in the CI test job. (The cited capsule-crate tests run under the `capsules` job; this registry centralises + indexes them, it does not re-run them — stated plainly in the file.) - Closes the one verified-but-UNENFORCED verdict: PRE-2's log-redaction half is now pinned by `log_fp_redacts_sensitive_identifiers` (was convention-only). The raw (wallet, content_id) must never appear in the fingerprint. - PRE_AUDIT.md + PRINCIPLES_CONFORMANCE.md now point to the registry as the build-enforced source of truth, the prose as the narrative. The registry itself caught my first cut (PRE-7/PRE-8 marked settled with a structural pin) — proof the ratchet has teeth; I made `structural:` an explicit, visible pin category rather than pretend everything is unit-tested. Gates (elastos workspace): cargo fmt --check clean, cargo clippy --workspace --all-targets -D warnings clean, verdicts_registry_is_intact + log_fp_redacts pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VjFQt6DK9ZGnLs4ykUWsuX
…y, permissionless/TEE Durable capture of the decisions discussed: where the scorecard points are, what was banked on-branch (Lane A), and the three movers that need a decision: - ① external crypto/protocol audit (schedule now; our verified-safe registries make it cheaper to scope). - ② one coordinated dKMS-node redeploy bundling AAD-binding + blinded-content-ids/ ephemeral-keys (privacy) + node-set-pin enforcement, with rollout-safety must-haves (execute later; operator has node access). - ③ permissionless track: staking/slashing (economic security + accountability) + attestation — TEE OR reproducible-builds+signing — analysed honestly (TEE strengthens the t=2 collusion bar but re-centralizes trust in a chip vendor and isn't a silver bullet; staking is the bigger lever for permissionless). Forward-looking design direction (node items re-verified at execution time), not a spec. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VjFQt6DK9ZGnLs4ykUWsuX
… registries The packet led well with the one OPEN invariant (§1 re-seal AAD binding) but didn't surface the build-enforced evidence for the RESOLVED/cleared findings — which is what lets the firm confirm-and-skip them and bill for the hard crypto instead. Adds §4b: the dDRM verdict registry (tests/ddrm_verdicts.rs) + the capability KNOWN_GAPS ratchet + the PRE_AUDIT 7/8-resolved pass as the scope-OUT index, with the registry repro commands in §5 and a matching reviewer-checklist line. §1 remains the scope-IN item. Supports scheduling decision ① at lower cost. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VjFQt6DK9ZGnLs4ykUWsuX
… strip) The workspace root tuned [profile.dev] and [profile.test] but had NO [profile.release], so elastos-server, the runtime, and every member shipped release with rustc defaults (no LTO, codegen-units=16, unstripped). Add a release profile: opt-level = 3 # server runtime: optimize for speed lto = "thin" # most of LTO's size/speed win without fat-LTO's CI build-time blow-up strip = true # smaller; KEEPS panic messages panic deliberately stays "unwind": elastos-identity's WebAuthn handler relies on std::panic::catch_unwind for its fail-closed DoS bounds-check (PRINCIPLE 11) — "abort" would break it. Dial-up path documented inline (lto = true + codegen-units = 1). Conformance: build-config only; touches no authority/transport/canonical-path/audit behavior (principles-neutral); keeps the fail-closed WebAuthn path intact. `cargo verify-project` clean. A full `cargo build --release -p elastos-server` is the confirming gate; result + binary-size delta to follow. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VjFQt6DK9ZGnLs4ykUWsuX
…one Engine
Closes the memory half of the untrusted-capsule DoS traced earlier: an Untrusted Wasm
capsule (launched by CID via request_handler.rs) ran in-process through WasmProvider with
Engine::default() and NO resource limits, so a memory bomb could OOM the host — a gap
against the runtime's OWN Principle 7 ("resource boundaries should apply") and Principle 11
(fail closed). This is part 1 of 2 (CPU/epoch runaway protection is part 2, pending the
service-vs-command model confirmation).
- Every capsule execution's Store now carries StoreLimits (memory_size, table_elements,
instances=1) via store.limiter(...). A capsule exceeding its budget fails closed (the
grow/instantiation is denied) instead of exhausting the host.
- Memory budget defaults to a GENEROUS 1 GiB, overridable via ELASTOS_WASM_MEMORY_LIMIT_MB.
This is a BACKSTOP that bounds the previously-unbounded case — NOT the final design. The
real design (documented inline + to be tracked): per-capsule manifest-declared,
capability-GRANTED budgets so game/AI capsules can request more while untrusted capsules
stay modest (Principle 7: explicit, not ambient), with a host-protective ceiling.
- Share ONE wasmtime Engine across all capsules instead of one per load() (recommended
pattern; the Engine holds the JIT/compile context, never tenant heap — per-tenant data
lives in each execution's Store, dropped per run, so multi-tenant clearing is unaffected;
comment updated to reflect this).
Tests (cargo test -p elastos-compute, 11 pass): over_budget_capsule_fails_closed_not_host_
exhaustion (a module wanting more memory than the cap cannot instantiate, host survives) and
within_budget_capsule_instantiates (the cap never penalizes legitimate use). fmt + clippy
-D warnings clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VjFQt6DK9ZGnLs4ykUWsuX
… follow-ups So they don't rot: Chunk A landed a backstop global memory cap; the principled per-capsule capability-granted budget (for games/AI) and the CPU/epoch runaway protection (Chunk B) are recorded as tracked Lane-A follow-ups. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VjFQt6DK9ZGnLs4ykUWsuX
…tching the VM path Refines the Chunk A backstop into the principled design. The manifest already declares `resources.memory_mb` and the crosvm/VM provider already enforces it (config.rs:270) — only the in-process WASM provider ignored it. Now WASM honors the per-capsule declared budget too: - execute_wasm takes the capsule's `manifest.resources.memory_mb` and enforces `min(declared, ceiling)` per Store (PRINCIPLE 7: explicit, granted — not a flat ambient cap; PRINCIPLE 11: fail closed). A capsule gets exactly the budget it asked for, and a malicious capsule declaring an absurd value is CLAMPED to a host ceiling (8 GiB default, override ELASTOS_WASM_MEMORY_CEILING_MB) so in-process WASM can't OOM the host (the VM gets this for free — an over-sized VM just fails to launch). - Replaces Chunk A's global 1 GiB default, which was actually too loose (a 16 MiB capsule got 1 GiB of WASM headroom vs its declared 16 MiB in a VM). Audited every WASM capsule: all declare memory_mb (16–128 MiB; the gba-emulator game declares 128) and none rely on the default, so honoring the declared value breaks nothing and makes WASM consistent with the VM. - Also fixes a doc-comment misplacement Chunk A introduced (struct doc had attached to a const). Tests (cargo test -p elastos-compute, 12 pass): declared_memory_is_honored_and_clamped_to_ ceiling (modest declarations honored exactly; an absurd one clamped) + the existing fail-closed/within-budget tests. fmt + clippy -D warnings clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VjFQt6DK9ZGnLs4ykUWsuX
…ll pending Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VjFQt6DK9ZGnLs4ykUWsuX
…ption) Before this, a WASM capsule that spun forever permanently held a blocking thread + CPU and `stop()` could not kill it (the execution runs in a `spawn_blocking` task that cannot be cancelled). That violated PRINCIPLE 7 (resource boundaries should be enforceable) and left no operator escape hatch. Wire wasmtime epoch interruption end-to-end: - Engine is built with `Config::epoch_interruption(true)` (cheap: a load+compare at loop backedges). - Each execution arms an epoch deadline whose callback checks a per-instance `should_stop: Arc<AtomicBool>`. With no stop signal it keeps extending the deadline, so a legitimate (even long-running) capsule runs untouched. - `stop()` sets `should_stop` and bumps the engine epoch, so a spinning capsule hits its next epoch check and traps. The `Arc` is shared with the running task, so the signal reaches the in-flight execution even after the instance is removed from the map. Test `runaway_capsule_is_terminable_via_stop_signal` runs a busy-loop capsule, signals stop, and asserts it terminates within 5s instead of running forever. The loop is finite as a CI-hang backstop. Behavior-preserving for every capsule that is not stopped; the only new effect is that `stop()` now actually halts a runaway. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VjFQt6DK9ZGnLs4ykUWsuX
…B2b deferred B2a (epoch-interruption + stop()-driven termination) is landed and pinned by runaway_capsule_is_terminable_via_stop_signal. The remaining automatic no-progress/timeout kill (B2b) stays deferred pending the service-vs-command policy decision. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VjFQt6DK9ZGnLs4ykUWsuX
The PRE-2 log_fp test (viewer_open.rs) and the new ddrm_verdicts registry had long assert!/println! calls that rustfmt wants line-wrapped. Per-crate fmt during the chunk work checked elastos-compute but not elastos-server, so this drift would have failed the CI fmt gate. Pure formatting — no logic change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VjFQt6DK9ZGnLs4ykUWsuX
Records the green-here vs run-live gate boundary (workspace fmt/clippy/test + verify-capsules passed in-container; carrier/PTY/release-install smokes are live-only), the four behavior-changing commits to focus the review on (M3, A7, B1, B2a) with their pins, the audit-ratchet scope-out evidence, the deferred follow-ups (B2b etc.), and a fast-forward merge sequence into the ddrm hardening branch. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VjFQt6DK9ZGnLs4ykUWsuX
The deep-audit A7 fix (edb02ec) makes a quorum-open retry regenerate a fresh-nonce grant from the cached delegation, so the node's single-use replay guard no longer rejects a legitimate retry. Update the Carrier runbook symptom table from "known gap (tracked)" to RESOLVED, pinned to access_grant::attempt_tests::retry_uses_freshly_regenerated_grant. Co-authored-by: Cursor <cursoragent@cursor.com>
…route + marketplace contracts Creator-parity work: substantial creator capsule UI updates (creator.js, index.html), media-provider changes, the gateway creator route (api/creator.rs), and a marketplace contracts reference doc (docs/ELACITY_MARKETPLACE_CONTRACTS.md). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Produce a single MPEG-DASH/CENC-compliant asset (ISO-IEC 23001-7) for every media (DASH) mint, while keeping the server-decrypt rail's own player working by down-converting back to a plaintext-looking init at the fetch point. - ddrm-envelope: shared `pssh` module -- single source of truth for producer, runtime decrypt read-path, and playback clients. ELASTOS_PQ_SYSTEM_ID (b6e254ef-0dc5-47fe-94e7-0e72ed1dc7b0); build_pssh (v1 box, default-KID + opaque .asset.protections JSON) / parse_pssh (v0/1, trailing-moov tolerant). - ddrm-media: cenc_signal_init() (avc1->encv / mp4a->enca + sinf(frma/schm/tenc) + pssh moov child) and strip_cenc_signal() as a byte-exact inverse. Roundtrip tests assert strip(signal(x)) == x, no-op on unsignaled, fail-closed on double. - encrypt-provider: CencSignalInits op -- pure public box surgery (no CEK/secret), wraps the runtime-built PSSH envelope and rewrites each per-track init; returns transformed inits + pssh_b64 for the MPD. - creator (producer): after the threshold seal, build the PSSH envelope from dkms_protection, CENC-signal each init, and patch stream.mpd with <ContentProtection> (mp4protection:2011 + cenc:default_KID + per-system pssh). - ddrm-media-authority: read_dash_init strips CENC signaling at the fetch point so the seal-bound AAD init and the runtime player's served init both match the plaintext init the mint sealed (no AAD mismatch). - Flip on by default: drop the ELASTOS_DDRM_CENC_PSSH gate -- CENC signaling + MPD ContentProtection are now standard output. Additive; existing playback unchanged. Squashed from: d012fc4 047d38f 4d26798 d6fb99f 3ac5fdc 4edfd9e elastos-server 782+95 green; helper 15 green; fmt clean.
…TY-2282) Stop the dKMS quorum path from wedging and leaking processes under playback+reload, and make the local test suite pass off the Linux x86_64 gate. - dkms-authority (Defect A): serve each accepted connection on its own thread (serve_unix_listener / serve_tcp_listener) so an idle/slow/leaked client can no longer head-of-line-block the daemon in read_frame; revoked_callers becomes daemon-lifetime Arc<Mutex> shared state (additive+idempotent); 30s per-conn read timeout on both transports. Regression test drives the real Unix accept loop (RED pre-fix, GREEN after); 35/35 green. - key-provider: bound the Unix recover read in establish_dkms_session with the same DKMS_TCP_READ_TIMEOUT_MS (5s) the tcp/carrier branches use, so a wedged node fails fail-closed within a bounded window. 18/18 green. - dkms (Defect B): reap leaked quorum helper/provider processes -- add Drop for the helper Capsule (kills+reaps key-provider/decrypt-provider children on every path), and guard MediaAuthorityProc launch/launch_quorum with a ChildReaper so early-return/error paths no longer orphan the raw Child. - browser: keep the runtime stream socket path within the macOS sun_path limit (104) -- fall back to a short "/tmp" base when temp_dir() would overflow, fixing the 6 browser-open route tests on macOS arm64 (Linux unaffected). - test(elastos-server): key component-checksum fixtures by detect_platform() so verify/stamp and agent-binary tests run on any host without masking the check. Squashed from: 50cdc46 0c22718 46a7ba4 d93f673 a9283b5
…view Address correctness, security, and robustness findings across the DKMS and encryption/decryption workflows, each with regression tests. - dkms-authority: revocations now share ONE live Arc<Mutex<HashSet>> across all connection threads (was a per-connection snapshot merged only on close), so a revoke binds every open connection immediately — "revocation outranks a live session" holds under concurrency. Unify the Unix/TCP accept loops into one generic serve_accept_loop with a MAX_ACTIVE_CONNECTIONS cap + RAII slot guard, bounding the thread/memory-exhaustion (slow-loris) vector on the network node. - key-provider: distinguish a transport fault from a node rejection (NodeRecoverError). A warm pooled connection the node's idle timeout closed is re-established and retried ONCE; a genuine rejection still fails closed with no retry. Fixes the first open after a >30s idle gap failing below quorum. - ddrm-media: drive the enca/encv choice off the authoritative hdlr handler type (fallback to an expanded audio-4CC allowlist), and make parse_codec_string use the same allowlist so the two classifiers can't diverge — an uncommon audio codec is no longer mis-signaled as video (non-compliant init + strip missize). - ddrm-media-authority: read_dash_init propagates strip_cenc_signal errors instead of unwrap_or(raw), so a malformed init fails with a precise diagnosis rather than an opaque downstream decrypt/quorum failure. - encrypt-provider: decode_kid16 validates length AND ASCII-hex charset before byte-slicing, rejecting a multibyte KID instead of panicking the capsule. - elastos-server: browser stream sockets use a per-euid dir created 0700 and refuse any pre-existing dir not owned by us or group/other-writable, closing the world-writable /tmp squatting / socket-hijack vector.
Resolve 25 conflicts across DKMS/DASH/creator + main's authority/provider work. Key merges: wasm execute_wasm (fuel+epoch+limits), browser-stream socket hardening on main's path refactor, peer capability allowlist + gossip ops, DID env-override before cache. Workspace builds; all affected test suites pass.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This branch brings the runtime to 0.5.0, headlined by standards-compliant MPEG-DASH / CENC media DRM (ELACITY-2283) and a hardening pass on the DKMS quorum key-authority plane (ELACITY-2282). Along the way it lands the creator publishing flow, per-capsule WASM resource limits, forensic A/V watermarking, a batch of serve/library performance work, and a security-review hardening pass.
mainhas been merged in (--no-ff) and all conflicts resolved.What's in it
🎬 MPEG-DASH / CENC compliance (ELACITY-2283)
encv/encasample entries carryingsinf/schm/tenc,psshinjection) so a stock CENC player / FFmpeg keys decryption offtenc.enca/encvchoice is driven by the track's authoritativehdlrhandler type.ddrm-media,encrypt-provider,decrypt-provider,ddrm-envelope,elacity-player,ddrm-viewer.🔑 DKMS quorum reliability + hardening (ELACITY-2282)
🎨 Creator publishing flow
🧱 Per-capsule WASM resource limits
Engineacross capsules.🕵️ Forensic A/V variant watermarking
⚡ Performance
🛡️ Security-review hardening pass
A focused pass on the DKMS/encryption workflows, each with regression tests:
enca/encvclassification driven by the authoritativehdlrtype, with an expanded codec fallback.read_dash_initpropagates strip errors instead of masking them as opaque decrypt failures.decode_kid16rejects malformed (multibyte) KIDs instead of panicking the capsule.0700dirs and refuse foreign-owned/writable dirs (closes a/tmpsquatting vector).📚 Audit & conformance
Merge with
mainmainwas merged in (--no-ff); 25 files conflicted and were resolved considering both branches. Highlights:wasm.rs— unified ours' memory-clamp + epoch-termination with main's fuel metering, hostcall wiring, and wall-clock timeout into oneexecute_wasm.gateway_browser_stream.rs— folded ours' socket hardening into main'sbrowser_stream_socket_path(directory)refactor (covers both stream + adapter-IPC sockets).provider_resource.rs— extended main'speercapability allowlist with ours' gossip ops.gateway.rs— env trusted-signer override (main) before the DID cache (ours).runtime_control.rs— main's portablepid_is_alive();chat/session.rs— ours' fail-closed presence signing.auditrecipe;components.jsontookwallet-provider.Testing
elastosworkspace builds clean.elastos-server928 tests pass;elastos-compute16,chat31,ipfs-provider23,dkms-authority27,encrypt-provider31 (escrow) all pass.components.jsonvalidate.Risk / compatibility
recovery_kit_password_package_imports_with_password_only) fails only under full-suite parallelism (passes in isolation); unrelated to this branch.