website-htmx-rustelo-code/lian-build/build_directives.ncl
2026-07-10 03:44:13 +01:00

139 lines
6 KiB
Text

# Evaluated by lian-build CLI with:
# LIAN_BUILD_NICKEL_IMPORT_PATH=/path/to/lian-build
# "defaults/build_directives.ncl" resolves via LIAN_BUILD_ROOT import-path.
# "jpl-project.ncl" resolves via LIAN_BUILD_NICKEL_IMPORT_PATH (not relative) so
# the justfile can shadow it with a version-patched copy without touching source.
#
# This file exports ONE directive PER render profile, keyed by profile name.
# Nickel 1.16 has no env access, so profile selection happens in provisioning/
# build.nu (which runs check-wasm-needed.nu against site/config/rendering.ncl):
# build.nu extracts the matching field and feeds that single directive to
# lian-build. The two profiles are genuinely disjoint builds — different base
# images, different Dockerfile, different artifacts (pkg/ vs none) — not one
# build with a flag.
let d = import "defaults/build_directives.ncl" in
let project = import "jpl-project.ncl" in
# Args common to both Dockerfiles. project.port is the canonical port.
let common_args = {
RUST_VERSION = "1.95",
NICKEL_VERSION = "1.16.0",
LAMINA_REGISTRY = "daoreg.librecloud.online/lamina",
BIN_NAME = "rustelo-htmx-server",
SERVER_PORT = std.string.from_number project.port,
} in
# leptos-hydration: cargo-leptos build over lamina/leptos + lamina/rustelo,
# emits the WASM pkg/ (version-matched to the binary). content-static bakes
# content + i18n at compile time.
let leptos_args = common_args & {
RUSTELO_VERSION = "0.1.0",
LEPTOS_VERSION = "0.3.6",
NODE_VERSION = "22",
LEPTOS_OUTPUT_NAME = "website",
BIN_FEATURES = "content-static",
} in
# htmx-ssr: plain cargo build over lamina/rust (no wasm toolchain, no node/css
# stage, no pkg/). Content is served from the PV at runtime, not baked.
let htmx_args = common_args & {
BIN_FEATURES = "htmx-ssr",
} in
# Fields identical across profiles: where to push, how to sign/cache/adapt.
# image: registry is the primary write surface (reachable from lian-01).
# registry.ontoref.dev (project.image_base) is the K8s pull address; it syncs
# from registry on-demand per ADR-019. These must not be the same ref — now
# true again: write surface is reg.librecloud.online (+ daoreg.librecloud.online
# replica), pull address stays registry.ontoref.dev.
let shared = {
# Direct port 443 — no NodePort bypass needed. The :31527 NodePort form was
# a workaround for the Cilium Gateway LB VIP (10.200.3.x) refusing
# connections from the fleet's network (2026-07-06); that routing/SNAT gap
# was fixed 2026-07-07 (VIP now reassigned, port 443 confirmed reachable
# with consistent 200s) and the NodePort no longer even accepts connections.
image_ref = "reg.librecloud.online/%{project.domain}/%{project.name}:%{project.image_tag}",
adapter = d.make_adapter_ref {
kind = 'fleet,
nats_url = "nats://10.0.8.5:30422",
consumer_identity = "lian-build",
subject_prefix = "fleet.libre-forge",
memory_hint_gb = 7,
},
# Dual push, both mandatory (adr per src/cli/build.rs: "daoreg/buildadm +
# reg/regadm" is the canonical two-credential pattern). Each endpoint carries
# its own push_credential; resolution of either failing fails the whole push.
# reg.librecloud.online and daoreg.librecloud.online's credentials are
# SOPS-encrypted for different age identities (libre-wuji, libre-daoshi).
# Both push_credentials share the SAME PATH-style secrets_base/key_file
# (lian-build schema addition, 2026-07-07) — a `:`-separated search path
# covering every known workspace; each credential finds its own file under
# whichever candidate has it and decrypts with whichever key matches. Values
# come from project.build_secrets, patched in by the justfile from
# wuji_secrets_base:secrets_base / wuji_kage:daoshi_kage — never hardcoded here.
registry = d.default_zot_registry "reg.librecloud.online" {
path = project.build_secrets.registry_push,
kind = 'docker_config,
secrets_base = project.build_secrets.secrets_base,
key_file = project.build_secrets.key_file,
} & {
replica_endpoints = [
{
endpoint = "daoreg.librecloud.online",
push_credential = {
path = project.build_secrets.registry_push_daoreg,
kind = 'docker_config,
secrets_base = project.build_secrets.secrets_base,
key_file = project.build_secrets.key_file,
},
},
],
},
cache = d.ci_cache_policy project.workspace_id,
signing = {
key_ref = { kind = 'cosign_private_key, path = project.build_secrets.cosign },
},
# sccache DISABLED TEMPORARILY (2026-07-06): the S3 backend below
# (wuji-sccache @ fsn1.your-objectstorage.com) was deliberately deleted in
# the 2026-07-01/02 Hetzner cost cleanup; the intended replacement (Garage,
# libre-wuji) is not yet reachable from the fleet's buildkit runners
# (cross-network routing unresolved — see Dockerfile.htmx-ssr). Uncomment
# once that's sorted, repointing endpoint/bucket/region/credential at Garage.
# sccache = {
# bucket = "wuji-sccache",
# endpoint = "https://fsn1.your-objectstorage.com",
# region = "eu-central-1",
# credential = { kind = 's3, path = project.build_secrets.sccache },
# },
} in
let make_directive = fun df bargs =>
d.make_build_directives {
workspace = project.workspace_id,
artifacts = [
d.make_artifact {
image = shared.image_ref,
dockerfile = df,
context = "..", # parent of lian-build/ = repo root
platforms = ["linux/amd64", "linux/arm64"],
build_args = bargs,
},
],
adapter = shared.adapter,
registry = shared.registry,
cache = shared.cache,
signing = shared.signing,
# sccache = shared.sccache, # disabled temporarily — see shared.sccache comment above
}
in
# Dockerfile suffix === profile name, so the path never drifts from the key.
{
"leptos-hydration" = make_directive "lian-build/Dockerfile.leptos-hydration" leptos_args,
"htmx-ssr" = make_directive "lian-build/Dockerfile.htmx-ssr" htmx_args,
}