main ece7682

run.sh RawHistoryFolder

1#!/usr/bin/env bash
2# Disposable navigation acceptance with the real client, daemons and UI driver.
3set -euo pipefail
4case "${1:-}" in
5  -h|--help) printf 'Usage: scripts/remote-picker-harness/run.sh\nRequires Docker, Python 3 and ssh-keygen.\nSet VEV_ACCEPTANCE_ARTIFACTS_DIR to keep logs elsewhere than /tmp.\nSet VEV_ACCEPTANCE_SCENARIOS to a space-separated subset, e.g.\n  VEV_ACCEPTANCE_SCENARIOS="warm-reuse@quic warm-reuse@stdio"\nNames: navigation-repro local-palette-cycle direct-remote-named@quic|@stdio\n  warm-reuse@quic|@stdio hybrid-exact-return@quic|@stdio\n  client-picker-navigate-local@quic client-picker-navigate-direct@quic|@stdio\n'; exit 0 ;;
6  '') ;;
7  *) exit 2 ;;
8esac
9repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
10for tool in docker python3 ssh-keygen; do command -v "$tool" >/dev/null; done
11docker info >/dev/null
12run_id="$(date +%s)-$$"
13image="vev-acceptance:${run_id}"
14network="vev-acceptance-${run_id}"
15local_container="${network}-local"
16remote_container="${network}-remote"
17context_dir="$(mktemp -d)"
18# Sanitized, per-run evidence outside the worktree. Container state logs carry
19# structured vev events only: no host state, credentials, sockets or keys.
20artifacts_dir="${VEV_ACCEPTANCE_ARTIFACTS_DIR:-$(mktemp -d "/tmp/vev-acceptance-artifacts-${run_id}.XXXXXX")}"
21export VEV_ACCEPTANCE_ARTIFACTS_DIR="$artifacts_dir"
22
23collect_artifacts() {
24  mkdir -p "$artifacts_dir"
25  for role in local remote; do
26    container="${network}-${role}"
27    for file in vev-daemon.log vev-client.log vev-stdio.log \
28                vev-daemon-crash.log vev-client-crash.log vev-stdio-crash.log; do
29      docker cp "$container:/home/demo/.local/state/vev/$file" \
30        "$artifacts_dir/${role}-${file}" >/dev/null 2>&1 || true
31    done
32    docker cp "$container:/home/demo/.local/state/vev/broker/log/vev-daemon.log" \
33      "$artifacts_dir/${role}-vev-broker.log" >/dev/null 2>&1 || true
34  done
35}
36
37cleanup() {
38  status=$?
39  trap - EXIT INT TERM
40  set +e
41  collect_artifacts
42  if [ "$status" -ne 0 ]; then
43    for file in "$artifacts_dir"/*.log; do
44      [ -f "$file" ] || continue
45      printf '===== %s =====\n' "$file" >&2
46      tail -n 60 "$file" >&2
47    done
48  fi
49  docker rm -f "$local_container" "$remote_container" >/dev/null 2>&1
50  docker network rm "$network" >/dev/null 2>&1
51  docker image rm "$image" >/dev/null 2>&1
52  rm -rf "$context_dir"
53  printf 'acceptance artifacts: %s\n' "$artifacts_dir"
54  exit "$status"
55}
56trap cleanup EXIT
57trap 'exit 130' INT
58trap 'exit 143' TERM
59
60docker build -f "$repo_root/scripts/demo/Dockerfile" -t "$image" "$repo_root" >/dev/null
61docker network create "$network" >/dev/null
62# Client and daemon debug logging is enabled container-wide; docker exec and
63# the daemon child both inherit it. Remote proxy children receive it through
64# ssh SendEnv/AcceptEnv below.
65for role in local remote; do
66  docker run -d --name "${network}-${role}" --network "$network" \
67    --network-alias "$role" -e VEV_LOG=debug \
68    --entrypoint sleep "$image" infinity >/dev/null
69done
70
71# Only generated fixture credentials enter these containers; no host HOME or
72# sockets are mounted. Pin the fresh remote key instead of trusting keyscan.
73ssh-keygen -q -t ed25519 -N '' -C acceptance-client -f "$context_dir/client"
74ssh-keygen -q -t ed25519 -N '' -C acceptance-host -f "$context_dir/host"
75docker exec --user root "$remote_container" sh -c 'rm -f /etc/ssh/ssh_host_* /home/demo/.ssh/id_ed25519*; mkdir -p /run/sshd'
76docker cp "$context_dir/host" "$remote_container:/etc/ssh/ssh_host_ed25519_key"
77docker cp "$context_dir/host.pub" "$remote_container:/etc/ssh/ssh_host_ed25519_key.pub"
78docker cp "$context_dir/client.pub" "$remote_container:/home/demo/.ssh/authorized_keys"
79# Accept the debug level the client forwards so remote _broker-mux-stdio/_broker-mux-quic-proxy and
80# the daemon they spawn log at debug too.
81docker exec --user root "$remote_container" sh -c 'printf "\nAcceptEnv VEV_LOG\n" >> /etc/ssh/sshd_config; chmod 600 /etc/ssh/ssh_host_ed25519_key /home/demo/.ssh/authorized_keys; chown demo:demo /home/demo/.ssh/authorized_keys; /usr/sbin/sshd'
82docker cp "$context_dir/client" "$local_container:/home/demo/.ssh/id_ed25519"
83docker cp "$context_dir/client.pub" "$local_container:/home/demo/.ssh/id_ed25519.pub"
84{ printf 'remote '; cut -d' ' -f1-2 "$context_dir/host.pub"; } > "$context_dir/known_hosts"
85docker cp "$context_dir/known_hosts" "$local_container:/home/demo/.ssh/known_hosts"
86docker exec --user root "$local_container" sh -c 'chown demo:demo /home/demo/.ssh/id_ed25519* /home/demo/.ssh/known_hosts; chmod 600 /home/demo/.ssh/id_ed25519 /home/demo/.ssh/known_hosts'
87# Forward VEV_LOG on every remote SSH child (global option before the first
88# Host block); the fixture ssh config itself is otherwise untouched.
89docker exec "$local_container" sh -c 'p="$HOME/.ssh/config"; { printf "SendEnv VEV_LOG\n"; cat "$p"; } > "$p.new" && mv "$p.new" "$p" && chmod 600 "$p"'
90docker exec "$local_container" ssh -o BatchMode=yes -o ConnectTimeout=5 remote true
91docker exec "$local_container" vev host add remote
92# Baseline matrix: local IPC, direct named-remote (QUIC + explicit stdio, no
93# local daemon), warm remote reuse (QUIC + stdio), and hybrid exact-return
94# (QUIC + stdio). Each scenario asserts committed outcomes, not sent keys.
95# navigation_repro.py keeps the original hybrid transport regression.
96acceptance_py="$repo_root/scripts/remote-picker-harness/acceptance.py"
97scenarios_env="${VEV_ACCEPTANCE_SCENARIOS:-}"
98known_scenarios="navigation-repro local-palette-cycle direct-remote-named@quic direct-remote-named@stdio warm-reuse@quic warm-reuse@stdio hybrid-exact-return@quic hybrid-exact-return@stdio client-picker-navigate-local@quic client-picker-navigate-direct@quic client-picker-navigate-direct@stdio"
99for requested in $scenarios_env; do
100  case " $known_scenarios " in
101    *" $requested "*) ;;
102    *) printf 'unknown acceptance scenario: %s\n' "$requested" >&2; exit 2 ;;
103  esac
104done
105if [ -n "$scenarios_env" ] && [ -z "${scenarios_env//[[:space:]]/}" ]; then
106  printf 'VEV_ACCEPTANCE_SCENARIOS selects no scenarios\n' >&2
107  exit 2
108fi
109wanted_scenario() {
110  [ -z "$scenarios_env" ] && return 0
111  for want in $scenarios_env; do [ "$want" = "$1" ] && return 0; done
112  return 1
113}
114run_scenario() { # name spec [topology]
115  wanted_scenario "$1" || return 0
116  if [ -n "${3:-}" ]; then
117    VEV_ACCEPTANCE_TOPOLOGY="$3" python3 "$acceptance_py" "$local_container" "$remote_container" "$2"
118  else
119    python3 "$acceptance_py" "$local_container" "$remote_container" "$2"
120  fi
121}
122if wanted_scenario navigation-repro; then
123  python3 "$repo_root/scripts/remote-picker-harness/navigation_repro.py" "$local_container" "$remote_container"
124fi
125run_scenario local-palette-cycle local-palette-cycle
126run_scenario direct-remote-named@quic direct-remote-named@quic
127run_scenario direct-remote-named@stdio direct-remote-named@stdio
128run_scenario warm-reuse@quic warm-reuse@quic
129run_scenario warm-reuse@stdio warm-reuse@stdio
130run_scenario hybrid-exact-return@quic hybrid-exact-return@quic
131run_scenario hybrid-exact-return@stdio hybrid-exact-return@stdio
132# Client-owned navigation picker where the serving attachment answers the
133# palette session-picker command itself: local IPC and direct remote (QUIC and
134# explicit stdio). A hybrid client advertises the home-picker capability, so
135# its session-picker command delegates to the home route overlay (an R1
136# behavior pinned by hybrid-exact-return) instead of this interaction.
137run_scenario client-picker-navigate-local@quic client-picker-navigate@quic local
138run_scenario client-picker-navigate-direct@quic client-picker-navigate@quic direct
139run_scenario client-picker-navigate-direct@stdio client-picker-navigate@stdio direct

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 12

Tags 11

↑↓ moveenter openesc close