Skip to content

ctest reports zero skips: delete the Docker-based SSH integration test, bind term_mapping to product code (vms-97d) - #9

Merged
baron-3dl merged 2 commits into
mainfrom
work/vms-97d
Jul 30, 2026
Merged

baron-3dl merged 2 commits into
mainfrom
work/vms-97d

Conversation

@baron-3dl

Copy link
Copy Markdown
Contributor

Closes the phantom-skip defect in vms-97d, first item of the vms-14f swarm to clear veracity.

What changed

  • Deleted tests/vmsssh/test_vmsssh.sh (it ran docker info, built the ROOT Dockerfile and SSHed into the container — i.e. it tested the dead Docker runtime, forbidden as a runtime by Rule 9) and its vmsssh_integration registration, plus test_ssh_client.c which was only that script's harness.
  • Kept and fixed test_term_mapping. It was a copy of map_term_to_vms_device_type() pasted into the test file — nothing bound the two, so any edit to vmssshd.c would have left it green. The function is now extracted to src/vmsssh/term_map.{c,h} and both the product daemon and the test use it.
  • Removed the dead libssh gating.

Verification

  • ctest with libssh headers present (the configuration that previously skipped): 39/39 passed, 0 failed, 0 skipped. Baseline was 40 tests / 1 skip; the delta is exactly the removed vmsssh_integration.
  • Independently reproduced by an adversarial reviewer from a clean git archive.

Notes

src/vmsssh/vmssshd.c is retained — only the Docker-runtime test surface was removed. Un-oracled VMS device-type assertions (VT100/VT400, and the xterm→VT inference, which has no OpenVMS analogue) were not promoted into CI; real terminal device types are owned by vms-d0b.

🤖 Generated with Claude Code

baron-3dl and others added 2 commits July 30, 2026 08:13
The Docker-based SSH integration test (test_vmsssh.sh, vmsssh_integration
ctest target, test_ssh_client.c) tested only the dead Docker runtime
(CLAUDE.md Rule 9) for a server ruled a show horse and cancelled (vms-02d,
2026-07-30). It was also a local-only phantom: CI never installs libssh, so
it never even registered there. Locally it registered and skipped
(SKIP_RETURN_CODE 77), and a skip reads as coverage it does not provide
(CLAUDE.md Rule 10).

Deleted:
 - tests/vmsssh/test_vmsssh.sh (Docker-based integration script)
 - tests/vmsssh/test_ssh_client.c (libssh test client, only a harness for
   the deleted integration test)
 - the vmsssh_integration ctest registration and its libssh gating in
   tests/vmsssh/CMakeLists.txt

Kept:
 - tests/vmsssh/test_term_mapping.c / term_mapping ctest target — a
   genuine unit test of TERM -> VMS device type mapping with no libssh
   dependency, unrelated to the deleted integration test; terminal
   fidelity remains a live Phase 3 concern. tests/vmsssh is now added
   unconditionally under BUILD_TESTS in the root CMakeLists.txt so this
   test always builds and runs, never gated on libssh.
 - src/vmsssh/vmssshd.c (the daemon source) — retained per item scope for
   a possible future revival. Its libssh gate in the root CMakeLists.txt
   is unchanged (the daemon itself genuinely needs libssh to link); only
   its test surface is removed.

Verified both configurations: with libssh installed, ctest goes from 40
tests/1 skip to 39 tests/0 skipped/0 failed. With LIBSSH_INCLUDE_DIR and
LIBSSH_LIBRARY forced to -NOTFOUND (simulating libssh absent without
touching the shared host package), src/vmsssh is correctly skipped
("libssh not found — vmssshd will not be built") while tests/vmsssh still
configures and term_mapping still builds and passes.

Co-Authored-By: Claude Sonnet 5 (implementer) <noreply@anthropic.com>
Veracity re-dispatch on vms-97d found two defects in the kept unit test:

1. tests/vmsssh/test_term_mapping.c #included a hand-maintained COPY of
   map_term_to_vms_device_type() instead of the real vmssshd.c function
   -- the classic mock-away-the-thing-under-test bug. Any future edit to
   the product function left the test green.

2. The kept device-type strings ("VT100"/"VT200"/"VT300"/"VT400") and the
   TERM->family mapping were asserted with no oracle citation, in
   violation of Rule 10 (self-certified VMS-facing values are illegal;
   green CI is not evidence of VMS correctness).

Fix, per the orchestrator ruling's option (a):
- Extracted the mapping into src/vmsssh/term_map.c + term_map.h, a
  dependency-free translation unit outside the libssh gate. vmssshd.c
  now calls the shared vmsssh_map_term_to_device_type() instead of
  defining its own static copy.
- tests/vmsssh/test_term_mapping.c now compiles and links
  src/vmsssh/term_map.c directly -- it exercises the real product code,
  and a drift in term_map.c now fails the test.
- term_map.h/.c and the test file carry an explicit Rule 8/Rule 10
  label: the mapping is an OVMX design choice, NOT a reproduction of
  documented OpenVMS behavior. OpenVMS sets terminal device type via SET
  TERMINAL/DEVICE_TYPE and renders $TTDEF values as e.g.
  "VT400_Series" via SHOW TERMINAL; it has no mechanism that infers a
  device type from a Unix TERM string. No VMS-fidelity claim is made or
  tested -- only internal consistency of the OVMX heuristic.

Verified both configurations from a clean build:
- WITH libssh (host has libssh-dev): ctest = 39/39 passed, 0 skipped.
  VMSSSHD.EXE links term_map.c.o; test_term_mapping links the same TU.
- WITHOUT libssh (cache-forced -DLIBSSH_INCLUDE_DIR/-DLIBSSH_LIBRARY
  =-NOTFOUND, no host mutation): "libssh not found -- vmssshd will not
  be built" fires, no VMSSSHD.EXE is produced, and ctest still reports
  39/39 passed, 0 skipped -- term_mapping builds and runs unconditionally.

Does not reopen the settled deletion of test_vmsssh.sh /
vmsssh_integration / test_ssh_client.c from the prior commit on this
branch (cc88896) -- that result was accepted by the orchestrator ruling
and is untouched here.

vms-97d
@baron-3dl
baron-3dl merged commit fa334c9 into main Jul 30, 2026
35 checks passed
baron-3dl added a commit that referenced this pull request Aug 13, 2026
…ee head must be pointer-width (#463)

MMK.EXE SIGSEGV'd in the guest before sp_open (post-parse/pre-drive),
nondeterministically and only with a real executive. Prior work (vms-b23
#462) characterized it via a SIGSEGV handler but lacked a real backtrace.

Root cause (real backtrace, this commit): a 64-bit pointer-width bug.
objects.c declares the LIB$*_TREE root cell as `static unsigned int
objtree` — 4 bytes. On the VAX a longword IS a pointer so stock MMK is
correct; on a 64-bit OVMX target that cell is too small. lib$insert_tree /
lib$lookup_tree take the head by reference and dereference it as a full
8-byte pointer, so they:
  - over-READ 8 bytes of a 4-byte global (the adjacent global's 4 bytes
    become the high half of a bogus root pointer), and
  - on insert, over-WRITE, truncating the stored root node address.
The reconstructed garbage pointer is later dereferenced -> SIGSEGV. Whether
it faults depends on address-space layout, which is exactly why it was
nondeterministic and "executive-dependent" (the executive changes the heap
layout); on the host the reconstructed pointer happened not to fault, so
MMK reached sp_open cleanly.

Pinned with a real backtrace via ASan on the host mmk_native ELF, run with
the identical input the guest capstone uses
(VMS_FOREIGN_CMD="/DESCRIPTION=OVMXB23.MMS OVMXB23.OUT"):

  ERROR: AddressSanitizer: global-buffer-overflow ... READ of size 8
    #0 lib$lookup_tree            src/libvms/rtl/lib_tree.c:108
    #1 Find_Object               tests/corpus/tier3-mmk/objects.c:102
    #2 make_objrefs              tests/corpus/tier3-mmk/parse_descrip.c:1135
    #3 parse_store               tests/corpus/tier3-mmk/parse_descrip.c:1051
    #4 act_prs                   tests/libvms/mmk_parse_tables.c:85
    ... lib$table_parse -> parse_descrip -> Read_Description
    #9 main                      tests/corpus/tier3-mmk/mmk.c:705
  0 bytes after global variable 'objtree' (size 4)

Fix: declare objtree pointer-width (`void *`), matching symbols.c's
apply_sort() `void *tree` and the LIB$ manual's quadword tree head on
64-bit architectures. After the fix ASan is clean on the same input and
MMK proceeds through the object tree to the drive (sp_open).

Clean-room (Rule 8): objects.c is stock MadGoat freeware; the one-line
width change is an OVMX portability fix, tagged inline.

Proof:
  - ASan before: global-buffer-overflow at lib_tree.c:108 (above).
  - ASan after: clean; MMK reaches the drive (same as host baseline).
  - toolchain-mmk-parse ctest: PASS (no host regression).
  - build-static (musl) mmk_native: builds clean.

Co-authored-by: alice <alice@workspace.local>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
baron-3dl added a commit that referenced this pull request Aug 17, 2026
The zero-match-glob hard-fail added to overlay-ovmx-drivers.sh (previous commit)
correctly aborts when a sources.conf glob stages nothing -- but it exposed a
STALE scaffold in tests/integration/test_ovmx_module_home.sh. The demonstrator
sub-test builds a scratch repo ($WORK/repo) that copies distro/kernel/drivers-
ovmx (so vmsfs's sources.conf now carries the src/vmsfs/ods2/*.c codec glob) plus
src/kernel + src/kernel-core, but NOT src/vmsfs. The codec glob then matched
nothing and the new guard aborted the overlay, cascading the demonstrator's
ovmxdemo-wiring assertions (ovmx_module_home_gate, Build & Test #9).

Fix mirrors the real distro/Dockerfile.bootable change: the scratch repo now
also stages src/vmsfs (carrying src/vmsfs/ods2/ + src/vmsfs/include/vmsfs/ods2.h),
the same tree the kernel-build stage COPYs into its overlay context. vmsfs's
codec glob matches, the overlay runs clean, and the demonstrator tests its
actual concern (a new drivers-ovmx/<mod>/ subdir wires itself in) without
tripping the guard. The guard is NOT weakened and vmsfs is NOT special-cased --
the test's scaffold was simply stale relative to the Dockerfile change.

Verified via the ctest wrapper this time (not just the script):
  ctest -R ovmx_module_home_gate  -> 1/1 Passed
  module-home gate: 29 passed, 0 failed (demonstrator + ovmxdemo assertions all green)

Rung of epic vms-208 (Files-11 ODS-2 ACP in the executive).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
baron-3dl added a commit that referenced this pull request Aug 17, 2026
…c (unblocks ACP boot) (#645)

* vms-4a8: bootable-image vms.ko carries the kernel-resident ODS-2 codec

The bootable vmsfs.ko is built by the in-tree drivers/ovmx/ overlay, which
FLATTENS all module sources to basenames. The genuine ODS-2 codec was absent
there: its sources #include the public header by a SUBDIR path
("vmsfs/ods2.h"), which the basename-flatten model could not resolve, so the
overlay Kbuild left -DOVMX_ODS2_KERNEL undefined and dropped the codec objects
(vms-dcd's tracked follow-up). The shipped module therefore could not read a
genuine ODS-2 volume.

Make the flatten subdir-safe, additively:

- overlay-ovmx-drivers.sh: a sources.conf line may now use `<glob> -> <subdir>/`
  to stage matched files UNDER the module dir's <subdir>/ instead of at the
  flat root. Lines without `->` flatten to basenames exactly as before -- the
  convention is purely additive and touches no other module.
- vmsfs/sources.conf: stage the codec (src/vmsfs/ods2/*.c,*.h) and stage the
  public header preserving its path: `src/vmsfs/include/vmsfs/ods2.h -> vmsfs/`,
  so #include "vmsfs/ods2.h" resolves via -I$(src) in the flat dir.
- vmsfs/Kbuild: add the codec objects (ods2_reader/writer/bdev/path/block_kern
  + vmsfs_ods2ro) and define -DOVMX_ODS2_KERNEL, so the OVMX_ODS2_KERNEL gate in
  vmsfs_super.c (vmsfs_ods2ro_register) now resolves -- no dangling symbol.
- Dockerfile.bootable: add binutils and an nm proof that the shipped vmsfs.ko
  carries vmsfs_ods2ro_register + ods2_* (codec-compiled-in gate).

ADDITIVE: this makes the shipping module CARRY the codec; it does NOT flip the
boot default or mount SYS$DISK via the ACP (the atomic-flip / boot rung).

Codec source and Kbuild object list are untouched, so the out-of-tree
(src/kernel/vmsfs/Makefile), userspace, Alpha (build-vmsko-alpha.sh) and VAX
(build-vms-module-vax.sh) builds keep their include paths. Alpha/VAX peers
should re-run their cross-builds as a heads-up.

Proof: staged the overlay into a fabricated kernel tree and built the FLAT
layout against real kernel headers with the real Kbuild + -DOVMX_ODS2_KERNEL --
modpost clean (no undefined ods2_/vmsfs_ods2ro symbols) and nm shows
vmsfs_ods2ro_register + ods2_bdev_finish_open + ods2_wvolume_append_file in the
produced vmsfs.ko. Module-home gate 29/29; out-of-tree vms.ko + vmsfs.ko green.

Rung of epic vms-208 (Files-11 ODS-2 ACP in the executive).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* vms-4a8: stage codec into the REAL Dockerfile kernel-build context + fail-loud on empty glob

The prior commit made the OVERLAY stage the ODS-2 codec, and proved it against a
fabricated kernel tree fed the FULL repo as REPO. But the real bootable build
(distro/Dockerfile.bootable, `kernel-build` stage) hands the overlay a REPO --
/tmp/ovmx-src -- assembled from only two COPYs: src/kernel and src/kernel-core.
src/vmsfs was never copied, so the codec globs (src/vmsfs/ods2/*.c and the
public header src/vmsfs/include/vmsfs/ods2.h) matched NOTHING in the real build.
The overlay merely WARNed (n stayed >0 from the src/kernel globs), the codec .c
files never staged, and the in-tree kernel build died with
    make: *** No rule to make target 'drivers/ovmx/vmsfs/ods2_reader.o'
-> no bootable image -> every boot/e2e gate red. The fabricated-tree modpost
proof could not see this because it was given the whole repo, not the Dockerfile
build context (the #623-class in-tree blind spot).

Two fixes:

- Dockerfile.bootable (kernel-build stage): COPY src/vmsfs into /tmp/ovmx-src
  before the overlay runs, so the codec sources + the subdir'd public header are
  present in the exact REPO the overlay flattens from.
- overlay-ovmx-drivers.sh: a sources.conf glob that matches ZERO files is now a
  hard FAIL, not a WARN. A glob naming files that aren't in the build context
  silently drops objects the Kbuild requires; failing loudly at overlay time --
  with the offending glob and REPO named -- turns a cryptic downstream
  "No rule to make target" into an immediate, legible error. This is the guard
  that would have caught the miss above at CI overlay time.

Verified: overlay against a REPO lacking src/vmsfs now FAILs with
"sources.conf glob 'src/vmsfs/ods2/*.c' ... matched no files"; against the full
repo it stages all 6 codec objects and the vmsfs/ods2.h header and completes.
Real `docker build --target kernel-build` proof appended below.

Rung of epic vms-208 (Files-11 ODS-2 ACP in the executive).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* vms-4a8: kernel-resident codec — cut ods2_wvolume_dir_insert stack frame under 2KB

The real Dockerfile kernel-build (previous commit unblocked staging) then
surfaced a genuine in-kernel error the userspace/fabricated builds never see:

  ods2_writer.c: In function 'ods2_wvolume_dir_insert':
  error: the frame size of 3288 bytes is larger than 2048 bytes
         [-Werror=frame-larger-than=]

The function put ~2.6KB of scratch on the stack -- hdr[512] + hdr_parsed(512) +
newrec[512] + lbns[256]*4(1024) -- fine in userspace, but over the kernel's
2048-byte per-frame limit (the kernel stack is a few pages, and this is a leaf
of the ACP call chain). An -O2 userspace sweep with -Wframe-larger-than=2048
confirmed this is the ONLY codec function over the limit.

Fix (behaviour-identical): bundle those four buffers into ONE heap block, struct
di_scratch, allocated through the codec's existing allocator seam (ods2_kzalloc
-> kvmalloc in-kernel, malloc in userspace -- the same seam `flat` already
uses), and free it once at a new single `done:` exit. Every post-allocation
return became `goto done`; `flat`'s own frees fold into the same label (guarded
+ NULLed so the free is idempotent, no double-free on the success path). The
four pre-allocation argument-check returns keep returning directly (nothing to
free yet). No on-disk bytes or control decisions change -- only where the
scratch lives.

Verified: gcc -O2 -Wall -Wextra -Wframe-larger-than=2048 on ods2_writer.c is now
clean (no frame warning, no warnings). Host ods2 ctest + real docker
kernel-build proof below.

Rung of epic vms-208 (Files-11 ODS-2 ACP in the executive).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* vms-4a8: kernel-resident codec — fix bd_inode removal for kernel 6.12 (bdev_nr_bytes)

With the frame-size fix in, the real Dockerfile kernel-build (6.12.103) advanced
past the codec objects to vmsfs_ods2ro.c and hit the next genuine in-kernel
break:

  vmsfs_ods2ro.c:387: error: 'struct block_device' has no member named 'bd_inode'

The 6.x block layer removed 'bd_inode' from the public struct block_device (the
bdev inode moved out of the struct). ods2ro_fill_super() used
i_size_read(sb->s_bdev->bd_inode) purely to read the backing device's size in
bytes. Replace it with bdev_nr_bytes(sb->s_bdev) -- the supported device-size
accessor (linux/blkdev.h, present since 5.16), same byte count -- and include
<linux/blkdev.h> explicitly rather than lean on a transitive include.

More portable than before, not less: bdev_nr_bytes() spans 5.16..6.12+, so this
also builds under the out-of-tree QEMU harness (src/kernel/vmsfs/Makefile) and
the Alpha/VAX cross-builds, which compile the same file. A scan of the rest of
vmsfs_ods2ro.c (mount_bdev / iget_locked / sb_set_blocksize / kill_block_super /
register_filesystem) shows every other API unchanged in 6.12; the codec .c
objects already compiled clean in the prior build. Real kernel-build proof to
follow.

Rung of epic vms-208 (Files-11 ODS-2 ACP in the executive).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* vms-4a8: stage src/vmsfs in the module-home gate demonstrator scaffold

The zero-match-glob hard-fail added to overlay-ovmx-drivers.sh (previous commit)
correctly aborts when a sources.conf glob stages nothing -- but it exposed a
STALE scaffold in tests/integration/test_ovmx_module_home.sh. The demonstrator
sub-test builds a scratch repo ($WORK/repo) that copies distro/kernel/drivers-
ovmx (so vmsfs's sources.conf now carries the src/vmsfs/ods2/*.c codec glob) plus
src/kernel + src/kernel-core, but NOT src/vmsfs. The codec glob then matched
nothing and the new guard aborted the overlay, cascading the demonstrator's
ovmxdemo-wiring assertions (ovmx_module_home_gate, Build & Test #9).

Fix mirrors the real distro/Dockerfile.bootable change: the scratch repo now
also stages src/vmsfs (carrying src/vmsfs/ods2/ + src/vmsfs/include/vmsfs/ods2.h),
the same tree the kernel-build stage COPYs into its overlay context. vmsfs's
codec glob matches, the overlay runs clean, and the demonstrator tests its
actual concern (a new drivers-ovmx/<mod>/ subdir wires itself in) without
tripping the guard. The guard is NOT weakened and vmsfs is NOT special-cased --
the test's scaffold was simply stale relative to the Dockerfile change.

Verified via the ctest wrapper this time (not just the script):
  ctest -R ovmx_module_home_gate  -> 1/1 Passed
  module-home gate: 29 passed, 0 failed (demonstrator + ovmxdemo assertions all green)

Rung of epic vms-208 (Files-11 ODS-2 ACP in the executive).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant