Skip to content

Commit ac3ef59

Browse files
authored
Merge pull request #2326 from edlitmus/codex/macos-portability-ctest
macos/freebsd portability
2 parents 09c08e2 + a8c8675 commit ac3ef59

66 files changed

Lines changed: 1291 additions & 213 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CMakeLists.txt

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,13 @@ find_package(Ldap)
108108
find_package(OpenDbx)
109109
find_package(PCRE2 REQUIRED)
110110

111+
foreach(_perl_cache_var IN ITEMS PERL_INCLUDE_PATH PERL_LIBRARY)
112+
if(DEFINED ${_perl_cache_var} AND NOT "${${_perl_cache_var}}" STREQUAL "" AND NOT EXISTS "${${_perl_cache_var}}")
113+
message(STATUS "Resetting stale ${_perl_cache_var} cache entry: ${${_perl_cache_var}}")
114+
unset(${_perl_cache_var} CACHE)
115+
endif()
116+
endforeach()
117+
111118
find_package(PerlLibs)
112119
find_package(Popt)
113120
find_package(Systemd)
@@ -226,7 +233,7 @@ endif()
226233
mark_as_advanced(ENV_PRESENT VALGRIND_PRESENT)
227234
find_program(ENV_PRESENT env)
228235
find_program(VALGRIND_PRESENT valgrind)
229-
find_program(ASCIIDOC_EXECUTABLE asciidoc)
236+
find_program(ASCIIDOC_EXECUTABLE NAMES asciidoc asciidoctor)
230237
find_program(SED_EXECUTABLE sed)
231238
find_program(GIT_EXECUTABLE git)
232239

@@ -529,8 +536,16 @@ if (MSVC)
529536
endif()
530537

531538
if (${CMAKE_C_COMPILER_ID} STREQUAL "GNU" OR ${CMAKE_C_COMPILER_ID} STREQUAL "Clang")
532-
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pipe -W -Wall -Wnonnull -Wshadow -Wformat -Wundef -Wno-unused-parameter -Wmissing-prototypes -Wno-unknown-pragmas -Wno-int-conversion -Werror=implicit-function-declaration -D_GNU_SOURCE -DRBT_IMPLICIT_LOCKING=1 -std=c99")
533-
add_link_options(-Wl,-z,now)
539+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pipe -W -Wall -Wnonnull -Wshadow -Wformat -Wundef -Wno-unused-parameter -Wmissing-prototypes -Wno-unknown-pragmas -Wno-int-conversion -Werror=implicit-function-declaration -DRBT_IMPLICIT_LOCKING=1 -std=c99")
540+
# -D_GNU_SOURCE exposes GNU extensions but changes function signatures on non-glibc
541+
# platforms (e.g. strerror_r on macOS becomes XSI). Only set it on glibc systems.
542+
if(NOT APPLE AND NOT CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
543+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_GNU_SOURCE")
544+
endif()
545+
# -Wl,-z,now is a Linux/ELF linker flag; not supported on macOS (uses -bind_at_load)
546+
if(NOT APPLE)
547+
add_link_options(-Wl,-z,now)
548+
endif()
534549
endif()
535550
if(${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
536551
add_link_options(-lkvm -lm -lprocstat)

docs/contribute/testing.adoc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,23 @@ library and then install additional packages required for testing. See the
2525
*Building OpenSCAP on Linux* section in the link:../developer/developer.adoc[OpenSCAP Developer Manual]
2626
for more details.
2727

28+
For platform-focused validation, prefer CTest labels over ad-hoc test lists.
29+
For example, after a successful non-Linux build you can run:
30+
31+
----
32+
$ ctest -L macos
33+
$ ctest -L freebsd
34+
----
35+
36+
For a containerized Linux full-suite run, make sure a local SMTP listener and a
37+
session D-Bus are available before invoking CTest, otherwise MITRE, `fwupd`,
38+
and `systemd` coverage may be skipped or fail for environmental reasons:
39+
40+
----
41+
$ postfix start
42+
$ dbus-run-session -- ctest --output-on-failure
43+
----
44+
2845

2946
== Writing a new test
3047
In this guide we will use an example to describe the process of writing a test

docs/developer/developer.adoc

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,12 @@ $ cmake ../
9797
$ make
9898
----
9999

100+
If you reuse an existing build tree after a Perl upgrade or package-manager
101+
change, CMake may retain stale `PERL_INCLUDE_PATH` or `PERL_LIBRARY` cache
102+
entries. The top-level build now clears cached Perl paths that no longer exist,
103+
so rerunning `cmake ../` in the same build directory is usually sufficient.
104+
If Perl detection still looks wrong, remove `CMakeCache.txt` and reconfigure.
105+
100106
On Ubuntu 18.04 and potentially other distro, the python3 dist-packages path is wrong.
101107
If the following command:
102108

@@ -168,6 +174,43 @@ Now you can execute the following command to run library self-checks:
168174
$ ctest
169175
----
170176

177+
For containerized Linux validation, start a local MTA and provide a session
178+
D-Bus before invoking the full suite so MITRE, `fwupd`, and `systemd`-related
179+
coverage stays active:
180+
181+
----
182+
$ postfix start
183+
$ dbus-run-session -- ctest --output-on-failure
184+
----
185+
186+
The test suite supports filtering by labels. This is useful for platform-specific
187+
or subsystem-specific runs:
188+
189+
----
190+
$ ctest -L probes
191+
$ ctest -L api
192+
$ ctest -L unix
193+
$ ctest -L independent
194+
$ ctest -L linux_only
195+
$ ctest -L macos
196+
$ ctest -L freebsd
197+
----
198+
199+
Labels are assigned in `tests/CMakeLists.txt` by helper functions:
200+
201+
* `add_oscap_test(script.sh [LABELS ...])`:
202+
** registers shell-based tests,
203+
** always adds `shell`,
204+
** automatically adds a suite label based on the top-level test path
205+
(`api`, `probes`, `report`, `sources`, etc.),
206+
** appends optional explicit labels (for example `unix`, `linux_only`, `macos`).
207+
208+
* `add_oscap_ctest(name COMMAND ... [LABELS ...])`:
209+
** registers direct CTest commands (for example Python/pytest tests),
210+
** always adds `ctest`,
211+
** automatically adds the same top-level suite label,
212+
** appends optional explicit labels.
213+
171214
Note that using the `--jobs/-j` flag is currently not supported.
172215
It will cause unexpected test failures.
173216
See link:https://github.com/OpenSCAP/openscap/issues/2057[#2057] for more details.
@@ -208,6 +251,55 @@ $ docker build --tag openscap_mitre_tests:latest -f Dockerfiles/mitre_tests . &&
208251

209252
--
210253

254+
== Building on macOS and FreeBSD
255+
256+
OpenSCAP can be built on macOS and FreeBSD with a reduced feature set depending
257+
on available libraries and enabled probes.
258+
259+
Typical configuration starts with:
260+
261+
----
262+
$ mkdir -p build && cd build
263+
$ cmake .. -DENABLE_TESTS=ON -DENABLE_PROBES_LINUX=OFF
264+
$ make
265+
----
266+
267+
Notes:
268+
269+
* Linux-specific probes (`ENABLE_PROBES_LINUX`) should be disabled on non-Linux
270+
systems unless you are explicitly cross-compiling for Linux.
271+
* Some tests are intentionally labeled `linux_only` and should be filtered out
272+
using CTest labels.
273+
* After a successful non-Linux build, `ctest -L macos` or `ctest -L freebsd`
274+
provides a quick portability smoke test without pulling in Linux-only cases.
275+
* On macOS, `SCE` is disabled by default in the main CMake configuration.
276+
277+
=== Recent portability updates
278+
279+
The codebase contains recent portability work for macOS/FreeBSD, including:
280+
281+
* `sysctl` probe support for macOS (`/usr/sbin/sysctl -ae`) and FreeBSD/macOS
282+
branching, including parsing of multiline BSD `sysctl -ae` values by treating
283+
only valid `name=value` headers as new items,
284+
* `memusage` support on macOS via Mach APIs,
285+
* `XCCDF` target MAC collection on macOS via `AF_LINK`,
286+
* fallback parser for password probe offline mode on systems without
287+
`fgetpwent(3)`,
288+
* shadow probe offline mode explicitly marked unsupported on platforms where
289+
the Linux-style shadow path does not apply,
290+
* runlevel probe behavior explicitly marked unsupported on macOS/FreeBSD
291+
(SysV runlevels are Linux/Solaris specific).
292+
293+
Targeted regression tests for these portability areas are located in:
294+
295+
* `tests/API/XCCDF/unittests/test_xccdf_result_sysinfo_platform.sh`
296+
* `tests/API/probes/test_memusage_platform.sh`
297+
* `tests/probes/password/test_probes_password_offline_fallback.sh`
298+
* `tests/probes/runlevel/test_probes_runlevel_unsupported.sh`
299+
* `tests/probes/shadow/test_probes_shadow_offline_unsupported.sh`
300+
* `tests/probes/sysctl/test_sysctl_probe.sh`
301+
* `tests/probes/sysctl/test_sysctl_probe_all.sh`
302+
211303
. *Install*
212304
+
213305
--
@@ -369,4 +461,3 @@ For more information about OpenSCAP library, you can refer to this online
369461
reference manual: http://static.open-scap.org/openscap-1.2/[OpenSCAP
370462
reference manual]. This manual is included in a release tarball and can be
371463
regenerated from project sources by Doxygen documentation system.
372-

src/OVAL/probes/unix/interface_probe.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,8 +298,10 @@ static void get_flags(const struct ifaddrs *ifa, char ***fp) {
298298
if (ifa->ifa_flags & IFF_RENAMING)
299299
flags_buf[i++] = "RENAMING";
300300

301+
#ifdef IFF_NOGROUP
301302
if (ifa->ifa_flags & IFF_NOGROUP)
302303
flags_buf[i++] = "NOGROUP";
304+
#endif
303305
}
304306

305307
flags_buf[i] = NULL;

src/OVAL/probes/unix/password_probe.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
#include <string.h>
5050
#include <stdio.h>
5151
#include <errno.h>
52+
#include <inttypes.h>
5253
#include <pwd.h>
5354
#include <paths.h>
5455
#if defined(OS_APPLE)
@@ -67,6 +68,79 @@
6768
#include <probe/option.h>
6869
#include "password_probe.h"
6970

71+
/*
72+
* fgetpwent() is a GNU/glibc extension; provide a portable fallback.
73+
* This parses a standard /etc/passwd-format file one entry at a time.
74+
*/
75+
#if defined(OS_APPLE) || defined(OS_FREEBSD)
76+
static int oscap_parse_passwd_id(const char *field, uintmax_t max_value,
77+
uintmax_t *parsed_value)
78+
{
79+
char *endptr;
80+
uintmax_t value;
81+
82+
errno = 0;
83+
value = strtoumax(field, &endptr, 10);
84+
if (errno != 0 || endptr == field || *endptr != '\0' || value > max_value)
85+
return -1;
86+
87+
*parsed_value = value;
88+
return 0;
89+
}
90+
91+
static struct passwd *oscap_fgetpwent(FILE *fp)
92+
{
93+
static char line[2048];
94+
static struct passwd pw;
95+
char *fields[7], *newline, *line_end, *p;
96+
uintmax_t parsed_uid, parsed_gid;
97+
int f;
98+
99+
while (fgets(line, sizeof(line), fp) != NULL) {
100+
newline = memchr(line, '\n', sizeof(line) - 1);
101+
line_end = memchr(line, '\0', sizeof(line));
102+
if (newline != NULL)
103+
*newline = '\0';
104+
else if (line_end == &line[sizeof(line) - 1]) {
105+
int ch;
106+
107+
/* Skip truncated records instead of parsing partial passwd entries. */
108+
while ((ch = fgetc(fp)) != '\n' && ch != EOF)
109+
;
110+
continue;
111+
}
112+
113+
if (line[0] == '#')
114+
continue;
115+
f = 0;
116+
p = line;
117+
while (f < 7) {
118+
fields[f++] = p;
119+
p = strchr(p, ':');
120+
if (p)
121+
*p++ = '\0';
122+
else
123+
break;
124+
}
125+
if (f < 7)
126+
continue;
127+
if (oscap_parse_passwd_id(fields[2], (uintmax_t)(uid_t)-1, &parsed_uid) != 0 ||
128+
oscap_parse_passwd_id(fields[3], (uintmax_t)(gid_t)-1, &parsed_gid) != 0)
129+
continue;
130+
pw.pw_name = fields[0];
131+
pw.pw_passwd = fields[1];
132+
pw.pw_uid = (uid_t)parsed_uid;
133+
pw.pw_gid = (gid_t)parsed_gid;
134+
pw.pw_gecos = fields[4];
135+
pw.pw_dir = fields[5];
136+
pw.pw_shell = fields[6];
137+
return &pw;
138+
}
139+
return NULL;
140+
}
141+
#define fgetpwent oscap_fgetpwent
142+
#endif
143+
70144
/* Convenience structure for the results being reported */
71145
struct result_info {
72146
const char *username;

src/OVAL/probes/unix/runlevel_probe.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,9 +468,10 @@ static int get_runlevel (struct runlevel_req *req, struct runlevel_rep **rep)
468468
_A(rep != NULL);
469469
return GET_RUNLEVEL(LINUX_DISTRO, req, rep);
470470
}
471-
#elif defined(OS_FREEBSD)
471+
#elif defined(OS_FREEBSD) || defined(OS_APPLE)
472472
static int get_runlevel (struct runlevel_req *req, struct runlevel_rep **rep)
473473
{
474+
/* SysV runlevels are a Linux/Solaris concept; not applicable on BSD/macOS */
474475
_A(req != NULL);
475476
_A(rep != NULL);
476477
return (-1);

src/OVAL/probes/unix/shadow_probe.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@
6262
#include "shadow_probe.h"
6363

6464
#ifndef HAVE_SHADOW_H
65+
int shadow_probe_offline_mode_supported()
66+
{
67+
return PROBE_OFFLINE_NONE;
68+
}
69+
6570
int shadow_probe_main(probe_ctx *ctx, void *arg)
6671
{
6772
SEXP_t *item_sexp;

0 commit comments

Comments
 (0)