. "$BST_LIB" # 79-libssh2.test — libssh2 1.11.1 (poky recipes-support/libssh2), the client-side # C library implementing the SSH2 protocol, on wasm32-hwjs. Closed on the # package's own upstream test suite, which oe-core packages as a ptest. # # Numbered into the 79 slot beside 79-libgcrypt and 79-libksba, this tree's # grouping for the crypto-adjacent libraries. libssh2 sits on top of openssl here # (the recipe's PACKAGECONFIG default, and the backend this image already carries) # and adds the SSH2 transport, key exchange, userauth, channel and SFTP layers # above it. # # WHAT THE GATE IS, AND WHAT IT IS NOT. Upstream's run-ptest drives exactly three # cases, and only one of them executes libssh2 code: # # test_simple — a standalone C program: libssh2_init(LIBSSH2_INIT_NO_CRYPTO), # libssh2_session_init(), the internal base64 decoder over a # known vector, libssh2_session_free(), libssh2_exit(). No # network, no server, no crypto backend. This is the real # assertion, and it is the one that has to be green. # mansyntax.sh — runs `man --warnings` over the 186 installed manual pages. # THIS IMAGE HAS NO man, so the script takes its own documented # skip branch and exits 0. It is a VACUOUS PASS and is pinned # as such below: the case asserts the CAUSE (no man) rather than # the verdict, so the day man-db lands on this image the pin # goes red and someone re-reads a pass that had been free. # test_sshd.test — starts a local sshd on port 4711 and runs two client tests # against it. EXPECTED RED, and attributed, not hidden: see the # sshd block below for the three independent reasons. # # The remaining 22 test programs upstream ships are its DOCKER_TESTS: they need a # containerised OpenSSH server and are not part of run-ptest on any architecture. # Nothing was added to the suite and nothing was taken away. ptestdir=/usr/lib/libssh2/ptest t=$ptestdir/tests # ------------------------------------------------------------- packaging --- # `test` is an ash builtin, so check_rc with it forks nothing — which matters on # an arm where every exec is a fresh wasm module instantiation. check_rc libssh2/lib 0 test -f /usr/lib/libssh2.a check_rc libssh2/header 0 test -f /usr/include/libssh2.h check_rc libssh2/header-sftp 0 test -f /usr/include/libssh2_sftp.h check_rc libssh2/header-publickey 0 test -f /usr/include/libssh2_publickey.h check_rc libssh2/pkgconfig 0 test -f /usr/lib/pkgconfig/libssh2.pc # Static-only is distro policy (conf/distro/brintos.conf). Pinned as a positive: # a shared object appearing here would mean the policy stopped reaching this # recipe, and that the archive above may no longer be what the ptest binaries # were linked against. if [ -e /usr/lib/libssh2.so ] || [ -e /usr/lib/libssh2.so.1 ]; then bst_notok libssh2/static-only "a shared libssh2 shipped on a static-only distro" else bst_ok libssh2/static-only fi # The version the headers declare, read from the header rather than from a # recipe variable, so a bbappend that silently pinned an older tarball shows up. check_out libssh2/version '"1.11.1"' grep -w LIBSSH2_VERSION /usr/include/libssh2.h # --------------------------------------------------------- ptest payload --- check_rc libssh2/ptest-runptest 0 test -x "$ptestdir/run-ptest" check_rc libssh2/ptest-driver 0 test -x "$ptestdir/test-driver" check_rc libssh2/ptest-testdir 0 test -d "$t" check_rc libssh2/ptest-simple 0 test -x "$t/test_simple" check_rc libssh2/ptest-mansyntax 0 test -x "$t/mansyntax.sh" check_rc libssh2/ptest-sshd-script 0 test -x "$t/test_sshd.test" check_rc libssh2/ptest-keys 0 test -f "$t/key_rsa" check_rc libssh2/ptest-fixtures 0 test -d "$t/openssh_server" # THIS LAYER'S run-ptest, NOT poky's. Poky's writes automake's per-case .log and # .trs into the installed ptest directory, which is read-only here (virtio-fs), # and test-driver runs the program with its output redirected into that log — so # a log it cannot create means the program never runs and ALL THREE cases report # FAIL for a filesystem reason. Anchored on the writable-scratch line rather than # on a string anywhere in the file, because our copy necessarily quotes upstream's # bad form in its own comment. A rebase that quietly restores poky's copy is then # one red here instead of three unexplained reds in the suite. if grep -qE '^d=\$\{TMPDIR:-/tmp\}/libssh2-ptest' "$ptestdir/run-ptest" 2>/dev/null; then bst_ok libssh2/ptest-runptest-scratch else bst_notok libssh2/ptest-runptest-scratch "run-ptest writes its .log/.trs into the read-only ptest dir; every case reports FAIL for that alone" fi # ------------------------------------------------ the library, on its own --- # test_simple driven directly, ahead of the harness, so that a green here and a # red under run-ptest separates "libssh2 is broken" from "the harness is". check_rc libssh2/simple-direct 0 "$t/test_simple" # ---------------------------------------- the two cases that cannot assert --- # mansyntax.sh's skip branch, pinned by its CAUSE. The script's own guard is # `man --help 2>/dev/null | grep -q warnings`; with no man on the image that is # false and it prints its skip line and exits 0. A pass here is therefore worth # nothing about the manual pages, and this pair is what says so out loud. if command -v man >/dev/null 2>&1; then bst_notok libssh2/mansyntax-vacuous "man is now on this image, so mansyntax.sh no longer takes its skip branch — its pass has become meaningful and the port's docs coverage should be re-read" else bst_ok libssh2/mansyntax-vacuous fi check_out libssh2/mansyntax-skip 'Required tool not found' sh "$t/mansyntax.sh" # The 186 manual pages the vacuous case above cannot check. Counted, so that a # packaging change that drops the docs tree is still visible from here. nman=0 for f in "$ptestdir"/docs/libssh2_*.3; do [ -f "$f" ] && nman=$((nman+1)) done if [ "$nman" -ge 186 ]; then bst_ok libssh2/docs-installed else bst_notok libssh2/docs-installed "only $nman libssh2_*.3 pages under $ptestdir/docs, expected at least 186"; fi # ------------------------------------------- test_sshd.test, read honestly --- # EVERY CLAIM IN THIS BLOCK IS MEASURED ON TARGET. The first version of it was # written from the image recipe's stated intent and the recipe was wrong, so the # rule here is that nothing is asserted from metadata that can be observed from # the running image instead. # # THIS IMAGE DOES CARRY A SERVER. EMCRAFT_TOOLS names `openssh`, and poky's # `openssh` is an umbrella package whose Depends are # "openssh-keygen, openssh-scp, openssh-sftp-server, openssh-ssh, openssh-sshd" -- # so asking for the client drags the server in, and /usr/sbin/sshd (40 MB, # OpenSSH_9.6p1) is on the rootfs whatever the image recipe's comment says. Pinned # as a positive: if the server ever leaves the image, the two cases below stop # meaning what they say and someone has to re-read them. if [ -x /usr/sbin/sshd ]; then bst_ok libssh2/sshd-present else bst_notok libssh2/sshd-present "no /usr/sbin/sshd on this image any more -- the openssh umbrella package stopped pulling openssh-sshd in, and the test_sshd.test attribution below needs re-reading" fi # WHY IT STILL CANNOT SERVE. Measured, in the order a reader hits them: # # 1. sshd exits before it forks a session: "Missing privilege separation # directory: /var/run/sshd". /var/run is a symlink to /run, /run is empty on # the rootfs, and nothing under the verify boot creates it -- the guest is # entered at /bin/sh, so /etc/init.d never runs. On a machine booted through # init this particular wall may not be the first one. # 2. Behind it, privilege separation cannot work on this arm at all: sshd's # unprivileged child is a setuid drop and this syscall table wires no # credential setter (setuid/setgid/setgroups are -ENOSYS, # brintos/linux#19) -- the same wall quilt's ptest hit at `su`. # 3. The script's own client cannot even be exec'd: "/usr/bin/ssh: Cannot # allocate memory" for a 40 MB static binary, every exec here being a fresh # wasm module instantiation. # # None of the three is libssh2's, and none is this port's to fix. # ------------------------------------------------- upstream's own test suite --- # THE GATE. ptest-runner is the harness the ticket closes on; where it cannot be # reached the ticket says to drive run-ptest directly, which is what the else arm # does — the same three cases either way. -t is set well past ptest-runner's 300 s # DEFAULT_TIMEOUT and bounds nothing in practice (relative timers do not fire, # linux-in-the-browser#120), so a tight value would assert nothing. if [ -x /usr/bin/ptest-runner ]; then out=$(/usr/bin/ptest-runner -t 4000 libssh2 2>&1) harness=ptest-runner else out=$(cd "$ptestdir" && ./run-ptest 2>&1) harness=run-ptest fi # Per-case verdicts off the PASS:/FAIL: protocol, one BST case each. Reported # separately from the harness framing below because the two fail differently: a # case the driver never reached shows up here, a harness that never ran shows up # there. case "$out" in *"PASS: test_simple"*) bst_ok libssh2/suite-simple ;; *"FAIL: test_simple"*) bst_notok libssh2/suite-simple "upstream's test_simple failed on target under $harness" ;; *) bst_notok libssh2/suite-simple "test_simple not reported at all by $harness" ;; esac case "$out" in *"PASS: mansyntax.sh"*) bst_ok libssh2/suite-mansyntax ;; *"FAIL: mansyntax.sh"*) bst_notok libssh2/suite-mansyntax "mansyntax.sh failed rather than taking its no-man skip branch under $harness" ;; *) bst_notok libssh2/suite-mansyntax "mansyntax.sh not reported at all by $harness" ;; esac # ------------------------- test_sshd.test: THE HARNESS VERDICT IS NOT EVIDENCE --- # The harness reports PASS: test_sshd.test on this image, and it is worth nothing. # Measured on target, running the script on its own: # # 1..2 # not ok 1 - sshd-test_ssh2 # not ok 2 - sshd-test_auth_pubkey_ok_ed25519 # rc=0 # # Both of its tests failed and it exited 0, so test-driver -- which reads the exit # status and nothing else -- calls the case a pass. THE CAUSE IS UPSTREAM'S OWN # SCRIPT, not the packaging and not this arm. Its last three lines are # # [ "${via_args}" = '1' ] && [ "${total}" != '1' ] && ec="${anyerror}" # exit "${ec}" # # and `via_args` is 1 only when the test names came in as command-line arguments. # run-ptest and automake both invoke it with none -- it reads its list from # tests/Makefile.inc instead -- so `ec` keeps its initial 0 and every TAP failure # is swallowed. That is architecture-independent: any oe-core ptest run of this # recipe reports a green test_sshd.test even where the SSHD tests genuinely fail. # # This is the SECOND vacuous green in the same case. The first was oe-core's # packaging (no Makefile.inc installed -> "1..0" -> nothing ran); fixing it made # the script run its two tests and report them, and revealed that upstream throws # the result away. So the suite reads the TAP and ignores the verdict. sshd_out=$(cd "$t" && ./test_sshd.test 2>&1) sshd_rc=$? # The packaging half, still pinned: a plan of 2 means Makefile.inc was installed # and the script learned its SSHD_TESTS. "1..0" is the vacuous form returning. case "$sshd_out" in *"1..2"*) bst_ok libssh2/sshd-plan ;; *"1..0"*) bst_notok libssh2/sshd-plan "test_sshd.test ran ZERO tests — tests/Makefile.inc is not installed, so the case is vacuous again" ;; *) bst_notok libssh2/sshd-plan "test_sshd.test emitted no TAP plan at all" ;; esac # The upstream defect itself, pinned by its symptom: failures reported, status 0. # ok while it is present; red the day upstream propagates the status, because then # the harness verdict becomes meaningful and should replace this whole block. case "$sshd_out" in *"not ok"*) if [ "$sshd_rc" -eq 0 ]; then bst_ok libssh2/sshd-exit-status-swallowed else bst_notok libssh2/sshd-exit-status-swallowed "upstream's test_sshd.test now exits $sshd_rc when its tests fail — it no longer swallows the status, so PASS:/FAIL: from the harness is evidence again and this block should be replaced by it" fi ;; *) bst_skip libssh2/sshd-exit-status-swallowed "no failing test to observe the exit status through" ;; esac # The two SSHD tests themselves. Skips, not reds: the server they need cannot run # here for three reasons, all named above and none of them libssh2's. "not ok" # is matched before "ok" because the first contains the second. for n in "1 sshd-test_ssh2" "2 sshd-test_auth_pubkey_ok_ed25519"; do i=${n%% *}; nm=${n#* } case "$sshd_out" in *"not ok $i - $nm"*) bst_skip "libssh2/$nm" "no usable sshd at run time (no /run/sshd, setuid -ENOSYS, and /usr/bin/ssh cannot be exec'd) — upstream's client-side assertion never got a server to talk to" ;; *"ok $i - $nm"*) bst_ok "libssh2/$nm" ;; *) bst_notok "libssh2/$nm" "test_sshd.test reported no verdict for $nm" ;; esac done # And the harness's own claim about this case, recorded so the contradiction is # visible in one report rather than inferred across two. case "$out" in *"PASS: test_sshd.test"*) bst_ok libssh2/suite-sshd-verdict-vacuous ;; *"FAIL: test_sshd.test"*) bst_notok libssh2/suite-sshd-verdict-vacuous "the harness now reports FAIL: test_sshd.test — upstream's swallowed exit status has changed and this pin is stale" ;; *) bst_notok libssh2/suite-sshd-verdict-vacuous "test_sshd.test not reported at all by $harness" ;; esac