feat(edge): send unsupported R minors to CRAN instead of serving them

Falling back to the flat index for an excluded minor is the silent case:
risky packages there are built under another minor and fail at load time,
far from the cause. Send those clients to CRAN for sources instead, which
is what the router already does for an unidentifiable distro.

The whole interaction has to move, not just the index. R resolves tarball
URLs against the repo it was configured with, so serving the index from
CRAN and tarballs from here would hand R a binary where it expects a
source tarball.

A client reporting no R minor at all is not excluded: mirror scripts and
image builds keep getting the flat slot.

- Declare the supported window once in cdn.tf as local.rpkgs_supported_minors
  and set KNOWN_MINORS from it on both zones, so the router cannot drift
  from build-env-images' LATEST/PREV1/PREV2 unnoticed.
- Split the verification script into supported and excluded minors: the
  former must have published indexes, the latter must have none and must
  redirect to CRAN under --live.
This commit is contained in:
Patrick Schratz 2026-08-30 15:44:14 +00:00
commit 771d3a7768
No known key found for this signature in database
GPG key ID: 62050D5BC68AB6DC

46
cdn.tf
View file

@ -52,6 +52,26 @@
### cran.rpkgs.com
locals {
rpkgs_slots = [
for pair in setproduct(
["amd64", "arm64"],
["resolute", "noble", "jammy", "rhel8", "rhel9", "rhel10", "alpine323", "alpine324"]
) : "${pair[0]}/${pair[1]}"
]
# The supported R minors: the current one plus the two previous, which is
# exactly what build-env-images installs as R_VERSION_LATEST / PREV1 / PREV2.
# These must stay in step. A minor listed here without a published index
# sends those clients to a 404; a published minor missing from this list
# sends them to CRAN for sources instead of serving the binaries we built.
rpkgs_supported_minors = ["4.4", "4.5", "4.6"]
# bunny.net serves every pull zone on <name>.b-cdn.net, so staging needs no
# DNS record and is never advertised.
rpkgs_test_hostname = "cran-rpkgs-test.b-cdn.net"
}
# The edge middleware that resolves the bare cran.rpkgs.com form to an
# <arch>/<os> slot and routes PACKAGES* to the per-R-minor slot. The source of
# truth is edge/rpkgs-router.ts; `tofu apply` publishes a new release.
@ -75,6 +95,13 @@ resource "bunnynet_compute_script_variable" "rpkgs_router_union_slots" {
required = false
}
resource "bunnynet_compute_script_variable" "rpkgs_router_known_minors" {
script = bunnynet_compute_script.rpkgs_router.id
name = "KNOWN_MINORS"
default_value = join(",", local.rpkgs_supported_minors)
required = false
}
resource "bunnynet_pullzone" "cran_rpkgs_com" {
name = "cran-rpkgs"
@ -152,18 +179,6 @@ resource "bunnynet_pullzone_hostname" "cran_rpkgs_com" {
# Every published <arch>/<os> slot. The staging zone enables per-minor routing
# for all of them at once; production adopts the same list only after
# `scripts/verify-r-minor-routing.sh --live` passes against staging.
locals {
rpkgs_slots = [
for pair in setproduct(
["amd64", "arm64"],
["resolute", "noble", "jammy", "rhel8", "rhel9", "rhel10", "alpine323", "alpine324"]
) : "${pair[0]}/${pair[1]}"
]
# bunny.net serves every pull zone on <name>.b-cdn.net, so staging needs no
# DNS record and is never advertised.
rpkgs_test_hostname = "cran-rpkgs-test.b-cdn.net"
}
# A second copy of the same router, bound to the same B2 origin, so UNION_SLOTS
# can be exercised end to end before production is touched.
@ -189,6 +204,13 @@ resource "bunnynet_compute_script_variable" "rpkgs_router_test_extra_hosts" {
required = false
}
resource "bunnynet_compute_script_variable" "rpkgs_router_test_known_minors" {
script = bunnynet_compute_script.rpkgs_router_test.id
name = "KNOWN_MINORS"
default_value = join(",", local.rpkgs_supported_minors)
required = false
}
resource "bunnynet_pullzone" "cran_rpkgs_test" {
name = "cran-rpkgs-test"