Skip to content

Commit f0e1788

Browse files
authored
Merge pull request #2339 from ggbecker/fix-autotailor-relative-path-maint-1.3
autotailor: Add --local-path option for layered product compatibility
2 parents 4397793 + 3ac1b5a commit f0e1788

5 files changed

Lines changed: 82 additions & 6 deletions

File tree

.github/workflows/codeql.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ on:
1212
jobs:
1313
analyze:
1414
name: Analyze
15-
runs-on: ubuntu-latest
15+
runs-on: ubuntu-22.04
1616
permissions:
1717
actions: read
1818
contents: read
@@ -32,12 +32,12 @@ jobs:
3232
- name: Install Deps
3333
run: |
3434
sudo apt-get update
35-
sudo apt-get -y install lcov swig xsltproc rpm-common lua5.3 libyaml-dev libdbus-1-dev libdbus-glib-1-dev libcurl4-openssl-dev libgcrypt-dev libselinux1-dev libglib2.0-dev libacl1-dev libblkid-dev libcap-dev libxml2-dev libxslt1-dev libxml-parser-perl libxml-xpath-perl libperl-dev librpm-dev librtmp-dev libxmlsec1-dev libxmlsec1-openssl python3-dbusmock
35+
sudo apt-get -y install lcov swig xsltproc rpm-common lua5.3 libpcre2-dev libyaml-dev libdbus-1-dev libdbus-glib-1-dev libcurl4-openssl-dev libgcrypt-dev libselinux1-dev libgconf2-dev libacl1-dev libblkid-dev libcap-dev libxml2-dev libxslt1-dev libxml-parser-perl libxml-xpath-perl libperl-dev librpm-dev librtmp-dev libxmlsec1-dev libxmlsec1-openssl python3-dbusmock python3-pytest
3636
sudo apt-get -y remove rpm
3737
3838
# Initializes the CodeQL tools for scanning.
3939
- name: Initialize CodeQL
40-
uses: github/codeql-action/init@v2
40+
uses: github/codeql-action/init@v3
4141
with:
4242
languages: ${{ matrix.language }}
4343
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -50,7 +50,7 @@ jobs:
5050
- name: Build
5151
working-directory: ./build
5252
run: |
53-
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ../
53+
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DWITH_PCRE2=True ../
5454
make all
5555
5656
- name: Perform CodeQL Analysis

tests/utils/autotailor_integration_test.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,21 @@ assert_exists 1 '/Benchmark/TestResult/rule-result[@idref="xccdf_com.example.www
125125
assert_exists 1 '/Benchmark/TestResult/rule-result[@idref="xccdf_com.example.www_rule_R3" and @severity="unknown"]'
126126
assert_exists 1 '/Benchmark/TestResult/rule-result[@idref="xccdf_com.example.www_rule_R4"]/result[text()="notselected"]'
127127
assert_exists 1 '/Benchmark/TestResult/rule-result[@idref="xccdf_com.example.www_rule_R4" and @role="unchecked"]'
128+
129+
# test --local-path option with absolute path (should use basename)
130+
python3 $autotailor --id-namespace "com.example.www" --local-path --select R3 $ds $original_profile > $tailoring
131+
saved_result=$result
132+
result=$tailoring
133+
assert_exists 1 '/*[local-name()="Tailoring"]/*[local-name()="benchmark"][@href="data_stream.xml"]'
134+
result=$saved_result
135+
$OSCAP xccdf eval --profile P1_customized --progress --tailoring-file $tailoring --results $result $ds
136+
assert_exists 1 '/Benchmark/TestResult/rule-result[@idref="xccdf_com.example.www_rule_R3"]/result[text()="pass"]'
137+
138+
# test default behavior (should use file:// URI)
139+
python3 $autotailor --id-namespace "com.example.www" --select R3 $ds $original_profile > $tailoring
140+
saved_result=$result
141+
result=$tailoring
142+
assert_exists 1 '/*[local-name()="Tailoring"]/*[local-name()="benchmark"][starts-with(@href, "file://")]'
143+
result=$saved_result
144+
$OSCAP xccdf eval --profile P1_customized --progress --tailoring-file $tailoring --results $result $ds
145+
assert_exists 1 '/Benchmark/TestResult/rule-result[@idref="xccdf_com.example.www_rule_R3"]/result[text()="pass"]'

tests/utils/test_autotailor.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,29 @@ def test_refine_rule():
9494
"'high'.")
9595
assert t.rule_refinements(fav, "severity") == "high"
9696
assert t.rule_refinements(fav, "role") == "full"
97+
98+
def test_get_datastream_uri():
99+
t = autotailor.Tailoring()
100+
101+
# Test default behavior with absolute path (file:// URI)
102+
t.original_ds_filename = "/nonexistent/path/test-ds.xml"
103+
t.use_local_path = False
104+
uri = t._get_datastream_uri()
105+
assert uri.startswith("file://")
106+
assert uri.endswith("/nonexistent/path/test-ds.xml")
107+
108+
# Test local path mode with absolute path (basename only)
109+
t.use_local_path = True
110+
uri = t._get_datastream_uri()
111+
assert uri == "test-ds.xml"
112+
113+
# Test local path mode with relative path (preserved as-is)
114+
t.original_ds_filename = "relative/path/to/ds.xml"
115+
uri = t._get_datastream_uri()
116+
assert uri == "relative/path/to/ds.xml"
117+
118+
# Test default behavior with relative path (file:// URI)
119+
t.use_local_path = False
120+
uri = t._get_datastream_uri()
121+
assert uri.startswith("file://")
122+
assert "relative/path/to/ds.xml" in uri

utils/autotailor

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ class Tailoring:
7070
self.groups_to_unselect = []
7171
self._rule_refinements = collections.defaultdict(dict)
7272
self._value_refinements = collections.defaultdict(dict)
73+
self.use_local_path = False
7374

7475
@property
7576
def profile_id(self):
@@ -244,8 +245,7 @@ class Tailoring:
244245
root.set("id", self.id)
245246

246247
benchmark = ET.SubElement(root, "{%s}benchmark" % NS)
247-
datastream_uri = pathlib.Path(
248-
self.original_ds_filename).absolute().as_uri()
248+
datastream_uri = self._get_datastream_uri()
249249
benchmark.set("href", datastream_uri)
250250

251251
version = ET.SubElement(root, "{%s}version" % NS)
@@ -304,6 +304,26 @@ class Tailoring:
304304
if attr in props:
305305
self.change_rule_attribute(rule_id, attr, props[attr])
306306

307+
def _get_datastream_uri(self):
308+
"""
309+
Determine the datastream URI based on the use_local_path setting.
310+
311+
Returns:
312+
str: The URI/path to use in the benchmark href attribute
313+
"""
314+
if self.use_local_path:
315+
# Preserve relative paths as-is, convert absolute paths to basename
316+
ds_path = pathlib.Path(self.original_ds_filename)
317+
if ds_path.is_absolute():
318+
# Convert absolute path to basename for compatibility with layered products
319+
return ds_path.name
320+
else:
321+
# Keep relative paths as provided by the user
322+
return self.original_ds_filename
323+
else:
324+
# Use absolute URI (default behavior for backward compatibility)
325+
return pathlib.Path(self.original_ds_filename).absolute().as_uri()
326+
307327
def import_json_tailoring(self, json_tailoring):
308328
with open(json_tailoring, "r") as jf:
309329
all_tailorings = json.load(jf)
@@ -402,6 +422,10 @@ def get_parser():
402422
"-o", "--output", default="-",
403423
help="Where to save the tailoring file. If not supplied, write to "
404424
"standard output.")
425+
parser.add_argument(
426+
"--local-path", action="store_true",
427+
help="Use local path for the benchmark href instead of absolute file:// URI. "
428+
"Absolute paths are converted to basename, relative paths are preserved.")
405429
return parser
406430

407431

@@ -418,6 +442,7 @@ if __name__ == "__main__":
418442
t = Tailoring()
419443
t.original_ds_filename = args.datastream
420444
t.reverse_dns = args.id_namespace
445+
t.use_local_path = args.local_path
421446

422447
if args.json_tailoring:
423448
t.import_json_tailoring(args.json_tailoring)

utils/autotailor.8

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ If left out, the new ID will be obtained by appending '_customized' to the tailo
6868
Import tailoring from a JSON file (https://github.com/ComplianceAsCode/schemas/tree/main/tailoring). This option makes BASE_PROFILE_ID positional argument optional.
6969
However, data passed in the command line options takes precedence over JSON contents, including the BASE_PROFILE_ID argument.
7070
.RE
71+
.TP
72+
\fB--local-path\fR
73+
.RS
74+
Use local path for the benchmark href instead of absolute file:// URI. This option is useful for compatibility with layered products like Red Hat Satellite that cannot resolve local filesystem paths.
75+
When this option is specified, absolute paths are converted to basename only, while relative paths are preserved as provided.
76+
By default, the tool uses absolute file:// URIs for backward compatibility.
77+
.RE
7178

7279
.SH USAGE
7380
.SS Modify a variable value

0 commit comments

Comments
 (0)