Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/agreements.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
12 changes: 7 additions & 5 deletions .github/workflows/ci-lite.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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: |
Expand Down Expand Up @@ -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 }}

Expand Down Expand Up @@ -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: |
Expand Down
12 changes: 7 additions & 5 deletions .github/workflows/ci-main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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: |
Expand Down Expand Up @@ -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 }}

Expand Down Expand Up @@ -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: |
Expand Down
4 changes: 2 additions & 2 deletions charts/splunk-connect-for-syslog/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
3 changes: 0 additions & 3 deletions package/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 0 additions & 3 deletions package/Dockerfile.lite
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion package/etc/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.40.0
3.41.0
Original file line number Diff line number Diff line change
@@ -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('^(?<pri>\<\d+\>) ?(?<timestamp>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2})?(?:Z|[+-]\d{2}:?\d{2})?) (?<host>[^ ]+) (?<message>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(); };
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
rewrite set_rfc3164_vmware_vsphere_isodate{
set-tag("wireformat:rfc3164_vmware_vsphere_isodate");
};
filter f_is_rfc3164_vmware_vsphere_isodate{
tags("wireformat:rfc3164_vmware_vsphere_isodate");
};

# Handles VMware vCenter/Aria logs with non-standard ISO 8601 timestamps
# using a space separator instead of "T" (e.g. "2025-02-04 12:43:21.777"
# rather than "2025-02-04T12:43:21.777").
# See: https://github.com/splunk/splunk-connect-for-syslog/issues/2696
block parser app-almost-syslog-vmware_vsphere_isodate() {
channel {
parser {
regexp-parser(
prefix(".tmp.")
patterns('^(?<pri>\<\d+\>) ?(?<date>\d{4}-\d{2}-\d{2}) (?<time>\d{2}:\d{2}:\d{2}[^ ]*) (?<host>[^ ]+) (?<message>.*)')
);
syslog-parser(
flags(assume-utf8)
template("${.tmp.pri} $R_DATE ${.tmp.host} ${.tmp.message}")
);
};
rewrite(set_rfc);
rewrite(set_rfc3164);
rewrite(set_rfc3164_vmware_vsphere_isodate);
};
};
application app-almost-syslog-vmware_vsphere_isodate[sc4s-almost-syslog] {
parser { app-almost-syslog-vmware_vsphere_isodate(); };
};
Original file line number Diff line number Diff line change
@@ -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('^(?<pri>\<\d+\>) ?(?<timestamp>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2})?(?:Z|[+-]\d{2}:?\d{2})?) (?<host>[^ ]+) (?<message>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(); };
};
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "splunk-connect-for-syslog"
version = "3.40.0"
version = "3.41.0"
description = ""
authors = ["rjha-splunk <rjha@splunk.com>"]
license = "Apache-2.0"
Expand Down
14 changes: 11 additions & 3 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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

Expand Down
84 changes: 63 additions & 21 deletions tests/test_guardicore.py
Original file line number Diff line number Diff line change
@@ -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)

Expand Down
Loading
Loading