Files
RedBear-OS/local/scripts/verify-tracked-sources.sh
T
vasilito fd11aa716c
redbear-ci / check (push) Has been cancelled
feat: port the missing KDE Plasma dependency chain and harden the auth stack
Unblocks plasma-workspace/plasma-desktop, which required 14 packages that had
no in-tree recipe. Sources are reproducible from each recipe's tar= + blake3;
the vendored source/ trees are deliberately not committed here (212M).

New recipes:
  KF6 6.28.0   kf6-kholidays, kf6-krunner, kf6-kstatusnotifieritem,
               kf6-kunitconversion
  Plasma 6.7.2 knighttime, layer-shell-qt, libkscreen, libksysguard,
               plasma-activities-stats, plasma5support, kscreenlocker
  Qt 6.11.1    qtpositioning, qtspeech, qttools

libksysguard carries P0-redox-process-backend.patch: processes_local_p.cpp
dispatches on platform macros and had no __redox__ arm, so ProcessesLocal was
entirely undefined. Adds a real backend reading /scheme/proc/ps (pid, ppid,
real+effective ids, thread count, state) and /scheme/sys/mem, with kill() for
signals. Upstream's generic fallback is a pure stub and was not used. Absent
facilities (no setpriority/sched_setscheduler/ioprio on a microkernel) report
NotSupported rather than pretending.

Restored, no longer disabled:
  - night colour: kcms/nighttime + kwin's nightlight plugin, now that
    KNightTime/Qt6Positioning/KF6Holidays exist
  - KIO FileWidgets (file dialog, places model), wrongly swept in with the
    unportable kiod/kssld/kioworkers subdirs
  - kf6-ktexteditor text-to-speech: removes a disguised stub that rewrote
    speechEngine() to return nullptr and mangled call sites into invalid C++
  - kwin KWIN_BUILD_SCREENLOCKER=ON (needs kscreenlocker; see below)

Toolchain and recipe fixes:
  - redox-toolchain.cmake: append -lgcc. __extendhfsf2/__extendbfsf2 are
    global in libgcc.a but hidden in libgcc_s.so (the Redox libgcc version map
    stops at GCC_7.0.0 and never emits the GCC_12/13 nodes upstream exports),
    and GCC omits -lgcc for -shared, so no C++23 shared library using
    std::format<_Float16|bfloat16_t> could link.
  - qtmultimedia: rewrite /usr/src/.../meta_types paths and stage metatypes,
    so consumers using qt_internal_add_qml_module can configure.
  - qtspeech: qtmultimedia is mandatory, not optional -- upstream return()s
    with only a NOTICE without it, yielding a green build over an empty
    package. Asserts its own output so that cannot recur.
  - narrow Linux-only guards with AND NOT REDOX where the toolchain sets
    CMAKE_SYSTEM_NAME=Linux purely to get UNIX=TRUE (kio LibMount,
    libksysguard NL/Sensors, plasma-workspace NetworkManagerQt).
  - drop REQUIRED components that are declared but referenced nowhere
    (Location, QCoro6, Qt6 Test) -- verified by exhaustive grep.
  - DESTDIR installs where KDE emits absolute KDE_INSTALL_FULL_* paths that
    --prefix cannot re-root, which otherwise write into the build host.

Auth stack:
  - pam-redbear: add PAM_MODULE_UNKNOWN (28), missing from both the header and
    lib.rs; realign 30/31 to Linux-PAM's PAM_CONV_AGAIN/PAM_INCOMPLETE, which
    previously held Red Bear-only names on standard values, so anything built
    against stock PAM headers mis-decoded them.
  - redbear-authd: support yescrypt ($y$ -- the default shadow format on
    current Debian/Ubuntu/Fedora, previously an unexplained login failure),
    bcrypt and md5-crypt. Plaintext shadow entries now require the
    /etc/redbear/allow-plaintext-passwords sentinel and warn on every use,
    instead of being compared silently. 19/19 host tests pass.

Build-system hardening:
  - verify-tracked-sources.sh, wired into preflight: fails on deletion of any
    tracked vendored source, and on modifications with no baseline entry.
    local/sources/ had a dirty gate and version checks; local/recipes/*/source/
    had none, which allowed an rm -rf to delete 7958 tracked files and a
    pristine re-extract to silently overwrite committed fixes (kwin's
    std::expected/vulkan-hpp and X11 gating, kio's Q_OS_REDOX resolver guards).
  - validate-source-trees.py: resolve recipe.toml through the overlay symlink;
    it reported false MISSING for symlinked recipes.
  - test-sddm-virgl-qemu.sh: the null-proxy check used report(), which PASSES
    on regex match -- so the known Qt6 Wayland null+8 fault would report PASS
    when present. Added report_absent().

kscreenlocker builds only its cmake-level Wayland-only changes so far; the
C++ X11 removal (61 call sites) is not yet applied, so kwin's screenlocker
flag is blocked on it.
2026-08-04 10:06:39 +03:00

223 lines
9.3 KiB
Bash
Executable File

#!/usr/bin/env bash
# verify-tracked-sources.sh — integrity gate for git-tracked vendored source trees.
#
# WHY THIS EXISTS
# ---------------
# Several recipes under local/recipes/ are "vendored forks": their source/ tree
# is committed to git and carries real Red Bear work baked directly into files
# that also exist upstream (see local/docs/VERSIONING.md, "baked shim"). That
# tree is durable state, but nothing guarded it, and two failure modes have
# actually happened:
#
# 1. DELETION. An ad-hoc `rm -rf <recipe>/source` (to force a clean
# re-extract) removes thousands of tracked files. AGENTS.md already warns
# that this "has wiped tracked local/recipes/*/source/ trees in the past".
#
# 2. SILENT OVERWRITE. For a `tar` recipe, deleting source/ makes the
# cookbook re-extract PRISTINE upstream over it. Files that exist upstream
# get their committed Red Bear edits replaced with upstream content. No
# error is raised -- the package may even still build -- so the loss ships
# as a silent regression. This is how kwin lost its std::expected /
# vulkan-hpp and X11-gating fixes, and kio lost the Q_OS_REDOX guards in
# hostinfo.cpp.
#
# Neither mode is detectable by the existing gates: verify-fork-versions.sh
# covers local/sources/ (the submodule forks), and the build-redbear.sh
# dirty-source gate likewise only looks at local/sources/. The vendored recipe
# trees carry equally durable work and had no equivalent check.
#
# WHAT IT CHECKS
# --------------
# Recipe seds legitimately rewrite tracked source files on every build (that is
# the current in-tree build model), so "modified" alone cannot mean "damaged".
# The gate therefore separates three cases:
#
# DELETED tracked file under */source/ -> ERROR, always. A build never
# legitimately deletes tracked
# source.
# MODIFIED, not in the baseline -> ERROR. Something changed a
# tracked source file that no
# recorded recipe sed accounts
# for -- the overwrite signature.
# MODIFIED, listed in the baseline -> known churn. Reported as a
# durability WARNING (this is
# uncommitted work living in a
# durable tree); escalate to an
# error with
# REDBEAR_STRICT_TRACKED_SOURCES=1.
#
# The baseline (local/tracked-source-baseline.txt) is itself tracked, so the set
# of "expected to be dirty" files is reviewable in git rather than invisible.
#
# USAGE
# verify-tracked-sources.sh [--quiet] # check (preflight mode)
# verify-tracked-sources.sh --update # regenerate the baseline
# verify-tracked-sources.sh --list # show current dirty tracked sources
#
# Bypass: REDBEAR_SKIP_TRACKED_SOURCE_CHECK=1 (emergency only).
# Escalate baseline churn to an error: REDBEAR_STRICT_TRACKED_SOURCES=1.
set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
BASELINE="$ROOT/local/tracked-source-baseline.txt"
QUIET=0
MODE=check
for arg in "$@"; do
case "$arg" in
--quiet) QUIET=1 ;;
--update) MODE=update ;;
--list) MODE=list ;;
-h|--help)
sed -n '2,60p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
exit 0 ;;
*) echo "verify-tracked-sources.sh: unknown argument '$arg'" >&2; exit 2 ;;
esac
done
say() { [ "$QUIET" -eq 1 ] || echo "$@"; }
cd "$ROOT" || exit 2
# Collect tracked files under any local/recipes/**/source/ that git reports as
# changed. -z keeps paths with spaces intact (several KDE avatar assets have
# them, which is exactly where a naive `xargs` split goes wrong).
collect() { # $1 = status filter letter (M or D)
local want="$1"
git status --porcelain -z -- local/recipes 2>/dev/null \
| while IFS= read -r -d '' entry; do
local st="${entry:0:2}" path="${entry:3}"
case "$st" in
*"$want"*) [[ "$path" == */source/* ]] && printf '%s\n' "$path" ;;
esac
done
}
mapfile -t DELETED < <(collect D | LC_ALL=C sort)
mapfile -t MODIFIED < <(collect M | LC_ALL=C sort)
if [ "$MODE" = list ]; then
printf '%s\n' "${MODIFIED[@]}" | sed '/^$/d'
exit 0
fi
if [ "$MODE" = update ]; then
{
echo "# tracked-source-baseline.txt"
echo "#"
echo "# Tracked files under local/recipes/*/source/ that are EXPECTED to differ"
echo "# from HEAD during a normal build -- almost all of it recipe-sed churn."
echo "# Consumed by local/scripts/verify-tracked-sources.sh."
echo "#"
echo "# A file listed here is uncommitted work sitting in a DURABLE tree. That is"
echo "# tolerated, not endorsed: commit it, or convert the change into a recipe sed"
echo "# or a patch, so a clean re-extract cannot lose it."
echo "#"
echo "# A line prefixed 'D ' records an INTENTIONAL deletion of a tracked source"
echo "# file (e.g. removing a vendored stub). Without an entry, any deletion is"
echo "# treated as damage."
echo "#"
echo "# Regenerate with: ./local/scripts/verify-tracked-sources.sh --update"
printf '%s\n' "${MODIFIED[@]}" | sed '/^$/d'
printf 'D %s\n' "${DELETED[@]}" | sed '/^D $/d'
} > "$BASELINE"
echo ">>> baseline updated: $(printf '%s\n' "${MODIFIED[@]}" | sed '/^$/d' | wc -l) modified," \
"$(printf '%s\n' "${DELETED[@]}" | sed '/^$/d' | wc -l) deleted -> $BASELINE"
exit 0
fi
# ---- check mode ----------------------------------------------------------
rc=0
if [ "${REDBEAR_SKIP_TRACKED_SOURCE_CHECK:-0}" = "1" ]; then
echo ">>> WARNING: tracked-source integrity check bypassed via REDBEAR_SKIP_TRACKED_SOURCE_CHECK=1." >&2
exit 0
fi
# Load the baseline first: it records both expected modifications (plain lines)
# and intentional deletions ("D <path>").
declare -A known=()
declare -A known_del=()
if [ -f "$BASELINE" ]; then
while IFS= read -r line; do
[[ -z "$line" || "$line" == \#* ]] && continue
if [[ "$line" == "D "* ]]; then
known_del["${line:2}"]=1
else
known["$line"]=1
fi
done < "$BASELINE"
fi
# 1. Deletions are damage unless explicitly recorded as intentional.
unexpected_del=()
for f in "${DELETED[@]}"; do
[ -z "$f" ] && continue
[ -n "${known_del[$f]:-}" ] || unexpected_del+=("$f")
done
DELETED=("${unexpected_del[@]}")
if [ "${#DELETED[@]}" -gt 0 ] && [ -n "${DELETED[0]:-}" ]; then
echo "" >&2
echo ">>> ERROR: ${#DELETED[@]} git-tracked file(s) under a vendored source/ tree are DELETED." >&2
echo " A build never legitimately deletes tracked source. This is the signature of an" >&2
echo " ad-hoc 'rm -rf <recipe>/source'." >&2
printf ' %s\n' "${DELETED[@]:0:15}" >&2
[ "${#DELETED[@]}" -gt 15 ] && echo " ... and $(( ${#DELETED[@]} - 15 )) more" >&2
echo "" >&2
echo " Restore with: git checkout -- local/recipes/<recipe>/source" >&2
echo " To force a clean re-extract of a tracked tree, restore it from git afterwards;" >&2
echo " never delete it." >&2
rc=1
fi
# 2. Modifications the baseline does not account for.
unexpected=()
for f in "${MODIFIED[@]}"; do
[ -z "$f" ] && continue
[ -n "${known[$f]:-}" ] || unexpected+=("$f")
done
if [ "${#unexpected[@]}" -gt 0 ]; then
echo "" >&2
echo ">>> ERROR: ${#unexpected[@]} tracked source file(s) changed with no baseline entry." >&2
echo " Either a recipe gained a new sed, or committed Red Bear work was overwritten" >&2
echo " (e.g. a pristine tarball re-extract replacing baked-in fixes)." >&2
printf ' %s\n' "${unexpected[@]:0:15}" >&2
[ "${#unexpected[@]}" -gt 15 ] && echo " ... and $(( ${#unexpected[@]} - 15 )) more" >&2
echo "" >&2
echo " Inspect: git diff -- <path>" >&2
echo " If the change is LOST WORK: git checkout -- <path>" >&2
echo " If the change is EXPECTED: ./local/scripts/verify-tracked-sources.sh --update" >&2
rc=1
fi
# 3. Baseline churn: uncommitted work in a durable tree. Visible, not fatal by
# default -- this is the local/recipes/ counterpart of the local/sources/
# dirty gate in build-redbear.sh.
baseline_dirty=0
for f in "${MODIFIED[@]}"; do
[ -z "$f" ] && continue
[ -n "${known[$f]:-}" ] && baseline_dirty=$(( baseline_dirty + 1 ))
done
if [ "$baseline_dirty" -gt 0 ]; then
if [ "${REDBEAR_STRICT_TRACKED_SOURCES:-0}" = "1" ]; then
echo ">>> ERROR: $baseline_dirty uncommitted change(s) in tracked source trees" \
"(REDBEAR_STRICT_TRACKED_SOURCES=1)." >&2
rc=1
else
say ">>> Preflight note: $baseline_dirty uncommitted change(s) in tracked vendored" \
"source trees (baseline-known)."
say " These live in a DURABLE tree but are not committed; a clean re-extract would" \
"lose them. Commit them, or move them into a recipe sed / patch."
fi
fi
if [ "$rc" -eq 0 ]; then
say ">>> Preflight: tracked vendored source trees intact (no deletions, no unexplained edits)."
fi
exit "$rc"