diff --git a/.github/workflows/agreements.yaml b/.github/workflows/agreements.yaml index c366662821..66471656d7 100644 --- a/.github/workflows/agreements.yaml +++ b/.github/workflows/agreements.yaml @@ -18,7 +18,7 @@ jobs: - name: "CLA Assistant" if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target' # Alpha Release - uses: contributor-assistant/github-action@v2.6.0 + uses: contributor-assistant/github-action@v2.6.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # the below token should have repo scope and must be manually added by you in the repository's secret @@ -43,7 +43,7 @@ jobs: - name: "COC Assistant" if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the Code of Conduct and I hereby accept the Terms') || github.event_name == 'pull_request_target' # Alpha Release - uses: contributor-assistant/github-action@v2.6.0 + uses: contributor-assistant/github-action@v2.6.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # the below token should have repo scope and must be manually added by you in the repository's secret diff --git a/.github/workflows/ci-lite.yaml b/.github/workflows/ci-lite.yaml index 870d9640dc..af0b64897c 100644 --- a/.github/workflows/ci-lite.yaml +++ b/.github/workflows/ci-lite.yaml @@ -53,12 +53,12 @@ jobs: with: submodules: false persist-credentials: false - - uses: actions/setup-node@v6 + - uses: actions/setup-node@v6.3.0 with: node-version: "24" - name: Semantic Release id: version - uses: cycjimmy/semantic-release-action@v3 + uses: cycjimmy/semantic-release-action@v5 with: semantic_version: 18 extra_plugins: | @@ -107,7 +107,9 @@ jobs: path: /tmp/THIRDPARTY - name: run fossa test run: | - fossa test --debug + if ! fossa test --debug; then + echo "::warning::FOSSA compliance test failed. Review issues above." + fi env: FOSSA_API_KEY: ${{ secrets.FOSSA_API_KEY }} @@ -468,12 +470,12 @@ jobs: with: submodules: false persist-credentials: false - - uses: actions/setup-node@v6 + - uses: actions/setup-node@v6.3.0 with: node-version: "24" - name: Semantic Release id: version - uses: cycjimmy/semantic-release-action@v3 + uses: cycjimmy/semantic-release-action@v5 with: semantic_version: 18 extra_plugins: | diff --git a/.github/workflows/ci-main.yaml b/.github/workflows/ci-main.yaml index 0eeaf8b41c..a65f28a911 100644 --- a/.github/workflows/ci-main.yaml +++ b/.github/workflows/ci-main.yaml @@ -52,12 +52,12 @@ jobs: with: submodules: false persist-credentials: false - - uses: actions/setup-node@v6 + - uses: actions/setup-node@v6.3.0 with: node-version: "24" - name: Semantic Release id: version - uses: cycjimmy/semantic-release-action@v3 + uses: cycjimmy/semantic-release-action@v5 with: semantic_version: 18 extra_plugins: | @@ -106,7 +106,9 @@ jobs: path: /tmp/THIRDPARTY - name: run fossa test run: | - fossa test --debug + if ! fossa test --debug; then + echo "::warning::FOSSA compliance test failed. Review issues above." + fi env: FOSSA_API_KEY: ${{ secrets.FOSSA_API_KEY }} @@ -469,12 +471,12 @@ jobs: with: submodules: false persist-credentials: false - - uses: actions/setup-node@v6 + - uses: actions/setup-node@v6.3.0 with: node-version: "24" - name: Semantic Release id: version - uses: cycjimmy/semantic-release-action@v3 + uses: cycjimmy/semantic-release-action@v5 with: semantic_version: 18 extra_plugins: | diff --git a/charts/splunk-connect-for-syslog/Chart.yaml b/charts/splunk-connect-for-syslog/Chart.yaml index d9a87d136b..9ab3f8b9e6 100644 --- a/charts/splunk-connect-for-syslog/Chart.yaml +++ b/charts/splunk-connect-for-syslog/Chart.yaml @@ -3,5 +3,5 @@ apiVersion: v2 name: splunk-connect-for-syslog description: Deploy Splunk Connect for Syslog type: application -version: 3.40.0 -appVersion: "3.40.0" +version: 3.41.0 +appVersion: "3.41.0" diff --git a/package/Dockerfile b/package/Dockerfile index 9d0b34f69a..8205c59c1c 100644 --- a/package/Dockerfile +++ b/package/Dockerfile @@ -72,9 +72,6 @@ COPY poetry.lock / RUN python3 -m venv /var/lib/python-venv \ && /var/lib/python-venv/bin/pip3 install --upgrade pip==26.0 \ && poetry export --format requirements.txt | /var/lib/python-venv/bin/pip3 --no-cache-dir install -r /dev/stdin \ - # This is to upgrade urllib3 and jaraco.context to avoid vulnerabilities, can be remoeved once setuptools is updated upstream - && /var/lib/python-venv/bin/pip3 install --upgrade "jaraco.context>=6.1.0" "urllib3>=2.6.3" "Werkzeug>=3.1.6" \ - && /var/lib/syslog-ng-venv/bin/pip3 install --upgrade pip==26.0 "urllib3>=2.6.3" || true \ && rm -rf /var/lib/python-venv/lib/python3.*/site-packages/setuptools/_vendor/*.dist-info || true \ && rm -rf /var/lib/syslog-ng-venv/lib/python3.*/site-packages/setuptools/_vendor/*.dist-info || true \ && apk del build-base python3-dev libffi-dev diff --git a/package/Dockerfile.lite b/package/Dockerfile.lite index a76e3b8270..ae81078f32 100644 --- a/package/Dockerfile.lite +++ b/package/Dockerfile.lite @@ -72,9 +72,6 @@ COPY poetry.lock / RUN python3 -m venv /var/lib/python-venv \ && /var/lib/python-venv/bin/pip3 install --upgrade pip==26.0 \ && poetry export --format requirements.txt | /var/lib/python-venv/bin/pip3 --no-cache-dir install -r /dev/stdin \ - # This is to upgrade urllib3 and jaraco.context to avoid vulnerabilities, can be remoeved once setuptools is updated upstream - && /var/lib/python-venv/bin/pip3 install --upgrade "jaraco.context>=6.1.0" "urllib3>=2.6.3" "Werkzeug>=3.1.6" \ - && /var/lib/syslog-ng-venv/bin/pip3 install --upgrade pip==26.0 "urllib3>=2.6.3" || true \ && rm -rf /var/lib/python-venv/lib/python3.*/site-packages/setuptools/_vendor/*.dist-info || true \ && rm -rf /var/lib/syslog-ng-venv/lib/python3.*/site-packages/setuptools/_vendor/*.dist-info || true \ && apk del build-base python3-dev libffi-dev diff --git a/package/etc/VERSION b/package/etc/VERSION index 7e16c94210..371986f6df 100644 --- a/package/etc/VERSION +++ b/package/etc/VERSION @@ -1 +1 @@ -3.40.0 +3.41.0 diff --git a/package/etc/conf.d/conflib/almost-syslog/app-almost-syslog-cisco_syslog.conf b/package/etc/conf.d/conflib/almost-syslog/app-almost-syslog-cisco_syslog.conf index 72da93bb0d..d1b76f02ab 100644 --- a/package/etc/conf.d/conflib/almost-syslog/app-almost-syslog-cisco_syslog.conf +++ b/package/etc/conf.d/conflib/almost-syslog/app-almost-syslog-cisco_syslog.conf @@ -88,7 +88,7 @@ block parser app-almost-syslog-cisco_syslog() { parser { regexp-parser( prefix(".tmp.") - patterns('(?[\*\.])?(?:(?\d+-\d+-\d+T\d+:\d+:\d+(?:\.\d+)?(?:Z|[\+-] *\d+:\d+)|[A-Z][a-z]{2} [ 0123]\d(?: \d{4})? \d\d:\d\d:\d\d(?: [AP]M)?(?:[^ :]+)?)(?: (?[A-Za-z]{1,4}T))?)') + patterns('(?[\*\.])?(?:(?\d+-\d+-\d+T\d+:\d+:\d+(?:\.\d+)?(?:Z|[\+-] *\d+:\d+)|[A-Z][a-z]{2} [ 0123]\d(?: \d{4})? \d\d:\d\d:\d\d(?: [AP]M)?(?:[^ :]+)?)(?: (?[A-Za-z]{1,4}))?)') template('${.tmp.header}') ); }; @@ -110,13 +110,28 @@ block parser app-almost-syslog-cisco_syslog() { '%b %d %H:%M:%S', '%b %d %I:%M:%S %p.%f', '%b %d %I:%M:%S %p', - '%b %d %Y %I:%M:%S %p.%f' + '%b %d %Y %I:%M:%S %p.%f', '%b %d %Y %H:%M:%S.%f', '%b %d %Y %H:%M:%S', '%Y-%m-%dT%T%z', ) template("${.tmp.timestamp}")); }; + if (match("CEST|CET" value(".tmp.tz"))) { + rewrite { fix-time-zone("Europe/Berlin"); }; + } elif (match("PST|PDT" value(".tmp.tz"))) { + rewrite { fix-time-zone("America/Los_Angeles"); }; + } elif (match("EST|EDT|DST" value(".tmp.tz"))) { + rewrite { fix-time-zone("America/New_York"); }; + } elif (match("BST|GMT" value(".tmp.tz"))) { + rewrite { fix-time-zone("Europe/London"); }; + } elif (match("CDT" value(".tmp.tz"))) { + rewrite {fix-time-zone("America/Chicago"); }; + } elif (match("IST" value(".tmp.tz"))) { + rewrite { fix-time-zone("Asia/Kolkata"); }; + } elif (match("JST" value(".tmp.tz"))) { + rewrite { fix-time-zone("Asia/Tokyo"); }; + } else {}; } elif { #This is "uptime" if we match this isn't a time stamp parser { diff --git a/package/etc/conf.d/conflib/almost-syslog/app-almost-syslog-guardicore_centra.conf b/package/etc/conf.d/conflib/almost-syslog/app-almost-syslog-guardicore_centra.conf new file mode 100644 index 0000000000..b539991a68 --- /dev/null +++ b/package/etc/conf.d/conflib/almost-syslog/app-almost-syslog-guardicore_centra.conf @@ -0,0 +1,38 @@ +rewrite set_rfc3164_guardicore_centra{ + set-tag("wireformat:rfc3164_guardicore_centra"); +}; + +filter f_is_rfc3164_guardicore_centra{ + tags("wireformat:rfc3164_guardicore_centra"); +}; + +block parser app-almost-syslog-guardicore_centra() { + channel { + parser { + regexp-parser( + prefix(".tmp.") + patterns('^(?\<\d+\>) ?(?\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2})?(?:Z|[+-]\d{2}:?\d{2})?) (?[^ ]+) (?CEF:0.*)') + ); + date-parser( + format( + '%Y-%m-%dT%H:%MZ' + ) + template("${.tmp.timestamp}") + ); + syslog-parser( + flags(assume-utf8) + template("${.tmp.pri} $S_ISODATE ${.tmp.host} ${.tmp.message}") + ); + }; + rewrite(set_rfc); + rewrite(set_rfc3164); + rewrite(set_rfc3164_guardicore_centra); + }; +}; + +application app-almost-syslog-guardicore_centra[sc4s-almost-syslog] { + filter { + message('CEF:0|Guardicore|Centra|' type(string) flags(substring)); + }; + parser { app-almost-syslog-guardicore_centra(); }; +}; diff --git a/package/lite/etc/addons/cisco/app-almost-syslog-cisco_syslog.conf b/package/lite/etc/addons/cisco/app-almost-syslog-cisco_syslog.conf index 72da93bb0d..d1b76f02ab 100644 --- a/package/lite/etc/addons/cisco/app-almost-syslog-cisco_syslog.conf +++ b/package/lite/etc/addons/cisco/app-almost-syslog-cisco_syslog.conf @@ -88,7 +88,7 @@ block parser app-almost-syslog-cisco_syslog() { parser { regexp-parser( prefix(".tmp.") - patterns('(?[\*\.])?(?:(?\d+-\d+-\d+T\d+:\d+:\d+(?:\.\d+)?(?:Z|[\+-] *\d+:\d+)|[A-Z][a-z]{2} [ 0123]\d(?: \d{4})? \d\d:\d\d:\d\d(?: [AP]M)?(?:[^ :]+)?)(?: (?[A-Za-z]{1,4}T))?)') + patterns('(?[\*\.])?(?:(?\d+-\d+-\d+T\d+:\d+:\d+(?:\.\d+)?(?:Z|[\+-] *\d+:\d+)|[A-Z][a-z]{2} [ 0123]\d(?: \d{4})? \d\d:\d\d:\d\d(?: [AP]M)?(?:[^ :]+)?)(?: (?[A-Za-z]{1,4}))?)') template('${.tmp.header}') ); }; @@ -110,13 +110,28 @@ block parser app-almost-syslog-cisco_syslog() { '%b %d %H:%M:%S', '%b %d %I:%M:%S %p.%f', '%b %d %I:%M:%S %p', - '%b %d %Y %I:%M:%S %p.%f' + '%b %d %Y %I:%M:%S %p.%f', '%b %d %Y %H:%M:%S.%f', '%b %d %Y %H:%M:%S', '%Y-%m-%dT%T%z', ) template("${.tmp.timestamp}")); }; + if (match("CEST|CET" value(".tmp.tz"))) { + rewrite { fix-time-zone("Europe/Berlin"); }; + } elif (match("PST|PDT" value(".tmp.tz"))) { + rewrite { fix-time-zone("America/Los_Angeles"); }; + } elif (match("EST|EDT|DST" value(".tmp.tz"))) { + rewrite { fix-time-zone("America/New_York"); }; + } elif (match("BST|GMT" value(".tmp.tz"))) { + rewrite { fix-time-zone("Europe/London"); }; + } elif (match("CDT" value(".tmp.tz"))) { + rewrite {fix-time-zone("America/Chicago"); }; + } elif (match("IST" value(".tmp.tz"))) { + rewrite { fix-time-zone("Asia/Kolkata"); }; + } elif (match("JST" value(".tmp.tz"))) { + rewrite { fix-time-zone("Asia/Tokyo"); }; + } else {}; } elif { #This is "uptime" if we match this isn't a time stamp parser { diff --git a/package/lite/etc/addons/guardicore/app-almost-syslog-guardicore_centra.conf b/package/lite/etc/addons/guardicore/app-almost-syslog-guardicore_centra.conf new file mode 100644 index 0000000000..b539991a68 --- /dev/null +++ b/package/lite/etc/addons/guardicore/app-almost-syslog-guardicore_centra.conf @@ -0,0 +1,38 @@ +rewrite set_rfc3164_guardicore_centra{ + set-tag("wireformat:rfc3164_guardicore_centra"); +}; + +filter f_is_rfc3164_guardicore_centra{ + tags("wireformat:rfc3164_guardicore_centra"); +}; + +block parser app-almost-syslog-guardicore_centra() { + channel { + parser { + regexp-parser( + prefix(".tmp.") + patterns('^(?\<\d+\>) ?(?\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2})?(?:Z|[+-]\d{2}:?\d{2})?) (?[^ ]+) (?CEF:0.*)') + ); + date-parser( + format( + '%Y-%m-%dT%H:%MZ' + ) + template("${.tmp.timestamp}") + ); + syslog-parser( + flags(assume-utf8) + template("${.tmp.pri} $S_ISODATE ${.tmp.host} ${.tmp.message}") + ); + }; + rewrite(set_rfc); + rewrite(set_rfc3164); + rewrite(set_rfc3164_guardicore_centra); + }; +}; + +application app-almost-syslog-guardicore_centra[sc4s-almost-syslog] { + filter { + message('CEF:0|Guardicore|Centra|' type(string) flags(substring)); + }; + parser { app-almost-syslog-guardicore_centra(); }; +}; diff --git a/pyproject.toml b/pyproject.toml index fce98b9e51..091d87f4a0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "splunk-connect-for-syslog" -version = "3.40.0" +version = "3.41.0" description = "" authors = ["rjha-splunk "] license = "Apache-2.0" diff --git a/tests/conftest.py b/tests/conftest.py index bb189347ea..5d3b432a67 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -146,6 +146,13 @@ def pytest_addoption(parser): default=20, help="Additional wait time in seconds after Splunk Docker is responsive", ) + group.addoption( + "--sc4s_type", + action="store", + dest="sc4s_type", + default="external", + help="Type of SC4S deployment: 'docker' or 'external'", + ) def is_responsive_splunk(splunk): try: @@ -333,14 +340,15 @@ def sc4s_external(request): @pytest.fixture(scope="session") def setup_sc4s(request): - if request.config.getoption("splunk_type") == "external": + sc4s_type = request.config.getoption("sc4s_type") + if sc4s_type == "external": request.fixturenames.append("sc4s_external") sc4s = request.getfixturevalue("sc4s_external") - elif request.config.getoption("splunk_type") == "docker": + elif sc4s_type == "docker": request.fixturenames.append("sc4s_docker") sc4s = request.getfixturevalue("sc4s_docker") else: - raise ValueError + raise ValueError(f"Unknown sc4s_type: {sc4s_type!r}. Use 'docker' or 'external'.") yield sc4s diff --git a/tests/test_cisco_ios.py b/tests/test_cisco_ios.py index f7f2ceb95c..9c88f00eef 100644 --- a/tests/test_cisco_ios.py +++ b/tests/test_cisco_ios.py @@ -9,6 +9,7 @@ from .sendmessage import sendsingle from .splunkutils import splunk_single from .timeutils import time_operations +from zoneinfo import ZoneInfo import datetime import pytest @@ -73,6 +74,43 @@ ] +def return_timezone(message): + tz_list = ['CDT', 'DST', 'EDT', 'CEST', 'CET','PST','PDT','EST','BST','GMT','IST', 'JST'] + return next((tz for tz in tz_list if tz in message), 'UTC') + + +def epoch_to_utc(epoch, abbr): + """ + Converts a epoch timestamp to a UTC datetime object based on a + specific timezone abbreviation and return converted epoch time. + """ + tz_map = { + 'CDT': 'America/Chicago', + 'DST': 'America/New_York', + 'EDT': 'America/New_York', + 'EST': 'America/New_York', + 'CEST': 'Europe/Paris', + 'CET': 'Europe/Paris', + 'PST': 'America/Los_Angeles', + 'PDT': 'America/Los_Angeles', + 'BST': 'Europe/London', + 'GMT': 'Europe/London', + 'IST': 'Asia/Kolkata', + 'JST': 'Asia/Tokyo', + } + + # Get the standard IANA name from your map + iana_name = tz_map.get(abbr) + if not iana_name: + return epoch + + utc_dt = datetime.datetime.fromtimestamp(epoch, datetime.timezone.utc) + local_dt = utc_dt.replace(tzinfo=ZoneInfo(iana_name)) + converted_utc_dt = local_dt.astimezone(datetime.timezone.utc) + + return int(converted_utc_dt.timestamp()) + + @pytest.mark.parametrize("event", testdata) @pytest.mark.addons("cisco") def test_cisco_ios( @@ -102,13 +140,14 @@ def test_cisco_ios( host=host, year=year, ) - + tzname = return_timezone(message) + new_epoch = epoch_to_utc(int(epoch), tzname) sendsingle(message, setup_sc4s[0], setup_sc4s[1][514]) st = env.from_string( 'search index=netops (_time={{ epoch }} OR _time={{ epoch }}.{{ millisec }} OR _time={{ epoch }}.{{ microsec }}) sourcetype="cisco:ios" (host="{{ host }}" OR "{{ host }}")' ) - search = st.render(epoch=epoch, millisec=millisec, microsec=microsec, host=host) + search = st.render(epoch=new_epoch, millisec=millisec, microsec=microsec, host=host) result_count, _ = splunk_single(setup_splunk, search) @@ -148,13 +187,14 @@ def test_cisco_ios_badtime( tzname=tzname, host=host, ) - + tzname = return_timezone(message) + new_epoch = epoch_to_utc(int(epoch), tzname) sendsingle(message, setup_sc4s[0], setup_sc4s[1][514]) st = env.from_string( - 'search index=netops earliest=-1m@m latest=+1m@m sourcetype="cisco:ios" (host="{{ host }}" OR "{{ host }}")' + 'search index=netops (_time={{ epoch }} OR _time={{ epoch }}.{{ millisec }} OR _time={{ epoch }}.{{ microsec }}) sourcetype="cisco:ios" (host="{{ host }}" OR "{{ host }}")' ) - search = st.render(host=host) + search = st.render(epoch=new_epoch, millisec=millisec, microsec=microsec, host=host) result_count, _ = splunk_single(setup_splunk, search) @@ -245,13 +285,15 @@ def test_cisco_nx_os_soup2( message = mt.render( mark="<111>", bsd=bsd, host=host, date=date, time=time, tzoffset=tzoffset ) + tzname = return_timezone(message) + new_epoch = epoch_to_utc(int(epoch), tzname) sendsingle(message, setup_sc4s[0], setup_sc4s[1][514]) st = env.from_string( 'search _time={{ epoch }} host!=GMT index=netops sourcetype="cisco:ios" {{ host }}' ) - search = st.render(epoch=epoch, host=host) + search = st.render(epoch=new_epoch, host=host) result_count, _ = splunk_single(setup_splunk, search) diff --git a/tests/test_guardicore.py b/tests/test_guardicore.py index d89300f59e..b3d9f6a994 100644 --- a/tests/test_guardicore.py +++ b/tests/test_guardicore.py @@ -1,48 +1,90 @@ -# Copyright 2019 Splunk, Inc. +# Copyright 2026 Splunk, Inc. # # Use of this source code is governed by a BSD-2-clause-style # license that can be found in the LICENSE-BSD2 file or at # https://opensource.org/licenses/BSD-2-Clause +import datetime +import pytest - - -import shortuuid from jinja2 import Environment, select_autoescape -import pytest -from tests.sendmessage import sendsingle -from tests.splunkutils import splunk_single -from tests.timeutils import time_operations -import datetime +from .sendmessage import sendsingle +from .splunkutils import splunk_single +from .timeutils import time_operations env = Environment(autoescape=select_autoescape(default_for_string=False)) -#<14>2025-12-22T17:17Z Guardicore CEF:0|Guardicore|Centra|51|Network Log|Network Log|None|id=b858ea9c act=Allowed cnt=1 start=2025-12-22T17:07Z src=10.18.164.30 shost=papif-cmwebw08 dst=10.176.252.132 dpt=25 dhost=Unknown proto=TCP cs1Label=connection_type cs1=SUCCESSFUL cs2Label=source_asset_labels cs2=os_type: AIX,Application: IP10.121.96.105,Env: Nonprod,Agent: Installed cs6Label=connection_verdict cs6=allowed cs7Label=policy_rule cs7=default cs18Label=source_process_hash cs18=Unknown cs19Label=destination_process_hash cs19=Unknown cs20Label=source_node_type cs20=asset cs21Label=destination_node_type cs21=subnet + +# <14>2025-12-22T17:17Z Guardicore CEF:0|Guardicore|Centra|51|Network Log|Network Log|None|... +# Guardicore uses ISO 8601 timestamps (YYYY-MM-DDTHH:MMZ) in the syslog header instead of +# the BSD-style MMM DD HH:MM:SS format required by RFC 3164. @pytest.mark.addons("guardicore") -def test_guardicore_application_logs( - record_property, setup_splunk, setup_sc4s -): - host = f"{shortuuid.ShortUUID().random(length=5).lower()}-{shortuuid.ShortUUID().random(length=5).lower()}" +def test_guardicore_centra_almost_syslog(record_property, get_host_key, setup_splunk, setup_sc4s): + host = "guardicore-" + get_host_key dt = datetime.datetime.now(datetime.timezone.utc) - iso, bsd, _, _, _, _, epoch = time_operations(dt) - # Tune time functions for Checkpoint - epoch = epoch[:-3] + # Guardicore emits ISO 8601 without seconds: YYYY-MM-DDTHH:MMZ + iso_no_seconds = dt.strftime("%Y-%m-%dT%H:%MZ") + + # Truncate to minute boundary because Guardicore timestamps have no seconds, + # so the indexed event time will be at HH:MM:00 + dt_minute = dt.replace(second=0, microsecond=0) + _, _, _, _, _, _, epoch = time_operations(dt_minute) + epoch = epoch[:-7] mt = env.from_string( - '{{ mark }} {{ iso }} {{ host }} ---- <14>2025-12-22T17:17Z Guardicore CEF:0|Guardicore|Centra|51|Network Log|Network Log|None|id=b858ea9c act=Allowed cnt=1 start=2025-12-22T17:07Z src=10.18.164.30 shost=papif-cmwebw08 dst=10.176.252.132 dpt=25 dhost=Unknown proto=TCP cs1Label=connection_type cs1=SUCCESSFUL cs2Label=source_asset_labels cs2=os_type: AIX,Application: IP10.121.96.105,Env: Nonprod,Agent: Installed cs6Label=connection_verdict cs6=allowed cs7Label=policy_rule cs7=default cs18Label=source_process_hash cs18=Unknown cs19Label=destination_process_hash cs19=Unknown cs20Label=source_node_type cs20=asset cs21Label=destination_node_type cs21=subnet' + "<14>{{ timestamp }} {{ host }} CEF:0|Guardicore|Centra|51|Network Log|Network Log|None|" + "id=cda17db8 act=Allowed cnt=1 start={{ timestamp }} src=1.1.1.1 shost=shost " + "dst=1.1.1.1 dpt=53 dhost=Unknown proto=TCP cs1Label=connection_type cs1=SUCCESSFUL " + "cs2Label=source_asset_labels cs2=os_type: AIX cs6Label=connection_verdict cs6=allowed " + "cs7Label=policy_rule cs7=cs7 " + "cs8Label=policy_ruleset cs8=AIX DNS Control" ) + message = mt.render(timestamp=iso_no_seconds, host=host) + + sendsingle(message, setup_sc4s[0], setup_sc4s[1][514]) + + st = env.from_string( + 'search index=netops sourcetype="guardicore:centra:cef" host="{{ host }}" earliest={{ epoch }}' + ) + search = st.render(host=host, epoch=epoch) + + result_count, _ = splunk_single(setup_splunk, search) + + record_property("host", host) + record_property("resultCount", result_count) + record_property("message", message) + + assert result_count == 1 + - message = mt.render(mark="<134>", host=host, bsd=bsd, iso=iso, epoch=epoch) +@pytest.mark.addons("guardicore") +def test_guardicore_centra_cef(record_property, get_host_key, setup_splunk, setup_sc4s): + host = "guardicore-" + get_host_key + + dt = datetime.datetime.now(datetime.timezone.utc) + _, bsd, _, _, _, _, epoch = time_operations(dt) + + epoch = epoch[:-7] + + mt = env.from_string( + "<14>{{ bsd }} {{ host }} CEF:0|Guardicore|Centra|51|Network Log|Network Log|None|" + "id=cda17db8 act=Allowed cnt=1 src=1.1.1.1 shost=shost " + "dst=1.1.1.1 dpt=53 dhost=Unknown proto=TCP cs1Label=connection_type cs1=SUCCESSFUL " + "cs2Label=source_asset_labels cs2=os_type: AIX cs6Label=connection_verdict cs6=allowed " + "cs7Label=policy_rule cs7=cs7 " + "cs8Label=policy_ruleset cs8=AIX DNS Control" + ) + message = mt.render(bsd=bsd, host=host) sendsingle(message, setup_sc4s[0], setup_sc4s[1][514]) st = env.from_string( - 'search _time={{ epoch }} index="netops" host="{{ host }}" sourcetype="guardicore:centra:cef"' + 'search index=netops sourcetype="guardicore:centra:cef" host="{{ host }}" earliest={{ epoch }}' ) - search = st.render(epoch=epoch, bsd=bsd, host=host) + search = st.render(host=host, epoch=epoch) result_count, _ = splunk_single(setup_splunk, search)