rowan.id.au— Piers Rowan

HomePiROS › UAT.md

PiROS — User Acceptance Tests

Manual acceptance steps for the programs and the admin list builder. Each case lists Do and Expect. Type at the serial console; under emulation, wait a few seconds for the login: prompt.

Setup

./build.sh                      # build + boot (or ./build.sh --build then boot manually)

Users: root/rootpw, bob/bobpw, mary/marypw. To start from a clean slate, rm dist/data.img before building (wipes all persistent /data and installed programs).


A. Core tools (as bob)

#DoExpect
A1bob bobpwwelcome, bob.
A2echo hello world > files/greeting then cat files/greetinghello world
A3ls fileslist includes greeting
A4grep hello files/greetinghello world
A5cp files/greeting files/copy then ls filescopy present
A6rm files/copy then ls filescopy gone
A7cat files/nopecat: not found

B. Editor (prano)

#DoExpect
B1prano files/notefull-screen editor with status bar
B2type a line, press ^Ostatus shows [saved]
B3press ^X, then cat files/noteyour text

C. Scripting (psh)

#DoExpect
C1prano files/demo.psh, enter the script below, ^O ^Xsaved
C2psh files/demo.psh15 then hello psh
$a = 5; $b = 10;
echo $a + $b; echo "\n";
$who = "psh";
echo "hello $who\n";

D. Publishing (cross-user)

#DoExpect
D1mary marypw, echo lunch at 1 > files/memo, publish files/memo bobpublished memo to bob
D2logout, bob bobpw, argo mary:memoconsumed -> files/memo (argo = inter-user consume-published fetch)
D3cat files/memolunch at 1
D4argo --list mary (still bob)lists memo — what mary has shared with bob
D5logout, root rootpw, argo mary:memoargo: not found or access denied (root not in the audience)
D6argo --list mary (still root)(nothing shared with you) (root not in the audience)

E. Admin — managing permission lists (as root)

The admin toolkit manages lists (e.g. which programs a group may use, or which users are in a group). Today the lists are stored per-user data; wiring a saved list into actual kernel grants is the next step, so this validates the management workflow.

list_build keys: ↑/↓ or k/j move · Space toggle · EnterSave? [Y/N] · Y save · X cancel.

#DoExpect
E1root rootpwwelcome, root.
E2admin list_build editors echo,cat,grep,prano,pshcheckbox list, all [ ]
E3Space on echo, ↓ to prano, Space, ↓ to psh, Spaceecho, prano, psh show [ * ]
E4Enter, then Ysaved tmp/sel.editors
E5admin list_save editorssaved files/list.editors
E6admin list_get editorsecho,prano,psh
E7admin list_get editors > files/editors.txt then cat files/editors.txtecho,prano,psh (redirect composes)
E8admin list_build editors echo,cat,grep,prano,psh echo,prano,pshreopens pre-checked with echo/prano/psh selected
E9In E8: deselect psh (Space on it), Enter, Y, then admin list_save editors, admin list_get editorsecho,prano
E10Build a user group: admin list_build wheel root,bob,mary root,bob, save, admin list_save wheel, admin list_get wheelroot,bob
E11Cancel path: admin list_build test a,b,c, toggle one, press Xlist_build: cancelled (exit 1; nothing saved)

F. Access control & isolation

#DoExpect
F1su bob bobpw, then admin list_get editors[DENIED] no grant for service 'admin' (admin is root-only)
F2as bob, ls filesbob's own files only — not root's list.editors (per-user isolation)
F3iambad (as bob)[DENIED] no grant for tool 'iambad'
F4iamgood iambad (as bob)Yes bob, you are good! (reachable via the service)

G. Persistence

#DoExpect
G1quit, then boot again (same dist/data.img)
G2root rootpw, admin list_get editorsecho,prano (survived reboot)
G3bob bobpw, ls filesfiles from earlier sessions still present

H. Shell & scripting extras

#DoExpect
H1bob bobpw, echo one > files/m, echo two >> files/m, cat files/mone then two (append)
H2echo <h1>Hi</h1> > files/pg.html then cat files/pg.html<h1>Hi</h1> (the > inside </h1> is not a redirect)
H3ls -vone row per file: SIZE OWNER NAME
H4type ec then Tabcompletes to echo
H5type cat fn then Tab (after any fn… file exists)completes the filename
H6author files/f.psh (with prano): function dbl($n){ return $n*2; } echo dbl(21); then psh files/f.psh42
H7author files/lib.psh: function sq($x){ return $x*$x; }; author files/use.psh: include "files/lib.psh"; echo sq(6);; then psh files/use.psh36

I. Directories & the shared /mnt volume

#DoExpect
I1bob bobpw, mkdir files/proj, cd files/proj, pwdfiles/proj
I2echo hi > note, ls, cd ..note listed; back at files
I3mv files/proj/note files/moved, ls filesmoved present
I4ls mnt, cat mnt/README.mdthe shared read-only volume (built from host mnt/)
I5echo x > mnt/y[DENIED] user-directed writes may only target files/ (mnt is read-only)

J. Networking & CLI tools (as bob)

(Outbound needs QEMU's user-net, which ./build.sh sets up.)

#DoExpect
J1ping 8.8.8.8replies with round-trip times
J2nslookup example.comexample.com -> <ip>
J3host example.comresolves to an IP
J4http example.com (or curl example.com)HTTP status + page bytes
J5echo hi > files/a, zip files/a.zip files/a, ls filesa.zip present (store-only zip)
J6unzip files/a.zipextracts a
J7wget http://example.com/, then ls filessaved -> files/<name> (wget = HTTP downloader, saves into files/; curl prints instead)

K. Runtime administration (as root)

Root mints users/grants live, signed by the box's machine key. New identities activate on the next boot (the record is written immediately).

#DoExpect
K1root rootpw, admin user create dave davepwcreated user 'dave'…
K2admin grant dave core clustergranted 'core' to 'dave'…
K3admin user create dave x (again)admin: user 'dave' already exists
K4bob bobpw, admin user create evil evilpw[DENIED] admin: root only
K5quit, reboot, dave davepw, whoami, ls, echo hi > files/n, cat files/ndave; his own encrypted /data works

L. Services — background daemons (as root) ⭐

Services are root-managed background processes. sshd is a privileged kernel-hosted service (it runs each session's shell as the authenticated user); tintin (HTTP), nemo (FTP), queequeg (SQL) are sandboxed ring-3 processes running as their own no-login service user. Only root can start/stop them; the console stays usable while they run.

SSH service (reach it from another Mac terminal; ./build.sh forwards host :2222): | # | Do | Expect | |---|----|--------| | L1 | root rootpw, admin service start sshd | started service 'sshd' (task 1) + sshd: listening on :2222 | | L2 | ps | rows for console and a kernel task (sshd); sockets 1/8 | | L3 | echo still-here (at the console, while sshd runs) | prints — console is not blocked | | L4 | from a Mac terminal: ssh -p 2222 bob@localhost (password bobpw), then whoami, exit | bob; the remote shell runs as bob | | L4a | leave L4's bob session open; from a second Mac terminal ssh -p 2222 mary@localhost (marypw), then whoami | mary — the second session connects immediately (no head-of-line wait); both are live at once | | L4b | run a command in each session at once (bob ls files, mary whoami); at the console ps | both shells respond concurrently; ps shows one worker task per live SSH session (per-connection workers, capped at MAX_TASKS = 8) | | L5 | admin service list | sshd (running) [kernel-hosted] | | L6 | admin service stop sshd, then ps | sshd gone from ps |

HTTP service (tintin) — a sandboxed ring-3 service. First create + provision it: | # | Do | Expect | |---|----|--------| | L7 | admin service create tintin, then quit and reboot | created service 'tintin'… (activates after reboot) | | L8 | root rootpw, mkdir services/tintin/files/default, mkdir services/tintin/files/default/www | root manages the service's own store | | L9 | echo hello-web > files/idx, cp files/idx services/tintin/files/default/www/index.html | seeds the web root in tintin's store | | L10 | admin service start tintin, ps | a process row, user tintin | | L11 | from a Mac terminal (forward host :80 → guest :80, or run tintin on a forwarded port): curl http://localhost:8080/ | hello-web with Server: tintin | | L12 | su bob bobpw, cat services/tintin/files/default/www/index.html | denied (services/ is root-only) |

(nemo/queequeg follow the same pattern: admin service create <name> → reboot → admin service start <name>. FTP passive data + SQL need their ports forwarded; the control/query channels work over one forward.)

L. Real-hardware regression: ring-3 services bind + console doesn't drop SSH ⭐ RELEASE-ONLY

Run these on real hardware / the cloud VM (KVM), NOT under QEMU-TCG. This class of bug is invisible under TCG: it was a preemption-timer livelock that only triggers when the LAPIC uses TSC-deadline mode (real HW). Fixed in fix/tsc-deadline-preempt-livelock (LAPIC initial-count). These steps confirm the fix held on the actual silicon.

#DoExpect (PASS)Regression (the bug is back)
L13Boot; at the console after login: `syslog \grep apic` (or watch boot)apic: preemption timer = LAPIC one-shot count… = LAPIC TSC-deadline → the fix is not in this image
L14admin service start tintin, then watch the console for ~3 stintin prints starting → config loaded → web root ready → logs ready, binding port → listeningonly started service 'tintin' … (task N) and then silence (no tintin: starting)
L15ps right aftera process row for tintin, and timer ticks are small/normaltintin row stuck ready; timer ticks climbing into the thousands with no progress = livelock
L16netstat (or ports)rows for both :2222 LISTEN (charon) and :80 LISTEN (tintin)only :2222; no :80
L17From your workstation (VM firewall port 80 open): curl http://<vm-ip>/HTTP 200 + the tintin site HTMLERR_CONNECTION_TIMED_OUT / connection refused
L18Open an SSH session to :2222 and leave it live; at the console run a few commands / a longer tool; then in the SSH session run echo still-aliveSSH session stays up and responds; console stays usableSSH session closes / hangs while the console is in use (the secondary symptom)
L19Over SSH, run netstat (and ports, syslog)prints the socket/log table and returns; box stays responsive (echo ok after)box freezes on the command (the diagnostic lock-across-send deadlock)

If L18 regresses even when L14–L17 pass, it is the separate NIC-polling gap (the NIC is polled only from inside accept/recv/send — no idle poller), not the timer bug; capture it and hand back to Dell.

M. Diagnostics — watching resources & crashes (as root)

#DoExpect
M1pstasks + resources: N RAM frames free, sockets X/8
M2freememory summary
M3syslogevent log: spawns, service starts, RES snapshots (oldest first)
M4start/stop a couple of services, then syslogwatch ram=… frames free change — evidence of resource use over time
M5if a service dies, sysloga FAULT: line + an at-fault resource snapshot pinpoints what happened

Notes