Files
forgefirm/meta-forgefirm/recipes-forgefirm/images/forgefirm-image-dev.bb
T
ScottW514 08c7df9cbb rootfs-lint.sh: the image content fixed at build time, checked as the last rootfs step
A new script beside the image recipe, run by both images as the last
rootfs step (ROOTFS_POSTPROCESS_COMMAND:append, after every +=, the dev
recipe's and debug-tweaks' included); a refusal is bbfatal. It checks
every rule and prints every failure before it exits. FORGEFIRM_IMAGE_KIND
(release by default, dev in forgefirm-image-dev.bb) picks the sshd policy.
The rules:

- syslog: /usr/sbin/rsyslogd is on the image, /etc/init.d/syslog starts
  it and runlevel 5 starts that script; no syslogd or klogd is linked in
  a bin directory and no init script runs one. This is the image half of
  what logs.routing checked on the board; that test left in 01f5991 with
  nothing else holding it.
- sshd: sshd_config and sshd_config_readonly take passwords
  (PasswordAuthentication yes) and send no banner; on a release image
  PermitRootLogin no and PermitEmptyPasswords no; sshd_config.d sets none
  of the four, since an included value comes first. setup.ssh-until-
  reboot checked the first two on the board and left in 01f5991;
  release.sh gates the release pair at release time only.
- dhcp-name: the wlan0 dhcp stanza's udhcpc_opts carries
  -x hostname:$(hostname).
- mdns: no /etc/avahi, avahi-daemon or libnss_mdns, and no mdns source
  on nsswitch.conf's hosts line.
dhcp-name and mdns are the image half of setup.machine-name, whose
scripts test_image.py's MachineNameTests already run.

test_image.py's RootfsLintTests run it on a fixture tree: the tree that
holds every rule passes as either image, the BSP layer's own interfaces
file passes, and one drift per rule fails naming the rule (a busybox
syslogd link; a Banner, on either image; root and an empty password,
refused on a release image and passed on a dev one; a dhcp stanza with
no name; /etc/avahi).

Proof: test_image.py under Linux, 21 OK; pyflakes clean. On image
20261015134521's two rootfs trees from the build, the release tree
passes as release, the dev tree passes as dev, and the dev tree linted
as release is refused on PermitRootLogin and PermitEmptyPasswords in
both sshd files. bitbake -e places rootfs_lint last in both images'
ROOTFS_POSTPROCESS_COMMAND, with FORGEFIRM_IMAGE_KIND release and dev.
The layer content hash moves: the next image cannot inherit a campaign.
2026-10-15 10:19:54 -04:00

81 lines
3.6 KiB
BlitzBasic

# SPDX-License-Identifier: MIT
require forgefirm-image.bb
DESCRIPTION = "OpenGlow/ForgeFIRM development image for Glowforge"
# Strict superset of forgefirm-image: everything the main image ships, plus
# debug tooling. forgetest is the release acceptance tool (HTTP :8090) and
# the bench diagnostics page; it belongs to the bench, never to a release
# image (https://docs.forgefirm.org/developers/acceptance/). The gfutilities
# emulator fixtures are the canned frames its service-protocol test answers
# the service with.
IMAGE_INSTALL += " \
forgetest \
python3-gfutilities-emulator \
python3-mmap \
python3-ctypes \
htop \
"
# python3-mmap and python3-ctypes serve the bench scripts that read the SoC
# pads through /dev/mem (resume_dark_lead.py, cp_watchdog_timing.py, the
# accelerometer probes). They are bench tooling: the release image carries
# neither, and forgetest itself imports neither.
# The release recipe trims nano from the shared base list (bench
# convenience, 8.7 MB with libmagic); the dev image keeps it. Removal specs
# accumulate and apply after every append, so the variable inside the
# release recipe's spec is what gets blanked here.
FORGEFIRM_RELEASE_TRIM = ""
# debug-tweaks (passwordless root, root SSH login) belongs ONLY to the dev
# image - never the release image. It lives here, not in the shared kas
# local.conf, so the release forgefirm-image cannot inherit it.
IMAGE_FEATURES += " \
tools-debug \
debug-tweaks \
"
# The rootfs lint holds a dev image to the dev policy: root and an empty
# password over SSH are what debug-tweaks turns on.
FORGEFIRM_IMAGE_KIND = "dev"
# Dev images boot from SD, never from a 200 MiB eMMC slot: lift the slot
# ceiling and give the filesystem generous working space instead.
IMAGE_ROOTFS_MAXSIZE = ""
IMAGE_ROOTFS_EXTRA_SPACE = "262144"
# Dev builds identify by build timestamp (matches the artifact name),
# tagged so a bench machine is never mistaken for a release.
FORGEFIRM_VERSION_STRING = "${DATETIME} (dev)"
# The rootfs functions that write the string are in the do_rootfs
# signature; DATETIME must not be, or the basehash changes at every parse
# and bitbake refuses the build as non-deterministic.
FORGEFIRM_VERSION_STRING[vardepsexclude] += "DATETIME"
# /etc/forgefirm-dev marks a dev image on the rootfs; its content is the
# version string. The sshd init script starts sshd on a dev image without
# the panel's enable flag (/run/forgefirm/ssh-enabled), and forgectrl
# reads the same marker. A release image has no such file.
write_forgefirm_dev_marker() {
echo "${FORGEFIRM_VERSION_STRING}" > ${IMAGE_ROOTFS}${sysconfdir}/forgefirm-dev
}
write_forgefirm_dev_marker[vardepsexclude] += "DATETIME"
ROOTFS_POSTPROCESS_COMMAND += "write_forgefirm_dev_marker "
# The two factory rootfs slots, read-only under /factory/img1 and
# /factory/img2: a bench convenience for reading a factory image in place
# (the ffboot inventory reuses the mounts). The release image mounts no
# factory slot; it reads one through a temporary read-only mount when it
# needs to (ffboot -l). No nofail: busybox mount hands it to the kernel
# as a filesystem parameter, which the kernel rejects (the mount fails
# with EINVAL); mount -a goes on past a slot that does not mount anyway.
add_factory_slot_mounts() {
install -d ${IMAGE_ROOTFS}/factory/img1 ${IMAGE_ROOTFS}/factory/img2
printf '%s\n' \
'/dev/mmcblk2p1 /factory/img1 auto ro,noatime 0 0' \
'/dev/mmcblk2p2 /factory/img2 auto ro,noatime 0 0' \
>> ${IMAGE_ROOTFS}${sysconfdir}/fstab
}
ROOTFS_POSTPROCESS_COMMAND += "add_factory_slot_mounts "