feat(ci): verify what clients actually receive from every published slot (#209)
Some checks failed
ci/crow/manual/verify-repo-routing/15 Pipeline was successful
ci/crow/manual/verify-repo-routing/3 Pipeline failed
ci/crow/manual/prune-stale-flat-binaries/15 Pipeline was successful
ci/crow/manual/reindex/7 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline failed
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/manual/verify-repo-routing/16 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/manual/repair-unsafe-flat-objects/7 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
Some checks failed
ci/crow/manual/verify-repo-routing/15 Pipeline was successful
ci/crow/manual/verify-repo-routing/3 Pipeline failed
ci/crow/manual/prune-stale-flat-binaries/15 Pipeline was successful
ci/crow/manual/reindex/7 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline failed
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/manual/verify-repo-routing/16 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/manual/repair-unsafe-flat-objects/7 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
## Why Everything built so far reasons about the *binaries*: `abi_flat_safety` records what an object's symbols say it can load under, and the index writer drops records on that verdict. None of it proves what a **client** actually receives, which is the product of the CDN rewrite, the per-minor indexes and the `Path:` field acting together. The reprex that found the `base64enc` failure ran on a workstation, could only reach amd64, and did not survive the session. This makes it a pipeline. ## What it does For every slot, under every R minor the image carries, it installs a fixed package set through each URL form the website documents and checks that each one loads in a fresh subprocess. | form | repository | user agent | | --- | --- | --- | | `arch` | `https://cran.rpkgs.com/<arch>/<codename>/latest` | R's own | | `generic` | `https://cran.rpkgs.com/` | the string the website's snippet builds | | `flat` | the arch URL | `curl/8.5.0`, so the edge cannot read an R minor | `arch` and `generic` are contractual, so a failure there fails the run. `flat` measures what a client hiding its R minor is exposed to: it is reported and never fatal, because pruning the flat slot is a separate decision. Two details that matter: - **CRAN is deliberately absent from `repos`.** A package missing from our index must fail loudly rather than be quietly compiled from source, which would hide exactly the gap this exists to find. - **One process per form.** `available.packages()` caches its index in `tempdir()` keyed by repository URL, and `arch` and `flat` share a URL. In a single process the second form would read the first form's index and prove nothing. ## Verification Run against the live repository in `build-env-ubuntu:noble` under R 4.6.0, mid-repair: ``` amd64/noble R 4.6 via arch: 11 of 11 packages usable amd64/noble R 4.6 via generic: 11 of 11 packages usable amd64/noble R 4.6 via flat: 8 of 11 packages usable ``` The three `flat` failures are `Rcpp`, `data.table` and `yaml`, each `Built: R 4.4.3` and each failing `dyn.load()` under 4.6. That is the unrouted-client exposure, measured rather than estimated. The rows also show the routed forms serving a mix of per-minor and flat objects (`Rcpp` at `R 4.6.0`, `stringi` at `R 4.4.3`), which is the intended behaviour: only objects that cannot load cross-minor get a per-minor copy. Reviewed-on: #209
This commit is contained in:
parent
4342fa773a
commit
af4cc6f414
1 changed files with 346 additions and 0 deletions
156
.crow/verify-repo-routing.yaml
Normal file
156
.crow/verify-repo-routing.yaml
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
# Install a fixed set of packages from a published slot under every R minor the
|
||||
# image carries, through each URL form the website tells people to configure,
|
||||
# and check that each one loads.
|
||||
#
|
||||
# This is the end-to-end counterpart to the ABI bookkeeping: `abi_flat_safety`
|
||||
# records what the binaries say about themselves, this proves what a client
|
||||
# actually receives once the CDN, the per-minor indexes and the `Path:` field
|
||||
# have had their say. It runs on the build agents rather than a workstation so
|
||||
# arm64 is covered on real hardware.
|
||||
#
|
||||
# crow pipeline create devxy/build-cran-binaries --var verify_routing=all
|
||||
|
||||
variables:
|
||||
# A manual pipeline creation instantiates every file in .crow/, so the default
|
||||
# must match no matrix row.
|
||||
verify_routing:
|
||||
description: "Verify target: a specific <os>-<arch>, 'all' for every slot, or 'none'."
|
||||
options:
|
||||
- none
|
||||
- all
|
||||
- alpine-322-amd64
|
||||
- alpine-322-arm64
|
||||
- alpine-323-amd64
|
||||
- alpine-323-arm64
|
||||
- alpine-324-amd64
|
||||
- alpine-324-arm64
|
||||
- redhat-8-amd64
|
||||
- redhat-8-arm64
|
||||
- redhat-9-amd64
|
||||
- redhat-9-arm64
|
||||
- redhat-10-amd64
|
||||
- redhat-10-arm64
|
||||
- ubuntu-2204-amd64
|
||||
- ubuntu-2204-arm64
|
||||
- ubuntu-2404-amd64
|
||||
- ubuntu-2404-arm64
|
||||
- ubuntu-2604-amd64
|
||||
- ubuntu-2604-arm64
|
||||
default: none
|
||||
|
||||
when:
|
||||
- event: manual
|
||||
evaluate: 'verify_routing == "all" || verify_routing == "${OS}-${ARCH}"'
|
||||
|
||||
skip_clone: true
|
||||
|
||||
labels:
|
||||
group: rpkgs-${ARCH}
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- OS: alpine-322
|
||||
ARCH: amd64
|
||||
R_VERSION: 4.5.3
|
||||
IMG: alpine:3.22
|
||||
- OS: alpine-322
|
||||
ARCH: arm64
|
||||
R_VERSION: 4.5.3
|
||||
IMG: alpine:3.22
|
||||
- OS: alpine-323
|
||||
ARCH: amd64
|
||||
R_VERSION: 4.5.3
|
||||
IMG: alpine:3.23
|
||||
- OS: alpine-323
|
||||
ARCH: arm64
|
||||
R_VERSION: 4.5.3
|
||||
IMG: alpine:3.23
|
||||
- OS: alpine-324
|
||||
ARCH: amd64
|
||||
R_VERSION: 4.5.3
|
||||
IMG: alpine:3.24
|
||||
- OS: alpine-324
|
||||
ARCH: arm64
|
||||
R_VERSION: 4.5.3
|
||||
IMG: alpine:3.24
|
||||
- OS: redhat-8
|
||||
ARCH: amd64
|
||||
R_VERSION: 4.4.3
|
||||
IMG: redhat:8
|
||||
- OS: redhat-8
|
||||
ARCH: arm64
|
||||
R_VERSION: 4.4.3
|
||||
IMG: redhat:8
|
||||
- OS: redhat-9
|
||||
ARCH: amd64
|
||||
R_VERSION: 4.4.3
|
||||
IMG: redhat:9
|
||||
- OS: redhat-9
|
||||
ARCH: arm64
|
||||
R_VERSION: 4.4.3
|
||||
IMG: redhat:9
|
||||
- OS: redhat-10
|
||||
ARCH: amd64
|
||||
R_VERSION: 4.5.3
|
||||
IMG: redhat:10
|
||||
- OS: redhat-10
|
||||
ARCH: arm64
|
||||
R_VERSION: 4.5.3
|
||||
IMG: redhat:10
|
||||
- OS: ubuntu-2204
|
||||
ARCH: amd64
|
||||
R_VERSION: 4.4.3
|
||||
IMG: ubuntu:jammy
|
||||
- OS: ubuntu-2204
|
||||
ARCH: arm64
|
||||
R_VERSION: 4.4.3
|
||||
IMG: ubuntu:jammy
|
||||
- OS: ubuntu-2404
|
||||
ARCH: amd64
|
||||
R_VERSION: 4.4.3
|
||||
IMG: ubuntu:noble
|
||||
- OS: ubuntu-2404
|
||||
ARCH: arm64
|
||||
R_VERSION: 4.4.3
|
||||
IMG: ubuntu:noble
|
||||
- OS: ubuntu-2604
|
||||
ARCH: amd64
|
||||
R_VERSION: 4.4.3
|
||||
IMG: ubuntu:resolute
|
||||
- OS: ubuntu-2604
|
||||
ARCH: arm64
|
||||
R_VERSION: 4.4.3
|
||||
IMG: ubuntu:resolute
|
||||
|
||||
steps:
|
||||
- name: 'Verify routing serves loadable binaries'
|
||||
image: reg.devxy.io/rpkgs/build-env-${IMG}
|
||||
pull: true
|
||||
environment:
|
||||
OTEL_R_TRACES_EXPORTER: none
|
||||
OTEL_R_LOGS_EXPORTER: none
|
||||
OTEL_R_METRICS_EXPORTER: none
|
||||
REPO_RO_TOKEN:
|
||||
from_secret: REPO_RO_TOKEN
|
||||
VERIFY_ARCH: ${ARCH}
|
||||
commands:
|
||||
- git clone -q https://pat-s:$$REPO_RO_TOKEN@git.devxy.io/devxy/build-cran-binaries.git .
|
||||
- |
|
||||
set -eu
|
||||
CODENAME=$(/opt/R/$R_VERSION/bin/Rscript -e 'cat(bincraft::set_codename(NULL))')
|
||||
rc=0
|
||||
for RBIN in /opt/R/[0-9]*/bin/R; do
|
||||
RV=$(basename "$(dirname "$(dirname "$$RBIN")")")
|
||||
for FORM in arch generic flat; do
|
||||
echo "=== R $$RV via $$FORM ==="
|
||||
"$(dirname "$$RBIN")/Rscript" local/verify-repo-routing.R \
|
||||
"$$VERIFY_ARCH" "$$CODENAME" "$$FORM" || rc=1
|
||||
done
|
||||
done
|
||||
exit $$rc
|
||||
backend_options:
|
||||
docker:
|
||||
resources:
|
||||
requests:
|
||||
memory: 4Gi
|
||||
cpu: 1000m
|
||||
Loading…
Reference in a new issue