Skip to content

feat(extensions): add netboot extension for TFTP+NFS diskless boot#9656

Draft
iav wants to merge 26 commits intoarmbian:mainfrom
iav:enh/netboot-extension
Draft

feat(extensions): add netboot extension for TFTP+NFS diskless boot#9656
iav wants to merge 26 commits intoarmbian:mainfrom
iav:enh/netboot-extension

Conversation

@iav
Copy link
Copy Markdown
Contributor

@iav iav commented Apr 11, 2026

Summary

Adds an opt-in netboot extension that produces a full network-boot payload — kernel, DTB, optional uInitrd, pxelinux.cfg and an NFS-exportable rootfs — from a regular Armbian build. For netboot the only thing that has to live on the device's local storage is U-Boot itself: the kernel and DTB come from TFTP, / is mounted over NFS, nothing else on mmc/eMMC/USB is touched during early boot.

Today ROOTFS_TYPE=nfs alone only gives a hybrid image (kernel+DTB still on SD/eMMC, only / over NFS). This PR keeps that path working and layers a real netboot flow on top via a new ROOTFS_TYPE=nfs-root.

What changes

  • lib/functions/configuration/main-config.sh — new ROOTFS_TYPE=nfs-root case branch, symmetric with the existing fs-f2fs-support / fs-btrfs wiring: the branch auto-enables the netboot extension so ROOTFS_TYPE=nfs-root is the single switch that selects the full netboot flow. check_filesystem_compatibility_on_host is skipped for both nfs and nfs-root — the host-side check is a sanity net for block-device targets and falsely rejects valid NFS configurations.

  • extensions/netboot/netboot.sh — new, directory-based extension. Directory layout (rather than a single extensions/netboot.sh file) exists so the long-form usage guide can live next to the code as README.md; inlining documentation of that size into the script body would be unwieldy. Hooks:

    • extension_prepare_config — validate variables, compute defaults for NETBOOT_TFTP_PREFIX / NETBOOT_NFS_PATH (shared by LINUXFAMILY/BOARD/BRANCH/RELEASE, or per-host when NETBOOT_HOSTNAME is set), normalize NETBOOT_CLIENT_MAC to the 01-<mac> PXELINUX form, fail fast on bad ROOTFS_COMPRESSION/ROOTFS_EXPORT_DIR combinations before debootstrap.
    • custom_kernel_config — enable ROOT_NFS, NFS_FS, NFS_V3, IP_PNP, IP_PNP_DHCP so root=/dev/nfs ip=dhcp works without an initrd.
    • post_customize_image — drop armbian-resize-filesystem.service (meaningless on NFS root) and /root/.not_logged_in_yet (the armbian-firstlogin interactive wizard blocks bring-up when there is no interactive console). armbian-firstrun.service stays — it only regenerates SSH host keys.
    • host_pre_docker_launch — bind-mount ROOTFS_EXPORT_DIR into the build container when it lives outside ${SRC}, so the single-step builder-as-NFS-server workflow works the same inside and outside Docker.
    • pre_umount_final_image — assemble the TFTP tree (Image/zImage, dtb/, uInitrd), write pxelinux.cfg/{default.example | 01-<mac>} with the right FDT/FDTDIR line and an explicit INITRD directive when uInitrd is present (U-Boot's PXE parser only loads an initramfs when the stanza names it), expose a netboot_artifacts_ready hook for userpatches that deploy to a real server.
  • lib/functions/image/rootfs-to-image.sh — two new controls for NFS-rootfs builds (both ROOTFS_TYPE=nfs and nfs-root):

    • ROOTFS_COMPRESSION=zstd|gzip|none (default zstd). zstd.tar.zst, gzip.tar.gz, none → no archive at all. Rejected early if none is set without ROOTFS_EXPORT_DIR. The tar | pv | compressor pipeline now runs in a set -o pipefail subshell so a broken archive step actually fails the build instead of producing a silently truncated file.
    • ROOTFS_EXPORT_DIR=/abs/path — also (or only) rsync the rootfs tree into this directory. Can point anywhere on the build host's filesystem — inside or outside the Armbian tree (the extension bind-mounts external paths into the Docker container automatically). If the path is an NFS mount or any other network filesystem, the build writes directly to the remote server with no intermediate archive. The rsync uses --delete so a re-used export dir stays in sync with the new build instead of accumulating stale files from previous runs. Combined with ROOTFS_COMPRESSION=none this turns deploy-to-NFS-server into a single build step.
    • ROOTFS_ARCHIVE_PATH is exported so downstream hooks (the new netboot_artifacts_ready) can reference the produced archive.
  • lib/functions/image/partitioning.shprepare_partitions skips the root partition entry for nfs-root the same way it does for nfs, and the SD-size sanity check no longer applies to either (there is no image file to size).

  • config/templates/nfs-boot.cmd.template — previously sunxi/arm32-only (zImage + bootz). Made arch-agnostic so the hybrid ROOTFS_TYPE=nfs path builds for arm64 boards too.

  • extensions/netboot/README.md — long-form guide: variable reference, server setup (tftpd-hpa + nfs-kernel-server), DHCP 66/67 config (OpenWRT + others), per-host / per-MAC deployments, firstrun vs firstlogin, end-to-end helios64 example, troubleshooting.

Variables (quick reference)

All optional. ROOTFS_TYPE=nfs-root alone gives you a shared-rootfs build with a pxelinux.cfg/default.example file.

Variable Default Purpose
NETBOOT_SERVER (empty) TFTP/NFS server IP. Empty → nfsroot= keeps ${serverip} literal for U-Boot to fill from DHCP siaddr.
NETBOOT_TFTP_PREFIX armbian/${LINUXFAMILY}/${BOARD}/${BRANCH}-${RELEASE} Path prefix under TFTP root.
NETBOOT_NFS_PATH /srv/netboot/rootfs/shared/... or /srv/netboot/rootfs/hosts/<hostname> Absolute NFS path used in nfsroot=.
NETBOOT_HOSTNAME (empty) Per-host rootfs under hosts/<hostname>/ — each machine owns its own writable copy.
NETBOOT_CLIENT_MAC (empty) When set, PXE config is written as 01-<mac> (per-MAC PXELINUX override). Accepts : or -, normalized to lowercase.
ROOTFS_COMPRESSION zstd zstd / gzip / none.
ROOTFS_EXPORT_DIR (empty) When set, rsync the rootfs tree here in addition to (or instead of) the archive.

Test plan

Validated end-to-end on helios64 (rockchip64, edge/resolute, ttyS2 @ 1500000), Armbian 26.05:

  • Baseline build (ROOTFS_TYPE=nfs-root NETBOOT_SERVER=192.168.1.125, shared NFS path, FDTDIR fallback for boards without BOOT_FDT_FILE, no hardcoded console=). 6:57 min, all artifacts correct.
  • Per-host + per-MAC (NETBOOT_HOSTNAME=helios64-a NETBOOT_CLIENT_MAC=aa:bb:cc:dd:ee:ff). pxelinux.cfg/01-aa-bb-cc-dd-ee-ff contains nfsroot=.../hosts/helios64-a. 7:44 min.
  • ROOTFS_COMPRESSION=gzip — produces .tar.gz (default zstd.tar.zst). On the helios64 rootfs: 503 MB gzip vs 460 MB zstd.
  • ROOTFS_COMPRESSION=none ROOTFS_EXPORT_DIR=... — single-step tree workflow, 1.5 GB tree in export dir, no archive produced. 5:17 min.
  • ROOTFS_COMPRESSION=none without ROOTFS_EXPORT_DIR — fails fast in extension_prepare_config before debootstrap, not hours later.
  • End-to-end boot test: TFTP tree deployed to tftpd-hpa + NFS rootfs via rsync to nfs-kernel-server. DHCP options 66/67 on OpenWRT. Helios64 cold boot → U-Boot bootflow scan -lb → TFTP → booti → kernel → ip_auto_config → NFS mount → systemd graphical.target → login prompt on ttyS2@1500000. No armbian-firstlogin wizard, no resize2fs errors, armbian-firstrun.service regenerates SSH host keys normally. Verified twice: once with archive workflow + manual unpack, once with tree workflow + rsync deploy.
  • helios4 (mvebu, armhf, U-Boot v2025.10) — second SoC family. PXE netboot: DHCP → TFTP (zImage + DTB) → bootz → kernel → NFS root → systemd → login prompt. No initrd needed (see notes below).
  • Other boards / other SoC families — review welcome, especially from boards with BOOT_FDT_FILE set (the FDTDIR vs FDT code path is exercised by helios64's missing BOOT_FDT_FILE, but a board with it set should also work).

Known issues found during helios4 testing (not blockers for this PR):

  • RD image overlaps OS image on mvebu: ramdisk_addr_r (0x2880000) is only 8 MB above kernel_addr_r (0x2080000), but zImage 6.12 is 8.1 MB → U-Boot refuses to boot with initrd. Workaround: omit INITRD from PXE config — kernel with CONFIG_ROOT_NFS=y mounts NFS root directly without initrd.
  • DNS not working after NFS boot: kernel ip=dhcp writes DNS to /proc/net/pnp but systemd-resolved doesn't read it → "No DNS servers known". Workaround: resolvectl dns <iface> <gateway>. Needs a networkd .network file or oneshot service in post_customize_image (future improvement).

Post-review update: architecture reworked after CodeRabbit #1 — the extension no longer forces ROOTFS_TYPE from inside extension_prepare_config (too late in the config lifecycle); instead a new ROOTFS_TYPE=nfs-root case branch in main-config.sh enables the extension, symmetric with existing filesystem-support extensions. pipefail on the archive pipeline (#4), rsync --delete on the export dir (#5), and an explicit INITRD directive when uInitrd is present (#2) are all in.

Post-review update (round 3): archive creation moved from the early if/else block to after pre_umount_final_image hooks so the tarball/export tree captures the fully finalized rootfs (includes update_initramfs output and all hook edits). Split out as a separate pre-feature commit — also fixes the same bug in the original ROOTFS_TYPE=nfs hybrid flow. Additionally: the netboot extension now sets BOOTSIZE=0 for nfs-root, preventing the phantom /boot fstab entry at its source; the compensating pre_umount_final_image__100_netboot_clean_fstab hook is gone.

Post-review update (round 4): config/templates/nfs-boot.cmd.template now wraps the DTB load in an if load ... ; then true; else echo FATAL; reset; fi block so a missing/wrong dtb/${fdtfile} aborts the boot with a clear message instead of continuing with an invalid ${fdt_addr_r} — consistent with the ramdisk and kernel handling on the following lines.

Related work

A companion PR to armbian/documentation will add Developer-Guide_Netboot.md with the short overview + variable reference; this extension's README.md is the long-form guide and is linked from that page.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Netboot extension: builds staged TFTP/NFS artifacts, per-host/per‑MAC PXE entries, rootfs archive/export options, container-friendly export handling, and a netboot artifacts-ready hook.
    • New nfs-root output mode: network-first image (no local .img), fixed default size, archive/export flow, and image naming suffix.
  • Bug Fixes / Reliability

    • Safer and clearer boot configuration and bootflow with DTB-driven console behavior, robust mainline vs legacy fallbacks, quoted nfs checks, and explicit error/reporting on missing artifacts.
  • Documentation

    • Comprehensive netboot guide with examples, deploy workflows and troubleshooting.

@iav iav requested review from a team, EvilOlaf, TRSx80, igorpecovnik and littlecxm as code owners April 11, 2026 23:32
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 11, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1901c947-bbc3-438c-92f1-e1db7b3e711b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • ✅ Review completed - (🔄 Check again to review again)
📝 Walkthrough

Walkthrough

Adds a netboot extension to produce TFTP/NFS boot artifacts and NFS-root deployments, integrates nfs-root into build flow (image/export/partitioning/config), and updates the U-Boot NFS boot script template to load kernel/DTB/initrd from the active distro boot partition with arm64-aware kernel selection.

Changes

Cohort / File(s) Summary
U-Boot NFS boot template
config/templates/nfs-boot.cmd.template
Rewrote bootargs to avoid hardcoded console= params; quote-check nfs_root; load DTB and initrd from active distro boot partition (${devtype} ${devnum}:${distro_bootpart}); fatal+reset on DTB load failure; simplify initrd failure handling; try Image+booti then fallback to zImage+bootz with appropriate fdt_high.
Netboot docs
extensions/netboot/README.md
New comprehensive guide describing ROOTFS_TYPE=nfs-root behavior, build variables/defaults, artifact staging layout, hook interface, TFTP/DHCP/NFS constraints, server setup examples, workflows, and troubleshooting.
Netboot extension script
extensions/netboot/netboot.sh
New extension: defaults/validation for netboot variables (NETBOOT_SERVER, HOSTNAME, MAC formatting, TFTP prefix, NFS path), validate ROOTFS_COMPRESSION, require ROOTFS_EXPORT_DIR when none, force BOOTSIZE=0 for nfs-root, enable kernel NFS options, disable resize/skip first-login in image customization, ensure export dir is mounted in container builds, collect kernel (prefer Image then zImage/vmlinuz), DTBs and optional uInitrd into TFTP tree, generate per‑MAC or default PXELINUX entries, build nfsroot= (use ${serverip} placeholder when NETBOOT_SERVER empty), export artifact context and call netboot_artifacts_ready.
Rootfs image/export handling
lib/functions/image/rootfs-to-image.sh
Add _nfsroot suffix for nfs-root; treat nfs-root like nfs for packaging control flow (defer archive/export to post-step); implement ROOTFS_COMPRESSION handling (`gzip
Partitioning & main config
lib/functions/image/partitioning.sh, lib/functions/configuration/main-config.sh
Recognize nfs-root alongside nfs when skipping root partition creation and when bypassing host FS compatibility checks; set FIXED_IMAGE_SIZE=256 for nfs-root and enable netboot extension during main configuration.

Sequence Diagram(s)

sequenceDiagram
    participant Builder as Armbian Builder
    participant Ext as Netboot Extension
    participant KernelCfg as Kernel Config
    participant ImgGen as Image Generator
    participant TFTP as TFTP Staging
    participant Hook as netboot_artifacts_ready Hook

    Builder->>Ext: triggered with ROOTFS_TYPE=nfs-root
    Ext->>Ext: normalize & validate vars (NETBOOT_SERVER, NETBOOT_CLIENT_MAC, paths)
    Ext->>KernelCfg: enable NFS-root kernel options
    Ext->>ImgGen: customize image (disable resize service, skip firstlogin)
    ImgGen->>ImgGen: build rootfs
    Ext->>ImgGen: create/archive or export rootfs based on ROOTFS_COMPRESSION/ROOTFS_EXPORT_DIR
    Ext->>TFTP: collect kernel (Image→zImage→vmlinuz), DTBs, optional uInitrd
    Ext->>TFTP: generate PXELINUX entries (per-MAC or default)
    Ext->>Hook: invoke netboot_artifacts_ready with artifact context
Loading
sequenceDiagram
    participant DHCP as DHCP Server
    participant Client as Target Device
    participant UBoot as U-Boot
    participant TFTP as TFTP Server
    participant NFS as NFS Server

    Client->>DHCP: request IP + boot options
    DHCP->>Client: reply (serverip, bootfile)
    Client->>UBoot: obtain bootfile (pxe/extlinux)
    UBoot->>TFTP: fetch pxelinux.cfg, kernel, dtb, uInitrd
    TFTP->>UBoot: deliver artifacts
    UBoot->>NFS: mount nfsroot (from kernel cmdline)
    NFS->>Client: provide root filesystem
    Client->>Client: kernel boots with NFS root
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 I hopped through scripts, templates, and docs,

Staged kernels, DTBs, and tidy boxocks.
PXE and NFS weaved netboot's tune,
Builder sang, U‑Boot hummed in tune.
A rabbit’s cheer — artifacts in bloom!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title clearly describes the main feature being added: a netboot extension for TFTP+NFS diskless boot, which aligns with the comprehensive changes introducing ROOTFS_TYPE=nfs-root, the netboot extension framework, and related infrastructure.
Docstring Coverage ✅ Passed Docstring coverage is 81.82% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added 05 Milestone: Second quarter release size/large PR with 250 lines or more Needs review Seeking for review Hardware Hardware related like kernel, U-Boot, ... Framework Framework components Documentation Documentation changes or additions labels Apr 11, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@extensions/netboot/netboot.sh`:
- Around line 38-42: The function
extension_prepare_config__netboot_force_nfs_rootfs sets ROOTFS_TYPE too late (it
runs during do_extra_configuration) so NFS-specific branches in
do_main_configuration never see it; move the ROOTFS_TYPE assignment earlier by
ensuring extension_prepare_config__netboot_force_nfs_rootfs (or its logic) runs
before do_main_configuration—either call that function in the init/startup hook
that executes prior to main configuration (e.g., extension_init or top-level
script before do_main_configuration) or export/set declare -g ROOTFS_TYPE="nfs"
at script initialization so the global variable is in effect for
do_main_configuration and the NFS setup in
lib/functions/configuration/main-config.sh executes.
- Around line 147-149: The PXE staging copies ${MOUNT}/boot/uInitrd but never
references it in the generated extlinux.cfg, so U-Boot won't load the initramfs;
modify the netboot stanza generation to set an initrd_line variable when the
file exists (mirror how fdt_line is created — e.g. check for
"${MOUNT}/boot/uInitrd", set initrd_line="INITRD ${tftp_prefix_dir}/uInitrd")
and then include ${initrd_line} in the emitted PXE stanza alongside fdt_line so
the INITRD directive is present for U-Boot.

In `@extensions/netboot/README.md`:
- Around line 137-155: The README has multiple unlabeled fenced code blocks
(e.g., the directory tree block showing "/srv/netboot/" and other blocks around
lines 159-164, 171-175, 465-489, 544-547); update each triple-backtick fence to
include an appropriate info string (for example use sh, ini, or text as
appropriate) so markdownlint stops flagging them—locate the fences by searching
for the blocks that display the directory tree and configuration snippets and
add the matching language tag to each opening ``` line.

In `@lib/functions/image/rootfs-to-image.sh`:
- Around line 82-93: The rsync into ROOTFS_EXPORT_DIR can leave stale files
behind when the export tree is reused; update the rsync invocation in
rootfs-to-image.sh (the run_host_command_logged rsync call) to include --delete
(and optionally --delete-excluded) so files removed from the source are removed
from "${ROOTFS_EXPORT_DIR}" as well; add the flag either into $rsync_ea or
directly in the rsync command invocation to ensure exported NFS root mirrors the
built image.
- Around line 69-76: The archive creation pipeline (tar … | pv … |
${archive_filter} > "${ROOTFS_ARCHIVE_PATH}") must be guarded with pipefail so
failures in tar or pv aren't masked by a later stage; wrap that pipeline in a
shell context with set -o pipefail (or enable set -o pipefail locally before
running the pipeline) so a nonzero exit from tar or pv will cause the script to
fail and propagate the error from creating ROOTFS_ARCHIVE_PATH; update the block
around display_alert/ tar / pv / ${archive_filter} to ensure pipefail is active
for that pipeline.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fca3bef5-36a8-4aaa-81dd-645853e7579e

📥 Commits

Reviewing files that changed from the base of the PR and between fdef407 and 2393977.

📒 Files selected for processing (5)
  • config/templates/nfs-boot.cmd.template
  • extensions/netboot/README.md
  • extensions/netboot/netboot.sh
  • lib/functions/configuration/main-config.sh
  • lib/functions/image/rootfs-to-image.sh

Comment thread extensions/netboot/netboot.sh Outdated
Comment thread extensions/netboot/netboot.sh
Comment thread extensions/netboot/README.md Outdated
Comment thread lib/functions/image/rootfs-to-image.sh Outdated
Comment thread lib/functions/image/rootfs-to-image.sh Outdated
@iav iav marked this pull request as draft April 11, 2026 23:50
iav added a commit to iav/armbian that referenced this pull request Apr 12, 2026
`nfs-root` is a new rootfs type distinct from the existing `nfs` hybrid
mode. Selecting it wires the `netboot` extension from the core
`ROOTFS_TYPE` dispatch in `do_main_configuration`, so callers no longer
need a separate `ENABLE_EXTENSIONS=netboot`. The legacy `nfs` branch
(kernel+DTB on local boot partition, `/` over NFS) is untouched — both
paths coexist until the hybrid mode's future is decided.

Core plumbing mirrors the `nfs` branch for all paths where local root
storage would be meaningless: partition layout skip
(`prepare_partitions`), archive/export gate and version suffix
(`rootfs-to-image.sh`), and the host-side filesystem compatibility
check in `main-config.sh`.

Extension hooks now key on `ROOTFS_TYPE=nfs-root` instead of guessing
from `nfs`, removing the `force ROOTFS_TYPE=nfs` shim that ran too
late relative to `do_main_configuration`.

Also folded in from CodeRabbit review on PR armbian#9656:
- pipefail around tar|pv|compressor so truncated archives no longer
  slip through on an intermediate stage failure
- `rsync --delete` on `ROOTFS_EXPORT_DIR` so stale files from a
  previous build don't linger in the NFS export tree
- explicit `INITRD` directive in extlinux when `uInitrd` is staged;
  U-Boot only loads an initramfs when the stanza names it
- README updated to document `ROOTFS_TYPE=nfs-root` as the single
  switch

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@rpardini
Copy link
Copy Markdown
Member

Very nice. With recent u-boot (2026.04, thanks to Kwiboo), one can enable LWIP networking stack for better TFTP performance (loading kernel and initramfs) -- there's also some TFTP Window Size stuff that can be tuned. U-boot with LWIP + u-boot's wget offers the best performance, but is not integrated in pxe or dhcp boot target AFAIK.

@iav
Copy link
Copy Markdown
Contributor Author

iav commented Apr 12, 2026

Thanks for the pointer! Let's get this merged first — iterating on something that works is the easy part.

@iav iav force-pushed the enh/netboot-extension branch from a76e4b2 to fec99ac Compare April 12, 2026 17:14
@iav iav added the Work in progress Unfinished / work in progress label Apr 12, 2026
@iav iav force-pushed the enh/netboot-extension branch 5 times, most recently from a10feb4 to 4ff6016 Compare April 14, 2026 17:14
@iav
Copy link
Copy Markdown
Contributor Author

iav commented Apr 14, 2026

@coderabbitai review

@iav
Copy link
Copy Markdown
Contributor Author

iav commented Apr 15, 2026

Pull my Helios64 to v2026.04 in #9675

@iav iav force-pushed the enh/netboot-extension branch 4 times, most recently from a61ff64 to dac19c8 Compare April 15, 2026 17:19
iav and others added 16 commits April 23, 2026 03:18
The previous template was hardcoded for sunxi arm32 — `zImage`/`bootz`,
`console=tty1 console=ttyS0,115200`, `disp.screen0_output_mode=...`,
`ext4load/fatload mmc 0`. It did not work on arm64 boards (e.g.
rockchip64/helios64) and baked in a 115200 baud that breaks non-standard
UART speeds (helios64 runs at 1500000).

Rewrites the U-Boot hush script to:
- Prefer `Image` + `booti` (arm64), fall back to `zImage` + `bootz` (arm32).
- Load via `${devtype} ${devnum}:${distro_bootpart}` from U-Boot's distro
  bootflow scanner instead of hardcoded `mmc 0`.
- Drop the `console=` overrides — let the kernel resolve the console from
  DTB `/chosen/stdout-path`, keeping `earlycon` for early output.
- Drop sunxi-specific `disp.screen0_output_mode` and legacy `.next`/
  `script.bin` probe paths.

For the full TFTP+NFS netboot flow see the new `netboot` extension; this
template remains the hybrid path where the kernel + DTB live on a local
boot partition and only the rootfs is NFS-mounted.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…the tree

The archive was created inside the if/else block at the top of
create_image_from_sdcard_rootfs(), BEFORE update_initramfs and
pre_umount_final_image hooks run.  Any rootfs changes made by those
hooks (initramfs regeneration, fstab fixups, extension tweaks) were
missing from the archive.

Move archive creation to after pre_umount_final_image so the tarball
captures the fully finalized rootfs tree.
…TFS_COMPRESSION

Split the rootfs pipeline so it can produce either (or both) of:
  * a tarball — via ROOTFS_COMPRESSION=gzip (default, .tar.gz) / zstd
    (.tar.zst); matches existing behaviour, with zstd now available for
    faster creation and decompression on modern hardware.
  * an exported tree — via ROOTFS_EXPORT_DIR=<abs path>, which rsyncs
    the built rootfs to a host-side directory (e.g. an NFS export)
    without an intermediate archive.

Set ROOTFS_COMPRESSION=none when only the exported tree is wanted;
this skips archive creation entirely. If both ROOTFS_COMPRESSION=none
and -z ROOTFS_EXPORT_DIR are set the run is aborted — otherwise the
rootfs stage would produce nothing.

This is infrastructure; no existing callers need to change. The
netboot extension (added in a following commit) consumes
ROOTFS_EXPORT_DIR to populate the NFS export tree.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Hooks:
- extension_prepare_config: validate variables, compute defaults for
  NETBOOT_TFTP_PREFIX / NETBOOT_NFS_PATH (shared by
  LINUXFAMILY/BOARD/BRANCH/RELEASE, or per-host when NETBOOT_HOSTNAME
  is set), normalize NETBOOT_CLIENT_MAC to PXELINUX 01-<mac> form,
  fail fast on bad ROOTFS_COMPRESSION/ROOTFS_EXPORT_DIR combinations.
- custom_kernel_config: enable ROOT_NFS, NFS_FS, NFS_V3, IP_PNP,
  IP_PNP_DHCP so root=/dev/nfs ip=dhcp works without an initrd.
- post_customize_image: drop armbian-resize-filesystem.service
  (meaningless on NFS root) and /root/.not_logged_in_yet (the
  armbian-firstlogin interactive wizard blocks bring-up when there is
  no interactive console). armbian-firstrun.service stays — it only
  regenerates SSH host keys.
- host_pre_docker_launch: append a bind-mount for ROOTFS_EXPORT_DIR to
  DOCKER_EXTRA_ARGS when the directory lives outside ${SRC}, using the
  hook's documented mechanism.
- pre_umount_final_image: assemble the TFTP tree (Image/zImage, dtb/,
  uInitrd), write pxelinux.cfg/{default.example | 01-<mac>} with the
  right FDT/FDTDIR line and explicit INITRD directive when uInitrd is
  present, expose a netboot_artifacts_ready hook for userpatches.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New rootfs type for full network boot: the only thing on the device's
local storage is U-Boot itself. Kernel, DTB, optional uInitrd and PXE
config come from TFTP; rootfs is mounted over NFS.

A new case branch in do_main_configuration auto-enables the netboot
extension, symmetric with existing fs-f2fs-support / fs-btrfs wiring.
The legacy ROOTFS_TYPE=nfs (hybrid: kernel on local storage, only /
over NFS) is untouched — both paths coexist.

- nfs-root case branch in ROOTFS_TYPE dispatch calls
  enable_extension "netboot"
- prepare_partitions skips root partition creation and SD-size sanity
  check
- check_filesystem_compatibility_on_host skipped for nfs-root
- create_image_from_sdcard_rootfs early-returns for nfs-root after the
  pre_umount hook has grabbed TFTP artifacts from /boot: SDCARD.raw is
  dropped, the .img pipeline (mv to DESTIMG, write-to-SD, fingerprint,
  compress) is skipped. For nfs-root the only deliverables are the
  rootfs archive / ROOTFS_EXPORT_DIR tree and the TFTP staging dir —
  producing a boot-partition .img would be misleading (nothing on the
  device reads it).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Documents the netboot extension: artifact server setup (tftpd-hpa +
nfs-kernel-server), TFTP tree layout, DHCP options 66/67 on the
network DHCP server, userpatches.conf knobs, the
netboot_artifacts_ready hook, a full end-to-end helios64 walkthrough,
and a troubleshooting section.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Address coderabbitai nitpicks (review 2026-04-22):
- netboot.sh:72 error message advertised gzip|zstd|none while the
  case already accepts zst; realign the message with the actual
  accepted set.
- README.md: netboot_artifacts_ready is dispatched from
  post_create_rootfs_archive__100_netboot_deploy, not from
  pre_umount_final_image__900_collect_netboot_artifacts.

Assisted-by: Claude:claude-opus-4-7
Address coderabbitai round 2026-04-22 21:43:

- netboot.sh: fail-fast when ROOTFS_EXPORT_DIR is relative; the
  Docker bind-mount at host_pre_docker_launch needs an absolute
  path and would otherwise error out long after config prep.
- README.md /etc/exports: replace wildcard '*' exports with an
  example 192.168.1.0/24 subnet placeholder and note that
  no_root_squash means the export MUST be restricted to trusted
  hosts. Copying the previous example into production gave
  root-equivalent write access to anyone who could reach NFS.
- README.md firstlogin: document the conditional suppression
  accurately. The extension removes /root/.not_logged_in_yet only
  when empty; a non-empty trigger file is kept so preset-firstrun
  can apply PRESET_* values non-interactively. Troubleshooting
  note updated to distinguish stale images from intentionally
  preserved preset files.

Assisted-by: Claude:claude-opus-4-7
The earlier /etc/exports section was updated to use a subnet
placeholder; the helios64 walk-through still copied wildcard '*'
with no_root_squash. Align the two so readers cannot paste the
unsafe form into production by following the step-by-step.

Assisted-by: Claude:claude-opus-4-7
@iav iav force-pushed the enh/netboot-extension branch from ee8e0e7 to 88c8e6f Compare April 23, 2026 00:20
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@extensions/netboot/netboot.sh`:
- Around line 188-200: The conditional and assignments that reference
BOOT_FDT_FILE must use a safe fallback expansion to avoid unbound-variable
errors under set -u; update all occurrences that read BOOT_FDT_FILE in this
block (the conditional, the declare fdt_file assignment, and the .dts check) to
use parameter expansion with a default (e.g. ${BOOT_FDT_FILE-}) so the test [[
-n ... ]] and subsequent logic can fall through to setting fdt_line="FDTDIR
${NETBOOT_TFTP_PREFIX}/dtb" when BOOT_FDT_FILE is unset.

In `@lib/functions/image/rootfs-to-image.sh`:
- Around line 147-162: Reject and normalize dangerous ROOTFS_EXPORT_DIR values
before creating or rsyncing: compute a canonical path (e.g. with realpath -m or
similar) and if the result is empty, "/" or otherwise equals the host root or SD
card root (compare against "$SDCARD" and "/"), abort with a clear error via
display_alert and non-zero exit; add this guard immediately before the
run_host_command_logged mkdir -pv "${ROOTFS_EXPORT_DIR}" and before the rsync
invocation so the run_host_command_logged mkdir and the rsync -aHWh --delete
--delete-excluded ... "$SDCARD/" "${ROOTFS_EXPORT_DIR}/" never run with a
dangerous target.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e9d5e2a3-2e6e-4178-94ba-bd86daa392f4

📥 Commits

Reviewing files that changed from the base of the PR and between 3b1129e and ee8e0e7.

📒 Files selected for processing (6)
  • config/templates/nfs-boot.cmd.template
  • extensions/netboot/README.md
  • extensions/netboot/netboot.sh
  • lib/functions/configuration/main-config.sh
  • lib/functions/image/partitioning.sh
  • lib/functions/image/rootfs-to-image.sh

Comment thread extensions/netboot/netboot.sh
Comment thread lib/functions/image/rootfs-to-image.sh
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (1)
lib/functions/image/rootfs-to-image.sh (1)

147-170: ⚠️ Potential issue | 🟠 Major

Also reject export paths that resolve to the live rootfs.

The guard rejects /, but ROOTFS_EXPORT_DIR can still resolve to ${SDCARD}, ${MOUNT}, or a child of either. With rsync --delete --delete-excluded, that can delete excluded paths from the rootfs being archived/exported or recurse into the export directory itself. This is the same dangerous-target class previously flagged, but the source/mount checks are still missing.

Proposed guard extension
 			declare rootfs_export_dir_resolved
 			rootfs_export_dir_resolved="$(realpath -m "${ROOTFS_EXPORT_DIR}")"
-			if [[ "${rootfs_export_dir_resolved}" == "/" ]]; then
-				exit_with_error "ROOTFS_EXPORT_DIR must not resolve to /" "${ROOTFS_EXPORT_DIR}"
+			declare rootfs_source_resolved rootfs_mount_resolved
+			rootfs_source_resolved="$(realpath -m "${SDCARD}")"
+			rootfs_mount_resolved="$(realpath -m "${MOUNT}")"
+			if [[ "${rootfs_export_dir_resolved}" == "/" ||
+				"${rootfs_export_dir_resolved}" == "${rootfs_source_resolved}" ||
+				"${rootfs_export_dir_resolved}" == "${rootfs_source_resolved}/"* ||
+				"${rootfs_export_dir_resolved}" == "${rootfs_mount_resolved}" ||
+				"${rootfs_export_dir_resolved}" == "${rootfs_mount_resolved}/"* ]]; then
+				exit_with_error "ROOTFS_EXPORT_DIR must not resolve to / or the live rootfs tree" "${ROOTFS_EXPORT_DIR}"
 			fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/functions/image/rootfs-to-image.sh` around lines 147 - 170, The current
guard only rejects "/" but must also reject export paths that resolve to the
live rootfs/mounts; update the check after
rootfs_export_dir_resolved="$(realpath -m "${ROOTFS_EXPORT_DIR}")" to compute
resolved paths for "${SDCARD}" and "${MOUNT}" (e.g., sdcard_resolved and
mount_resolved via realpath -m) and fail if rootfs_export_dir_resolved equals
either of those or is a descendant (prefix) of either (use a trailing-slash
prefix comparison to avoid partial matches); call exit_with_error with a clear
message if the export target is the same as or inside SDCARD or MOUNT before
running run_host_command_logged and rsync to prevent destructive --delete
behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@extensions/netboot/netboot.sh`:
- Around line 193-199: The PXE stanza normalization sets fdt_file from
BOOT_FDT_FILE but doesn't verify the compiled ${fdt_file} actually exists under
${NETBOOT_TFTP_PREFIX}/dtb; add a validation step inside the existing if [[ -n
"${BOOT_FDT_FILE:-}" ... ]] block (where fdt_file is derived) to check for the
file's presence in the dtb tree and if missing emit a clear error via
echo/process logger and exit non‑zero so the build fails fast; reference
BOOT_FDT_FILE, fdt_file, NETBOOT_TFTP_PREFIX and the dtb/ destination when
implementing the existence check and failure path.

In `@extensions/netboot/README.md`:
- Line 75: The README currently documents NETBOOT_TFTP_OUT as pointing to
output/images but the implementation stages it at
${FINALDEST}/${version}-netboot-tftp; update the NETBOOT_TFTP_OUT description to
read "Absolute path of the staging directory
(${FINALDEST}/${version}-netboot-tftp)" and replace any other occurrences that
hard-code "output/images/<version>-netboot-tftp" (the other instances in the
same README) to use ${FINALDEST}/${version}-netboot-tftp so docs match the
actual behavior.

In `@lib/functions/image/rootfs-to-image.sh`:
- Around line 108-115: The comment and error message for accepted ROOTFS
compression values are inconsistent: the case handler accepts "zst" but the top
comment and the exit_with_error message only advertise "gzip|zstd|none"; update
the human-facing text to include "zst" everywhere. Edit the comment line that
lists accepted values and the exit_with_error call that mentions expected:
gzip|zstd|none to include zst (e.g., gzip|zstd|zst|none) so the
ROOTFS_COMPRESSION, rootfs_compression case and error paths are consistent.

---

Duplicate comments:
In `@lib/functions/image/rootfs-to-image.sh`:
- Around line 147-170: The current guard only rejects "/" but must also reject
export paths that resolve to the live rootfs/mounts; update the check after
rootfs_export_dir_resolved="$(realpath -m "${ROOTFS_EXPORT_DIR}")" to compute
resolved paths for "${SDCARD}" and "${MOUNT}" (e.g., sdcard_resolved and
mount_resolved via realpath -m) and fail if rootfs_export_dir_resolved equals
either of those or is a descendant (prefix) of either (use a trailing-slash
prefix comparison to avoid partial matches); call exit_with_error with a clear
message if the export target is the same as or inside SDCARD or MOUNT before
running run_host_command_logged and rsync to prevent destructive --delete
behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 486fa577-2c72-4fae-b71d-d9b68e2fb384

📥 Commits

Reviewing files that changed from the base of the PR and between 3b1129e and ce251b8.

📒 Files selected for processing (6)
  • config/templates/nfs-boot.cmd.template
  • extensions/netboot/README.md
  • extensions/netboot/netboot.sh
  • lib/functions/configuration/main-config.sh
  • lib/functions/image/partitioning.sh
  • lib/functions/image/rootfs-to-image.sh
🚧 Files skipped from review as they are similar to previous changes (2)
  • lib/functions/configuration/main-config.sh
  • config/templates/nfs-boot.cmd.template

Comment thread extensions/netboot/netboot.sh
Comment thread extensions/netboot/README.md Outdated
Comment thread lib/functions/image/rootfs-to-image.sh Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (1)
lib/functions/image/rootfs-to-image.sh (1)

147-170: ⚠️ Potential issue | 🟠 Major

Complete the ROOTFS_EXPORT_DIR safety guard for source aliases.

The guard rejects /, but rsync --delete --delete-excluded "$SDCARD/" "$ROOTFS_EXPORT_DIR/" is still dangerous if the export path resolves to ${SDCARD}, ${MOUNT}, or a child of either. In those cases the receiver is the staged rootfs itself or inside it, so excluded paths like /boot//home can be deleted or recursively copied.

🛡️ Proposed guard
 			declare rootfs_export_dir_resolved
 			rootfs_export_dir_resolved="$(realpath -m "${ROOTFS_EXPORT_DIR}")"
-			if [[ "${rootfs_export_dir_resolved}" == "/" ]]; then
-				exit_with_error "ROOTFS_EXPORT_DIR must not resolve to /" "${ROOTFS_EXPORT_DIR}"
+			declare sdcard_resolved mount_resolved
+			sdcard_resolved="$(realpath -m "${SDCARD}")"
+			mount_resolved="$(realpath -m "${MOUNT}")"
+			if [[ "${rootfs_export_dir_resolved}" == "/" ||
+				"${rootfs_export_dir_resolved}" == "${sdcard_resolved}" ||
+				"${rootfs_export_dir_resolved}" == "${sdcard_resolved}/"* ||
+				"${rootfs_export_dir_resolved}" == "${mount_resolved}" ||
+				"${rootfs_export_dir_resolved}" == "${mount_resolved}/"* ]]; then
+				exit_with_error "ROOTFS_EXPORT_DIR must not resolve to /, SDCARD, MOUNT, or a child of them" "${ROOTFS_EXPORT_DIR}"
 			fi

Run this read-only check to confirm the current guard only rejects / and has no source-alias checks:

#!/bin/bash
# Description: Inspect ROOTFS_EXPORT_DIR validation in rootfs-to-image.sh.
# Expected before fix: only "/" is rejected.
# Expected after fix: SDCARD/MOUNT equality and child-path checks are present.

fd -i '^rootfs-to-image\.sh$' -x awk 'NR>=147 && NR<=170 { printf "%s:%d:%s\n", FILENAME, NR, $0 }' {}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/functions/image/rootfs-to-image.sh` around lines 147 - 170, The current
safety guard only rejects "/" via rootfs_export_dir_resolved but misses cases
where ROOTFS_EXPORT_DIR points at or inside the source (SDCARD or MOUNT), which
makes the rsync (in the rsync ... "$SDCARD/" "${rootfs_export_dir_resolved}/")
destructive; update the validation around rootfs_export_dir_resolved to also
realpath -m SDCARD and MOUNT into variables (e.g. sdcard_resolved,
mount_resolved) and then reject if rootfs_export_dir_resolved equals or is a
descendant of either (string-equals or prefix-with-slash checks to avoid false
matches), calling exit_with_error (same message style) when detected; keep using
run_host_command_logged and the existing rsync logic otherwise.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@extensions/netboot/netboot.sh`:
- Around line 80-84: The path validation for ROOTFS_EXPORT_DIR is insufficient
and can allow dangerous values like "/" or the build checkout (SRC) which rsync
--delete could wipe; update the validation in the netboot export logic to reject
ROOTFS_EXPORT_DIR when it is "/" or when it resolves to the same path as the
source/checkout (SRC), and also reject empty when ROOTFS_COMPRESSION="none" as
before; use the existing exit_with_error call to fail with a clear message
referencing EXTENSION and ROOTFS_EXPORT_DIR when the value is "/" or equals SRC
(or resolves to it), and ensure you perform resolution/comparison (realpath or
equivalent) before comparing to avoid symlink tricks.

In `@extensions/netboot/README.md`:
- Line 65: The README's ROOTFS_COMPRESSION documentation and any workflow text
referencing accepted values should be updated to include the accepted alias
"zst" in addition to "zstd" (e.g., list as "gzip|zstd|zst|none"); specifically
update the variable table entry for ROOTFS_COMPRESSION and any mentions around
the create_image_from_sdcard_rootfs workflow so they advertise "zst" as a valid
value alongside "zstd".
- Line 80: The README incorrectly calls NETBOOT_CLIENT_MAC and NETBOOT_HOSTNAME
"sanitized" values; update the text to state that NETBOOT_CLIENT_MAC is the
original user-provided value and that any normalized/cleaned MAC is exposed via
NETBOOT_PXE_FILE (or another appropriate variable), and clarify NETBOOT_HOSTNAME
is the extension-used hostname rather than a sanitized hook value; edit the
table row describing `NETBOOT_HOSTNAME, NETBOOT_CLIENT_MAC` to explicitly
distinguish "user-provided/raw" vs "normalized/used by extension
(NETBOOT_PXE_FILE)" and adjust wording accordingly.

---

Duplicate comments:
In `@lib/functions/image/rootfs-to-image.sh`:
- Around line 147-170: The current safety guard only rejects "/" via
rootfs_export_dir_resolved but misses cases where ROOTFS_EXPORT_DIR points at or
inside the source (SDCARD or MOUNT), which makes the rsync (in the rsync ...
"$SDCARD/" "${rootfs_export_dir_resolved}/") destructive; update the validation
around rootfs_export_dir_resolved to also realpath -m SDCARD and MOUNT into
variables (e.g. sdcard_resolved, mount_resolved) and then reject if
rootfs_export_dir_resolved equals or is a descendant of either (string-equals or
prefix-with-slash checks to avoid false matches), calling exit_with_error (same
message style) when detected; keep using run_host_command_logged and the
existing rsync logic otherwise.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 49bee0c1-488d-4f80-8b38-daede5b3bc82

📥 Commits

Reviewing files that changed from the base of the PR and between 3b1129e and a5afeab.

📒 Files selected for processing (6)
  • config/templates/nfs-boot.cmd.template
  • extensions/netboot/README.md
  • extensions/netboot/netboot.sh
  • lib/functions/configuration/main-config.sh
  • lib/functions/image/partitioning.sh
  • lib/functions/image/rootfs-to-image.sh
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/functions/configuration/main-config.sh

Comment thread extensions/netboot/netboot.sh Outdated
Comment on lines +80 to +84
if [[ -n "${ROOTFS_EXPORT_DIR}" && "${ROOTFS_EXPORT_DIR}" != /* ]]; then
exit_with_error "${EXTENSION}: ROOTFS_EXPORT_DIR must be an absolute path (got '${ROOTFS_EXPORT_DIR}')"
fi
if [[ "${ROOTFS_COMPRESSION}" == "none" && -z "${ROOTFS_EXPORT_DIR}" ]]; then
exit_with_error "${EXTENSION}: ROOTFS_COMPRESSION=none requires ROOTFS_EXPORT_DIR (otherwise nothing is produced)"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Reject export targets that can be wiped by rsync --delete.

ROOTFS_EXPORT_DIR=/ or ROOTFS_EXPORT_DIR=${SRC} passes the current absolute-path validation; the latter is later translated to /armbian in Docker. Since the export flow uses delete-sync semantics, these values can erase the container root or the build checkout instead of only refreshing an NFS export tree.

🛡️ Proposed validation hardening
-	if [[ -n "${ROOTFS_EXPORT_DIR}" && "${ROOTFS_EXPORT_DIR}" != /* ]]; then
-		exit_with_error "${EXTENSION}: ROOTFS_EXPORT_DIR must be an absolute path (got '${ROOTFS_EXPORT_DIR}')"
+	if [[ -n "${ROOTFS_EXPORT_DIR}" ]]; then
+		if [[ "${ROOTFS_EXPORT_DIR}" != /* ]]; then
+			exit_with_error "${EXTENSION}: ROOTFS_EXPORT_DIR must be an absolute path (got '${ROOTFS_EXPORT_DIR}')"
+		fi
+		if [[ "${ROOTFS_EXPORT_DIR}" == "/" || "${ROOTFS_EXPORT_DIR%/}" == "${SRC%/}" ]]; then
+			exit_with_error "${EXTENSION}: ROOTFS_EXPORT_DIR must point to a dedicated export directory" "${ROOTFS_EXPORT_DIR}"
+		fi
 	fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if [[ -n "${ROOTFS_EXPORT_DIR}" && "${ROOTFS_EXPORT_DIR}" != /* ]]; then
exit_with_error "${EXTENSION}: ROOTFS_EXPORT_DIR must be an absolute path (got '${ROOTFS_EXPORT_DIR}')"
fi
if [[ "${ROOTFS_COMPRESSION}" == "none" && -z "${ROOTFS_EXPORT_DIR}" ]]; then
exit_with_error "${EXTENSION}: ROOTFS_COMPRESSION=none requires ROOTFS_EXPORT_DIR (otherwise nothing is produced)"
if [[ -n "${ROOTFS_EXPORT_DIR}" ]]; then
if [[ "${ROOTFS_EXPORT_DIR}" != /* ]]; then
exit_with_error "${EXTENSION}: ROOTFS_EXPORT_DIR must be an absolute path (got '${ROOTFS_EXPORT_DIR}')"
fi
if [[ "${ROOTFS_EXPORT_DIR}" == "/" || "${ROOTFS_EXPORT_DIR%/}" == "${SRC%/}" ]]; then
exit_with_error "${EXTENSION}: ROOTFS_EXPORT_DIR must point to a dedicated export directory" "${ROOTFS_EXPORT_DIR}"
fi
fi
if [[ "${ROOTFS_COMPRESSION}" == "none" && -z "${ROOTFS_EXPORT_DIR}" ]]; then
exit_with_error "${EXTENSION}: ROOTFS_COMPRESSION=none requires ROOTFS_EXPORT_DIR (otherwise nothing is produced)"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@extensions/netboot/netboot.sh` around lines 80 - 84, The path validation for
ROOTFS_EXPORT_DIR is insufficient and can allow dangerous values like "/" or the
build checkout (SRC) which rsync --delete could wipe; update the validation in
the netboot export logic to reject ROOTFS_EXPORT_DIR when it is "/" or when it
resolves to the same path as the source/checkout (SRC), and also reject empty
when ROOTFS_COMPRESSION="none" as before; use the existing exit_with_error call
to fail with a clear message referencing EXTENSION and ROOTFS_EXPORT_DIR when
the value is "/" or equals SRC (or resolves to it), and ensure you perform
resolution/comparison (realpath or equivalent) before comparing to avoid symlink
tricks.

| `NETBOOT_NFS_PATH` | see below | Absolute NFS path of the rootfs on the server. The APPEND line uses exactly this string for `nfsroot=...`. |
| `NETBOOT_HOSTNAME` | _(empty)_ | Per-host deployment. When set, the default `NETBOOT_NFS_PATH` becomes `/srv/netboot/rootfs/hosts/<hostname>` — each machine owns its own writable rootfs copy. When empty, the default is `/srv/netboot/rootfs/shared/${LINUXFAMILY}/${BOARD}/${BRANCH}-${RELEASE}` (one image, potentially reused by identical boards). |
| `NETBOOT_CLIENT_MAC` | _(empty)_ | Client MAC (`aa:bb:cc:dd:ee:ff` or `aa-bb-cc-dd-ee-ff`). When set, the PXE config is written as `pxelinux.cfg/01-<mac>` (the PXELINUX per-MAC override) instead of `default.example`; multiple boards then coexist on one TFTP root, each picking its own extlinux. |
| `ROOTFS_COMPRESSION` | `zstd` | Format of the rootfs archive produced by `create_image_from_sdcard_rootfs`. `zstd` → `.tar.zst`, `gzip` → `.tar.gz`, `none` → no archive at all. The `none` case requires `ROOTFS_EXPORT_DIR`. |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Include the accepted zst alias in the README.

The implementation accepts ROOTFS_COMPRESSION=zst, but the variable table and workflow text only advertise gzip|zstd|none.

📝 Proposed documentation fix
-| `ROOTFS_COMPRESSION` | `zstd` | Format of the rootfs archive produced by `create_image_from_sdcard_rootfs`. `zstd` → `.tar.zst`, `gzip` → `.tar.gz`, `none` → no archive at all. The `none` case requires `ROOTFS_EXPORT_DIR`. |
+| `ROOTFS_COMPRESSION` | `zstd` | Format of the rootfs archive produced by `create_image_from_sdcard_rootfs`. `zstd`/`zst` → `.tar.zst`, `gzip` → `.tar.gz`, `none` → no archive at all. The `none` case requires `ROOTFS_EXPORT_DIR`. |
@@
-  Use `ROOTFS_COMPRESSION=gzip|zstd` and rsync/ssh the archive via a
+  Use `ROOTFS_COMPRESSION=gzip|zstd|zst` and rsync/ssh the archive via a

Also applies to: 315-317

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@extensions/netboot/README.md` at line 65, The README's ROOTFS_COMPRESSION
documentation and any workflow text referencing accepted values should be
updated to include the accepted alias "zst" in addition to "zstd" (e.g., list as
"gzip|zstd|zst|none"); specifically update the variable table entry for
ROOTFS_COMPRESSION and any mentions around the create_image_from_sdcard_rootfs
workflow so they advertise "zst" as a valid value alongside "zstd".

| `NETBOOT_NFS_PATH` | As above. |
| `NETBOOT_PXE_FILE` | `default.example` or `01-<mac>` — the file that was written under `pxelinux.cfg/`. |
| `NETBOOT_ROOTFS_ARCHIVE` | Full path to the produced rootfs archive (empty when `ROOTFS_COMPRESSION=none`). |
| `NETBOOT_HOSTNAME`, `NETBOOT_CLIENT_MAC` | The sanitized values the extension used. |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Do not describe raw hook values as sanitized.

NETBOOT_CLIENT_MAC remains the user-provided value; the normalized value is reflected in NETBOOT_PXE_FILE. This wording can mislead hook authors.

📝 Proposed documentation fix
-| `NETBOOT_HOSTNAME`, `NETBOOT_CLIENT_MAC` | The sanitized values the extension used. |
+| `NETBOOT_HOSTNAME`, `NETBOOT_CLIENT_MAC` | The hostname and original MAC value supplied to the extension. Use `NETBOOT_PXE_FILE` for the normalized per-MAC PXE filename. |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@extensions/netboot/README.md` at line 80, The README incorrectly calls
NETBOOT_CLIENT_MAC and NETBOOT_HOSTNAME "sanitized" values; update the text to
state that NETBOOT_CLIENT_MAC is the original user-provided value and that any
normalized/cleaned MAC is exposed via NETBOOT_PXE_FILE (or another appropriate
variable), and clarify NETBOOT_HOSTNAME is the extension-used hostname rather
than a sanitized hook value; edit the table row describing `NETBOOT_HOSTNAME,
NETBOOT_CLIENT_MAC` to explicitly distinguish "user-provided/raw" vs
"normalized/used by extension (NETBOOT_PXE_FILE)" and adjust wording
accordingly.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (3)
lib/functions/image/rootfs-to-image.sh (1)

147-162: ⚠️ Potential issue | 🟠 Major

Validate ROOTFS_EXPORT_DIR before running destructive rsync.

Line 154 runs rsync --delete --delete-excluded against a raw user path. If ROOTFS_EXPORT_DIR resolves to /, ${SDCARD}, ${MOUNT}, or a child of the source tree, this can delete host/container files or the build rootfs itself. Keep the guard at the destructive operation site so it covers both ROOTFS_TYPE=nfs and ROOTFS_TYPE=nfs-root.

🛡️ Proposed guard
 		if [[ -n "${ROOTFS_EXPORT_DIR}" ]]; then
-			display_alert "Exporting rootfs tree" "${ROOTFS_EXPORT_DIR}" "info"
-			run_host_command_logged mkdir -pv "${ROOTFS_EXPORT_DIR}"
+			declare rootfs_export_dir_resolved sdcard_resolved mount_resolved
+			rootfs_export_dir_resolved="$(realpath -m "${ROOTFS_EXPORT_DIR}")"
+			sdcard_resolved="$(realpath -m "${SDCARD}")"
+			mount_resolved="$(realpath -m "${MOUNT}")"
+
+			case "${rootfs_export_dir_resolved}" in
+				/ | "${sdcard_resolved}" | "${sdcard_resolved}/"* | "${mount_resolved}" | "${mount_resolved}/"*)
+					exit_with_error "Refusing unsafe ROOTFS_EXPORT_DIR" "${ROOTFS_EXPORT_DIR} resolves to ${rootfs_export_dir_resolved}"
+					;;
+			esac
+
+			display_alert "Exporting rootfs tree" "${rootfs_export_dir_resolved}" "info"
+			run_host_command_logged mkdir -pv "${rootfs_export_dir_resolved}"
 			# --delete so files removed from the source rootfs don't survive in a
 			# reused export tree (otherwise the NFS root silently drifts from the image).
 			# --delete-excluded additionally purges receiver-side files that match our
 			# excludes (e.g. stale /home/* left over from a prior INCLUDE_HOME_DIR=yes build).
@@
 				--exclude="/tmp/*" \
 				--exclude="/sys/*" \
 				$exclude_home \
-				--info=progress0,stats1 "$SDCARD/" "${ROOTFS_EXPORT_DIR}/"
+				--info=progress0,stats1 "$SDCARD/" "${rootfs_export_dir_resolved}/"
 		fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/functions/image/rootfs-to-image.sh` around lines 147 - 162, Add a safety
check immediately before the destructive rsync invocation that verifies
ROOTFS_EXPORT_DIR is a sane, non-root, non-source path: ensure ROOTFS_EXPORT_DIR
is non-empty, absolute, not "/" and not equal to or a parent/child of the source
variables (SDCARD or MOUNT/build rootfs), and fail early with a clear error if
it does; implement this guard in the same scope around the rsync call (the block
that calls run_host_command_logged rsync) so it covers both ROOTFS_TYPE=nfs and
nfs-root scenarios and prevents accidental deletes of host/container files.
extensions/netboot/README.md (2)

80-80: ⚠️ Potential issue | 🟡 Minor

Do not call raw hook values sanitized.

NETBOOT_CLIENT_MAC remains the user-supplied value; the normalized MAC is represented by NETBOOT_PXE_FILE when a per-MAC PXE filename is generated.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@extensions/netboot/README.md` at line 80, Update the README description to
stop implying hook outputs are sanitized: clarify that NETBOOT_CLIENT_MAC is the
raw user-supplied MAC and not normalized, and that any normalized/per-MAC PXE
filename is provided via NETBOOT_PXE_FILE; adjust the table row mentioning
`NETBOOT_HOSTNAME`, `NETBOOT_CLIENT_MAC` to explicitly state that
`NETBOOT_CLIENT_MAC` is the original user value and `NETBOOT_PXE_FILE` contains
the normalized/derived PXE filename when applicable.

65-65: ⚠️ Potential issue | 🟡 Minor

Include the accepted zst alias in the README.

The implementation accepts ROOTFS_COMPRESSION=zst, but the variable table and workflow text still advertise only gzip|zstd|none.

Also applies to: 315-317

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@extensions/netboot/README.md` at line 65, Update the README entries that
document the ROOTFS_COMPRESSION variable and the workflow text around
create_image_from_sdcard_rootfs to include the accepted alias "zst" alongside
"zstd", i.e. advertise accepted values as gzip|zstd|zst|none; ensure both the
variable table cell and any prose that lists allowed values (including the
paragraphs covering create_image_from_sdcard_rootfs) mention "zst" so the docs
match the implementation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@extensions/netboot/netboot.sh`:
- Line 62: Reject any path-traversal in NETBOOT_TFTP_PREFIX before using it to
build tftp_prefix_dir and before calling mkdir/cp: validate NETBOOT_TFTP_PREFIX
(and any places where it’s re-read at the later block around the logic currently
at lines 171-174) to ensure it is not empty, does not contain “..” segments or
leading “/”, and only contains safe characters (letters, digits, -, _, /). If
needed, normalize it to remove redundant slashes and resolve/deny any ..
segments (or refuse the value) and then construct tftp_prefix_dir by joining the
validated prefix to the known netboot staging root so mkdir/cp cannot write
outside the staging area; also mirror this validation when composing PXE paths
to avoid generating unusable paths.
- Around line 104-113: The normalize function rewrites container-side bind-mount
targets like /armbian/netboot-export into ${SRC}/output/netboot-export/...
causing rsync to miss the mounted path; update _netboot_normalize_export_dir to
treat the Docker bind-mount target as already normalized by returning early when
ROOTFS_EXPORT_DIR is exactly /armbian/netboot-export or starts with
/armbian/netboot-export/ (in addition to the existing check for
${SRC}/output/netboot-export/), and apply the same guard in the analogous logic
around the other occurrence (lines ~153-164) so in-container config prep
preserves the bind-mount target instead of prefixing
${SRC}/output/netboot-export/.

In `@extensions/netboot/README.md`:
- Line 66: Update the ROOTFS_EXPORT_DIR documentation to reflect the confinement
behavior: explain that any path is rewritten into ${SRC}/output/netboot-export/,
so setting ROOTFS_EXPORT_DIR=/srv/netboot/rootfs/... will not populate
/srv/netboot/rootfs/... directly; instead document two supported workflows—(a)
specify a relative subpath inside ROOTFS_EXPORT_DIR (e.g.
ROOTFS_EXPORT_DIR=relative/path) and then create or document a host-side symlink
or NFS export that maps ${SRC}/output/netboot-export/relative/path →
/srv/netboot/rootfs, or (b) keep ROOTFS_EXPORT_DIR as an absolute host path but
explicitly state that the NFS server must export the confined directory
${SRC}/output/netboot-export/... (i.e., export the rewritten path). Update the
paragraph describing ROOTFS_EXPORT_DIR and the corresponding guidance around
lines 274-299 to include this behavior and example commands or symlink/export
notes.

---

Duplicate comments:
In `@extensions/netboot/README.md`:
- Line 80: Update the README description to stop implying hook outputs are
sanitized: clarify that NETBOOT_CLIENT_MAC is the raw user-supplied MAC and not
normalized, and that any normalized/per-MAC PXE filename is provided via
NETBOOT_PXE_FILE; adjust the table row mentioning `NETBOOT_HOSTNAME`,
`NETBOOT_CLIENT_MAC` to explicitly state that `NETBOOT_CLIENT_MAC` is the
original user value and `NETBOOT_PXE_FILE` contains the normalized/derived PXE
filename when applicable.
- Line 65: Update the README entries that document the ROOTFS_COMPRESSION
variable and the workflow text around create_image_from_sdcard_rootfs to include
the accepted alias "zst" alongside "zstd", i.e. advertise accepted values as
gzip|zstd|zst|none; ensure both the variable table cell and any prose that lists
allowed values (including the paragraphs covering
create_image_from_sdcard_rootfs) mention "zst" so the docs match the
implementation.

In `@lib/functions/image/rootfs-to-image.sh`:
- Around line 147-162: Add a safety check immediately before the destructive
rsync invocation that verifies ROOTFS_EXPORT_DIR is a sane, non-root, non-source
path: ensure ROOTFS_EXPORT_DIR is non-empty, absolute, not "/" and not equal to
or a parent/child of the source variables (SDCARD or MOUNT/build rootfs), and
fail early with a clear error if it does; implement this guard in the same scope
around the rsync call (the block that calls run_host_command_logged rsync) so it
covers both ROOTFS_TYPE=nfs and nfs-root scenarios and prevents accidental
deletes of host/container files.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4833b431-e485-46e9-ad62-6393c9235918

📥 Commits

Reviewing files that changed from the base of the PR and between 3b1129e and 3022e9b.

📒 Files selected for processing (6)
  • config/templates/nfs-boot.cmd.template
  • extensions/netboot/README.md
  • extensions/netboot/netboot.sh
  • lib/functions/configuration/main-config.sh
  • lib/functions/image/partitioning.sh
  • lib/functions/image/rootfs-to-image.sh

# Declared unconditionally so later `[[ -n "${NETBOOT_CLIENT_MAC_NORMALIZED}" ]]`
# checks remain safe under `set -u` when no MAC is configured.
declare -g NETBOOT_CLIENT_MAC_NORMALIZED=""
declare -g NETBOOT_TFTP_PREFIX="${NETBOOT_TFTP_PREFIX:-armbian/${LINUXFAMILY}/${BOARD}/${BRANCH}-${RELEASE}}"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Reject traversal in NETBOOT_TFTP_PREFIX before staging files.

NETBOOT_TFTP_PREFIX flows into tftp_prefix_dir; values like ../../foo can make mkdir/cp write outside the netboot staging directory and also generate unusable PXE paths.

🛡️ Proposed validation
 	declare -g NETBOOT_TFTP_PREFIX="${NETBOOT_TFTP_PREFIX:-armbian/${LINUXFAMILY}/${BOARD}/${BRANCH}-${RELEASE}}"
+	case "${NETBOOT_TFTP_PREFIX}" in
+		"" | /* | . | .. | ../* | */../* | */..)
+			exit_with_error "${EXTENSION}: NETBOOT_TFTP_PREFIX must be a relative path inside the TFTP root" "${NETBOOT_TFTP_PREFIX}"
+			;;
+	esac
 
 	if [[ -n "${NETBOOT_HOSTNAME}" ]]; then

Also applies to: 171-174

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@extensions/netboot/netboot.sh` at line 62, Reject any path-traversal in
NETBOOT_TFTP_PREFIX before using it to build tftp_prefix_dir and before calling
mkdir/cp: validate NETBOOT_TFTP_PREFIX (and any places where it’s re-read at the
later block around the logic currently at lines 171-174) to ensure it is not
empty, does not contain “..” segments or leading “/”, and only contains safe
characters (letters, digits, -, _, /). If needed, normalize it to remove
redundant slashes and resolve/deny any .. segments (or refuse the value) and
then construct tftp_prefix_dir by joining the validated prefix to the known
netboot staging root so mkdir/cp cannot write outside the staging area; also
mirror this validation when composing PXE paths to avoid generating unusable
paths.

Comment on lines +104 to +113
function _netboot_normalize_export_dir() {
[[ -z "${ROOTFS_EXPORT_DIR}" ]] && return 0
# Already normalized — extension_prepare_config may fire after host_pre_docker_launch
# has already run on the host side.
[[ "${ROOTFS_EXPORT_DIR}" == "${SRC}/output/netboot-export/"* ]] && return 0
case "${ROOTFS_EXPORT_DIR}" in
*..*) exit_with_error "${EXTENSION}: ROOTFS_EXPORT_DIR must not contain '..'" "${ROOTFS_EXPORT_DIR}" ;;
esac
declare -g ROOTFS_EXPORT_DIR="${SRC}/output/netboot-export/${ROOTFS_EXPORT_DIR}"
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Preserve the Docker bind-mount target during in-container config prep.

host_pre_docker_launch__netboot_mount_export_dir exports ROOTFS_EXPORT_DIR=/armbian/netboot-export, but _netboot_normalize_export_dir does not treat that as already normalized. When extension_prepare_config runs in the container, it rewrites the value to ${SRC}/output/netboot-export//armbian/netboot-export, so rsync no longer writes to the bind mount.

🐛 Proposed fix
 function _netboot_normalize_export_dir() {
 	[[ -z "${ROOTFS_EXPORT_DIR}" ]] && return 0
+	declare container_export_dir="${NETBOOT_CONTAINER_EXPORT_DIR:-/armbian/netboot-export}"
+	[[ "${ROOTFS_EXPORT_DIR}" == "${container_export_dir}" || "${ROOTFS_EXPORT_DIR}" == "${container_export_dir}/"* ]] && return 0
 	# Already normalized — extension_prepare_config may fire after host_pre_docker_launch
 	# has already run on the host side.
 	[[ "${ROOTFS_EXPORT_DIR}" == "${SRC}/output/netboot-export/"* ]] && return 0
@@
 	# Host-phase normalization: extension_prepare_config runs inside the container,
 	# which is too late — docker needs an absolute source path for the bind-mount below.
 	_netboot_normalize_export_dir
-	declare container_export_dir="/armbian/netboot-export"
+	declare container_export_dir="${NETBOOT_CONTAINER_EXPORT_DIR:-/armbian/netboot-export}"

Also applies to: 153-164

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@extensions/netboot/netboot.sh` around lines 104 - 113, The normalize function
rewrites container-side bind-mount targets like /armbian/netboot-export into
${SRC}/output/netboot-export/... causing rsync to miss the mounted path; update
_netboot_normalize_export_dir to treat the Docker bind-mount target as already
normalized by returning early when ROOTFS_EXPORT_DIR is exactly
/armbian/netboot-export or starts with /armbian/netboot-export/ (in addition to
the existing check for ${SRC}/output/netboot-export/), and apply the same guard
in the analogous logic around the other occurrence (lines ~153-164) so
in-container config prep preserves the bind-mount target instead of prefixing
${SRC}/output/netboot-export/.

| `NETBOOT_HOSTNAME` | _(empty)_ | Per-host deployment. When set, the default `NETBOOT_NFS_PATH` becomes `/srv/netboot/rootfs/hosts/<hostname>` — each machine owns its own writable rootfs copy. When empty, the default is `/srv/netboot/rootfs/shared/${LINUXFAMILY}/${BOARD}/${BRANCH}-${RELEASE}` (one image, potentially reused by identical boards). |
| `NETBOOT_CLIENT_MAC` | _(empty)_ | Client MAC (`aa:bb:cc:dd:ee:ff` or `aa-bb-cc-dd-ee-ff`). When set, the PXE config is written as `pxelinux.cfg/01-<mac>` (the PXELINUX per-MAC override) instead of `default.example`; multiple boards then coexist on one TFTP root, each picking its own extlinux. |
| `ROOTFS_COMPRESSION` | `zstd` | Format of the rootfs archive produced by `create_image_from_sdcard_rootfs`. `zstd` → `.tar.zst`, `gzip` → `.tar.gz`, `none` → no archive at all. The `none` case requires `ROOTFS_EXPORT_DIR`. |
| `ROOTFS_EXPORT_DIR` | _(empty)_ | Absolute path. When set, the rootfs tree is rsync'd directly into this directory in addition to (or instead of) the archive. Primary use: builder host is also the NFS server — single-step `build → boot` loop with no tar/unpack/rsync step. If this path is outside `${SRC}`, the extension bind-mounts it into the build container so the same path works on host and inside Docker. |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Align ROOTFS_EXPORT_DIR docs with the confinement behavior.

The script now rewrites any export path under ${SRC}/output/netboot-export/, so ROOTFS_EXPORT_DIR=/srv/netboot/rootfs/... does not directly populate /srv/netboot/rootfs/.... Update this workflow to either use a relative subpath plus a documented symlink/export-root setup, or state that the NFS server should export the confined output directory.

Also applies to: 274-299

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@extensions/netboot/README.md` at line 66, Update the ROOTFS_EXPORT_DIR
documentation to reflect the confinement behavior: explain that any path is
rewritten into ${SRC}/output/netboot-export/, so setting
ROOTFS_EXPORT_DIR=/srv/netboot/rootfs/... will not populate
/srv/netboot/rootfs/... directly; instead document two supported workflows—(a)
specify a relative subpath inside ROOTFS_EXPORT_DIR (e.g.
ROOTFS_EXPORT_DIR=relative/path) and then create or document a host-side symlink
or NFS export that maps ${SRC}/output/netboot-export/relative/path →
/srv/netboot/rootfs, or (b) keep ROOTFS_EXPORT_DIR as an absolute host path but
explicitly state that the NFS server must export the confined directory
${SRC}/output/netboot-export/... (i.e., export the rewritten path). Update the
paragraph describing ROOTFS_EXPORT_DIR and the corresponding guidance around
lines 274-299 to include this behavior and example commands or symlink/export
notes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

05 Milestone: Second quarter release Documentation Documentation changes or additions Framework Framework components Hardware Hardware related like kernel, U-Boot, ... Needs review Seeking for review size/large PR with 250 lines or more Work in progress Unfinished / work in progress

Development

Successfully merging this pull request may close these issues.

2 participants