diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index d657a68e80..19da6596c8 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -54,6 +54,6 @@ jobs:
make all
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v2
+ uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0d97186721..3304cddf72 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -330,6 +330,7 @@ cmake_dependent_option(ENABLE_OSCAP_UTIL_AS_RPM "enable the scap-as-rpm utility,
cmake_dependent_option(ENABLE_OSCAP_UTIL_SSH "enables the oscap-ssh utility, this lets you scan remote machines over ssh" ON "NOT WIN32" OFF)
cmake_dependent_option(ENABLE_OSCAP_UTIL_VM "enables the oscap-vm utility, this lets you scan VMs and VM storage images" ON "NOT WIN32" OFF)
cmake_dependent_option(ENABLE_OSCAP_UTIL_PODMAN "enables the oscap-podman utility, this lets you scan Podman containers and container images" ON "NOT WIN32" OFF)
+cmake_dependent_option(ENABLE_OSCAP_UTIL_BOOTC "enables the oscap-bootc utility, this lets you build hardened bootable container images" ON "NOT WIN32" OFF)
cmake_dependent_option(ENABLE_OSCAP_UTIL_CHROOT "enables the oscap-chroot utility, this lets you scan entire chroots using offline scanning" ON "NOT WIN32" OFF)
option(ENABLE_OSCAP_UTIL_AUTOTAILOR "enables the autotailor utility that is able to perform command-line tailoring" TRUE)
option(ENABLE_OSCAP_REMEDIATE_SERVICE "enables the oscap-remediate service" FALSE)
@@ -467,6 +468,7 @@ message(STATUS "scap-as-rpm: ${ENABLE_OSCAP_UTIL_AS_RPM}")
message(STATUS "oscap-ssh: ${ENABLE_OSCAP_UTIL_SSH}")
message(STATUS "oscap-vm: ${ENABLE_OSCAP_UTIL_VM}")
message(STATUS "oscap-podman: ${ENABLE_OSCAP_UTIL_PODMAN}")
+message(STATUS "oscap-bootc: ${ENABLE_OSCAP_UTIL_BOOTC}")
message(STATUS "oscap-chroot: ${ENABLE_OSCAP_UTIL_CHROOT}")
message(STATUS "autotailor: ${ENABLE_OSCAP_UTIL_AUTOTAILOR}")
message(STATUS " ")
diff --git a/docs/manual/manual.adoc b/docs/manual/manual.adoc
index 2391e06a05..82d6096bc6 100644
--- a/docs/manual/manual.adoc
+++ b/docs/manual/manual.adoc
@@ -1614,6 +1614,7 @@ If OpenSCAP is executed with verbosity level INFO or DEVEL their runtime values
* `OSCAP_PROBE_MEMORY_USAGE_RATIO` - maximum memory usage ratio (used/total) for OpenSCAP probes, default: 0.1
* `OSCAP_PROBE_MAX_COLLECTED_ITEMS` - maximal count of collected items by OpenSCAP probe for a single OVAL object evaluation
* `OSCAP_PROBE_IGNORE_PATHS` - Skip given paths during evaluation. If multiple paths should be skipped they need to be separated by a colon. The paths should be absolute canonical paths.
+* `OSCAP_PREFERRED_ENGINE` - Set a preffered check engine for XCCDF rules. If a rule has multiple checks, the checks for the preffered check engine will be used. Allowed values: `SCE`, `OVAL`. If this variable is set to `SCE` and a rule has both SCE and OVAL checks the SCE check will be used. If this variable is set to `OVAL` and a rule has both SCE and OVAL checks the OVAL check will be used. If this environment variable isn't set, the standard XCCDF mechanism will be used for check selection.
Also, OpenSCAP uses `libcurl` library which also can be configured using environment variables. See https://curl.se/libcurl/c/libcurl-env.html[the list of libcurl environment variables].
@@ -1839,6 +1840,43 @@ registry.access.redhat.com/ubi8 latest 3269c37eae33 2 months ago 208 MB
Note that the `oscap-podman` command requires root privileges.
+=== Building hardened bootable container images using oscap-bootc
+
+The `oscap-bootc` tool is a convenience script that makes building hardened bootable container images easier.
+This tool is designed to be used during the build of the bootable container image.
+
+Include `oscap-bootc` in your `Containerfile` that will be used to build your bootable container image.
+The `Containerfile` first needs to install the `openscap-utils` package which ships the `oscap-bootc` tool.
+
+Also, SCAP content needs to be installed to the image before `oscap-bootc` will be run.
+Although any SCAP content can be consumed by the tool, the SCAP source data streams shipped in `scap-security-guide` are specially cared to be compatible with bootable containers.
+
+Example `Containerfile`:
+
+----
+FROM quay.io/centos-bootc/centos-bootc:stream9
+
+RUN dnf install -y openscap-utils scap-security-guide
+
+RUN oscap-bootc --profile stig /usr/share/xml/scap/ssg/content/ssg-cs9-ds.xml
+----
+
+Once you have your `Containerfile`, execute the image build:
+
+----
+podman build -t hardened_image .
+----
+
+The `oscap-bootc` tool installs and removes all packages required by the selected profile to or from the image.
+Then, it runs a scan and remediation with the selected profile.
+It doesn't use offline scanning.
+The configuration files and other content in the image are modified by this process, depending on the used SCAP content.
+
+The built bootable container image can be then deployed and booted.
+After booting the image, the state of the resulting system will be in line with the selected security profile.
+
+The `oscap-bootc` tool can't be used anywhere else than in a `Containerfile`.
+
=== Scanning of Docker containers and images using oscap-docker
The `oscap-docker` is used to scan Docker containers and images. It can
diff --git a/openscap.spec b/openscap.spec
index edccd6100b..0440b4c689 100644
--- a/openscap.spec
+++ b/openscap.spec
@@ -88,6 +88,7 @@ Summary: OpenSCAP Utilities
Requires: %{name}%{?_isa} = %{epoch}:%{version}-%{release}
Requires: rpmdevtools rpm-build
Requires: %{name}-scanner%{?_isa} = %{epoch}:%{version}-%{release}
+Requires: %{name}-engine-sce%{?_isa} = %{epoch}:%{version}-%{release}
%description utils
The %{name}-utils package contains command-line tools build on top
diff --git a/src/OVAL/probes/unix/linux/rpm-helper.c b/src/OVAL/probes/unix/linux/rpm-helper.c
index f7e29cc3d2..e31b2b2e0d 100644
--- a/src/OVAL/probes/unix/linux/rpm-helper.c
+++ b/src/OVAL/probes/unix/linux/rpm-helper.c
@@ -51,3 +51,32 @@ void rpmLibsPreload()
const char* rcfiles = "";
rpmReadConfigFiles(rcfiles, NULL);
}
+
+void set_rpm_db_path()
+{
+ /*
+ * Fedora >=36 changed the default dbpath in librpm from /var/lib/rpm to /usr/lib/sysimage/rpm.
+ * See: https://fedoraproject.org/wiki/Changes/RelocateRPMToUsr
+ *
+ * Therefore, when running openscap on a Fedora >=36 system scanning another systems (such as RHEL, SLES, Fedora<36)
+ * openscap's librpm will try to read the rpm db from /usr/lib/sysimage/rpm which doesn't exist and therefore won't work.
+ * On many systems, /var/lib/rpm is still a symlink to /usr/lib/sysimage/rpm, so using /var/lib/rpm can work there.
+ * However, on some systems, eg. bootc images, /var/lib/rpm isn't a symlink and doesn't contain the RPM database.
+ *
+ * We will first try if the "new" location /usr/lib/sysimage/rpm exists, and use it only if it exists.
+ * If it doesn't exist, we will fall back to the "old" location /var/lib/rpm.
+ */
+
+ struct stat sb;
+ const char *dbpath;
+ const char *prefix = getenv("OSCAP_PROBE_ROOT");
+ char *path_with_prefix = oscap_path_join(prefix, "/usr/lib/sysimage/rpm");
+ if (stat(path_with_prefix, &sb) == 0) {
+ dbpath = "/usr/lib/sysimage/rpm";
+ } else {
+ dbpath = "/var/lib/rpm";
+ }
+ free(path_with_prefix);
+ dI("Using %s as rpm database.", dbpath);
+ rpmPushMacro(NULL, "_dbpath", NULL, dbpath, RMIL_CMDLINE);
+}
diff --git a/src/OVAL/probes/unix/linux/rpm-helper.h b/src/OVAL/probes/unix/linux/rpm-helper.h
index de7b5fe351..d58f6ccaf5 100644
--- a/src/OVAL/probes/unix/linux/rpm-helper.h
+++ b/src/OVAL/probes/unix/linux/rpm-helper.h
@@ -99,4 +99,7 @@ int rpmVerifyFile(const rpmts ts, const rpmfi fi,
*/
void rpmLibsPreload(void);
+void set_rpm_db_path(void);
+
+
#endif
diff --git a/src/OVAL/probes/unix/linux/rpminfo_probe.c b/src/OVAL/probes/unix/linux/rpminfo_probe.c
index 46ad1d9719..53f97bd4b4 100644
--- a/src/OVAL/probes/unix/linux/rpminfo_probe.c
+++ b/src/OVAL/probes/unix/linux/rpminfo_probe.c
@@ -294,17 +294,7 @@ void *rpminfo_probe_init(void)
return ((void *)g_rpm);
}
- /*
- * Fedora >=36 changed the default dbpath in librpm from /var/lib/rpm to /usr/lib/sysimage/rpm
- * See: https://fedoraproject.org/wiki/Changes/RelocateRPMToUsr
- * Therefore, when running openscap on a Fedora >=36 system scanning another systems (such as RHEL, SLES, Fedora<36)
- * openscap's librpm will try to read the rpm db from /usr/lib/sysimage/rpm which doesn't exist and therefore won't work.
- * In implementing this change, /var/lib/rpm is still a symlink to /usr/lib/sysimage/rpm
- * so /var/lib/rpm still works. So /var/lib/rpm is a dbpath that will work on all systems.
- * Therefore, set the dbpath to be /var/lib/rpm, allow openscap running on any system to scan any system.
- */
- rpmPushMacro(NULL, "_dbpath", NULL, "/var/lib/rpm", RMIL_CMDLINE);
-
+ set_rpm_db_path();
g_rpm->rpmts = rpmtsCreate();
pthread_mutex_init (&(g_rpm->mutex), NULL);
diff --git a/src/OVAL/probes/unix/linux/rpmverify_probe.c b/src/OVAL/probes/unix/linux/rpmverify_probe.c
index 6a8f4b4992..bf310ea7d7 100644
--- a/src/OVAL/probes/unix/linux/rpmverify_probe.c
+++ b/src/OVAL/probes/unix/linux/rpmverify_probe.c
@@ -236,16 +236,7 @@ void *rpmverify_probe_init(void)
return (NULL);
}
- /*
- * Fedora >=36 changed the default dbpath in librpm from /var/lib/rpm to /usr/lib/sysimage/rpm
- * See: https://fedoraproject.org/wiki/Changes/RelocateRPMToUsr
- * Therefore, when running openscap on a Fedora >=36 system scanning another systems (such as RHEL, SLES, Fedora<36)
- * openscap's librpm will try to read the rpm db from /usr/lib/sysimage/rpm which doesn't exist and therefore won't work.
- * In implementing this change, /var/lib/rpm is still a symlink to /usr/lib/sysimage/rpm
- * so /var/lib/rpm still works. So /var/lib/rpm is a dbpath that will work on all systems.
- * Therefore, set the dbpath to be /var/lib/rpm, allow openscap running on any system to scan any system.
- */
- rpmPushMacro(NULL, "_dbpath", NULL, "/var/lib/rpm", RMIL_CMDLINE);
+ set_rpm_db_path();
struct rpm_probe_global *g_rpm = malloc(sizeof(struct rpm_probe_global));
g_rpm->rpmts = rpmtsCreate();
diff --git a/src/OVAL/probes/unix/linux/rpmverifyfile_probe.c b/src/OVAL/probes/unix/linux/rpmverifyfile_probe.c
index 12145c411f..8da310e51b 100644
--- a/src/OVAL/probes/unix/linux/rpmverifyfile_probe.c
+++ b/src/OVAL/probes/unix/linux/rpmverifyfile_probe.c
@@ -358,16 +358,7 @@ void *rpmverifyfile_probe_init(void)
struct rpm_probe_global *g_rpm = malloc(sizeof(struct rpm_probe_global));
- /*
- * Fedora >=36 changed the default dbpath in librpm from /var/lib/rpm to /usr/lib/sysimage/rpm
- * See: https://fedoraproject.org/wiki/Changes/RelocateRPMToUsr
- * Therefore, when running openscap on a Fedora >=36 system scanning another systems (such as RHEL, SLES, Fedora<36)
- * openscap's librpm will try to read the rpm db from /usr/lib/sysimage/rpm which doesn't exist and therefore won't work.
- * In implementing this change, /var/lib/rpm is still a symlink to /usr/lib/sysimage/rpm
- * so /var/lib/rpm still works. So /var/lib/rpm is a dbpath that will work on all systems.
- * Therefore, set the dbpath to be /var/lib/rpm, allow openscap running on any system to scan any system.
- */
- rpmPushMacro(NULL, "_dbpath", NULL, "/var/lib/rpm", RMIL_CMDLINE);
+ set_rpm_db_path();
g_rpm->rpmts = rpmtsCreate();
diff --git a/src/OVAL/probes/unix/linux/rpmverifypackage_probe.c b/src/OVAL/probes/unix/linux/rpmverifypackage_probe.c
index 90d053aaae..55aae69744 100644
--- a/src/OVAL/probes/unix/linux/rpmverifypackage_probe.c
+++ b/src/OVAL/probes/unix/linux/rpmverifypackage_probe.c
@@ -354,16 +354,6 @@ void *rpmverifypackage_probe_init(void)
return ((void *)g_rpm);
}
- /*
- * Fedora >=36 changed the default dbpath in librpm from /var/lib/rpm to /usr/lib/sysimage/rpm
- * See: https://fedoraproject.org/wiki/Changes/RelocateRPMToUsr
- * Therefore, when running openscap on a Fedora >=36 system scanning another systems (such as RHEL, SLES, Fedora<36)
- * openscap's librpm will try to read the rpm db from /usr/lib/sysimage/rpm which doesn't exist and therefore won't work.
- * In implementing this change, /var/lib/rpm is still a symlink to /usr/lib/sysimage/rpm
- * so /var/lib/rpm still works. So /var/lib/rpm is a dbpath that will work on all systems.
- * Therefore, set the dbpath to be /var/lib/rpm, allow openscap running on any system to scan any system.
- */
- rpmPushMacro(NULL, "_dbpath", NULL, "/var/lib/rpm", RMIL_CMDLINE);
g_rpm->rpm.rpmts = rpmtsCreate();
@@ -377,6 +367,7 @@ void *rpmverifypackage_probe_init(void)
rpmtsSetRootDir(g_rpm->rpm.rpmts, CHROOT_PATH());
}
+ set_rpm_db_path();
pthread_mutex_init(&(g_rpm->rpm.mutex), NULL);
return ((void *)g_rpm);
}
diff --git a/src/SCE/sce_engine.c b/src/SCE/sce_engine.c
index 962e409885..70670975b6 100644
--- a/src/SCE/sce_engine.c
+++ b/src/SCE/sce_engine.c
@@ -370,6 +370,7 @@ xccdf_test_result_type_t sce_engine_eval_rule(struct xccdf_policy *policy, const
struct xccdf_check_import_iterator *check_import_it,
void *usr)
{
+ dI("Executing SCE check '%s'", href);
struct sce_parameters* parameters = (struct sce_parameters*)usr;
const char* xccdf_directory = parameters->xccdf_directory;
bool use_sce_wrapper = false; // use osca-run-sce-script ?
diff --git a/src/XCCDF_POLICY/xccdf_policy.c b/src/XCCDF_POLICY/xccdf_policy.c
index f12b046baf..5ab9b16090 100644
--- a/src/XCCDF_POLICY/xccdf_policy.c
+++ b/src/XCCDF_POLICY/xccdf_policy.c
@@ -588,6 +588,16 @@ _xccdf_policy_rule_get_applicable_check(struct xccdf_policy *policy, struct xccd
struct xccdf_check *check = xccdf_check_iterator_next(candidate_it);
if (_xccdf_policy_is_engine_registered(policy, (char *) xccdf_check_get_system(check))) {
result = check;
+ char *preferred_engine = getenv("OSCAP_PREFERRED_ENGINE");
+ if (preferred_engine) {
+ if (strcmp("SCE", preferred_engine) && strcmp("OVAL", preferred_engine)) {
+ dW("Unknown value of OSCAP_PREFFERED_ENGINE: '%s'. It will be ignored.", preferred_engine);
+ }
+ if ((!strcmp("SCE", preferred_engine) && !strcmp("http://open-scap.org/page/SCE", check->system)) ||
+ (!strcmp("OVAL", preferred_engine) && !strcmp("http://oval.mitre.org/XMLSchema/oval-definitions-5", check->system))) {
+ break;
+ }
+ }
} else if (strcmp("http://oval.mitre.org/XMLSchema/oval-definitions-5", check->system) == 0) {
print_oval_warning = true;
} else if (strcmp("http://scap.nist.gov/schema/ocil/2", check->system) == 0) {
diff --git a/src/XCCDF_POLICY/xccdf_policy_remediate.c b/src/XCCDF_POLICY/xccdf_policy_remediate.c
index 9233913d9c..1dc30720d1 100644
--- a/src/XCCDF_POLICY/xccdf_policy_remediate.c
+++ b/src/XCCDF_POLICY/xccdf_policy_remediate.c
@@ -68,6 +68,11 @@ struct logvol_cmd {
char *size;
};
+struct bootc_commands {
+ struct oscap_list *dnf_install;
+ struct oscap_list *dnf_remove;
+};
+
static int _rule_add_info_message(struct xccdf_rule_result *rr, ...)
{
va_list ap;
@@ -464,9 +469,9 @@ static inline int _xccdf_fix_execute(struct xccdf_rule_result *rr, struct xccdf_
int fork_result = fork();
if (fork_result >= 0) {
- /* fork succeded */
+ /* fork succeeded */
if (fork_result == 0) {
- /* Execute fix and forward output to the parrent. */
+ /* Execute fix and forward output to the parent. */
close(pipefd[0]);
dup2(pipefd[1], fileno(stdout));
dup2(pipefd[1], fileno(stderr));
@@ -478,8 +483,14 @@ static inline int _xccdf_fix_execute(struct xccdf_rule_result *rr, struct xccdf_
NULL
};
- char *const envp[2] = {
+ char *oscap_bootc_build = getenv("OSCAP_BOOTC_BUILD");
+ char *oscap_bootc_build_kvarg = NULL;
+ if (oscap_bootc_build != NULL) {
+ oscap_bootc_build_kvarg = oscap_sprintf("OSCAP_BOOTC_BUILD=%s", oscap_bootc_build);
+ }
+ char *const envp[3] = {
"PATH=/bin:/sbin:/usr/bin:/usr/sbin",
+ oscap_bootc_build_kvarg,
NULL
};
@@ -1860,6 +1871,144 @@ static int _xccdf_policy_generate_fix_kickstart(struct oscap_list *rules_to_fix,
return ret;
}
+static int _parse_bootc_line(const char *line, struct bootc_commands *cmds)
+{
+ int ret = 0;
+ char *dup = strdup(line);
+ char **words = oscap_split(dup, " ");
+ enum states {
+ BOOTC_START,
+ BOOTC_DNF,
+ BOOTC_DNF_INSTALL,
+ BOOTC_DNF_REMOVE,
+ BOOTC_ERROR
+ };
+ int state = BOOTC_START;
+ for (unsigned int i = 0; words[i] != NULL; i++) {
+ char *word = oscap_trim(words[i]);
+ if (*word == '\0')
+ continue;
+ switch (state) {
+ case BOOTC_START:
+ if (!strcmp(word, "dnf")) {
+ state = BOOTC_DNF;
+ } else {
+ ret = 1;
+ oscap_seterr(OSCAP_EFAMILY_OSCAP, "Unsupported command keyword '%s' in command: '%s'", word, line);
+ goto cleanup;
+ }
+ break;
+ case BOOTC_DNF:
+ if (!strcmp(word, "install")) {
+ state = BOOTC_DNF_INSTALL;
+ } else if (!strcmp(word, "remove")) {
+ state = BOOTC_DNF_REMOVE;
+ } else {
+ ret = 1;
+ oscap_seterr(OSCAP_EFAMILY_OSCAP, "Unsupported 'dnf' command keyword '%s' in command:'%s'", word, line);
+ goto cleanup;
+ }
+ break;
+ case BOOTC_DNF_INSTALL:
+ oscap_list_add(cmds->dnf_install, strdup(word));
+ break;
+ case BOOTC_DNF_REMOVE:
+ oscap_list_add(cmds->dnf_remove, strdup(word));
+ break;
+ case BOOTC_ERROR:
+ ret = 1;
+ oscap_seterr(OSCAP_EFAMILY_OSCAP, "Unexpected string '%s' in command: '%s'", word, line);
+ goto cleanup;
+ default:
+ break;
+ }
+ }
+
+cleanup:
+ free(words);
+ free(dup);
+ return ret;
+}
+
+static int _xccdf_policy_rule_generate_bootc_fix(struct xccdf_policy *policy, struct xccdf_rule *rule, const char *template, struct bootc_commands *cmds)
+{
+ char *fix_text = NULL;
+ int ret = _xccdf_policy_rule_get_fix_text(policy, rule, template, &fix_text);
+ if (fix_text == NULL) {
+ return ret;
+ }
+ char *dup = strdup(fix_text);
+ char **lines = oscap_split(dup, "\n");
+ for (unsigned int i = 0; lines[i] != NULL; i++) {
+ char *line = lines[i];
+ char *trim_line = oscap_trim(strdup(line));
+ if (*trim_line != '#' && *trim_line != '\0') {
+ _parse_bootc_line(trim_line, cmds);
+ }
+ free(trim_line);
+ }
+ free(lines);
+ free(dup);
+ free(fix_text);
+ return ret;
+}
+
+static int _generate_bootc_dnf(struct bootc_commands *cmds, int output_fd)
+{
+ struct oscap_iterator *dnf_install_it = oscap_iterator_new(cmds->dnf_install);
+ if (oscap_iterator_has_more(dnf_install_it)) {
+ _write_text_to_fd(output_fd, "dnf -y install \\\n");
+ while (oscap_iterator_has_more(dnf_install_it)) {
+ char *package = (char *) oscap_iterator_next(dnf_install_it);
+ _write_text_to_fd(output_fd, " ");
+ _write_text_to_fd(output_fd, package);
+ if (oscap_iterator_has_more(dnf_install_it))
+ _write_text_to_fd(output_fd, " \\\n");
+ }
+ _write_text_to_fd(output_fd, "\n\n");
+ }
+ oscap_iterator_free(dnf_install_it);
+
+ struct oscap_iterator *dnf_remove_it = oscap_iterator_new(cmds->dnf_remove);
+ if (oscap_iterator_has_more(dnf_remove_it)) {
+ _write_text_to_fd(output_fd, "dnf -y remove \\\n");
+ while (oscap_iterator_has_more(dnf_remove_it)) {
+ char *package = (char *) oscap_iterator_next(dnf_remove_it);
+ _write_text_to_fd(output_fd, " ");
+ _write_text_to_fd(output_fd, package);
+ if (oscap_iterator_has_more(dnf_remove_it))
+ _write_text_to_fd(output_fd, " \\\n");
+ }
+ _write_text_to_fd(output_fd, "\n");
+ }
+ oscap_iterator_free(dnf_remove_it);
+ return 0;
+}
+
+static int _xccdf_policy_generate_fix_bootc(struct oscap_list *rules_to_fix, struct xccdf_policy *policy, const char *sys, int output_fd)
+{
+ struct bootc_commands cmds = {
+ .dnf_install = oscap_list_new(),
+ .dnf_remove = oscap_list_new(),
+ };
+ int ret = 0;
+ struct oscap_iterator *rules_to_fix_it = oscap_iterator_new(rules_to_fix);
+ while (oscap_iterator_has_more(rules_to_fix_it)) {
+ struct xccdf_rule *rule = (struct xccdf_rule *) oscap_iterator_next(rules_to_fix_it);
+ ret = _xccdf_policy_rule_generate_bootc_fix(policy, rule, sys, &cmds);
+ if (ret != 0)
+ break;
+ }
+ oscap_iterator_free(rules_to_fix_it);
+
+ _write_text_to_fd(output_fd, "#!/bin/bash\n");
+ _generate_bootc_dnf(&cmds, output_fd);
+
+ oscap_list_free(cmds.dnf_install, free);
+ oscap_list_free(cmds.dnf_remove, free);
+ return ret;
+}
+
int xccdf_policy_generate_fix(struct xccdf_policy *policy, struct xccdf_result *result, const char *sys, const char *input_file_name, struct oscap_source *tailoring, int output_fd, int raw)
{
__attribute__nonnull__(policy);
@@ -1919,6 +2068,8 @@ int xccdf_policy_generate_fix(struct xccdf_policy *policy, struct xccdf_result *
ret = _xccdf_policy_generate_fix_blueprint(rules_to_fix, policy, sys, output_fd);
} else if (strcmp(sys, "urn:xccdf:fix:script:kickstart") == 0) {
ret = _xccdf_policy_generate_fix_kickstart(rules_to_fix, policy, sys, input_file_name, tailoring, raw, output_fd);
+ } else if (strcmp(sys, "urn:xccdf:fix:script:bootc") == 0) {
+ ret = _xccdf_policy_generate_fix_bootc(rules_to_fix, policy, sys, output_fd);
} else {
ret = _xccdf_policy_generate_fix_other(rules_to_fix, policy, sys, output_fd);
}
diff --git a/src/common/debug.c b/src/common/debug.c
index 30d37845dc..dc56874fb2 100644
--- a/src/common/debug.c
+++ b/src/common/debug.c
@@ -311,6 +311,7 @@ void oscap_print_env_vars()
"OSCAP_PROBE_MEMORY_USAGE_RATIO",
"OSCAP_PROBE_MAX_COLLECTED_ITEMS",
"OSCAP_PROBE_IGNORE_PATHS",
+ "OSCAP_PREFERRED_ENGINE",
NULL
};
dI("Using environment variables:");
diff --git a/tests/API/XCCDF/unittests/CMakeLists.txt b/tests/API/XCCDF/unittests/CMakeLists.txt
index 25f6f79689..6b557d0837 100644
--- a/tests/API/XCCDF/unittests/CMakeLists.txt
+++ b/tests/API/XCCDF/unittests/CMakeLists.txt
@@ -112,3 +112,5 @@ add_oscap_test("test_skip_rule.sh")
add_oscap_test("test_no_newline_between_select_elements.sh")
add_oscap_test("test_single_line_tailoring.sh")
add_oscap_test("test_reference.sh")
+add_oscap_test("test_remediation_bootc.sh")
+add_oscap_test("test_oscap_bootc_pass_down.sh")
diff --git a/tests/API/XCCDF/unittests/test_oscap_bootc_pass_down.ds.xml b/tests/API/XCCDF/unittests/test_oscap_bootc_pass_down.ds.xml
new file mode 100644
index 0000000000..660575d55e
--- /dev/null
+++ b/tests/API/XCCDF/unittests/test_oscap_bootc_pass_down.ds.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 5.11.1
+ 2009-01-12T10:41:00-05:00
+
+
+
+
+ FAIL
+ fail
+
+
+
+
+
+
+
+
+
+
+
+
+
+ oval:x:var:1
+
+
+
+
+ 100
+
+
+
+
+
+
+ accepted
+ 1.0
+
+ This rule always fails
+
+ if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then
+ printf "WE ARE BUILDING BOOTABLE CONTAINER IMAGE NOW"
+ fi
+
+
+
+
+
+
+
+
diff --git a/tests/API/XCCDF/unittests/test_oscap_bootc_pass_down.sh b/tests/API/XCCDF/unittests/test_oscap_bootc_pass_down.sh
new file mode 100755
index 0000000000..09783de1d3
--- /dev/null
+++ b/tests/API/XCCDF/unittests/test_oscap_bootc_pass_down.sh
@@ -0,0 +1,31 @@
+#!/usr/bin/env bash
+
+. $builddir/tests/test_common.sh
+
+set -e -o pipefail
+
+function test_pass_env_var_down() {
+ stdout=$(mktemp)
+ stderr=$(mktemp)
+ result=$(mktemp)
+
+ OSCAP_BOOTC_BUILD=YES $OSCAP xccdf eval --remediate --results "$result" "$srcdir/test_oscap_bootc_pass_down.ds.xml" > "$stdout" 2> "$stderr" || ret=$?
+ assert_exists 1 '//rule-result/message[text()="WE ARE BUILDING BOOTABLE CONTAINER IMAGE NOW"]'
+
+ rm -rf "$stdout" "$stderr" "$result"
+}
+
+function test_no_env_var() {
+ stdout=$(mktemp)
+ stderr=$(mktemp)
+ result=$(mktemp)
+
+ $OSCAP xccdf eval --remediate --results "$result" "$srcdir/test_oscap_bootc_pass_down.ds.xml" > "$stdout" 2> "$stderr" || ret=$?
+ assert_exists 0 '//rule-result/message[text()="WE ARE BUILDING BOOTABLE CONTAINER IMAGE NOW"]'
+
+ rm -rf "$stdout" "$stderr" "$result"
+}
+
+
+test_pass_env_var_down
+test_no_env_var
diff --git a/tests/API/XCCDF/unittests/test_remediation_bootc.ds.xml b/tests/API/XCCDF/unittests/test_remediation_bootc.ds.xml
new file mode 100644
index 0000000000..6134381d4c
--- /dev/null
+++ b/tests/API/XCCDF/unittests/test_remediation_bootc.ds.xml
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 5.11.2
+ 2021-02-01T08:07:06+01:00
+
+
+
+
+ PASS
+ pass
+
+
+
+
+
+
+
+
+
+
+
+
+
+ oval:org.openscap.www:var:1
+
+
+
+
+ 100
+
+
+
+
+
+
+ accepted
+ 1.0
+
+ Common hardening profile
+ This is a very cool profile
+
+
+
+
+
+
+ Rule 1: Install rsyslog package
+
+ dnf install rsyslog
+
+
+
+ Rule 2: Remove USBGuard
+
+ dnf remove usbguard
+
+
+
+ Rule 3: Install reboot package
+
+ dnf install reboot
+
+
+
+ Rule 4: Install podman package
+
+ dnf install podman
+
+
+
+
+
diff --git a/tests/API/XCCDF/unittests/test_remediation_bootc.sh b/tests/API/XCCDF/unittests/test_remediation_bootc.sh
new file mode 100755
index 0000000000..cf193e75a5
--- /dev/null
+++ b/tests/API/XCCDF/unittests/test_remediation_bootc.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+. $builddir/tests/test_common.sh
+
+set -e
+set -o pipefail
+
+name=$(basename $0 .sh)
+result=$(mktemp)
+stderr=$(mktemp)
+
+echo "Result file = $result"
+echo "Stderr file = $stderr"
+
+$OSCAP xccdf generate fix --fix-type bootc --profile common "$srcdir/test_remediation_bootc.ds.xml" > "$result" 2> "$stderr"
+[ -e $stderr ]
+
+diff -u "$srcdir/test_remediation_bootc_expected_output.sh" "$result"
+
+rm -rf "$stdout" "$stderr" "$result"
diff --git a/tests/API/XCCDF/unittests/test_remediation_bootc_expected_output.sh b/tests/API/XCCDF/unittests/test_remediation_bootc_expected_output.sh
new file mode 100644
index 0000000000..57a7ffb3df
--- /dev/null
+++ b/tests/API/XCCDF/unittests/test_remediation_bootc_expected_output.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+dnf -y install \
+ rsyslog \
+ reboot \
+ podman
+
+dnf -y remove \
+ usbguard
diff --git a/tests/probes/rpm/rpm_common.sh b/tests/probes/rpm/rpm_common.sh
index c8b4661f87..eb96f76d80 100755
--- a/tests/probes/rpm/rpm_common.sh
+++ b/tests/probes/rpm/rpm_common.sh
@@ -11,10 +11,7 @@ RPMBUILD="${RPMBASE}/build"
# Since Fedora 36 RPM database location changed, see
# https://fedoraproject.org/wiki/Changes/RelocateRPMToUsr
-# However, /var/lib/rpm/ still works as it is a symlink to
-# the new path, /usr/lib/sysimage/rpm/, in Fedora >= 36
-# Therefore, always use /var/lib/rpm/ as it always works.
-RPMDB_PATH="/var/lib/rpm/"
+RPMDB_PATH="/usr/lib/sysimage/rpm/"
function rpm_build {
require "rpmbuild" || return 255
diff --git a/tests/probes/rpm/rpmverifypackage/rpmverifypackage_common.sh b/tests/probes/rpm/rpmverifypackage/rpmverifypackage_common.sh
index c03bd2e169..0ae994ccbc 100755
--- a/tests/probes/rpm/rpmverifypackage/rpmverifypackage_common.sh
+++ b/tests/probes/rpm/rpmverifypackage/rpmverifypackage_common.sh
@@ -30,7 +30,7 @@ function test_probes_rpmverifypackage {
rm -f $RF
- $OSCAP oval eval --results $RF $DF
+ $OSCAP oval eval --verbose INFO --results $RF $DF
result=$RF
diff --git a/tests/sce/CMakeLists.txt b/tests/sce/CMakeLists.txt
index 18c65bc79e..f9d945f0ba 100644
--- a/tests/sce/CMakeLists.txt
+++ b/tests/sce/CMakeLists.txt
@@ -1,4 +1,5 @@
if(ENABLE_SCE)
+ add_oscap_test("test_prefer_sce.sh")
add_oscap_test("test_sce.sh")
add_oscap_test("test_passing_vars.sh")
add_oscap_test("test_check_engine_results.sh")
diff --git a/tests/sce/test_prefer_sce.ds.xml b/tests/sce/test_prefer_sce.ds.xml
new file mode 100644
index 0000000000..e95c666397
--- /dev/null
+++ b/tests/sce/test_prefer_sce.ds.xml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 5.11.2
+ 2021-02-01T08:07:06+01:00
+
+
+
+
+ OVAL check for rule 1
+ pass
+
+
+
+
+
+
+
+
+
+
+
+
+
+ oval:org.openscap.www:var:1
+
+
+
+
+ 100
+
+
+
+
+
+
+ accepted
+ 1.0
+
+ Common hardening profile
+ This is a very cool profile
+
+
+
+ Rule 1: Enable Audit Service
+
+
+
+
+
+
+
+
+
+
+
+ #!/bin/bash
+echo "Hello how are you"
+exit "$XCCDF_RESULT_FAIL"
+
+
+
diff --git a/tests/sce/test_prefer_sce.sh b/tests/sce/test_prefer_sce.sh
new file mode 100755
index 0000000000..990dfbe9d7
--- /dev/null
+++ b/tests/sce/test_prefer_sce.sh
@@ -0,0 +1,64 @@
+#!/usr/bin/env bash
+
+. $builddir/tests/test_common.sh
+
+set -e -o pipefail
+
+
+function test_prefer_sce_on () {
+ stdout=$(mktemp)
+ stderr=$(mktemp)
+ arf=$(mktemp)
+
+ OSCAP_PREFERRED_ENGINE="SCE" $OSCAP xccdf eval --verbose INFO --progress --profile common --results-arf "$arf" > "$stdout" 2> "$stderr" "$srcdir/test_prefer_sce.ds.xml" || ret="$?"
+ grep -q "xccdf_org.openscap.www_rule_1:fail" "$stdout"
+ ! grep -q "I: oscap: Evaluating definition 'oval:org.openscap.www:def:1': OVAL check for rule 1." "$stderr"
+ grep -q "I: oscap: Executing SCE check 'fedora/checks/sce/rule_1.sh'" "$stderr"
+
+ rm -rf "$stdout" "$stderr" "$arf"
+}
+
+test_prefer_sce_off () {
+ stdout=$(mktemp)
+ stderr=$(mktemp)
+ arf=$(mktemp)
+
+ $OSCAP xccdf eval --verbose INFO --progress --profile common --results-arf "$arf" > "$stdout" 2> "$stderr" "$srcdir/test_prefer_sce.ds.xml" || ret="$?"
+ grep -q "xccdf_org.openscap.www_rule_1:pass" "$stdout"
+ grep -q "I: oscap: Evaluating definition 'oval:org.openscap.www:def:1': OVAL check for rule 1." "$stderr"
+ ! grep -q "I: oscap: Executing SCE check 'fedora/checks/sce/rule_1.sh'" "$stderr"
+
+ rm -rf "$stdout" "$stderr" "$arf"
+}
+
+test_prefer_oval_explicit () {
+ stdout=$(mktemp)
+ stderr=$(mktemp)
+ arf=$(mktemp)
+
+ OSCAP_PREFERRED_ENGINE="OVAL" $OSCAP xccdf eval --verbose INFO --progress --profile common --results-arf "$arf" > "$stdout" 2> "$stderr" "$srcdir/test_prefer_sce.ds.xml" || ret="$?"
+ grep -q "xccdf_org.openscap.www_rule_1:pass" "$stdout"
+ grep -q "I: oscap: Evaluating definition 'oval:org.openscap.www:def:1': OVAL check for rule 1." "$stderr"
+ ! grep -q "I: oscap: Executing SCE check 'fedora/checks/sce/rule_1.sh'" "$stderr"
+
+ rm -rf "$stdout" "$stderr" "$arf"
+}
+
+test_invalid_envi_variable () {
+ stdout=$(mktemp)
+ stderr=$(mktemp)
+ arf=$(mktemp)
+
+ OSCAP_PREFERRED_ENGINE="FOOBARVIM" $OSCAP xccdf eval --verbose INFO --progress --profile common --results-arf "$arf" > "$stdout" 2> "$stderr" "$srcdir/test_prefer_sce.ds.xml" || ret="$?"
+ grep -q "Unknown value of OSCAP_PREFFERED_ENGINE: 'FOOBARVIM'. It will be ignored." "$stderr"
+ grep -q "xccdf_org.openscap.www_rule_1:pass" "$stdout"
+ grep -q "I: oscap: Evaluating definition 'oval:org.openscap.www:def:1': OVAL check for rule 1." "$stderr"
+ ! grep -q "I: oscap: Executing SCE check 'fedora/checks/sce/rule_1.sh'" "$stderr"
+
+ rm -rf "$stdout" "$stderr" "$arf"
+}
+
+test_prefer_sce_on
+test_prefer_sce_off
+test_prefer_oval_explicit
+test_invalid_envi_variable
diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt
index 9347c29767..7b9274434e 100644
--- a/utils/CMakeLists.txt
+++ b/utils/CMakeLists.txt
@@ -139,6 +139,14 @@ if(ENABLE_OSCAP_UTIL_PODMAN)
DESTINATION "${CMAKE_INSTALL_MANDIR}/man8"
)
endif()
+if(ENABLE_OSCAP_UTIL_BOOTC)
+ install(PROGRAMS "oscap-bootc"
+ DESTINATION ${CMAKE_INSTALL_BINDIR}
+ )
+ install(FILES "oscap-bootc.8"
+ DESTINATION "${CMAKE_INSTALL_MANDIR}/man8"
+ )
+endif()
if(ENABLE_OSCAP_UTIL_AS_RPM)
install(PROGRAMS "scap-as-rpm"
DESTINATION ${CMAKE_INSTALL_BINDIR}
diff --git a/utils/oscap-bootc b/utils/oscap-bootc
new file mode 100755
index 0000000000..8ac7c17b87
--- /dev/null
+++ b/utils/oscap-bootc
@@ -0,0 +1,134 @@
+#!/usr/bin/env python3
+
+# Copyright 2024 Red Hat Inc., Durham, North Carolina.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+import argparse
+import subprocess
+import sys
+import tempfile
+
+
+def parse_args():
+ parser = argparse.ArgumentParser(
+ description="Use in your Containerfile to build hardened bootable "
+ "container images. Performs OpenSCAP scan and remediation of the "
+ "image.")
+ parser.add_argument(
+ "--profile",
+ help="ID of the profile to be evaluated")
+ parser.add_argument(
+ "--tailoring-file",
+ help="Use given XCCDF Tailoring file")
+ parser.add_argument(
+ "--tailoring-id", metavar="COMPONENT_ID",
+ help="Use given DS component as XCCDF Tailoring file")
+ parser.add_argument(
+ "--results-arf",
+ help="Write ARF (result data stream) into file")
+ parser.add_argument(
+ "--report",
+ help="Write HTML report into file")
+ parser.add_argument(
+ "data_stream", metavar="DATA_STREAM",
+ help="Path to a SCAP source data stream, eg. "
+ "/usr/share/xml/scap/ssg/content/ssg-rhel10-ds.xml")
+ # Unfortunately, we can't add "--rule", "--skip-rule", or "--reference"
+ # because the "oscap xccdf generate fix" submodule doesn't support these
+ # options.
+ return parser.parse_args()
+
+
+def ensure_sce_installed():
+ query_cmd = ["rpm", "-q", "openscap-engine-sce"]
+ query_process = subprocess.run(query_cmd, capture_output=True)
+ if query_process.returncode != 0:
+ raise RuntimeError(
+ "The script requires to have the openscap-engine-sce package "
+ "installed.")
+
+
+def install_sce_dependencies():
+ required_packages = [
+ "setools-console" # seinfo is used by the sebool template
+ ]
+ install_cmd = ["dnf", "-y", "install"] + required_packages
+ install_process = subprocess.run(
+ install_cmd, universal_newlines=True,
+ stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ if install_process.returncode != 0:
+ raise RuntimeError(
+ f"{install_process.stdout}\nFailed to install SCE dependencies.")
+
+
+def add_args(option_args_list, cmd):
+ for o, a in option_args_list:
+ if a:
+ cmd.append(o)
+ cmd.append(a)
+
+
+def add_common_args(args, cmd):
+ oal = [
+ ("--profile", args.profile),
+ ("--tailoring-file", args.tailoring_file),
+ ("--tailoring-id", args.tailoring_id)
+ ]
+ add_args(oal, cmd)
+
+
+def add_eval_args(args, cmd):
+ oal = [
+ ("--results-arf", args.results_arf),
+ ("--report", args.report),
+ ]
+ add_args(oal, cmd)
+
+
+def pre_scan_fix(args):
+ with tempfile.NamedTemporaryFile(delete=False) as remediation_script:
+ gen_fix_cmd = [
+ "oscap", "xccdf", "generate", "fix", "--fix-type", "bootc",
+ "--output", remediation_script.name]
+ add_common_args(args, gen_fix_cmd)
+ gen_fix_cmd.append(args.data_stream)
+ subprocess.run(gen_fix_cmd, check=True)
+ subprocess.run(["bash", remediation_script.name], check=True)
+
+
+def scan_and_remediate(args):
+ oscap_cmd = ["oscap", "xccdf", "eval", "--progress", "--remediate"]
+ add_common_args(args, oscap_cmd)
+ add_eval_args(args, oscap_cmd)
+ oscap_cmd.append(args.data_stream)
+ env = {"OSCAP_PREFERRED_ENGINE": "SCE", "OSCAP_BOOTC_BUILD": "YES"}
+ try:
+ subprocess.run(oscap_cmd, env=env, check=True)
+ except subprocess.CalledProcessError as e:
+ if e.returncode not in [0, 2]:
+ print(e, file=sys.stderr)
+
+
+def main():
+ args = parse_args()
+ ensure_sce_installed()
+ install_sce_dependencies()
+ pre_scan_fix(args)
+ scan_and_remediate(args)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/utils/oscap-bootc.8 b/utils/oscap-bootc.8
new file mode 100644
index 0000000000..9c911807b6
--- /dev/null
+++ b/utils/oscap-bootc.8
@@ -0,0 +1,54 @@
+.TH oscap-bootc "8" "November 2024" "Red Hat, Inc." "System Administration Utilities"
+
+.SH NAME
+oscap-bootc \- Tool for building hardened bootable container images
+
+.SH DESCRIPTION
+The oscap-bootc tool is a convenience script that makes building hardened bootable container images easier.
+This tool is designed to be used during the build of the bootable container image.
+Include oscap-bootc in your Containerfile that will be used to build your bootable container image.
+The oscap-bootc runs oscap tool on a given container image.
+
+The oscap-bootc tool can't be used anywhere else than in a Containerfile.
+
+.SH USAGE
+
+oscap-bootc [OPTION...] DATASTREAM_FILE
+
+Usage of the tool mimics usage and options of oscap(8) tool.
+
+.SH OPTIONS
+.TP
+\fB\-\-profile PROFILE_ID\fR
+.RS
+ID of the profile to be evaluated.
+.RE
+.TP
+\fB\-\-tailoring-file TAILORING_FILE\fR
+.RS
+Use given file for XCCDF tailoring. Select profile from tailoring file to apply using --profile. If both --tailoring-file and --tailoring-id are specified, --tailoring-file takes priority.
+.RE
+.TP
+\fB\-\-tailoring-id COMPONENT_REF_ID\fR
+.RS
+Use tailoring component in input source data stream for XCCDF tailoring. The tailoring component must be specified by its Ref-ID (value of component-ref/@id attribute in input source data stream). Select profile from tailoring component to apply using --profile. If both --tailoring-file and --tailoring-id are specified, --tailoring-file takes priority.
+.RE
+.TP
+\fB\-\-results-arf FILE\fR
+.RS
+Writes results to a given FILE in Asset Reporting Format.
+.RE
+.TP
+\fB\-\-report FILE\fR
+.RS
+Write HTML report into FILE.
+.RE
+
+.SH REPORTING BUGS
+.nf
+Please report bugs using https://github.com/OpenSCAP/openscap/issues
+
+.SH AUTHORS
+.nf
+Jan Černý
+.fi
diff --git a/utils/oscap-xccdf.c b/utils/oscap-xccdf.c
index 598234e709..0f62e49c51 100644
--- a/utils/oscap-xccdf.c
+++ b/utils/oscap-xccdf.c
@@ -281,7 +281,7 @@ static struct oscap_module XCCDF_GEN_FIX = {
.help = GEN_OPTS
"\nFix Options:\n"
" --fix-type - Fix type. Should be one of: bash, ansible, puppet, anaconda, ignition, kubernetes,\n"
- " blueprint, kickstart (default: bash).\n"
+ " blueprint, kickstart, bootc (default: bash).\n"
" --output - Write the script into file.\n"
" --raw - Don't write extra headers or boilerplate instructions, only compose the content snippets.\n"
" --result-id - Fixes will be generated for failed rule-results of the specified TestResult.\n"
@@ -961,10 +961,13 @@ int app_generate_fix(const struct oscap_action *action)
remediation_system = "urn:xccdf:fix:script:kubernetes";
} else if (strcmp(action->fix_type, "blueprint") == 0) {
remediation_system = "urn:redhat:osbuild:blueprint";
+ } else if (strcmp(action->fix_type, "bootc") == 0) {
+ remediation_system = "urn:xccdf:fix:script:bootc";
} else {
fprintf(stderr,
"Unknown fix type '%s'.\n"
- "Please provide one of: bash, ansible, kickstart, puppet, anaconda, ignition, kubernetes, blueprint.\n",
+ "Please provide one of: bash, ansible, kickstart, puppet, anaconda, ignition, kubernetes, blueprint, bootc.\n"
+ "Or provide a custom template using '--template' instead.\n",
action->fix_type);
return OSCAP_ERROR;
}
@@ -976,6 +979,10 @@ int app_generate_fix(const struct oscap_action *action)
fprintf(stderr, "It isn't possible to generate results-oriented Kickstarts.\n");
return OSCAP_ERROR;
}
+ if (action->id != NULL && action->fix_type != NULL && !strcmp(action->fix_type, "bootc")) {
+ fprintf(stderr, "It isn't possible to generate results-oriented bootc remediations.\n");
+ return OSCAP_ERROR;
+ }
int ret = OSCAP_ERROR;
struct oscap_source *source = oscap_source_new_from_file(action->f_xccdf);
diff --git a/utils/oscap.8 b/utils/oscap.8
index 412e578982..58df71dcce 100644
--- a/utils/oscap.8
+++ b/utils/oscap.8
@@ -415,12 +415,12 @@ ID of the XCCDF TestResult from which the report will be generated.
Generate a script that shall bring the system to a state of compliance with given XCCDF Benchmark. There are 2 possibilities when generating fixes: Result-oriented fixes (--result-id) or Profile-oriented fixes (--profile). Result-oriented takes precedences over Profile-oriented, if result-id is given, oscap will ignore any profile provided.
.TP
Result-oriented fixes are generated using result-id provided to select only the failing rules from results in xccdf-file, it skips all other rules.
-It isn't possible to generate result-oriented fixes for the kickstart fix type.
+It isn't possible to generate result-oriented fixes for the kickstart and bootc fix type.
.TP
Profile-oriented fixes are generated using all rules within the provided profile. If no result-id/profile are provided, (default) profile will be used to generate fixes.
.TP
\fB\-\-fix-type TYPE\fR
-Specify fix type. There are multiple programming languages in which the fix script can be generated. TYPE should be one of: bash, ansible, puppet, anaconda, ignition, kubernetes, blueprint, kickstart. Default is bash.
+Specify fix type. There are multiple programming languages in which the fix script can be generated. TYPE should be one of: bash, ansible, puppet, anaconda, ignition, kubernetes, blueprint, kickstart, bootc. Default is bash.
.TP
\fB\-\-output FILE\fR
Write the report to this file instead of standard output.