mirror of
https://github.com/Klipper4FlashForge/firmware.git
synced 2026-10-21 21:02:16 -05:00
PR #10 was green on this machine and red on both CI jobs. Three separate faults, none of which a local signed build could show. apk-tools is cloned from gitlab.alpinelinux.org, which answers a GitHub runner with HTTP 418 or with nothing until the connection times out. It clones from the GitHub mirror now. Which host serves it cannot change what is fetched: the pin is a commit sha, and git names a commit by the hash of its content, so a mirror answering with this sha is serving this tree or is not answering. get_git also sets the remote url on every run, so a checkout made before this commit does not keep fetching from the host that refuses. anvil-core's cache key hashed the feed's public key as sha256sum "${APK_SIGN_KEY:-/dev/null}.pub" 2>/dev/null | cut ... With no key that file is absent, sha256sum is non-zero, pipefail makes the pipeline non-zero, and build-packages.sh -- which sources every pkg.conf under `set -euo pipefail` -- died before emitting a single package. The 2>/dev/null ate the reason, so `make packages` exited 1 having said only that it had sealed a cache entry. Every signed build passed. Every CI build is unsigned. It is now pkg_signkey_hash, which answers `unsigned` and succeeds. The build container mounts the checkout and nothing else, so a key at the documented ~/.anvil/anvil.rsa was visible in the developer's shell and invisible to apk. The Makefile reads APK_SIGN_KEY out of $(CONFIG_ENV) and bind-mounts its directory read-only. This survived review because the key used while writing the migration sat under work/, inside the one directory already mounted. Gates for all three, each verified against its own bug by reverting the fix under it. The recipe-reads-unsigned test runs pkg_conf under the same flags build-packages.sh uses -- the existing _conf helper does not, and would have stayed green throughout. Its companion asserts the recipe SET does not change with the key, because pkg_recipes evaluates PKG_WHEN in a subshell and a recipe that fails to source is dropped rather than reported: broken only when unsigned, a package would leave the feed with nothing turning red. Both are scoped to what pkg_recipes lists, so busybox -- gated off whenever there is no stock firmware to take one from -- is not asked a question it cannot answer. release.yml takes the private key PEM from secrets.APK_SIGN_KEY, writes it to $RUNNER_TEMP outside the checkout where no later step can archive it into a release, and derives the public half rather than storing a second secret that could drift out of step with the first. Unset, the release builds unsigned with a warning: a fork has no such secret, and firmware nobody else can build is worse than a feed untrusted on a stick the printer was handed by hand. Verified from a cold work/host and work/packages, three ways: no key (the CI case), a key inside the tree, and a key outside it at the documented location. Each gives 47 packages plus the index, a payload, 286 static and 135 replica tests. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013rbKEyLXrzSE6wm3iNApVp
153 lines
8.1 KiB
Bash
153 lines
8.1 KiB
Bash
# creator5-fw-builder — build configuration
|
|
# Edit paths to match your machine, then run `make build`.
|
|
|
|
# ---- identity of the package you are building -------------------------------
|
|
MOD_NAME=anvil # goes into the .tgz filename
|
|
MOD_VER="" # empty = today's UTC date, e.g. 20260823.
|
|
# Pin it to rebuild an old release, or for a
|
|
# second release on the same day (20260823b).
|
|
|
|
# ---- which printer is this for? --------------------------------------------
|
|
# Creator5Pro / 0029 or Creator5 / 0028
|
|
# Find it on the printer: Settings -> About, or in
|
|
# /usr/data/firmwareRes/config/general.json ("machineName").
|
|
#
|
|
# This MUST match the model the stock package was built for. A package's
|
|
# runFirmwareExe.sh carries its own MACHINE=/PID= gate and refuses to install
|
|
# on the other model, so a Pro cannot be recovered or modded with a non-Pro
|
|
# package (and vice versa).
|
|
TARGET_MACHINE=Creator5Pro
|
|
|
|
# Override for one command: MODEL=Creator5 make build
|
|
# Build both at once: make release
|
|
|
|
# ---- inputs -----------------------------------------------------------------
|
|
# THERE ARE NO PATHS TO EDIT HERE ANY MORE. Every source this build reads is
|
|
# downloaded into vendor/ by bin/fetch-assets.sh, pinned by name and sha256 in
|
|
# versions.env -- the stock FlashForge OTA package included, which used to be
|
|
# the one file you had to go and find yourself. `make build` fetches what it
|
|
# needs; `make vendor` fetches the lot.
|
|
#
|
|
# The stock packages are ONE PER MODEL and not interchangeable: each carries a
|
|
# different firmwareExe and refuses to install on the other model. The one
|
|
# matching TARGET_MACHINE (or MODEL=) is selected automatically.
|
|
#
|
|
# Set one of these ONLY to build against firmware you downloaded yourself.
|
|
# Unlike HELIX_TGZ below, a path you put here is never checksummed and never
|
|
# overwritten -- it is 93MB you fetched by hand, and this build will not
|
|
# replace it with one you did not ask for. That also means nothing verifies it:
|
|
# it is your file and your problem.
|
|
#STOCK_TGZ_CREATOR5PRO="/path/to/Creator5Pro-1.9.7-1.2.9-20260810.tgz"
|
|
#STOCK_TGZ_CREATOR5="/path/to/Creator5-1.9.7-1.2.9-20260810.tgz"
|
|
|
|
# Set this only to force one specific package regardless of model. It does not
|
|
# suppress the download above; point the per-model variable at your file
|
|
# instead if that is what you want.
|
|
STOCK_TGZ=""
|
|
|
|
# KLIPPER_FORK USED TO BE HERE and pointed the build at a local checkout of
|
|
# the fork. It is gone: the Klipper build is pkg/klipper now, and a recipe
|
|
# names its source exactly once -- a checkout beside the pinned tarball is the
|
|
# second source that rule forbids, and the one that let a release ship a tree
|
|
# nobody had built. To build your own fork, put its tarball in vendor/ and
|
|
# re-pin KLIPPER_VERSION and KLIPPER_SHA256 in versions.env; the sha is then
|
|
# the same guarantee every other source in this repo carries.
|
|
|
|
# The toolchanger mod (klippy-extras + configs + helixscreen db entry) used to
|
|
# be a TOOLCHANGE= path to a creator5-toolchange checkout. It now lives in this
|
|
# repo under payload/klipper/, so there is nothing to set. BUILD_TOOLCHANGE=0
|
|
# here still turns it off.
|
|
|
|
# Mainsail, the HelixScreen build for the Creator 5 (MIPS static) and Moonraker
|
|
# are NOT set here. They are downloaded on demand into vendor/ by
|
|
# bin/fetch-assets.sh, pinned by version and sha256 in versions.env, so the
|
|
# repo carries no binaries. Set any of these ONLY to build against your own
|
|
# local copy.
|
|
# NOTE: the path is still checksummed against versions.env, and on a mismatch
|
|
# fetch-assets.sh OVERWRITES it with the pinned release -- SKIP does not save
|
|
# you, it re-downloads too. To build against your own file, also put ITS
|
|
# sha256 in versions.env; only an exact match is left alone ("cached"):
|
|
#HELIX_TGZ="/path/to/helixscreen-creator5-v0.99.115.tar.gz"
|
|
#MAINSAIL_ZIP="/path/to/mainsail.zip"
|
|
#MOONRAKER_TGZ="/path/to/moonraker-v0.9.3.tar.gz"
|
|
|
|
# ---- optional extras -- leave empty to skip that feature ---------------------
|
|
# The ONE input with no pinned source, because it has no source at all: a
|
|
# busybox someone built elsewhere, for the applets FlashForge left out. Nothing
|
|
# needs it (the printer's own busybox works), so `make vendor` has nothing to
|
|
# fetch and an empty value simply leaves the package out of the feed. See
|
|
# pkgs/3rdparty/busybox/build.sh.
|
|
BUSYBOX_BIN=""
|
|
|
|
# The private key the package feed is signed with, or empty for an unsigned
|
|
# feed. A PATH, never a key: config.env is gitignored and this points outside
|
|
# the repo, so the key is never a thing the repository can leak.
|
|
#
|
|
# ./bin/apk-keygen.sh ~/.anvil/anvil.rsa makes the pair
|
|
# APK_SIGN_KEY="/home/you/.anvil/anvil.rsa"
|
|
#
|
|
# EMPTY IS A WORKING CONFIGURATION, deliberately: `make packages` has to run on
|
|
# a bare checkout with no secrets, which is what keeps the packaging lane a
|
|
# gate in CI. An unsigned feed installs with --allow-untrusted, exactly as it
|
|
# does today; a signed one does not need the flag and refuses a package whose
|
|
# signature does not match. RSA or Ed25519 only -- ECDSA signatures are
|
|
# randomised and two builds of one tree would stop being byte-identical.
|
|
#
|
|
# The PUBLIC half is generated beside the private one and ships in anvil-core,
|
|
# so a printer can verify what it is offered. Losing the private key means
|
|
# printers stop accepting new packages until one is reflashed by .tgz.
|
|
#
|
|
# The DIRECTORY holding the key is bind-mounted read-only into the build
|
|
# container by the Makefile, which is what lets this point outside the
|
|
# checkout at all. Both halves must live in it, named as apk-keygen.sh leaves
|
|
# them, and it must be a path docker is allowed to mount.
|
|
#
|
|
# In CI the same value comes from a repository secret rather than from here:
|
|
# see the signing section of docs/notes/85-packaging.md.
|
|
APK_SIGN_KEY=""
|
|
|
|
# ---- what the installed image does at boot ----------------------------------
|
|
# NOTHING, from here. There is no build-time knob for boot behaviour any more,
|
|
# and no runtime config file on the printer either: /usr/data/anvil/anvil.conf
|
|
# is gone. Every component that is installed runs, and the settings that used
|
|
# to live in that file -- the splash, the startup wait and its timeout, the
|
|
# first-boot import, the camera resolution, the nice values -- are now stated
|
|
# once each, in the service that uses them, under
|
|
# pkgs/anvil-core/payload/etc/s6-rc/source/.
|
|
#
|
|
# A printer that should not run a component does not have it: leave it out of
|
|
# the build with the BUILD_* flags, or `apk del` it on the printer. What
|
|
# there is no longer a way to ask for is a component that is installed and
|
|
# switched off -- a half-installed mod nobody chose on purpose, that everything
|
|
# downstream had to keep a second answer for.
|
|
#
|
|
# The BUILD_* flags that decide what goes INTO a package (BUILD_TOOLCHANGE,
|
|
# BUILD_MAINSAIL, BUILD_MOONRAKER, BUILD_HELIX) are not set
|
|
# here: bin/common.sh defaults them to the full firmware, and setting one in
|
|
# this file overrides that. Only touch them if you want a piece left out.
|
|
|
|
# ---- root login shipped in the image ---------------------------------------
|
|
# This is the whole "enable ssh" feature. The stock rootfs already runs
|
|
# dropbear from /etc/init.d/S50dropbear, so port 22 is ALREADY open on a
|
|
# stock printer -- there is simply no published root password.
|
|
#
|
|
# Empty = the INSTALLER picks a random password on the printer -- on the
|
|
# FIRST install only, updates keep the one the machine already has -- and
|
|
# writes it to anvil-password.txt on the USB stick you flashed from. Every
|
|
# machine gets a different one, which a hash baked into a shared package
|
|
# never could.
|
|
# Set one here to choose your own: make passwd
|
|
# (it prompts, and runs inside the build image -- the same python everywhere,
|
|
# where a host openssl may lack `passwd -6` entirely)
|
|
ROOT_PW_HASH=""
|
|
|
|
# ---- crypto (from /usr/prog/bin/unTar on the printer) -----------------------
|
|
FF_KEY='FFP0331&*%root'
|
|
|
|
# ---- the printer replica -----------------------------------------------------
|
|
# Nothing here. The replica's settings -- the factory image, the partition
|
|
# sizes, a prebuilt printer image -- live in test.env, because they exist only
|
|
# for the tests and must never reach a printer:
|
|
#
|
|
# cp test.env.example test.env
|