From 2c42a33320c808ebf99c00bf1e36222c32aafe76 Mon Sep 17 00:00:00 2001 From: Samaresh Kumar Singh Date: Fri, 12 Jun 2026 08:52:31 -0500 Subject: [PATCH] config: test deterministic glob include ordering Add config-includes-glob-order, which checks that a glob pattern in an include directive expands to all matching files and includes them in sorted order. glob.yaml includes *-order.yaml, matching three drop-in files (01/50/99) that each define their own unique marker key. The test asserts that all three keys are present in --dump-config output and that they appear in sorted-filename order, observable because the config tree preserves insertion order. No key is defined twice, so the test does not rely on duplicate-key override behavior. Include order matters because settings from later includes override earlier ones, which is what makes the numbered 01..99 drop-in convention predictable for users. The glob config is kept in glob.yaml and run via command: rather than a shipped suricata.yaml, because suricata-verify runs "suricata -c suricata.yaml --dump-config" during test setup before the min-version check. A glob include in suricata.yaml would break that setup step on Suricata versions without glob support. Until the Suricata side lands, a requires script greps src/conf-yaml-loader.c for the glob expansion code and skips the test on builds without it, the same way the eve-alert-metadata tests probe for METADATA_DEFAULTS. This keeps CI green against main and the release branches. A second requires script greps src/autoconf.h for HAVE_GLOB_H. Glob expansion needs glob(3), which Windows builds do not have; there an include pattern is skipped with a warning and none of the matched files are loaded, so the ordering checks could not hold. Probing the build rather than the platform keeps the test running everywhere glob(3) is available, including macOS and the BSDs. Exercises the include glob support added in OISF/suricata for this ticket. Ticket: #8427 --- .../config-includes-glob-order/01-order.yaml | 3 ++ .../config-includes-glob-order/50-order.yaml | 3 ++ .../config-includes-glob-order/99-order.yaml | 3 ++ tests/config-includes-glob-order/README.md | 44 +++++++++++++++++ tests/config-includes-glob-order/glob.yaml | 10 ++++ tests/config-includes-glob-order/test.yaml | 49 +++++++++++++++++++ 6 files changed, 112 insertions(+) create mode 100644 tests/config-includes-glob-order/01-order.yaml create mode 100644 tests/config-includes-glob-order/50-order.yaml create mode 100644 tests/config-includes-glob-order/99-order.yaml create mode 100644 tests/config-includes-glob-order/README.md create mode 100644 tests/config-includes-glob-order/glob.yaml create mode 100644 tests/config-includes-glob-order/test.yaml diff --git a/tests/config-includes-glob-order/01-order.yaml b/tests/config-includes-glob-order/01-order.yaml new file mode 100644 index 0000000000..3e0397ab39 --- /dev/null +++ b/tests/config-includes-glob-order/01-order.yaml @@ -0,0 +1,3 @@ +%YAML 1.1 +--- +glob-order-seen-01: present diff --git a/tests/config-includes-glob-order/50-order.yaml b/tests/config-includes-glob-order/50-order.yaml new file mode 100644 index 0000000000..062c12643e --- /dev/null +++ b/tests/config-includes-glob-order/50-order.yaml @@ -0,0 +1,3 @@ +%YAML 1.1 +--- +glob-order-seen-50: present diff --git a/tests/config-includes-glob-order/99-order.yaml b/tests/config-includes-glob-order/99-order.yaml new file mode 100644 index 0000000000..ae0941a4d8 --- /dev/null +++ b/tests/config-includes-glob-order/99-order.yaml @@ -0,0 +1,3 @@ +%YAML 1.1 +--- +glob-order-seen-99: present diff --git a/tests/config-includes-glob-order/README.md b/tests/config-includes-glob-order/README.md new file mode 100644 index 0000000000..ece11249d4 --- /dev/null +++ b/tests/config-includes-glob-order/README.md @@ -0,0 +1,44 @@ +# config-includes-glob-order + +Verifies that a glob pattern in an `include:` directive expands to all matching +files and includes them in a deterministic (sorted) order. + +`glob.yaml` includes `*-order.yaml`, which matches three drop-in files +(`01-order.yaml`, `50-order.yaml`, `99-order.yaml`). Each file defines its own +unique marker key (`glob-order-seen-NN`). Because `glob(3)` returns matches in +sorted (lexicographic) order, the files are merged in ascending numeric-prefix +order. + +The test runs suricata against `glob.yaml` with `--dump-config` (via `command:`) +and asserts that: + +- all three matched files were included (one unique marker key per file), and +- the marker keys appear in the dump output in sorted-filename order. The + config tree preserves insertion order, so the position of each key in the + output reflects the order the files were merged. No key is defined twice, so + the test does not depend on duplicate-key override behavior. + +What this test proves is narrow: sorted glob expansion. Real users care about +that property because it makes the common numbered drop-in convention +(`01-*.yaml` .. `99-*.yaml`, as in `conf.d`-style directories) predictable, +including the case where the same key is set in more than one drop-in. This +test does not exercise any of those override scenarios. It just pins the sort +order so it cannot silently regress (for example by expanding with +`GLOB_NOSORT` or a plain directory scan). + +The glob config is kept in `glob.yaml` (not the default `suricata.yaml`) on +purpose: suricata-verify runs `suricata -c suricata.yaml --dump-config` during +test setup before the `min-version` check, so a glob `include:` in a shipped +`suricata.yaml` would break setup on Suricata builds without glob support. + +Note: this test requires the `include:` glob support added in OISF/suricata +(#15574, Redmine #8427). Until that lands, a `requires: script:` probe greps +`src/conf-yaml-loader.c` for the glob expansion code and skips the test on +builds that don't have it, so it does not fail CI runs against main or the +release branches. + +A second probe greps `src/autoconf.h` for `HAVE_GLOB_H`. Glob expansion needs +`glob(3)`, which Windows builds do not have; there an include pattern is +skipped with a warning and none of the matched files are loaded, so the checks +below could not hold. Probing the build rather than the platform keeps the test +running everywhere `glob(3)` is available, including macOS and the BSDs. diff --git a/tests/config-includes-glob-order/glob.yaml b/tests/config-includes-glob-order/glob.yaml new file mode 100644 index 0000000000..0bbfcaacd3 --- /dev/null +++ b/tests/config-includes-glob-order/glob.yaml @@ -0,0 +1,10 @@ +%YAML 1.1 +--- + +# The pattern expands to 01-order.yaml, 50-order.yaml and 99-order.yaml. +# glob(3) returns matches in sorted (lexicographic) order, so the drop-in files +# are included in ascending numeric-prefix order. Each file defines its own +# unique marker key; the order the keys appear in --dump-config output reflects +# the order the files were merged. +include: + - "*-order.yaml" diff --git a/tests/config-includes-glob-order/test.yaml b/tests/config-includes-glob-order/test.yaml new file mode 100644 index 0000000000..18b1ccb421 --- /dev/null +++ b/tests/config-includes-glob-order/test.yaml @@ -0,0 +1,49 @@ +requires: + min-version: 9 + # Glob support in include: is not merged yet (OISF/suricata#15574), so a + # min-version alone can't gate this test. Probe the source tree for the + # glob(3) expansion code instead and skip on builds that don't have it, + # the same way the eve-alert-metadata tests probe for METADATA_DEFAULTS. + # Glob expansion needs glob(3). Builds without glob.h, notably Windows, + # skip an include pattern with a warning and load none of the matched + # files, so the ordering checks below cannot hold there. Probe the build + # rather than the platform, so the test still runs anywhere glob(3) is + # available. + script: + - grep globfree src/conf-yaml-loader.c > /dev/null + - grep '^#define HAVE_GLOB_H 1' src/autoconf.h > /dev/null + +pcap: false + +# Run suricata against glob.yaml explicitly rather than shipping a suricata.yaml. +# suricata-verify always runs `suricata -c /suricata.yaml --dump-config` +# during test setup (before the min-version check), so a glob include in +# suricata.yaml would make that setup step fail on Suricata versions without +# glob support. Using a separate config exercised via `command:` keeps setup on +# the default suricata.yaml and only runs the glob config on a supported build. +command: | + ${SRCDIR}/src/suricata -c ${TEST_DIR}/glob.yaml -l ${OUTPUT_DIR} --dump-config + +checks: + # Every globbed drop-in file is included, not just one: the unique marker key + # from each of 01/50/99-order.yaml is present in the merged config. + - shell: + args: grep '^glob-order-seen-01 = present' stdout | wc -l + expect: 1 + - shell: + args: grep '^glob-order-seen-50 = present' stdout | wc -l + expect: 1 + - shell: + args: grep '^glob-order-seen-99 = present' stdout | wc -l + expect: 1 + + # Ordering is deterministic: glob(3) returns matches sorted, so the files are + # included in ascending numeric-prefix order. Include order is observable in + # --dump-config output because the config tree preserves insertion order, so + # the distinct per-file marker keys must appear in sorted-filename order. + # The test does not exercise override-on-duplicate-keys (each file uses a + # unique key on purpose). What this pins is just the sort order, which is + # what the numbered conf.d-style drop-in convention relies on in practice. + - shell: + args: grep -o '^glob-order-seen-[0-9][0-9]' stdout | tr '\n' ' ' + expect: glob-order-seen-01 glob-order-seen-50 glob-order-seen-99