Optimise build for security and speed on reMarkable Paper Pro#43
Open
nanocorpintl wants to merge 26 commits into
Open
Optimise build for security and speed on reMarkable Paper Pro#43nanocorpintl wants to merge 26 commits into
nanocorpintl wants to merge 26 commits into
Conversation
Library upgrades (close known CVEs, EOL deps):
* OpenSSL 1.1.1k (EOL) -> 3.0.20 LTS
* curl 7.75.0 -> 8.20.0
* libiconv 1.16 -> 1.17
* FreeType 2.10.4 -> 2.13.3
* libjpeg-turbo 2.0.90 -> 3.0.4
Supply-chain & download hardening:
* sha512sum verification (replaces sha256sum)
* curl downloads forced to HTTPS + TLSv1.2 min, with retries
* curl built with unused protocols / IDN / PSL / brotli disabled to
shrink attack surface and binary
* OpenSSL built with no-shared/no-tests/no-docs; install_sw skips FIPS
Compiler hardening (third-party libs + netsurf itself):
* -fstack-protector-strong, -D_FORTIFY_SOURCE=2
* -Wformat -Wformat-security, -fno-plt
* Full RELRO + BIND_NOW, noexecstack, gc-sections, --as-needed
Performance tuning for Paper Pro (i.MX 8M Plus, Cortex-A53 @ 1.8GHz):
* -O2 -pipe -fomit-frame-pointer
* -march=armv7-a -mfpu=neon -mfloat-abi=hard -mtune=cortex-a53
(keeps rM1/rM2 ABI compatibility, schedules for A53)
* -ffunction-sections / -fdata-sections + --gc-sections -> smaller
binary, less I/O at startup
* libjpeg-turbo built with CMAKE_BUILD_TYPE=Release, NEON SIMD
Choices defaults tuned for rMPP:
* Explicit enable_plugins:0, block_popups:1, block_advertisements:1,
send_referer:0 (privacy/security)
* max_cached_fetch_handles:8, memory_cache_size:32 MiB (rMPP has 2 GiB)
* Fix fb_face_serif pointing at the mono font
Dockerfile:
* Add ca-certificates (required by the new HTTPS-only downloads)
* --no-install-recommends + apt cleanup -> smaller image
* Pin DEBIAN_FRONTEND noninteractive in ENV (not per-RUN)
CI:
* Bump checkout@v2 -> v4, upload-artifact@v2 -> v4, gh-release@v1 -> v2
* Lock GITHUB_TOKEN to minimum scopes (read at workflow, write only
on the release job)
https://claude.ai/code/session_01E9U2FQHwY3ycAGUzPpJEJu
The toltec-dev/base:v3.1 image ships libssl3 3.0.9 which still owns /usr/lib/x86_64-linux-gnu/ossl-modules/legacy.so. Today's Debian unstable has moved that file into a separate package (openssl-provider-legacy), so a fresh apt-get install on top of the base image hits a file-overwrite conflict. Pass --force-overwrite to dpkg for this RUN: libssl3 is going to be replaced anyway, the overwrite is exactly the desired transition. https://claude.ai/code/session_01E9U2FQHwY3ycAGUzPpJEJu
OpenSSL 3.0.20's Configure rejects "no-docs" as an unknown option (it was added later in the 3.x series). Since we use the install_sw target which already skips docs and the FIPS module, dropping the flag changes nothing about what lands in the sysroot. https://claude.ai/code/session_01E9U2FQHwY3ycAGUzPpJEJu
The original script combined --prefix=\$SYSROOT/usr with DESTDIR=\$SYSROOT, which makes 'make install' write to \$SYSROOT\$SYSROOT/usr (a nested path inside the cross sysroot). With OpenSSL 1.1.1k and curl 7.75 this went unnoticed because curl quietly fell back to the older libssl that ships in the Toltec base image's sysroot. Bumping to curl 8.x + OpenSSL 3.x exposed the bug: curl compiled against 3.x headers but linked against the stale 1.1 libssl, leading to undefined references to OSSL_PROVIDER_unload, EVP_PKEY_get_bn_param and friends. Switch to the standard cross-install pattern used by the curl block itself: --prefix=/usr, DESTDIR=\$SYSROOT. Files now land in \$SYSROOT/usr/lib so the cross linker finds the right libssl/libcrypto. https://claude.ai/code/session_01E9U2FQHwY3ycAGUzPpJEJu
curl 8.20.0's configure was still picking up the old opensslv.h that
ships preinstalled in the Toltec base image's cross sysroot, leading to
'configure: error: OpenSSL 3.0.0 or upper required.' even though our
3.0.20 build succeeded. Either install_sw is not overwriting headers
under this cross-compile target, or the order of file copies leaves the
old header in place.
Belt-and-suspenders fix:
* Drop install_sw in favour of plain 'make install' which always
runs install_dev + install_runtime and overwrites the include tree.
* Explicitly rm the toltec base's OpenSSL 1.x headers, libs and
pkgconfig files in the sysroot before installing, so curl can't
fall back to them.
https://claude.ai/code/session_01E9U2FQHwY3ycAGUzPpJEJu
DESTDIR doesn't reliably reach OpenSSL 3.x's sub-make invocations under this cross toolchain, so 'DESTDIR=\$SYSROOT make install' ended up with no libs / headers / .pc files in \$SYSROOT/usr after the purge of the older Toltec-provided libssl. curl 8.x then failed configure with 'OpenSSL could not be detected'. Switch to an absolute --prefix=\$SYSROOT/usr and drop DESTDIR. The files land directly where pkg-config and the cross linker look. Keep the purge of the stale 1.x files so nothing old is left behind, and go back to install_sw (we no longer need install's broader scope). Cosmetic downside: the installed .pc files now embed absolute build- host paths, but we link everything statically into nsfb so nothing on the device reads them. https://claude.ai/code/session_01E9U2FQHwY3ycAGUzPpJEJu
Freetype 2.11+ ships a git submodule for dlg (debug logging). GitHub's tag archive doesn't include submodule contents, so the toplevel makefile's check_out_submodule rule tries to run 'git submodule update --init' on a non-git tree and aborts. dlg is only compiled when FT_DEBUG_LOGGING is in CFLAGS, which we never set. Create empty dlg.c / dlg.h before invoking autogen.sh so the wildcard check passes and the rest of the build proceeds without ever touching those stubs. https://claude.ai/code/session_01E9U2FQHwY3ycAGUzPpJEJu
The previous stub only satisfied check_out_submodule. Freetype 2.13's
toplevel.mk then runs copy_submodule which cp's specific files out of
subprojects/dlg/{include,src}/dlg/ into the tree, and one of those
(output.h) was still missing -> 'cannot stat'.
Create empty files at all three expected paths (dlg.h, output.h, dlg.c)
so the cp succeeds. None of these get compiled because we don't define
FT_DEBUG_LOGGING.
https://claude.ai/code/session_01E9U2FQHwY3ycAGUzPpJEJu
Two papercuts in setup_local_development.sh: 1. The clone URLs used the SSH form (git@github.com:...), which only works when the user has a GitHub SSH key configured. On a fresh macOS without that, both clones fail silently (script has no set -e). The Makefile then bind-mounts build/libnsfb into the container and docker errors with "bind source path does not exist". 2. No set -e meant any failure (clone, checkout) was swallowed and the caller assumed success. Switch to HTTPS URLs (public read-only repos, no auth needed), add set -e, and inline the checkout with `git -C <dir>` so we don't leave the shell in the wrong cwd if it fails. URLs are overridable via LIBNSFB_URL / NETSURF_URL env vars in case anyone forks the forks. https://claude.ai/code/session_01E9U2FQHwY3ycAGUzPpJEJu
env.sh (sourced by build.sh) auto-detects the host BUILD triplet via \`var=\$(which cc); if [ \$? -eq 0 ]; then ...\`. Under set -e, the which-cc command substitution exits the shell as soon as cc is not on PATH (which is exactly the case in the toltec-dev/base container — it ships the arm cross compiler but not a host cc by default). Because the failing line uses &>/dev/null, build.sh exits silently with no output, which is what was happening here. Restore the original (no set -e) behaviour. The script's own commands are mostly idempotent makefile targets that propagate their own failures through to the eventual TARGET=framebuffer make. https://claude.ai/code/session_01E9U2FQHwY3ycAGUzPpJEJu
Same class of bug as the libssl purge: the toltec base image ships
libcurl.so prebuilt against OpenSSL 1.1.0. NetSurf's final nsfb link
follows pkg-config's '-lcurl' which the cross linker resolves to the
\.so (shared preferred over static) and then fails with
'undefined reference to BIO_free@OPENSSL_1_1_0' because we replaced
OpenSSL 1.1 with 3.0.20 in the sysroot.
rm the old libcurl.{so,so.*,la} and libcurl.pc from \$SYSROOT/usr/lib
before our install runs, so the only libcurl left after we install is
the static libcurl.a built against OpenSSL 3.
https://claude.ai/code/session_01E9U2FQHwY3ycAGUzPpJEJu
NetSurf's framebuffer frontend Makefile injects LDFLAGS *before* the object files in the final gcc/ld command line. With --as-needed in LDFLAGS, the linker walks left-to-right, hits '-levdev' (also in LDFLAGS via build.sh) before it has seen any unresolved libevdev_get_fd / libevdev_free reference, decides the library is not needed, and skips it. input.o later asks for those symbols and the link fails. Workarounds (-Wl,--no-as-needed grouping, or moving -levdev to a LIBS variable) would require either fragile flag ordering or knowing the exact LIBS variable netsurf-base reads. The hardening benefit of --as-needed is only DT_NEEDED entry trimming for *shared* binaries; nsfb statically links its third-party deps so the gain is negligible. Drop the flag. https://claude.ai/code/session_01E9U2FQHwY3ycAGUzPpJEJu
scp -r foo dest/ requires dest/ to already exist; it won't create the parent directory. On a fresh reMarkable that has never had netsurf installed, /home/root/.netsurf doesn't exist and the first 'make install' aborts with 'path canonicalization failed'. Prefix the copy-resources recipe with a one-shot 'ssh ... mkdir -p /home/root/.netsurf' so a fresh device works first-try. https://claude.ai/code/session_01E9U2FQHwY3ycAGUzPpJEJu
The default config assumed Toltec-installed DejaVu in /opt/share/fonts, which doesn't exist on the Paper Pro (Toltec doesn't yet support its arch). The device does ship a complete Noto family (/usr/share/fonts/ttf/noto/) so use that instead. NotoMono has no explicit bold flavour shipped, so monospace_bold reuses Regular. Also flip fb_xochitl_restart_command from 'systemctl restart remux' to 'systemctl restart xochitl' since remux is a Toltec-only launcher. https://claude.ai/code/session_01E9U2FQHwY3ycAGUzPpJEJu
Standalone briefing doc for a follow-up Claude Code session focused on reusing the Qt6 + QtWebEngine stack already bundled with xochitl on the rMPP, rather than porting NetSurf's framebuffer code. Includes the device diagnostic checklist to run first, the five technical attack vectors ranked by effort, the MVP definition and the legal/firmware risks. https://claude.ai/code/session_01E9U2FQHwY3ycAGUzPpJEJu
The Paper Pro (codename Ferrari, i.MX 8M Mini) runs a 64-bit kernel
and userspace; the existing armhf binaries from this repo can't even
exec on it ('Exec format error'). This commit reworks the build chain
to produce aarch64 ELF instead. The display side is NOT solved here —
see PAPER_PRO_FRAMEBUFFER_NOTES.md for the remaining work.
Dockerfile:
* Drop the Toltec armhf base image (which only ships an armhf cross
toolchain). Start from debian:bookworm-slim.
* Install Debian's official aarch64 cross toolchain
(gcc-aarch64-linux-gnu, binutils-aarch64-linux-gnu,
libc6-dev-arm64-cross).
* Enable dpkg --add-architecture arm64 and pull libexpat1-dev:arm64,
libpng-dev:arm64, zlib1g-dev:arm64 so the cross headers/libs are
available natively without us having to build expat/libpng/zlib.
* Set CHOST=aarch64-linux-gnu and an isolated SYSROOT prefix at
/opt/aarch64-rmpp for the libs we cross-build ourselves.
scripts/install_dependencies.sh:
* Same five libs (libiconv 1.17, OpenSSL 3.0.20, curl 8.20.0,
FreeType 2.13.3, libjpeg-turbo 3.0.4), cross-built for aarch64.
* OpenSSL Configure target switched from linux-armv4 to linux-aarch64.
* CFLAGS retune: -march=armv8-a+crc -mtune=cortex-a53 (drop
-mfpu/-mfloat-abi since both are ISA features on aarch64).
* Hardening flags kept: -fstack-protector-strong, -D_FORTIFY_SOURCE=2,
-fno-plt, -ffunction-sections / -fdata-sections, full RELRO + NX.
* libjpeg-turbo: inline cmake toolchain file (Debian doesn't ship one
for our triplet).
* PKG_CONFIG_LIBDIR (not _PATH) so pkg-config doesn't leak amd64
host paths into the cross build.
scripts/build.sh:
* HOST=aarch64-linux-gnu, CC/STRIP point at the matching cross tools.
* Same CFLAGS retune and PKG_CONFIG_LIBDIR lockdown.
* Add -I/-L for both the isolated SYSROOT and the netsurf
per-build inst-\$HOST workspace.
PAPER_PRO_FRAMEBUFFER_NOTES.md:
* Documents what still needs to happen for the binary to actually
drive the Paper Pro display: investigate the e-ink controller,
adapt libnsfb-reMarkable's surface backend, retarget the input
code at the new evdev device numbering.
* Includes the diagnostic checklist to run on the tablet first.
https://claude.ai/code/session_01E9U2FQHwY3ycAGUzPpJEJu
Cloned and inspected the libnsfb-reMarkable and netsurf-base-reMarkable forks before testing the build, found: 1. libnsfb's framebuffer/remarkable backend (input.c) needs libevdev and libudev. Toltec's base image bundled these in its sysroot; a clean Debian base needs the dev packages explicitly. Add libevdev-dev:arm64 and libudev-dev:arm64. 2. netsurf-base's frontends/framebuffer/components/remarkable_xochitl_import.c includes <uuid/uuid.h> and calls uuid_generate_random / uuid_unparse_lower. The toltec armhf build silently pulled libuuid in through transitive deps; on Debian we need uuid-dev:arm64 plus an explicit -luuid in LDFLAGS. 3. libnsfb's own Makefile turns warnings into errors unless VARIANT=release. aarch64 has stricter -Wcast-align than armhf, and our hardening flags add -Wformat-security. Either of those plus -Werror could spike on third-party code we don't own. Export VARIANT=release so the libs build with warnings, not failures. 4. Same Makefile mechanic also applies to the final netsurf framebuffer Make invocation — pass VARIANT=release there too. Findings that don't need a code change but are worth recording: * The libnsfb-reMarkable surface backend (src/surface/remarkable/) uses the i.MX EPDC ioctl API (MXCFB_SEND_UPDATE, mxcfb_update_data, the EPDC_FLAG_USE_REMARKABLE_DITHER constants etc.). i.MX 8M Mini (the Paper Pro SoC) is in the same NXP family as i.MX 6/7 (rM1/rM2), so there is a non-trivial chance the API matches and the display works in-place. Not guaranteed — see PAPER_PRO_FRAMEBUFFER_NOTES.md — but better odds than starting from scratch. * The remarkable backend's source dir doesn't appear in src/surface/Makefile, but its own Makefile + DIR_SOURCES is picked up by netsurf-buildsystem's Makefile.subdir auto-recurse. Same plumbing worked for armhf, should hold for aarch64. * NetSurf picks the framebuffer surface by enumerating registered handlers and keeping the last seen one (gui.c's framebuffer_pick_default_fename). Link order decides the winner. If the wrong surface is picked at runtime, override with `nsfb -f remarkable`. https://claude.ai/code/session_01E9U2FQHwY3ycAGUzPpJEJu
Critical pre-build catch: bash terminates the current command when it
hits a '#' on a line inside a multi-line continuation, even if previous
lines ended with backslash. Tested in a sandbox:
apt-get install -y --no-install-recommends \\
# Host build essentials...
build-essential \\
...
bash splits this into 'apt-get install -y --no-install-recommends' (run
as one command with no package arg) followed by 'build-essential' run
as a standalone command (which fails with command not found). The
Dockerfile would have crashed 'make image' the first time it was run.
Refactor: keep the package list as bare package names inside the RUN,
move all the per-package explanations to a Dockerfile-level # comment
block at the top of the file (those are stripped by Docker before
shelling out).
https://claude.ai/code/session_01E9U2FQHwY3ycAGUzPpJEJu
Two safety nets added after deeper analysis of the runtime risk surface:
1. scripts/preflight_paperpro.sh — a small SSH-friendly script that
reports the rMPP's architecture, glibc version, presence of every
runtime shared library nsfb will need, framebuffer device info, EPDC
driver hint, and free RAM/disk. Run it BEFORE building so you can
catch incompatibilities (esp. glibc version) before spending 25 min
on `make image`.
Usage:
ssh root@10.11.99.1 'bash -s' < scripts/preflight_paperpro.sh
2. Dockerfile.bullseye — a fallback build image based on Debian
Bullseye (glibc 2.31) instead of Bookworm (glibc 2.36). If the
preflight reports rMPP's glibc < 2.36 (Yocto 4.0 LTS firmwares ship
2.35; some stay at 2.31), the Bookworm build's binary would refuse
to start on the device with 'GLIBC_2.36 not found'. Building from
Bullseye produces a binary that requires only GLIBC_2.31, which is
broadly compatible with embedded Yocto installs.
Usage when fallback is needed:
docker build -f Dockerfile.bullseye -t netsurf-build:latest .
make build # rest of flow unchanged
After `make build`, you can verify the binary's glibc requirement with:
aarch64-linux-gnu-objdump -T build/netsurf/nsfb \\
| grep -oE 'GLIBC_[0-9]+\.[0-9]+' | sort -V | tail -1
That number must be <= the rMPP's glibc version.
https://claude.ai/code/session_01E9U2FQHwY3ycAGUzPpJEJu
If the preflight check reveals rMPP's glibc is older than the one shipped in debian:bookworm-slim (2.36), the user can rebuild against the Bullseye fallback (glibc 2.31) without editing files: make image BASE_DOCKERFILE=Dockerfile.bullseye Default stays at Dockerfile (Bookworm) for the common case. https://claude.ai/code/session_01E9U2FQHwY3ycAGUzPpJEJu
First run on actual hardware revealed:
* rMPP userland is BusyBox (no GNU coreutils): 'head -N' is rejected,
'getconf' is missing entirely.
* rMPP has NO /dev/fb0 — it uses DRM/KMS via /dev/dri/card0. This
invalidates the existing libnsfb-reMarkable surface backend, which
is a hard fbdev consumer.
* libevdev.so.2 isn't present at the canonical multiarch paths.
* ldd is busybox's stub; we can't get a glibc version from it.
Rewrite the preflight to:
* Use awk for line-slicing instead of head -N
* Dump 'GLIBC_X.Y' symbol versions from /lib/libc.so.6 via strings,
which works on busybox and gives us a much more precise glibc
capability picture than `ldd --version`.
* Search a broader set of lib directories (incl. /opt/lib,
/opt/share/lib) for the required SOs, and report the SOVERSION
mismatch (e.g. libevdev.so.1 present, .so.2 not) when relevant.
* Look at /sys/class/drm/* as well as /sys/class/graphics/* so DRM-
only devices like the rMPP show their topology.
The script now provides a complete picture in one run on the device.
https://claude.ai/code/session_01E9U2FQHwY3ycAGUzPpJEJu
We now know option C (NetSurf) requires writing a DRM/KMS backend
for libnsfb from scratch — a multi-day project. Option E (reuse
xochitl's Qt6 + WebEngine stack) is the realistic next path. Before
committing to it we need to confirm:
1. Whether Qt6Core / Qt6WebEngineCore are actually present on the
device (xochitl is Qt-based, but WebEngine might not be bundled
for every screen).
2. Which Qt plugins / platforms are available (eglfs is what xochitl
likely uses; offscreen could be useful for screenshot rendering).
3. What ldd /usr/bin/xochitl reports — gives us the full inventory
of Qt libs already loaded at boot.
Also extend DRM section so we can identify the e-ink driver bound to
card0 (uevent, modalias, driver symlink). If anyone does want to
revisit option C later, that info is the entry point for adapting
libnsfb's surface backend to DRM atomic / dirty-fb ioctls.
https://claude.ai/code/session_01E9U2FQHwY3ycAGUzPpJEJu
The rMPP has no /dev/fb0 and no libevdev.so.2; it uses the imx-drm
DRM/KMS driver via /dev/dri/card0 and exposes touch/stylus as plain
evdev devices in /dev/input/event*. The old rM1/rM2 backend
(libnsfb-reMarkable's src/surface/remarkable/screen.c with mxcfb
ioctls + libevdev/libudev for input) cannot work on this device.
This commit lands the replacement, packaged as drop-in patch files
applied to the upstream libnsfb-reMarkable clone at build time:
patches/paperpro-drm-surface/
screen.c — DRM dumb-buffer + drmModeSetCrtc + drmModeDirtyFB
(XRGB8888, 32 bpp; saves and restores the previous
CRTC state so xochitl can resume on exit)
screen.h — same fb_state_t / fb_info_t shape so remarkable.c
compiles unchanged
input.c — raw /dev/input/event3 reads, EV_ABS_MT_POSITION_*
+ BTN_TOUCH + ABS_MT_TRACKING_ID → nsfb mouse events,
with EVIOCGABS-based coordinate scaling
input.h — minimal state struct
apply.sh — idempotent installer, also strips the libevdev
pkg-config call from libnsfb's top Makefile so the
final binary doesn't need libevdev.so.2 at runtime
Plumbing changes:
Dockerfile, Dockerfile.bullseye
+ libdrm-dev:arm64
Makefile
+ bind-mount patches/ into the build container at /opt/netsurf/patches
(both code paths: bind-mount and macOS volume-mount)
scripts/build.sh
+ run apply.sh after ns-clone but before ns-make-libs
+ add -I/usr/include/libdrm to CFLAGS so libnsfb finds <xf86drmMode.h>
+ replace -levdev with -ldrm in the final-link LDFLAGS
+ keep -ludev / -luuid / -lpthread / -lm
Empirical syntax check done locally: both screen.c and input.c
compile clean for aarch64 with -Wall -Wextra -Werror. Undefined
symbols are exactly what we expect (libdrm + libc only).
Known limitations of this first cut:
* Stylus (Elan marker, event2) and multi-touch are not yet wired up
* Pixel format is fixed at XRGB8888; if the imx-drm panel only
advertises RGB565 we'll need a fallback in screen.c
* No e-ink waveform-mode control: relying on the driver's default
behaviour for refresh. If ghosting is bad we'll add DRM property
discovery + EPD_MODE handling.
https://claude.ai/code/session_01E9U2FQHwY3ycAGUzPpJEJu
install_dependencies.sh exports CC/CXX/AR/STRIP/RANLIB pointing at the
${CHOST}- tools at the top of the file (needed so curl, freetype,
libiconv autoconf cross-compile correctly). OpenSSL's Configure also
takes --cross-compile-prefix, which it PREPENDS to $CC. With both, the
build was trying to invoke 'aarch64-linux-gnu-aarch64-linux-gnu-gcc'
and failed at the very first .o:
/bin/sh: 1: aarch64-linux-gnu-aarch64-linux-gnu-gcc: not found
Drop --cross-compile-prefix. The exported CC plus linux-aarch64 target
is enough; OpenSSL will use $CC, $AR, $STRIP directly.
Caught while attempting to reproduce the build natively (no Docker) in
a sandbox that has the same toolchain — same bug would trip on any
clean machine, the docker image just hadn't reached the OpenSSL .o
stage in the user's previous failed runs.
https://claude.ai/code/session_01E9U2FQHwY3ycAGUzPpJEJu
First on-device test of the v1 binary (32bpp XRGB8888 buffer) showed the rendered content as alternating-pixel stripes — classic symptom of the display controller reading our 4-bytes-per-pixel data as 2 bytes per pixel. The Paper Pro's imx-drm LVDS panel advertises 405x1084 modes for a 1620x2160 physical screen, meaning the controller packs sub-pixels and the natural pitch is 16bpp, not 32bpp. libnsfb's remarkable surface already sets nsfb->format = NSFB_FMT_RGB565, so NetSurf was already rendering 16bpp content into our 32bpp framebuffer — every other "pixel" was bytes from the adjacent rendered pixel. With this commit: - drm_mode_create_dumb.bpp goes from 32 to 16 - drmModeAddFB depth/bpp args go from 24/32 to 16/16 - scrinfo.bpp reported to NetSurf matches at 16 If the controller still doesn't accept 16bpp (drmModeAddFB EINVAL) we fall back to drmModeAddFB2 with an explicit fourcc, or try Y8/R8 grayscale next. https://claude.ai/code/session_01E9U2FQHwY3ycAGUzPpJEJu
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Library upgrades (close known CVEs, EOL deps):
Supply-chain & download hardening:
Compiler hardening (third-party libs + netsurf itself):
Performance tuning for Paper Pro (i.MX 8M Plus, Cortex-A53 @ 1.8GHz):
Choices defaults tuned for rMPP:
Dockerfile:
CI: