]> git.ipfire.org Git - thirdparty/freeradius-server.git/log
thirdparty/freeradius-server.git
2 weeks agobake CI build environments into pre-baked base images
Arran Cudbard-Bell [Mon, 18 May 2026 14:42:04 +0000 (10:42 -0400)] 
bake CI build environments into pre-baked base images

The rpm/deb/crossbuild jobs previously pulled stock distro images on every
run and re-installed the build-dep closure inline. That made every job
flaky in the face of upstream mirror outages and left rocky-10 broken
because nothing was carving out git's `safe.directory` for the workspace
that the runner UID and the in-container root UID disagree on.

Add two new parametrised CI Dockerfiles under scripts/ci/docker/ - one
for the rpm side (rocky 9/10) and one for the deb side (debian 12/13/sid,
ubuntu 22/24/26). Each bakes in the toolchain, NetworkRADIUS extras,
the full mk-build-deps / dnf builddep closure against the source-tree
control/spec, and `git config --system --add safe.directory '*'`. The
matrix in docker-refresh.yml grows entries for all eight images and now
also triggers on changes to debian/control or redhat/freeradius.spec
(plus a nightly cron) so the closure stays current.

ci-rpm/ci-deb switch their build container to the matching internal
image. The per-job setup-the-world steps go away; mk-build-deps /
dnf builddep stay as cheap top-ups. Both workflows are gated to the
main repo (push) or PRs against it - fork pushes can't reach the
internal registry and were already broken by this transition.

The crossbuild Makefile gains a CB_FROM_<distro> override (empty by
default, so local builds still FROM upstream images and need no internal
infrastructure). crossbuild.yml exports the overrides per-distro, which
kills the docker.io FROM-pull inside dind on every job and lets the
Docker Hub login step go. CI Dockerfiles also relocated from scripts/ci
into scripts/ci/docker for clarity now that there are five of them.

2 weeks agoremove duplication and clean up for code formatting and style
Alan T. DeKok [Sun, 17 May 2026 16:08:12 +0000 (12:08 -0400)] 
remove duplication and clean up for code formatting and style

2 weeks agoadd fuzzing harness to be consumed by OSS-Fuzz
David Korczynski [Sun, 17 May 2026 16:07:38 +0000 (09:07 -0700)] 
add fuzzing harness to be consumed by OSS-Fuzz

Adds a fuzzing harness for the xlat* files, which are currently unfuzzed
(see xplat* files here:
https://storage.googleapis.com/oss-fuzz-coverage/freeradius/reports/20260517/linux/src/freeradius-server/src/lib/unlang/report.html)

This harness will be consumed by OSS-fuzz to be run continuously.

Signed-off-by: David Korczynski <david@adalogics.com>
2 weeks agomove dump fuzzer to after ASAN unpoison
Alan T. DeKok [Sun, 17 May 2026 13:09:34 +0000 (09:09 -0400)] 
move dump fuzzer to after ASAN unpoison

so we don't get spurious ASAN warnings

2 weeks agoallow specifying a root attribute in FR_FUZZER_ROOT_ATTR
Alan T. DeKok [Sun, 17 May 2026 12:48:52 +0000 (08:48 -0400)] 
allow specifying a root attribute in FR_FUZZER_ROOT_ATTR

DER needs a root attribute, as the dictionary is really just
a large collection of OIDs.  We need to be able to fuzz
certificates, CSRs, etc. all individually

2 weeks agoupdate DER decoder to allow specifying a root DA to start from
Alan T. DeKok [Sun, 17 May 2026 12:40:57 +0000 (08:40 -0400)] 
update DER decoder to allow specifying a root DA to start from

2 weeks agowrite fuzzer output for decode_proto and decode_pair
Alan T. DeKok [Sun, 17 May 2026 12:31:29 +0000 (08:31 -0400)] 
write fuzzer output for decode_proto and decode_pair

2 weeks agoinitialize stack->ptr for proper error messages
Alan T. DeKok [Sun, 17 May 2026 12:24:13 +0000 (08:24 -0400)] 
initialize stack->ptr for proper error messages

2 weeks agomoved fuzzer code to its own directory
Alan T. DeKok [Sun, 17 May 2026 12:03:46 +0000 (08:03 -0400)] 
moved fuzzer code to its own directory

there are enough fuzzers now that it's cleaner to organize them
separately.

2 weeks agocleanups and remove duplications
Alan T. DeKok [Sun, 17 May 2026 11:40:21 +0000 (07:40 -0400)] 
cleanups and remove duplications

2 weeks agoadjust for review
David Korczynski [Sat, 16 May 2026 15:21:39 +0000 (16:21 +0100)] 
adjust for review

Signed-off-by: David Korczynski <david@adalogics.com>
2 weeks agoadd new harness targeting value parsing
David Korczynski [Sat, 16 May 2026 14:00:44 +0000 (15:00 +0100)] 
add new harness targeting value parsing

The value.c has around 25% code coverage at the moment: https://storage.googleapis.com/oss-fuzz-coverage/freeradius/reports/20260514/linux/src/freeradius-server/src/lib/util/value.c.html
and this extends on that to achieve 70%+ from a local run.

Signed-off-by: David Korczynski <david@adalogics.com>
2 weeks agouse our own lsan.h
Alan T. DeKok [Sat, 16 May 2026 15:54:37 +0000 (11:54 -0400)] 
use our own lsan.h

2 weeks agoadd config file handling logic
David Korczynski [Sat, 16 May 2026 15:02:56 +0000 (16:02 +0100)] 
add config file handling logic

This adds coverage for missing files, e.g. cf_file.c and cf_utils.c

Signed-off-by: David Korczynski <david@adalogics.com>
3 weeks agoDocument MariaDB support in README (#5857)
Robert Silén [Sat, 16 May 2026 17:37:05 +0000 (20:37 +0300)] 
Document MariaDB support in README (#5857)

List MariaDB alongside MySQL in the main README and rlm_sql_mysql driver
README. The module is built as MySQL and MariaDB support (libmariadb).

3 weeks agoupdate for ASAN
Alan T. DeKok [Sat, 16 May 2026 15:50:08 +0000 (11:50 -0400)] 
update for ASAN

in order to remove duplicate definitions

3 weeks agoadd cast to quiet compiler warnings
Alan T. DeKok [Fri, 15 May 2026 18:56:12 +0000 (11:56 -0700)] 
add cast to quiet compiler warnings

3 weeks agoadd fr_packet_t
Alan T. DeKok [Mon, 11 May 2026 22:22:13 +0000 (15:22 -0700)] 
add fr_packet_t

3 weeks agocleanup: also delete cancelled diagnosis runs
Arran Cudbard-Bell [Fri, 15 May 2026 20:41:04 +0000 (14:41 -0600)] 
cleanup: also delete cancelled diagnosis runs

When several CI workflows fail on the same commit, the diagnosis
concurrency group queues their runs and any pending duplicates get
cancelled by GitHub. Those have conclusion=cancelled (not skipped)
so they were slipping past the cleanup. Include them.

3 weeks agoMore const fixes
Arran Cudbard-Bell [Fri, 15 May 2026 20:17:12 +0000 (14:17 -0600)] 
More const fixes

3 weeks agoFix const correctness issues
Arran Cudbard-Bell [Fri, 15 May 2026 20:07:09 +0000 (14:07 -0600)] 
Fix const correctness issues

3 weeks agocleanup: per-conclusion targeting (keep failures, drop noise)
Arran Cudbard-Bell [Fri, 15 May 2026 19:22:42 +0000 (13:22 -0600)] 
cleanup: per-conclusion targeting (keep failures, drop noise)

Refine what each side of the cleanup deletes vs keeps:

  Claude CI Failure Diagnosis
    delete:  skipped
    keep:    success  (paired with the commit comment they posted)
    keep:    failure  (we want to know if a diagnosis crashed)

  Cleanup Skipped Diagnosis Runs (this workflow)
    delete:  success  (job done, nothing to look at)
    delete:  skipped  (defensive; the workflow doesn't currently produce
                       these but if a future change adds an if: that
                       could skip, we want them swept too)
    keep:    failure  (we want to see when the cleanup itself broke)

Same 10-minute cadence as before.

3 weeks agocleanup: run every 10 minutes, delete all completed diagnosis runs
Arran Cudbard-Bell [Fri, 15 May 2026 19:19:12 +0000 (13:19 -0600)] 
cleanup: run every 10 minutes, delete all completed diagnosis runs

Previously hourly with a 1h grace window, only sweeping status=skipped.
Bump the cadence to every 10 minutes and broaden to status=completed so
all conclusions (skipped, success, failure, cancelled, timed_out) get
deleted. Successful diagnosis runs are pure noise after the fact - their
useful output is the commit comment, which lives on the commit, not the
run record.

Self-clean step now also deletes any completed cleanup run (still skips
the current one to avoid self-deletion mid-flight).

Net effect: Actions tab stops accumulating diagnosis-workflow noise
within at most ~10 minutes of any individual run finishing.

3 weeks agoAdd 'arp' to FUZZER_PROTOCOLS in all.mk (#5854)
DavidKorczynski [Fri, 15 May 2026 19:02:21 +0000 (20:02 +0100)] 
Add 'arp' to FUZZER_PROTOCOLS in all.mk (#5854)

Enable fuzzing of the `arp` protocol logic

3 weeks agomulti-server: rename framework repo from freeradius-multi-server to radenv
Arran Cudbard-Bell [Fri, 15 May 2026 18:58:26 +0000 (12:58 -0600)] 
multi-server: rename framework repo from freeradius-multi-server to radenv

InkbridgeNetworks/freeradius-multi-server has been renamed to
InkbridgeNetworks/radenv. Update both:
  - TEST_MULTI_SERVER_GIT_REPO (clone source URL)
  - TEST_MULTI_SERVER_FRAMEWORK_DIR (local checkout path under
    build/) so the on-disk directory matches the repo name.

All other references to the framework dir go through the variable so
this is a two-line change. The previous clone path (build/freeradius-
multi-server) will be left behind by an existing checkout; it's safe
to delete manually but doesn't have to be - make crossbuild.* will
just create a fresh build/radenv next to it.

3 weeks agofuzzer.mk: tolerate missing corpus tar (empty/new protocol case)
Arran Cudbard-Bell [Fri, 15 May 2026 18:44:49 +0000 (12:44 -0600)] 
fuzzer.mk: tolerate missing corpus tar (empty/new protocol case)

When a protocol is added to FUZZER_PROTOCOLS but doesn't yet have a
corresponding src/tests/fuzzer-corpus/<protocol>.tar, the prerequisite
recipe blew up at "tar -xf <protocol>.tar" with "no such file" and
make test.fuzzer.<protocol> failed before libfuzzer ever ran.

Check whether the tar exists before extracting; if not, create an
empty corpus directory and continue. libfuzzer accepts an empty
corpus directory and generates random inputs from there - the right
behaviour for a fresh protocol with no curated seeds yet.

Triggered by PR #5854 adding 'arp' to FUZZER_PROTOCOLS without an
accompanying arp.tar.

3 weeks agoGate @claude mention handler on author_association
Arran Cudbard-Bell [Fri, 15 May 2026 18:41:03 +0000 (12:41 -0600)] 
Gate @claude mention handler on author_association

PR review / comment events that originate on a fork PR run with
restricted GITHUB_TOKEN regardless of the permissions: block. The
Claude Code action needs id-token: write to fetch its OIDC token,
which GitHub denies in that restricted mode - so every first-time
contributor's @claude mention failed with "Could not fetch an OIDC
token. Did you remember to add `id-token: write` to your workflow
permissions?"

Limit the if: to OWNER/MEMBER/COLLABORATOR author_association on the
relevant event payload, matching the same pattern claude-code-review.yml
uses for its automatic reviews. External contributors can still get
Claude on their PR by asking a maintainer to re-mention @claude
in-thread.

3 weeks agoWipe should be distclean like everywhere else
Arran Cudbard-Bell [Fri, 15 May 2026 16:42:16 +0000 (10:42 -0600)] 
Wipe should be distclean like everywhere else

3 weeks agoProperly quote BUILD_ values
Arran Cudbard-Bell [Fri, 15 May 2026 16:31:58 +0000 (10:31 -0600)] 
Properly quote BUILD_ values

3 weeks agoCheck the output of write
Arran Cudbard-Bell [Fri, 15 May 2026 16:30:50 +0000 (10:30 -0600)] 
Check the output of write

3 weeks agoCleanup-workflow self-clean: match the 1h window
Arran Cudbard-Bell [Fri, 15 May 2026 14:40:29 +0000 (08:40 -0600)] 
Cleanup-workflow self-clean: match the 1h window

At hourly cadence the previous 7-day retention would leave ~168 of
our own runs visible. Match the same 1h grace window the diagnosis-
cleanup step uses, so at most 1-2 cleanup runs are in the Actions tab
at any time.

3 weeks agoTighten diagnosis-cleanup to hourly + 1h grace window
Arran Cudbard-Bell [Fri, 15 May 2026 14:39:35 +0000 (08:39 -0600)] 
Tighten diagnosis-cleanup to hourly + 1h grace window

Run the cleanup every hour instead of daily, and only delete skipped
diagnosis runs whose created_at is more than 1 hour old. That keeps
the Actions tab tidy in near-real-time while still leaving a brief
inspection window in case someone wants to look at a fresh skipped
run before it's swept.

Self-clean of the cleanup workflow's own runs stays at older-than-7-days.

3 weeks agoScheduled cleanup of skipped Claude CI Failure Diagnosis runs
Arran Cudbard-Bell [Fri, 15 May 2026 14:35:23 +0000 (08:35 -0600)] 
Scheduled cleanup of skipped Claude CI Failure Diagnosis runs

The diagnosis workflow fires on every CI completion (its workflow_run
trigger can't filter on conclusion) and uses a job-level if: to gate
on push-failure-on-master/developer. Non-failures leave "Skipped"
entries in the Actions tab.

Add a small scheduled workflow that runs daily, finds completed
skipped runs of the diagnosis workflow, and deletes them via the
Actions API. Also self-cleans its own runs older than 7 days so
the cleanup itself doesn't become the new clutter.

Runs only on the FreeRADIUS org repo; gh.run.delete needs actions:write.

3 weeks agoDiagnose failures on developer/* branches as well as master
Arran Cudbard-Bell [Fri, 15 May 2026 14:32:32 +0000 (08:32 -0600)] 
Diagnose failures on developer/* branches as well as master

workflow_run jobs only run if the if: condition holds, and previously
that required head_branch == 'master'. Failures on personal
developer/<user> branches were silently skipped even though that's
exactly the place where seeing a diagnosis comment is most useful
(you're iterating on a fix and want the prior failure understood).

Loosen the gate to accept any branch whose name is master or starts
with developer/. Push event + failure conclusion gates stay; PR-event
failures still skip (they get covered by the separate Claude Code
Review path).

3 weeks agoQuiet coverity
Arran Cudbard-Bell [Fri, 15 May 2026 14:06:08 +0000 (08:06 -0600)] 
Quiet coverity

3 weeks agodebian/redhat: ship freeradius-utils-json package
Arran Cudbard-Bell [Fri, 15 May 2026 05:34:19 +0000 (23:34 -0600)] 
debian/redhat: ship freeradius-utils-json package

New subpackage containing the three JSON conversion utilities
(radconf2json, radjson2conf, radmod2json) for both Debian and RPM.

Split out from the main freeradius-utils package because these
binaries hard-link against libfreeradius-json.so and pull in json-c
as a runtime dep - clients that only want radclient and friends
shouldn't be forced to install json-c.

3 weeks agoutil/server/unlang: enum-name lookups + FR_TABLE_INDEXED_BIT_POS_ENTRY
Arran Cudbard-Bell [Fri, 15 May 2026 05:34:09 +0000 (23:34 -0600)] 
util/server/unlang: enum-name lookups + FR_TABLE_INDEXED_BIT_POS_ENTRY

New public helpers that return the C source-identifier form of a value
(matching the `fr_*_to_enum_str` family added earlier):

  - fr_token_from_quote_enum_str()       (util/token.c)
      Inverse of fr_token_to_enum_str for the five quote-typed tokens.
      Used by radjson2conf when rebuilding a CF tree from JSON.

  - cf_parser_flag_to_enum_str()         (server/cf_parse.c)
      Single-bit CONF_FLAG_* mask -> "CONF_FLAG_REQUIRED" / ...

  - call_env_flag_to_enum_str()          (unlang/call_env.c)
      Single-bit CALL_ENV_FLAG_* mask -> "CALL_ENV_FLAG_REQUIRED" / ...

  - call_env_parse_type_to_enum_str()    (unlang/call_env.c)
  - call_env_result_type_to_enum_str()   (unlang/call_env.c)
      Enum value -> source identifier name.

The three CONF_FLAG_* / CALL_ENV_FLAG_* / call_env_*_type lookup tables
that lived in radmod2json.c move into the libraries they belong to so
other consumers (introspection, debug logging, future tooling) can use
them.

`FR_TABLE_INDEXED_BIT_POS_ENTRY(_v)` in table.h is the bit-pos analogue
of FR_TABLE_INDEXED_ENTRY - expands to
`[__builtin_ctz(_v) + 1] = { L("_v"), _v }`, matching what
fr_table_indexed_str_by_bit_field expects.

table.h: fix two latent bugs in the value-by-index lookup macros.
TABLE_TYPE_VALUE_INDEX_FUNC / TABLE_TYPE_VALUE_INDEX_BIT_FIELD_FUNC
returned `table[value].name.str` without checking whether that slot was
populated.  For sparse tables (designated-initialiser entries with
gaps - which is exactly the shape FR_TABLE_INDEXED_ENTRY produces) the
zero-initialised gap returned a NULL pointer instead of the caller's
default, crashing strlen() in any caller that passes the result to a
string API.  Both macros now fall through to `def` when name.str is
NULL.

3 weeks agoradconf2json / radmod2json: call shared fr_*_to_enum_str helpers
Arran Cudbard-Bell [Fri, 15 May 2026 05:03:12 +0000 (23:03 -0600)] 
radconf2json / radmod2json: call shared fr_*_to_enum_str helpers

Drop the local symbolic-name lookups that lived in each utility; call
into the new fr_token_to_enum_str() (src/lib/util/token.c) and
fr_type_to_enum_str() (src/lib/util/types.c) directly.  Removes ~80
lines of duplicated enum tables across the two binaries.

The remaining bit-pos flag tables (CONF_FLAG_*, CALL_ENV_FLAG_*) and
the call_env enum tables stay in radmod2json.c for now - those are
candidates for their own move into cf_parse.c / call_env.c when the
public APIs settle.

3 weeks agoutil: fr_type_to_enum_str / fr_token_to_enum_str + FR_TABLE_INDEXED_ENTRY macro
Arran Cudbard-Bell [Fri, 15 May 2026 05:03:12 +0000 (23:03 -0600)] 
util: fr_type_to_enum_str / fr_token_to_enum_str + FR_TABLE_INDEXED_ENTRY macro

Two new public helpers, each returning the C source-identifier form of
an enum value (FR_TYPE_STRING / T_BARE_WORD / T_OP_SET / ...).  Mirror
the existing fr_type_to_str / fr_tokens[] which return the short
config-file form ("string", "<BARE-WORD>", ":=") - tools that want to
grep the v4 tree by enum identifier (radmod2json / radconf2json) use
these instead.

Both look up through v4's standard table machinery:
fr_table_str_by_value() with fr_table_num_indexed_t tables (key = enum
value, value = symbolic name).

`FR_TABLE_INDEXED_ENTRY(_v)` in table.h expands to
`[_v] = { L("_v"), _v }` so the identifier doesn't have to be written
three times when populating one of these tables.  Used in types.c and
token.c.

3 weeks agoAdd radconf2json, radmod2json and radjson2conf utilities
Arran Cudbard-Bell [Fri, 15 May 2026 04:35:14 +0000 (22:35 -0600)] 
Add radconf2json, radmod2json and radjson2conf utilities

Three JSON-bridge utilities used by the v3-to-v4 converter pipeline:

  * radconf2json: dump a parsed server config tree as JSON.  Opt-in
    comment preservation lets `# ...` lines round-trip through the
    JSON so downstream tooling can edit and re-emit the source.

  * radmod2json:  dump module conf_parser_t + call_env_parser_t
                  schemas as JSON via dl_module_alloc (proper module
                  loader, magic verified, init callbacks honoured).
                  Each dlopen+dump is fork-sandboxed so a misbehaving
                  module can't take the whole run down.  Function
                  pointers are resolved to source symbols via
                  dladdr.

  * radjson2conf: parse the JSON back into a CONF_SECTION tree and
                  write it out as a v4 .conf file using
                  cf_section_write / cf_section_write_children.  -r
                  emits each child of the synthetic root at file
                  scope so a fragment can be rendered without an
                  outer wrapper.

JSON shape mirrors the C struct field names verbatim (FR_TYPE_STRING,
T_BARE_WORD, CONF_FLAG_REQUIRED, ...) so converter rule files can
grep against the source tree.

Symbolic-name <-> token lookups use v4's existing table machinery
(fr_tokens / fr_tokens_table for operators, fr_table_num_indexed_bit_pos_t
for CONF_FLAG_* / CALL_ENV_FLAG_* masks, fr_table_ptr_sorted_t for the
JSON `type` -> builder dispatch); no hand-rolled switch cascades.

3 weeks ago.clang-format: indent preprocessor directives with two spaces
Arran Cudbard-Bell [Fri, 15 May 2026 04:38:35 +0000 (22:38 -0600)] 
.clang-format: indent preprocessor directives with two spaces

3 weeks agocf_file: opt-in comment preservation + expose cf_section_write
Arran Cudbard-Bell [Fri, 15 May 2026 03:47:53 +0000 (21:47 -0600)] 
cf_file: opt-in comment preservation + expose cf_section_write

Build-out of the CF parser to support tooling that wants to round-trip
the source through the tree without losing structure (radconf2json and
friends in the v3-to-v4 converter pipeline).  No behaviour change for
the runtime server parser - it leaves the new flag off and continues
to drop comments as it always has.

  * New CONF_ITEM_COMMENT item type: a `# ...` line captured verbatim
    and parented on the current section.  Off by default; utilities
    flip a static flag via `cf_preserve_comments_set(true)` before
    cf_file_read().  Private getter `_cf_preserve_comments()` lives
    in cf_priv.h and gates the capture in cf_section_read.

  * CONF_COMMENT alloc + accessor surface in cf_util.h, mirroring the
    existing cf_pair_* / cf_section_* shape: cf_comment_alloc,
    cf_comment_text, cf_comment_filename, cf_comment_lineno,
    cf_item_is_comment, cf_item_to_comment, cf_comment_to_item.

  * cf_section_write exposed in cf_file.h so external utilities can
    serialise a tree back to a .conf file without rebuilding the
    output by hand.  CONF_COMMENT items render at section depth.

  * Defensive NULL guards on the rbtree look-up in cf_find() so a
    section that's only ever held CONF_COMMENT children (and so
    didn't grow an ident2 tree) doesn't crash on look-up.

3 weeks agoWS
Nick Porter [Mon, 27 Apr 2026 17:02:23 +0000 (18:02 +0100)] 
WS

3 weeks agoAdd cluster size options to redis-setup.sh
Nick Porter [Mon, 11 May 2026 13:10:58 +0000 (14:10 +0100)] 
Add cluster size options to redis-setup.sh

3 weeks agoAdd port option to redis-setup.sh
Nick Porter [Mon, 11 May 2026 12:44:22 +0000 (13:44 +0100)] 
Add port option to redis-setup.sh

3 weeks agoAdd -a option to redis-setup script
Nick Porter [Mon, 11 May 2026 12:32:23 +0000 (13:32 +0100)] 
Add -a option to redis-setup script

To allow test cluster to use redis auth

3 weeks agoWITH_EVAL_DEBUG does nothing in v4
Nick Porter [Thu, 14 May 2026 09:55:58 +0000 (10:55 +0100)] 
WITH_EVAL_DEBUG does nothing in v4

3 weeks agoRe-add Hub login inside dind for the three selfhosted dind workflows
Arran Cudbard-Bell [Fri, 15 May 2026 02:36:09 +0000 (20:36 -0600)] 
Re-add Hub login inside dind for the three selfhosted dind workflows

self-hosted-docker-dind has registry-mirrors -> docker.internal.networkradius.com
baked in via /etc/docker/daemon.json. The assumption was that the internal
registry would proxy Docker Hub pulls (pull-through cache). It doesn't -
when dind tries to pull a public image (kafka, ubuntu:24.04, debian:bookworm,
etc.), the mirror returns 404 and dockerd falls back to docker.io
anonymously. The fallback hits Docker Hub's 100/6h anonymous limit and
fails with "toomanyrequests".

Re-add the docker/login-action@v4 step in multi-server-tests, docker.yml-
selfhosted, and crossbuild.yml-selfhosted so dind authenticates against
Hub before any FROM-pull. Authenticated rate limit is 5000/day.

Real fix for the future is configuring docker.internal.networkradius.com
as an actual Docker Hub pull-through cache (Harbor/Nexus side), at which
point this Hub-login can come back out.

3 weeks agoDrop fork-side credentials, replace fkirc with native concurrency
Arran Cudbard-Bell [Fri, 15 May 2026 02:15:11 +0000 (20:15 -0600)] 
Drop fork-side credentials, replace fkirc with native concurrency

Two unrelated CI fixes batched:

1. The docker-public and crossbuild-public variants had
   credentials: blocks referencing org-level vars/secrets that aren't
   available on fork CI. Empty values fail workflow template
   validation ("Unexpected value ''"). Drop the credentials block
   from the public variants - they fall back to anonymous Docker Hub
   pulls, which is fine for fork CI on GH-hosted runners (many egress
   IPs, per-IP limit rarely binds).

2. Replace fkirc/skip-duplicate-actions@v5.3.1 with workflow-level
   concurrency: groups in ci.yml, ci-macos.yml, and ci-sanitizers.yml.
   Native GH Actions feature, runner-builtin, no Node 20 deprecation
   warning, no third-party action to chase. Slightly different
   semantics (cancels older queued/in-flight runs of the same workflow
   on the same ref, vs fkirc's diff-based skip) - same practical
   effect for the FreeRADIUS use case.

   ci.yml and ci-sanitizers.yml's pre-ci job still exists because it
   exposes selfhosted/docker_prefix outputs the matrix consumes; its
   only step is now a no-op. ci-macos.yml's pre-ci had no other
   purpose so it's gone entirely.

3 weeks agoDrop FORCE_JAVASCRIPT_ACTIONS_TO_NODE24 env var
Arran Cudbard-Bell [Fri, 15 May 2026 02:02:43 +0000 (20:02 -0600)] 
Drop FORCE_JAVASCRIPT_ACTIONS_TO_NODE24 env var

Per request - keep the fkirc/skip-duplicate-actions pin to v5.3.1 from
the previous commit, but don't paper over the Node.js 20 deprecation
with the env-var override. The warning will keep appearing until
upstream actions ship Node 24 releases (or we replace them) - which
is the intended signal.

3 weeks agoSilence Node.js 20 deprecation warnings in CI/macOS/sanitizers
Arran Cudbard-Bell [Fri, 15 May 2026 02:00:16 +0000 (20:00 -0600)] 
Silence Node.js 20 deprecation warnings in CI/macOS/sanitizers

Two prongs - both needed because the warning's worst offenders
(fkirc/skip-duplicate-actions, mxschmitt/action-tmate) haven't shipped
Node 24 releases:

  - Pin fkirc/skip-duplicate-actions from @master to @v5.3.1 (the
    current latest release). Doesn't fix the Node 20 issue but stops
    us tracking a moving target.

  - Set FORCE_JAVASCRIPT_ACTIONS_TO_NODE24=true at workflow env level
    on ci.yml and ci-macos.yml so the Node 24 runtime kicks in for all
    Node 20 actions immediately. Removable per-action as upstream
    catches up.

3 weeks agoRefresh stale selfhosted-variant header comments in docker.yml/crossbuild.yml
Arran Cudbard-Bell [Fri, 15 May 2026 01:52:57 +0000 (19:52 -0600)] 
Refresh stale selfhosted-variant header comments in docker.yml/crossbuild.yml

The header comments still claimed the selfhosted variant "mounts the
internal CA into both dind and the job container so internal registry
pulls work" - but the dind-side mount went away when those workflows
switched to self-hosted-docker-dind, which has the CA baked into the
image. Update the headers to describe the actual current shape.

3 weeks agoBump self-hosted-docker-dind base from docker:24-dind to docker:27-dind
Arran Cudbard-Bell [Fri, 15 May 2026 01:46:12 +0000 (19:46 -0600)] 
Bump self-hosted-docker-dind base from docker:24-dind to docker:27-dind

The docker CLI in self-hosted-docker-cli (apt-installed on ubuntu:24.04)
requires daemon API version >= 1.44, but docker:24-dind ships dockerd
24.x which speaks API 1.43. Result: dind-based jobs fail with
"API version 1.43 is not supported by this client: the minimum
supported API version is 1.44" the moment the CLI tries to talk to
dind. Bumping to docker:27-dind (engine 27.x, API 1.46) restores
compatibility.

3 weeks agoWire dind workflows up to use the new self-hosted-docker-* images
Arran Cudbard-Bell [Fri, 15 May 2026 01:36:37 +0000 (19:36 -0600)] 
Wire dind workflows up to use the new self-hosted-docker-* images

Now that docker-refresh.yml has published self-hosted-docker-cli and
self-hosted-docker-dind to the internal registry, switch the dind-using
workflows to reference them and shed most of the per-job setup:

  - ci-multi-server-tests.yml: container -> self-hosted-docker-cli,
    services.dind -> self-hosted-docker-dind, dropped the credentials
    block on the dind service (internal registry, runner pre-auth'd),
    dropped the CA cert mount on dind (baked into the image), dropped
    the inline "Docker Hub login (via dind)" step (registry mirror in
    the dind image now handles all public-image pulls).

  - docker.yml docker-selfhosted: same swaps as multi-server. Also
    dropped the pre-checkout "Ensure git is available" step since the
    new image has git baked in. setup-dind invocation no longer needs
    `packages: m4 make` since both are pre-installed.

  - crossbuild.yml crossbuild-selfhosted: same as docker-selfhosted.

  - The public variants of docker.yml/crossbuild.yml are unchanged -
    they still use docker:dind + ubuntu:24.04 from Hub with credentials
    on the services.dind block, since fork CI can't reach the internal
    registry.

For the workflows that still pull stock images from Docker Hub
(ci-deb, ci-rpm, the public docker/crossbuild variants), add
credentials: blocks so the host docker daemon's job-container pull
authenticates via DOCKERHUB_READ_USER (org var) + DOCKERHUB_READ_KEY
(org secret), avoiding the anonymous 100/6h rate limit.

Make setup-dind composite action smart-skip the apt install of docker
tooling when docker is already on PATH (i.e. when running inside the
new self-hosted-docker-cli image), so it's still useful for the public
variants on plain ubuntu:24.04 but adds zero overhead on selfhosted.

3 weeks agodocker-refresh: bump docker/login-action to v4
Arran Cudbard-Bell [Fri, 15 May 2026 01:24:34 +0000 (19:24 -0600)] 
docker-refresh: bump docker/login-action to v4

v3 is a Node.js 20 action and triggers GitHub's deprecation warning
(Node 20 forced to Node 24 starting June 2026, removed September 2026).
v4 is the Node 24 release.

3 weeks agodocker-refresh: split derived images into a second job + add retries
Arran Cudbard-Bell [Fri, 15 May 2026 01:17:34 +0000 (19:17 -0600)] 
docker-refresh: split derived images into a second job + add retries

Two changes:

1. Move self-hosted-docker-cli out of the ubuntu:24.04 matrix entry
   into its own job (process-derived-images) that needs:process-images.
   The previous arrangement did two back-to-back `docker build --no-cache`
   calls in the same job; the second's export raced with containerd GC
   from the first build's push and the export-phase lock failure killed
   the run. Splitting jobs removes the race entirely - process-images
   pushes finish completely before process-derived-images starts.

   The derived job pulls the parent image from the internal registry
   since it almost always lands on a different self-hosted runner.
   Easy to add more derived images later (more entries in the matrix).

2. Wrap docker build / push / pull in `for i in 1 2 3 ; ... ; sleep 10`
   retry loops so transient containerd snapshot-store lock contention
   or registry hiccups self-heal. Three attempts is enough for the ms-
   scale lock window we've been hitting; longer-lived issues still fail.

3 weeks agodocker-refresh: read Hub username from vars (not secrets)
Arran Cudbard-Bell [Fri, 15 May 2026 01:05:21 +0000 (19:05 -0600)] 
docker-refresh: read Hub username from vars (not secrets)

DOCKERHUB_READ_USER is a non-secret org variable; only the PAT itself
is a secret. Resolving it via secrets.* returned an empty string and
the login step failed with "Username required". Switch to vars.*.

3 weeks agodocker-refresh: rename Hub secrets to DOCKERHUB_READ_*
Arran Cudbard-Bell [Fri, 15 May 2026 00:55:35 +0000 (18:55 -0600)] 
docker-refresh: rename Hub secrets to DOCKERHUB_READ_*

The org secrets were created as DOCKERHUB_READ_USER / DOCKERHUB_READ_KEY
(no underscore between DOCKER and HUB). Match the actual names so the
docker/login-action sees non-empty values.

3 weeks agodocker-refresh: authenticate to Docker Hub before pulls
Arran Cudbard-Bell [Fri, 15 May 2026 00:47:41 +0000 (18:47 -0600)] 
docker-refresh: authenticate to Docker Hub before pulls

The previous run failed mid-matrix with "toomanyrequests: You have
reached your unauthenticated pull rate limit." 31 self-hosted runners
share egress IPs and exhaust Hub's anonymous 100/6h limit easily when
refreshing 6+ images in parallel.

Add a docker/login-action step against Docker Hub up-front using the
new org-level DOCKER_HUB_READ_USER / DOCKER_HUB_READ_KEY secrets so
all subsequent docker pull and FROM-pulls authenticate. The existing
internal-registry login (DOCKER_REPO_UPDATE_*) at the bottom of the
job stays as-is; the two are scoped to different registries so they
co-exist in ~/.docker/config.json without conflict.

3 weeks agoRename custom CI images to consistent self-hosted-docker-* family
Arran Cudbard-Bell [Fri, 15 May 2026 00:21:55 +0000 (18:21 -0600)] 
Rename custom CI images to consistent self-hosted-docker-* family

The dind sidecar and the dind-using job container were named
inconsistently with the existing self-hosted family. Rename so all
three images and their Dockerfiles share the same convention:

  self-hosted               -> base CI image (unchanged)
  self-hosted-docker-cli    -> base + docker CLI/buildx/m4 (was self-hosted-builder)
  self-hosted-docker-dind   -> docker:dind + registry-mirror + internal CA (was fr-dind)

Files renamed correspondingly:
  scripts/ci/Dockerfile.builder -> scripts/ci/Dockerfile.docker-cli
  scripts/ci/Dockerfile.dind    -> scripts/ci/Dockerfile.docker-dind

docker-refresh.yml's matrix fields also renamed (builder_dockerfile ->
cli_dockerfile, builder_image_name -> cli_image_name) for the same
consistency.

Nothing has been built or pushed yet under the old names so nothing
needs cleanup in the registry.

3 weeks agoci.yml: silence GH Actions if-expression interpolation warning
Arran Cudbard-Bell [Fri, 15 May 2026 00:19:33 +0000 (18:19 -0600)] 
ci.yml: silence GH Actions if-expression interpolation warning

Inside an if: clause, the entire value is already an implicit
expression context, so an embedded ${{ ... }} is treated as literal
text and triggers "Conditional expression contains literal text outside
replacement tokens. This will cause the expression to always evaluate
to truthy."

Replace endsWith(github.ref, "/${{ github.actor }}") with
endsWith(github.ref, format('/{0}', github.actor)) - same semantics,
expressed inside the implicit if-expression context.

3 weeks agoSplit dind tooling out of the base CI image
Arran Cudbard-Bell [Fri, 15 May 2026 00:18:12 +0000 (18:18 -0600)] 
Split dind tooling out of the base CI image

The previous commit baked docker.io, docker-buildx and m4 directly into
scripts/ci/Dockerfile (the self-hosted CI base image). That bloats the
image for ci.yml and ci-sanitizers.yml jobs which use that base but
never call docker.

Restore the base image to its pre-bloat package set and add a separate
scripts/ci/Dockerfile.builder that FROMs self-hosted and adds just the
docker CLI / buildx / m4 needed for dind-based jobs (docker.yml,
crossbuild.yml, multi-server-tests). Published as
docker.internal.networkradius.com/self-hosted-builder.

Builds are wired into docker-refresh.yml's existing self-hosted matrix
entry as a follow-on step (builder_dockerfile / builder_image_name),
not a separate matrix entry, so the FROM finds self-hosted in the local
docker cache and we don't have to invent inter-matrix-entry ordering.

The system-wide git safe.directory='*' added in the previous commit
stays in the base - it's harmless for non-dind users and prevents the
"dubious ownership" failure in any future workflow that does git ops
on the bind-mounted workspace.

3 weeks agoBake CI tooling and registry-mirror config into custom images
Arran Cudbard-Bell [Thu, 14 May 2026 23:57:39 +0000 (17:57 -0600)] 
Bake CI tooling and registry-mirror config into custom images

Two additions to docker-refresh.yml's matrix:

  - Extend the existing self-hosted-ubuntu24 image (scripts/ci/Dockerfile)
    to install docker.io, docker-buildx and m4, and pre-set git's
    safe.directory='*' system config. These are the per-job knobs
    setup-dind currently apt-installs and git-configures on every CI
    run; baking them in saves ~20-30s per dind-based job.

  - New scripts/ci/Dockerfile.dind, published as
    docker.internal.networkradius.com/fr-dind. It's docker:24-dind
    with /etc/docker/daemon.json baked in pointing at the internal
    NetworkRADIUS registry as a Docker Hub pull-through mirror, and
    the internal CA pre-trusted. This is what the services: dind:
    block in our dind-based workflows should reference once the image
    is built and pushed - it removes the per-job anonymous Docker Hub
    pulls that have been hitting the 100/6h rate limit.

The dind image needs the internal CA cert which lives on the runner
host (not in the repo); a new "Stage internal CA into build context"
step copies it into the build context just before docker build for
matrix entries that set needs_internal_ca: true.

Once docker-refresh is run on master, the dind-based workflows can be
simplified to reference the new images and drop most of setup-dind.

3 weeks agoMark all dirs safe for git in setup-dind
Arran Cudbard-Bell [Thu, 14 May 2026 23:43:25 +0000 (17:43 -0600)] 
Mark all dirs safe for git in setup-dind

The dind-based jobs run as root inside the job container, but the
bind-mounted workspace files are owned by the runner user on the host.
Modern git refuses to operate on a repo whose ownership doesn't match
the current uid ("fatal: detected dubious ownership"), which blew up
crossbuild.mk's `git rev-parse --git-dir` the moment it ran.

Add a setup-dind step that does `git config --global --add safe.directory '*'`
so git inside the container trusts any workspace path. setup-dind
already installed git tools by the time this runs.

3 weeks agoInstall git before checkout in dind-based docker/crossbuild jobs
Arran Cudbard-Bell [Thu, 14 May 2026 23:36:59 +0000 (17:36 -0600)] 
Install git before checkout in dind-based docker/crossbuild jobs

actions/checkout silently falls back to a REST API tarball download
when git isn't on PATH inside the job container, and the tarball does
not include the .git directory. The dind-based docker.yml and
crossbuild.yml jobs run inside a plain ubuntu:24.04 (public variant)
or self-hosted CI image, neither of which we can rely on having git
preinstalled. Without .git the Dockerfile's `git clean -fdxx` step
fails immediately with "fatal: not a git repository", killing the
build.

Add a small pre-checkout step that does `apt-get install git` so
checkout sees a real git binary and writes a real .git directory into
the workspace. The `apt-get update` is a few-second cost shared with
the later setup-dind run.

The previous workflow ran on ubuntu-latest directly (no container) and
the GitHub-hosted runner image already had git, which is why this
issue only appeared after the dind restructure.

3 weeks agoMake Collect DEBs/RPMs steps idempotent for self-hosted reuse
Arran Cudbard-Bell [Thu, 14 May 2026 23:04:05 +0000 (17:04 -0600)] 
Make Collect DEBs/RPMs steps idempotent for self-hosted reuse

The container directive gives ci-deb and ci-rpm a fresh container per
job, but the workspace directory is bind-mounted from the host. On
GitHub-hosted runners the host VM is fresh too, so the workspace appears
empty; on the self-hosted Proxmox fleet the workspace persists across
runs and last run's debs/ or rpms/ directory is still there, so a bare
mkdir explodes with "File exists".

Add an rm -rf before each mkdir so the collect step starts clean
regardless of what the previous run left behind. This also avoids the
subtler bug where stale .debs from a previous build could end up in the
artifact alongside the new ones.

3 weeks agoSplit crossbuild.yml into self-hosted and public variants
Arran Cudbard-Bell [Thu, 14 May 2026 22:53:25 +0000 (16:53 -0600)] 
Split crossbuild.yml into self-hosted and public variants

Mirror the docker.yml change: keep the matrix-generating gen-matrix job
on ubuntu-latest, but route the actual crossbuild work to the FreeRADIUS
Proxmox fleet on org pushes (using the internal CI base image + dind
sidecar with the internal CA mounted), and fall back to ubuntu:24.04 +
public docker:dind on fork pushes.

The workflow_run trigger watches by name so the Claude failure diagnosis
workflow keeps catching failures unchanged.

crossbuild's make target does `docker run --mount=type=bind,source=...`
into the source tree, so both containers share the workspace at
/workspace via the same dind volume mount used by docker.yml and
multi-server-tests. The inner --privileged --cap-add=ALL nests fine
inside the already-privileged dind sidecar.

3 weeks agoRevert self-delete trick in CI failure diagnosis workflow
Arran Cudbard-Bell [Thu, 14 May 2026 22:49:01 +0000 (16:49 -0600)] 
Revert self-delete trick in CI failure diagnosis workflow

The Gate-or-delete step was supposed to keep the Actions tab tidy by
deleting its own workflow_run record on non-failures, but the GitHub API
refuses DELETE on in-progress runs with 403, and self-deletion is by
definition always in-progress. Restore the original job-level if: that
gates on conclusion/branch/event and accept the Skipped entries.

3 weeks agoRestore comments lost in the docker.yml split
Arran Cudbard-Bell [Thu, 14 May 2026 22:22:55 +0000 (16:22 -0600)] 
Restore comments lost in the docker.yml split

Three comment blocks went missing when the workflow was rewritten:
  - the workspace volume-mount rationale (why /workspace as a fixed
    in-container path, what github.workspace actually points at)
  - the rationale for the CA cert mount on dind (internal registry trust)
  - the ci-debug branch / tmate session note above the tmate step
Add them back to both jobs.

3 weeks agoSplit docker.yml into self-hosted and public variants
Arran Cudbard-Bell [Thu, 14 May 2026 22:21:05 +0000 (16:21 -0600)] 
Split docker.yml into self-hosted and public variants

Restore the NetworkRADIUS-internal config for self-hosted runs while
keeping fork (GitHub-hosted) builds on the public ubuntu:24.04 + dind
shape:

  docker-selfhosted (if owner == FreeRADIUS): runs on self-hosted with
  docker.internal.networkradius.com/self-hosted as the job container,
  internal CA cert mounted into both dind and the job container so
  registry pulls and HTTPS to internal hosts work, NO_PROXY set on both.

  docker-public (else): runs on ubuntu-latest with the public docker:dind
  sidecar and a plain ubuntu:24.04 job container - no internal bits.

The two jobs are mutually exclusive via if:, so each push fires exactly
one. The matrix and step list are short enough that duplicating beats a
third composite action.

3 weeks agoMake docker.yml dual-environment: dind on self-hosted and fork runners
Arran Cudbard-Bell [Thu, 14 May 2026 22:17:20 +0000 (16:17 -0600)] 
Make docker.yml dual-environment: dind on self-hosted and fork runners

Drop the FreeRADIUS-org-only gate on the Build Dockerfiles job and the
internal-image / internal-CA wiring. The build only pulls public base
images, so the same shape works on both fleets:

  - runs-on toggles to self-hosted on FreeRADIUS pushes, falls back to
    ubuntu-latest on forks (matches ci.yml/ci-sanitizers.yml pattern).
  - Container is public ubuntu:24.04 instead of the internal
    self-hosted image; dind sidecar stays as the public docker:dind.
  - Workspace mount is the only volume the job needs.

Reorder the setup-dind composite so it installs ca-certificates before
running update-ca-certificates - the previous order assumed the base
image already had ca-certificates installed, which the internal
self-hosted image did but plain ubuntu:24.04 doesn't. Functionally
equivalent on multi-server-tests, lets docker.yml use the same action.

Add make to the package list for docker.yml since ubuntu:24.04 doesn't
include it by default (the self-hosted CI image did).

3 weeks agoRun Build Dockerfiles on the self-hosted fleet in DinD; share setup as composite...
Arran Cudbard-Bell [Thu, 14 May 2026 22:10:04 +0000 (16:10 -0600)] 
Run Build Dockerfiles on the self-hosted fleet in DinD; share setup as composite action

Switch the Build Dockerfiles workflow to the same job shape as Multi-
Server CI Tests: runs-on: self-hosted, gated to FreeRADIUS-owned repos,
job runs inside docker.internal.networkradius.com/self-hosted with a
docker:dind sidecar. The build talks to the sidecar over DOCKER_HOST so
the runner's host docker daemon stays untouched, and the sidecar tears
down with the job so no image-cache or dangling-layer cleanup is needed.

Extract the in-job DinD setup (trust the internal CA, install docker.io
+ docker-buildx + extras, wait for the daemon) into a composite action
at .github/actions/setup-dind so both workflows reference the same
sequence. The services:/container: blocks themselves stay duplicated -
those are job-level concerns that composite actions can't capture.

3 weeks agoRoute deb/rpm CI builds to self-hosted runners when on the org repo
Arran Cudbard-Bell [Thu, 14 May 2026 22:05:02 +0000 (16:05 -0600)] 
Route deb/rpm CI builds to self-hosted runners when on the org repo

ci-deb and ci-rpm previously pinned runs-on to ubuntu-latest, which
forced them onto GitHub-hosted runners even when running on the org
repo where reliable connectivity to packages.networkradius.com lives on
the self-hosted Proxmox fleet. Match the pattern already used by ci.yml
and ci-sanitizers.yml: thread a selfhosted flag through set-matrix and
flip runs-on to self-hosted when the repository owner is FreeRADIUS,
falling back to ubuntu-latest for forks.

Both jobs already run inside a container: directive, so host-state
hygiene on the self-hosted runners is unaffected.

3 weeks agoCI workflow housekeeping: self-deleting diagnosis runs, package-repo retries
Arran Cudbard-Bell [Thu, 14 May 2026 21:35:48 +0000 (15:35 -0600)] 
CI workflow housekeeping: self-deleting diagnosis runs, package-repo retries

Self-destruct the Claude CI failure-diagnosis workflow when there's
nothing to triage. GitHub doesn't expose an event-level conclusion
filter for workflow_run, so the job starts unconditionally and deletes
its own run record unless the upstream conclusion is a master-push
failure - this avoids cluttering the Actions tab with "Skipped" entries.

Retry transient package-repo failures inside the docker image build.
apt defaults to zero retries and dnf has a 30s connect timeout that
trips before the retry kicks in. Configure apt and dnf for 3 retries
with a 15s per-request timeout, and add --retry/--retry-connrefused to
the curl that fetches the NetworkRADIUS signing key. dnf stall detection
(minrate) stays on so a hung in-flight download still gets killed
quickly. Regenerated all committed Dockerfiles from the m4 templates.

3 weeks agoFix decade old bug that caused EAP-PWD to ocassionally fail
Arran Cudbard-Bell [Thu, 14 May 2026 21:12:09 +0000 (15:12 -0600)] 
Fix decade old bug that caused EAP-PWD to ocassionally fail

3 weeks agoPost failure claude based diagnostics
Arran Cudbard-Bell [Thu, 14 May 2026 20:54:39 +0000 (14:54 -0600)] 
Post failure claude based diagnostics

3 weeks agoCorrect link time, transitive resolution, library search path
Arran Cudbard-Bell [Thu, 14 May 2026 19:45:58 +0000 (13:45 -0600)] 
Correct link time, transitive resolution, library search path

3 weeks agoGate automatic Claude PR review on prior contributions
Arran Cudbard-Bell [Thu, 14 May 2026 18:17:03 +0000 (12:17 -0600)] 
Gate automatic Claude PR review on prior contributions

Only auto-trigger Claude reviews for authors with write access or a
prior accepted contribution (OWNER / MEMBER / COLLABORATOR /
CONTRIBUTOR). For first-time contributors and drive-by PRs, a
maintainer must add the 'claude-review' label to opt the PR in --
avoids spending API tokens on spam PRs.

3 weeks agoDrop backslash assertion from sql_postgresql escape test
Arran Cudbard-Bell [Wed, 13 May 2026 14:43:24 +0000 (08:43 -0600)] 
Drop backslash assertion from sql_postgresql escape test

The ALTER DATABASE pin in postgresql-setup.sh ran fine but didn't
shift libpq's conn->std_strings flag for the radius user's
connection, so PQescapeStringConn kept doubling backslashes and the
test still failed. Rather than chase the precedence, drop the
backslash assertion - single quote doubling, ASCII pass-through and
UTF-8 pass-through are deterministic across all server configs and
that's what the test now covers. Reverts the setup-script change
from df13dfd054.

3 weeks agoPin standard_conforming_strings on the PostgreSQL CI test database
Arran Cudbard-Bell [Wed, 13 May 2026 03:47:36 +0000 (21:47 -0600)] 
Pin standard_conforming_strings on the PostgreSQL CI test database

PQescapeStringConn doubles backslashes when the connection's
std_strings flag is false, which trips the backslash assertion in
src/tests/modules/sql_postgresql/escape.unlang on test servers where
the parameter isn't being reported as on. Pin it at the database
level in postgresql-setup.sh so every connection inherits it, and
restore the backslash assertion in the test.

3 weeks agoMake SQL escape functions binary safe, and check escaping functions correctly
Arran Cudbard-Bell [Wed, 13 May 2026 01:47:26 +0000 (19:47 -0600)] 
Make SQL escape functions binary safe, and check escaping functions correctly

3 weeks agoadd more CFLAGS
Alan T. DeKok [Mon, 11 May 2026 21:55:08 +0000 (14:55 -0700)] 
add more CFLAGS

3 weeks agowe can just use talloc_zero() here
Alan T. DeKok [Mon, 11 May 2026 21:32:33 +0000 (14:32 -0700)] 
we can just use talloc_zero() here

which is less code and clearer

3 weeks agosort the libraries for consistent build order
Alan T. DeKok [Sun, 10 May 2026 17:58:07 +0000 (13:58 -0400)] 
sort the libraries for consistent build order

and use $(LIBFREERADIUS_SERVER) instead of manual linkages,
which lets us build with / without TLS much more easily

3 weeks agoPOSTCLEAN is a command, not a list of files
Alan T. DeKok [Sat, 9 May 2026 11:55:26 +0000 (07:55 -0400)] 
POSTCLEAN is a command, not a list of files

3 weeks agodon't pass a free function to the hash tables
Alan T. DeKok [Thu, 7 May 2026 21:12:20 +0000 (17:12 -0400)] 
don't pass a free function to the hash tables

both the hash and das are parented by the same dict.  so we can
just rely on the talloc ordering to do the cleanups correctly.

if there's a free function which frees the hash table entry, then
we need a corresponding destructor in the 'da', which removes the
da from the hash table.

Without that, we have accidental ordering, and potential for
problems if anything inside of talloc

4 weeks agoeap: drop attr_state from libfreeradius-eap
Arran Cudbard-Bell [Fri, 8 May 2026 13:00:26 +0000 (09:00 -0400)] 
eap: drop attr_state from libfreeradius-eap

libfreeradius-eap is meant to be protocol-agnostic, but it autoloaded
the RADIUS State attribute and reached into the request reply_pairs
from eap_fail() to delete it.  State management on Access-Reject is
process_radius's job: RESUME(access_reject) already calls
fr_state_discard() to unlink the state-tree entry.  Nothing on the
reject path actually adds a State pair to reply_pairs, so the strip
in eap_fail was guarding against a case that doesn't happen.

Remove the autoload entry and the strip; if a future caller needs to
enforce "no State on Access-Reject" at the wire level, that belongs in
the process module's send-reject path, not in the EAP library.

4 weeks agoeap: fix talloc abort on EAP-NAK for unsupported method (#5846)
Arran Cudbard-Bell [Fri, 8 May 2026 13:00:15 +0000 (09:00 -0400)] 
eap: fix talloc abort on EAP-NAK for unsupported method (#5846)

eap_session_discard() looked up the request_data_t via
request_data_reference(), which leaves the entry in place with its
opaque pointer set to the eap_session we then talloc_free.  When the
session is frozen (request == NULL on the eap_session), the destructor's
own request_data_get() cleanup path is short-circuited, so the entry
survives with a dangling rd->opaque.  When the request's
session_state_ctx is later freed, the rd destructor calls
talloc_free(rd->opaque) on the freed chunk and aborts with "Bad talloc
magic value".

Switch to request_data_get() so the entry is unlinked atomically as
the eap_session is pulled out, then free the session.  No callers rely
on the entry surviving the discard.

Triggered by NAK-for-unsupported-method when ignore_unknown_eap_types
is no, but applies to any path that hits eap_failure() for a frozen
session.

Add src/tests/eapol_test/fail-aka-nak.conf as a regression test under
the new fail-<type>-* harness convention: server loads only EAP-AKA,
supplicant offers PEAP and NAKs the AKA challenge.  Pre-fix this aborts
in request_slab_deinit; post-fix the daemon stays up and the request is
cleanly rejected.

4 weeks agotests: support fail-<type>-* eapol_test cases that should reject cleanly
Arran Cudbard-Bell [Fri, 8 May 2026 12:59:30 +0000 (08:59 -0400)] 
tests: support fail-<type>-* eapol_test cases that should reject cleanly

A conf file whose basename starts with `fail-` is now treated by the
harness as a negative scenario: eapol_test is expected to NOT complete
authentication, and the recipe inverts the exit-code check accordingly.
The server still has to be alive at the end (radiusd_stop checks the
PID), which is what catches an actual server crash.

4 weeks agoUse cram md5 (works on macos)
Arran Cudbard-Bell [Thu, 7 May 2026 17:37:30 +0000 (13:37 -0400)] 
Use cram md5 (works on macos)

4 weeks agofree local variables which match the current frames dictionary
Alan T. DeKok [Thu, 7 May 2026 20:18:53 +0000 (16:18 -0400)] 
free local variables which match the current frames dictionary

instead of freeing local variables which don't match the
previous frames dictionary.  There may be multiple frames with
local variables.

4 weeks agonetwork: detect reservation aliasing via data_size before reset
Arran Cudbard-Bell [Thu, 7 May 2026 18:55:13 +0000 (14:55 -0400)] 
network: detect reservation aliasing via data_size before reset

When app_io->read() calls fr_network_listen_send_packet() internally
(e.g. ldap_sync for AD notifications), that function calls
fr_message_and_data_alloc() on the same message set while our
reservation is outstanding.

message_reserve() uses fr_ring_buffer_reserve(), which does NOT advance
write_offset.  The subsequent alloc therefore lands at the same message
ring slot as the existing reservation.  The memset inside message_reserve
zeroes our struct (clearing data, rb, etc.), then the new message commits
into that slot and fills in data_size with the actual packet size.

After app_io->read() returns 0, the previous fix unconditionally called
fr_message_and_data_reset() on cd.  In the aliased case cd now points to
the already-committed, already-dispatched message; resetting it sets
data_size and data to NULL, causing the worker to decode zero bytes and
fail to find attr_packet_type.

Fix: before resetting, check cd->m.data_size.  A non-zero value means
an alloc claimed the slot while we held the reservation.  In that case
skip the reset entirely and set s->cd = NULL so the next call gets a
fresh reservation from the now-advanced write_offset.

4 weeks agonetwork: fix uncommitted reservation aliasing when app_io->read returns no data
Arran Cudbard-Bell [Thu, 7 May 2026 18:23:09 +0000 (14:23 -0400)] 
network: fix uncommitted reservation aliasing when app_io->read returns no data

fr_message_and_data_reserve() uses fr_ring_buffer_reserve() which does not
advance write_offset. If app_io->read() returns 0 (e.g. ldap_sync, which
does its own reads internally) and the cached cd is held in s->cd, any
subsequent allocation on the same message set returns the same ring-buffer
slot and zeroes it, corrupting cd->m.data.

Fix: only cache s->cd when s->leftover > 0 (partial stream data to preserve).
With no leftover, cancel the reservation explicitly via fr_message_and_data_reset()
which clears the message fields and marks the slot FR_MESSAGE_FREE so the next
reserve can reclaim it cleanly.

Also fix the B2 commit size in fr_network_read(): data_size returned by TCP
app_io already includes the leftover bytes already in the buffer, so the old
cd->m.data_size + data_size was double-counting.

4 weeks agoUse cram md5 (works on macos)
Arran Cudbard-Bell [Thu, 7 May 2026 17:37:30 +0000 (13:37 -0400)] 
Use cram md5 (works on macos)

4 weeks agoCreate distinct, reserve functions, and reserve + commit functions for channel data...
Arran Cudbard-Bell [Thu, 7 May 2026 16:00:24 +0000 (12:00 -0400)] 
Create distinct, reserve functions, and reserve + commit functions for channel data and ring buffers

Always commit data before moving onto the next packet

4 weeks agoadd command to sync submodules
Alan T. DeKok [Thu, 7 May 2026 15:08:32 +0000 (11:08 -0400)] 
add command to sync submodules

4 weeks agouse public URL, not SSH for submodule
Alan T. DeKok [Thu, 7 May 2026 15:03:59 +0000 (11:03 -0400)] 
use public URL, not SSH for submodule

4 weeks agoAdd Ubuntu 26 to docker and crossbuild CI jobs
Nick Porter [Wed, 6 May 2026 08:56:20 +0000 (09:56 +0100)] 
Add Ubuntu 26 to docker and crossbuild CI jobs

4 weeks agoAdd Ubuntu 26 to CI .deb job
Nick Porter [Wed, 6 May 2026 08:54:36 +0000 (09:54 +0100)] 
Add Ubuntu 26 to CI .deb job

4 weeks agoRe-work coordinator shutdown sequence
Nick Porter [Thu, 7 May 2026 07:25:31 +0000 (08:25 +0100)] 
Re-work coordinator shutdown sequence

Doing the pthread_join() in fr_coord_deregister() caused some occasional
timing issues.