sync: converge nightly into dev (share-flow removal + accumulated 0.7/0.8 commits) - #1249
Open
Koh0920 wants to merge 183 commits into
Open
sync: converge nightly into dev (share-flow removal + accumulated 0.7/0.8 commits)#1249Koh0920 wants to merge 183 commits into
Koh0920 wants to merge 183 commits into
Conversation
…ort pixel_rfb_port The session-surface arc (#1062) shipped the restore/gateway side of ato.pixel-stream.v1 but no build lane could produce a pixel artifact: every import lane sealed surface_requirement=None and no lane emitted the explicit pixel_rfb restore endpoint the runner's restore gate requires (selected_pixel_rfb_port fails a pixel descriptor without exactly one). - dockerfile_import params gain pixel_rfb_port (strict u16, fail-closed parse mirroring port_override). Presence opts the import into SessionSurface(kind=pixel_stream, ato.pixel-stream.v1). - The producer derives + validates the sealed contract pair fail-closed (pixel_import_contract): host_internal app_http readiness endpoint + guest_private first_frame pixel_rfb endpoint, re-validated through EndpointContract::validate; the app-port collision is refused at plan derivation and again at produce time. - process_job seals produced.endpoints into the manifest restore contract; Web artifacts seal an empty list so every pre-existing manifest stays byte-identical. - DockerImportOptions/DockerfileImportRequest carry pixel_rfb_port as an identity input, skipped when None so pre-existing import descriptors keep their identity digests (host_bind_relay discipline). - The recipe lane now fails closed on a pixel_stream capsule.toml surface requirement instead of sealing an artifact that can never restore. - docker_import_build dev CLI gains --pixel-rfb-port.
A terminal-class GUI workload allocates ptys (xterm opens /dev/ptmx) and the minimal guest init never mounts devpts — the live KVM build failed with 'get_pty: not enough ptys'. Mount it ONLY for a pixel build (pixel_rfb_port set), fail-closed like the managed mounts, so every Web import keeps a byte-identical init (same rootfs digest / identity).
…g named for a webview login_with_store_device_flow_desktop (used when ato-desktop spawns `ato login` as a child process) now calls try_open_browser on the computed login_url, the same helper the plain interactive `ato login` flow already uses. Previously it only emitted the URL over NDJSON and relied on the desktop app to render it inside an embedded WebView, which is what this change (and the paired desktop-side commit) removes. Renamed the CLI flag from --desktop-webview to --desktop since there is no more webview involved, and renamed the internal desktop_webview bool in run_publisher_onboarding_flow to non_interactive, which is what it actually distinguishes (no TTY available to prompt).
…op instead auth_login_window.rs opened the auth_bridge login URL inside an app-embedded Wry WebView, which departs from RFC 8252 (OAuth for native apps must use the system browser). The CLI's login_with_store_device_flow_desktop now opens the OS default browser itself, so the Dock's Login command no longer needs to open any window at all - it just spawns `ato login --desktop`, watches its NDJSON stdout for a terminal event, and refreshes the Dock identity or re-shows the Dock on failure, exactly like the old window's completion handling did minus the WebView. - Deleted window/auth_login_window.rs and its module declaration. - Moved the child-process spawn/watch logic into ato_dock as a private trigger_login helper (DockCommand::Login's only job now). - Removed the AuthLoginWindowSlot global from app.rs. - Removed ContentWindowKind::Auth and its three match arms (card_switcher's glyph_for/kind_tag, ato_start's snapshot builder) - no window of that kind is ever opened anymore. - DockCommand::Login no longer creates a WebView, so its required capability changed from WebviewCreate to LaunchSystemCapsule (matching the analogous StoreCommand::Login), and WebviewCreate was dropped from AtoDock's capability allowlist since Login was its only consumer. - Updated the stale ato-store comments that still described the old embedded-WebView design.
…s/URL to Dock UI Round-1 review fixes for ato#1077 (Desktop external-browser login): - Add a release gate (EXTERNAL_BROWSER_LOGIN_HARDENING_LANDED, default false) in login_with_store_device_flow_desktop: this path widens exposure to auth_bridge.ts's current auto-approval / session-token-copy weaknesses by routing through the OS browser instead of an app-isolated WebView. ato#1077 and RFC ato-api#261 rev.3 §6 both require this to stay off until ato-api#275 (Phase 1b hardening) has actually landed and deployed, not merely been authored (verified via `gh pr view` that ato-api#279/#281 are still open drafts). Fails closed with a clear NDJSON error naming the dependency; regression-tested. - Fix the fail-silent Desktop login UX: `ato login --desktop` now emits a structured `desktop_browser_launch_failed` NDJSON event (carrying login_url) when the automatic browser launch fails, instead of only an eprintln! that ato-desktop discarded via Stdio::null(). ato_dock now captures login_url, forwards this event and the terminal failure message into the Dock's existing (previously unused) event_queue/toast channel via a new dock_event_queue() accessor, so denial/cancellation/timeout/ HTTP errors are no longer silently invisible to the user. - Add regression tests that would have caught both classes of defect: CLI flag-parsing tests for `--desktop` wiring, a pure classify_ndjson_line unit (extracted from watch_login_completion) covering success/failure/ forward/ignore classification, and an async test asserting the bridge- hardening gate trips before any network/filesystem work. Verified: cargo check clean for both crates; full cli test suite (2897 tests) and ato_dock tests (7/7) green; cargo clippy clean on touched files; cargo fmt clean on touched files. Confirmed the 25-27 pre-existing desktop test failures (env-lock poisoning in webview/settings/materializer tests) reproduce identically on the pre-fix commit — unrelated to this change.
… copy, actionable link toast Addresses five round-2 findings on ato#1077's external-browser Desktop login: - trigger_login had no single-flight guard against overlapping Login invocations (regression from the deleted embedded-WebView flow's window-reuse check). Add LOGIN_IN_FLIGHT plus try_begin_login/end_login, wired through a guarded trigger_login wrapper around the existing spawn logic (renamed to trigger_login_inner); released on every exit path, including early errors before a child process is ever spawned. - The fail-closed gate's message (EXTERNAL_BROWSER_LOGIN_HARDENING_LANDED pending ato-api#275) was forwarded verbatim into the Dock's user-facing toast, showing real users a multi-sentence paragraph naming internal GitHub issue numbers with no next step. Split the gate's messaging into a developer-facing detail (stderr/bail!, still names ato-api#275 for logs) and a clean user-facing message that points at the one login path that still works today: `ato login` from a terminal (not gated by this constant). The security posture itself (fail closed before any network/filesystem work) is unchanged — that's a deliberate, tested decision from round 1 and outside this lane's scope to relax. - desktop_browser_launch_failed baked login_url into the message string, so the Dock could only show it as unclickable plain text in a toast that auto-dismisses in ~2.8s — not enough time to read or copy a URL. login_url now travels as its own JSON field; App.jsx renders it as a clickable link plus a "Copy link" button and keeps the toast open until manually dismissed instead of auto-dismissing. - JS-side single-flight guard: handleLogin now tracks a `signingIn` state, ignores repeat clicks, disables/relabels the "Sign in with Ato" button while a login is in flight, and stays in sync with the Rust-side guard via the desktop_login_failed / desktop_login_in_progress events. New/updated tests: login_guard_rejects_concurrent_acquire_until_released, desktop_login_gate_user_message_has_no_internal_jargon, forwards_browser_launch_failure_with_login_url_as_a_separate_field (+ without_login_url variant). Existing desktop_device_flow_fails_closed_pending_bridge_hardening still passes unchanged since the security-relevant bail! text is untouched.
…e substitute The fail-closed gate's user-facing fallback recommended `ato login` in a terminal "instead," implying it was a safe alternative to the very OS-browser exposure the Desktop gate blocks. It isn't: plain `ato login`'s existing non-headless branch already opens a real OS browser against the same unhardened auth_bridge.ts endpoints today on main. Reworded the fallback copy to drop the "instead" framing, and made the doc comments explicit that this is a pre-existing, already-shipped, separately-tracked gap rather than something silently walked back by the message — gating the CLI path too is out of scope for this Desktop-only lane (ato#1077). Added a regression test pinning the absence of the "safe substitute" framing while still requiring the message to name a working next step.
…erage, sanitized failures, persistent failure toasts Addresses five Major findings from round-4 review of ato#1077: - store.rs: EXTERNAL_BROWSER_LOGIN_HARDENING_LANDED flipping is no longer a bare, discipline-based boolean — a companion EXTERNAL_BROWSER_LOGIN_HARDENING_EVIDENCE constant must be updated in the same commit, and hardening_flag_requires_recorded_evidence_when_enabled fails CI if it isn't. - store.rs: extracted compute_poll_timing, browser_launch_failed_event, and sanitize_bridge_failure as pure, directly unit-tested functions covering the previously-untested browser-open/NDJSON logic that sits behind the fail-closed gate, and deduplicated poll-timing arithmetic between the plain-CLI and Desktop device-code flows so the two paths cannot silently diverge. - store.rs + mod.rs: the desktop flow's poll/exchange/init failure branches no longer forward raw ato-api HTTP status/response bodies verbatim into the Dock's user-facing toast. sanitize_bridge_failure splits each failure into a generic user message and a `detail` string that only reaches tracing::warn! logs, mirroring the dev/user split the fail-closed gate message already had. - App.jsx: desktop_login_failed toasts (including the fail-closed gate's explanation) now persist until dismissed instead of auto-vanishing in ~2.8s — persistence was previously keyed only on a URL being present, which this event never carries. - store.rs: added an explicit RELEASE-SEQUENCING NOTE flagging that this PR removes the only working in-app Desktop login until ato-api#275 lands, deploys, and the gate is flipped — requires an explicit human sign-off before promoting this branch past nightly/dev, which this commit cannot itself provide. Verified: cargo test -p cli --lib application::auth:: (44 passed) and cargo test --bin ato-desktop ato_dock (10 passed, both crates their own workspace), cargo clippy -p cli --lib --tests -D warnings (clean), npm run build in ato-dock (clean).
cargo fmt formatting for the new LoginCompletion::Failure variant and the new test assertions added in the previous commit.
…ess lanes join pixel-surface lane)
- imported_pack_script gained pixel_rfb_port on nightly; dev's seed-files test call passes None (web import, no pixel endpoint) - ProducedBuild gained endpoints on nightly; compose_import produces a Web artifact, so it seals no restore endpoints (legacy ports projection stays authoritative) cargo test -p snapshot -p snapshot-builder -p guest-agent: all green (349+54+…).
merge: forward-port dev into nightly (compose_import joins pixel-surface lane)
…n review) Integration review, DESKTOP-LOGIN-GAP (Major): this branch removes the embedded WebView login while the new external-browser login is gated behind EXTERNAL_BROWSER_LOGIN_HARDENING_LANDED (false until ato-api #275 is deployed). A standalone desktop release cut while the flag is false would ship with NO working in-app login. The existing CI test already prevents flipping the flag true without recorded evidence; this closes the other direction — add a publish-release gate to desktop-release.yml that FAILS the release if the flag is still false, so a desktop release cannot be published until #275 is live and the flag is flipped. The gate only runs on release tags / workflow_dispatch, so it doesn't affect normal branch CI; it activates exactly when the WebView removal would otherwise ship a login-less build.
desktop: open OS browser for login instead of embedded WebView (#1077)
…y restore readiness P0 — Seal point * Add `[snapshot] warmup_paths / stable_successes / stable_interval_ms / content_ready_path` to the capsule manifest's SnapshotConfig (additive — an empty `[snapshot]` parses byte-identically to v1) and thread them through `snapshot::RestoreContract` so they ride the sealed artifact to the runner. `effective_*` apply the v1 fallback (1 success / 250ms), so a manifest sealed before this change restores unchanged. * `FirecrackerBackend::build_ready_state` hits every `warmup_path` until it is stable for `stable_successes` rounds AFTER the healthcheck answers and BEFORE `Paused` + `CreateSnapshot`. The sealed memory therefore already carries template generation, JIT, DB init and First-Frame prep — the user's first request hits warm pages instead of redoing that work after resume. Skipped for the required-binding supervisor carve-out (its workload is stop+revoke'd before the seal, so warming it would be wasted I/O). * `boot_timeout` is the only budget for that wait. A shorter private round cap would fail the build on exactly the ~3s post-health first-screen work this feature exists to absorb; a broken path still fails closed, it just takes the full boot budget to prove it. * Recipe lane takes the recipe from `[snapshot]`; the import lanes (no capsule.toml — dockerfile / OCI / compose) from operator env (`ATO_SNAPSHOT_BUILDER_WARMUP_PATHS` / `_STABLE_SUCCESSES` / `_STABLE_INTERVAL_MS` / `_CONTENT_READY_PATH`). Both go through one `WarmupRecipe`, so every lane freezes the same fields by the same rule. * Probe paths are validated (origin-form, no spaces/control chars) wherever a recipe is built. A typo now fails with a pointed error instead of an opaque warmup timeout or a full boot-timeout restore hang, and a CR/LF can never be smuggled into the guest probe's request line. P2 — Restore readiness = user first-screen * `restore()` judges readiness with `content_ready_path || healthcheck || /`, not only `/health`, so a runner's "ready" means the actual first screen is serveable. Build-time warmup and restore-time readiness share ONE probe (`probe_ready` + nightly's `http_status_ready`), so a path cannot be accepted at build and then judged by a different rule at restore. P1 — UFFD lazy restore canary behind an operator flag * `ATO_RUNNER_UFFD_PREVIEW=1` opts a Connected Runner into UFFD demand-paging on `restore_snapshot` leases (the 512 MB eager rehydrate moves off the restore critical path; only faulted pages stream from CAS). Off by default. * The flag is gated on host capability (`userfaultfd(2)` usable + local CAS openable) and DEGRADES to the eager File path, printing why. Without the gate, opting in on a host that cannot serve page faults does not keep the File path — it fails every restore on that runner, which is not a canary. The env gate (`ATO_FC_UFFD`) stays ungated and hard-fails: a smoke that silently fell back to File would assert nothing. * Local `ato run` (`ATO_READY_STATE_UFFD_PREVIEW`) behaves as before. P3 — Content-ready metric on the RESTORE_PROF line * `RESTORE_PROF` carries `content_ready_ms`: how long after resume the user's first screen was serveable, so the PWA progress UI can interpolate p50 from real measurements rather than the proxy-only `proxy_ready_wait_ms`. It is the restore's own measurement, returned on `RestoreReceipt` — NOT a `snapshot::bench` span. `bench` is opt-in via `ATO_READY_STATE_BENCH=1`, which only the benchmark harness sets, so a bench-sourced metric would read `ungated` on every product runner and on every UFFD restore (the UFFD branch records no `restore.wait_health` span). `ungated` now means only what it says: a supervisor artifact, whose readiness is the agent probe, not a GET. Tests * Capsule SnapshotConfig parse / round-trip; probe-path validation. * Warmup loop against a local guest stand-in: no-paths is a no-op; N stable rounds are required and a 302 counts as ready; a slow path keeps retrying to the boot timeout (regression: a 10-round cap would fail the ~3s case this feature targets); a never-ready path fails the build; an invalid path is rejected before any guest dial. * WarmupRecipe carries `stable_*` only when warming (keeps the seal additive); `effective_stable_successes` clamps 0 → 1. * Snapshot RestoreContract warmup round-trip + content_ready_path_or chain; CLI `restore_contract_from_manifest` copies warmup fields.
…t a new one The first cut of the P1 gate hand-rolled a `userfaultfd(2)` syscall probe. That duplicated `crate::uffd::evaluate` — the pure, unit-tested rule this backend already reports as `BackendCapabilities::supports_uffd_mem_backend` — and was weaker: it checked only the kernel, missing the arch / KVM / Firecracker-version conditions `evaluate` covers. Gate on `self.probe()` instead. The preview flag can no longer disagree with what the runner advertises, and a refusal now carries `uffd_reason`, the exact string the probe already produces. U0 built that probe noting "no restore path uses it yet" — this is that path, so the note is updated rather than bypassed.
…oken invariant (ato#1077) (#1081) Finalizes the external-browser Desktop login test coverage on top of the #1078 core (already on nightly). Extracts two pure helpers from login_with_store_device_flow_desktop so the security-relevant properties are unit-testable from a single host build: - browser_open_command(os, url): per-OS launcher argv (macOS `open`, Linux `xdg-open`, Windows `cmd /C start "" <url>`) with the login URL always a single discrete argument, never spliced into a shell string. try_open_browser now dispatches on std::env::consts::OS through it; runtime behavior unchanged. - desktop_login_completed_event(handle, storage): the stdout success signal, guarded by a test asserting it can never carry a session/device token. Adds 8 tests: macOS/Linux/Windows argv, a shell-metacharacter URL kept as one argument on every OS, and completion-event shape / absent-handle / no-token. Ships inert: EXTERNAL_BROWSER_LOGIN_HARDENING_LANDED stays false, so the desktop login path still fails closed. The feature stays off until ato-api#275 is merged AND deployed to production and the flag is flipped with recorded evidence in the same commit (CI-enforced by hardening_flag_requires_recorded_evidence_when_enabled and the desktop-release.yml publish gate) — a later, human-gated step. PR_BODY.md documents the go-live sequence and the required human browser-open verification. Co-authored-by: koh0920 <koh0920@users.noreply.github.com>
feat(snapshot): warm first-screen before seal + content-ready restore readiness (P0/P1/P2/P3)
…isplay flag openbox has no --display option (it reads DISPLAY from the environment); the flag makes it exit 1 immediately, wait -n reaps it, and the whole fixture tears down before the health endpoint ever answers — the guest never becomes healthy. Found by the first live dockerfile_import build of the fixture; the static contract tests never execute the script. DISPLAY is already exported earlier in the script.
…mpfs The Ready-State guest mounts the rootfs read-only; mkdir -p /home/ato dies (set -e) before Xvfb ever starts. Found via the live KVM build's console diagnostics. /tmp is the guest's writable tmpfs — move HOME and XDG_RUNTIME_DIR there.
The Ready-State seal is a memory resume: whatever is (not) listening at seal time is (not) listening at restore. Gating /health on the mapped window alone let the seal race ahead of x11vnc binding 5900, so the restored guest refused the host pixel gateway's RFB connect. Require an accepted TCP connect to 127.0.0.1:5900 before reporting ready.
…store The Ready-State artifact is a memory snapshot; x11vnc's internal select() timers can trip on the seal->restore wall-clock jump and make it exit once right after resume. As a one-shot in the fatal wait set that tore the whole fixture down, so the restored guest refused the host pixel gateway's RFB connect. Run x11vnc under a restart supervisor and drop it from the fatal wait set — it rebinds 5900 within ~1s, so the gateway readiness retry connects on the restored session.
…veness The resumed x11vnc can come back WEDGED after a memory-snapshot restore: the process still exists — an exit-triggered supervisor never fires — but its RFB listener is gone and the host gateway's connect is refused (observed live: 8080 python survives the restore, 5900 refuses). Probe the actual service (TCP connect to the RFB port) once a second; on failure kill the leftover x11vnc and start a fresh one within the gateway readiness probe's retry window.
x11vnc comes back WEDGED from a memory-snapshot restore (process alive, RFB listener gone — observed live), so an exit-triggered supervisor never fires and the restored guest refuses the gateway's connect. Use TigerVNC's scraping server under a SERVICE-liveness watchdog (TCP-probe 5900 every second, kill + restart on a dead listener). -SecurityTypes None keeps the credential-free build contract; static tests updated to the TigerVNC markers.
ato-web was retired and /s/<id> was never carried into ato-pwa, so the web-upload/fetch share path (POST/GET /v1/shares, ato.run/s/<id> links) has no working destination. Keep local-file sharing (share.spec.json / share.lock.json) as the only mechanism. - Remove the hidden top-level encap/decap aliases entirely. - Drop EncapVisibility and the --internal/--private/--local flags; workspace share/setup are now the only names for the feature. - Delete upload_share/fetch_share_url/rewrite_api_to_site_url/ api_base_for_share_host and the ShareApiCreateRequest/ ShareRevisionPayload structs. - ato run <share-url> and ato workspace setup <share-url> no longer accept web share links; only local share files are valid inputs. - Update docs and tests accordingly.
The web share flow is gone, so the desktop share-URL path has no working destination. Remove is_share_url, resolve_and_start_from_share, share_tmp_dir, and the pending-share-terminal machinery (plus the corresponding navigate_to_url branches and tests). The ato:// deep-link scheme and all other verbs (run, app/<ipk>, open?handle=, cli, launch, runner/*, auth/callback/*) are untouched.
feat(authoring): execute and stream immutable build plans
Mirror the ato-api authoring asset contract (ato-api#459) on the Rust side: an authoring metadata asset is image/png, image/jpeg, image/webp or image/svg+xml, and SVG is only accepted when it survives the strict passive profile. inspect_svg_markup enforces: - well-formed single-root XML via roxmltree (rejects DTD/entities/ mismatched tags/multiple roots), with a fail-closed raw scan for CDATA, processing instructions and markup declarations - root <svg> in the w3.org SVG namespace - element allowlist (no script/foreignObject/style/a/iframe/animate*) judged by namespace + local name, so prefix aliasing cannot dodge it - url(...) fragment-only across all attributes; href/src fragment-only; javascript:/data:/file:/protocol-relative/backslash rejected; on* handlers and xml:base banned - dimensions from fixed width/height else viewBox, clamped to 16384 - element/depth/attribute count limits Binary types are magic-byte checked; pixels are not decoded.
A URL asset descriptor may carry the materialized identity fields (content_digest, artifact_ref, media_type) all together or not at all (ato-api#459), artifact_ref must be derived from content_digest, and media_type is restricted to the authoring allowlist (image/png, image/jpeg, image/webp, image/svg+xml). origin_url, when present, must be a credential-free HTTPS URL. Enforced in CapsuleManifestV1::validate, which every from_toml parse already runs.
Before an Execution Identity is minted, validate authoring metadata assets the manifest references by path: SVG bytes must survive the passive inspection profile and binary formats must match their magic signatures (ato-api#459 mirror). Missing files and unknown media types are refused, so a manifest can no longer mint over hostile or corrupt asset bytes.
A builder reporting materialized assets back to ato-api must first validate them against the authoring contract (ato-api#459 mirror): the bytes must match the declared media type (SVG through the passive profile, binaries by magic bytes) and content_digest must be the sha256 of the bytes. The gate is exported for the setup-detected/ready payload sites that currently report an empty materialized_assets list.
The builder now materializes the manifest's path-locator metadata assets from the workspace at setup-detected time, validates each against the authoring contract (SVG passive profile, binary magic bytes, sha256 content_digest), and reports them in the materialized_assets payload ato-api's ingestBuilderPathAssets expects. A missing, unreadable, unknown-type, or hostile asset is refused before setup is reported.
…d links Fixes the clean-env regression where `ato run <share.spec.json>` invoked the deleted `ato decap` subcommand via the capsule ShareExecutor. - capsule share executor: materialize via `ato workspace setup --into <dir> --dev` (--dev is required so captured install_steps run; the old hidden decap alias passed dev:true). Pin the subprocess to the running binary via current_exe from the CLI caller. - Add clean-ATO_HOME regression tests covering share.spec.json and share.lock.json inputs (install step runs, entry output), and a guard that decap is never invoked. - Retired web share links (`ato.run/s/<id>`, incl. staging/www spellings) now fail with actionable migration guidance in `ato run`, `ato workspace setup`, and the desktop omnibar/deep-link paths, instead of a generic error or an external-browser navigation. - Update active docs (root README, crates/cli README, both accepted ATO_CLI_SPEC copies, run.md, publishing guide, TESTING.md, demo runbook, ADR-005, security schema README, samples) and the manual suites (06-share-url rewritten for the local-file flow, 15-dogfooding, README) so removed encap/decap commands and share URLs are no longer presented as the current contract.
No user-facing behavior change — cleans up comments/strings that still referenced the deleted encap/decap aliases or the web share flow in dead desktop helpers and capsule doc comments.
Address review blockers/majors on PR #1248: - Blocker: url(...) targets must now begin with '#' (a same-document fragment). url(evil), url(data:image), url(javascript:evil) and mixed 'url(#safe) url(evil)' are rejected. ':' is dropped from the fragment NCName charset, matching the ato-api contract. - Major 1: validate_asset_bytes now enforces the 5 MiB bound (1..=5 MiB) shared with ato-api, and snapshot-builder checks file size via metadata() before reading a path asset. - Major 2: viewBox requires exactly four tokens and every token must parse; a 5-token '0 junk 0 100 100' is now refused instead of being silently filtered to four. - Major 3: materialized asset failures are reported at the 'metadata_assets' stage (setup_metadata_assets_failed) instead of 'detect'. Golden-vector tests mirror the ato-api cases.
… mismatch Blocker 1 — the ShareExecutor cached workspaces keyed on the raw input string (`./share.spec.json`), so two different projects run from different directories (or an edited file at the same path) could alias each other and execute the wrong code. The workspace dir is now derived from a SHA-256 content identity over the canonical spec+lock bytes plus a materialization-contract version, and a cached workspace is reused only when the stored identity matches AND sources are all ok AND verification.result == "ok" AND no install step failed. Blocker 2 — `ato run` executed a spec even when its digest did not match the lock. It now fails closed before any entry execution with an explicit "refusing to execute an unverified share" error. Also in this commit: - `ato run` pins the ato subprocess to current_exe fail-closed (no silent PATH fallback to a different binary version). - Regression tests now compute the real spec digest (share_run_local_e2e) and cover: digest-mismatch rejection (spec+lock inputs), cross-directory ./share.spec.json non-aliasing, same-path spec update freshness, install step + entry execution on a clean ATO_HOME, and the retired-link error. - cli-ci.yml now gates share_run_local_e2e, capsule share lib tests, the interactive capture e2e, and run_install_semantics, and triggers on crates/capsule/src/engine/share/** changes. - Desktop ato://open?handle=<retired share link> shows guidance without leaving an empty tab. - Manual suites: 06-share-url keeps its fixture for the whole suite (run/setup now PASS instead of SKIP); 04-group4 4c is now a local-file share roundtrip.
feat(ato): mirror authoring asset SVG contract from ato-api#459
Remove web-based encap/decap share flow (CLI + desktop)
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
Full sync of
nightlyintodev. Primary purpose: bring the web-share-flow removal (ato#1241— removeencap/decap+/v1/sharesweb upload/fetch, keep local-file sharing) forward toward release. Also carries the 180 other accumulated 0.7/0.8 commits onnightly(authoring builder, ready-state/snapshot, desktop auth, fix/feat line — see below).nightlywas 182 commits ahead ofdev(anddevhad 3 commits not onnightly: pocketllm-demo/openURL fix + retrigger + docs). The merge was clean — 0 conflicts; no manual resolutions required.Contents of the 182 nightly commits (by scope)
cli,capsule,snapshot,snapshot-builder,desktop,netd(authoring build-diagnostics, ready-state acceptance, v1 execution-contract, hardware-binding, native-inference, runner leases, desktop shell/Home, and more)Verification
git merge origin/nightlyinto a branch based onorigin/dev: 0 conflicts.d3695ade(ato#1241) is an ancestor of the merge head.cargo check -p cliat the merge head: clean (0 errors).rust-ci.yml+cli-ci.yml+ the contract/architecture gates ondev) is the authoritative gate for this PR — please let it run before merging.This is a mechanical branch sync; the individual feature PRs were each reviewed on
nightlybefore landing there.