Skip to content

Commit be5268d

Browse files
Merge pull request #533 from splunk/release/1.7.4
Release/1.7.4
2 parents e441358 + ce6f5d2 commit be5268d

14 files changed

+72
-29
lines changed

.github/workflows/release.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,17 @@ jobs:
99
runs-on: ubuntu-latest
1010
steps:
1111
- name: Checkout source
12-
uses: actions/checkout@v2.3.2
12+
uses: actions/checkout@v3
1313
- name: Set up Python
14-
uses: actions/setup-python@v2
14+
uses: actions/setup-python@v4
1515
with:
1616
python-version: 3.7
1717
- name: Install dependencies
1818
run: pip install twine
1919
- name: Build package
2020
run: python setup.py sdist
2121
- name: Publish package to PyPI
22-
uses: pypa/gh-action-pypi-publish@v1.3.1
22+
uses: pypa/gh-action-pypi-publish@v1.8.8
2323
with:
2424
user: __token__
2525
password: ${{ secrets.pypi_password }}

.github/workflows/test.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
matrix:
1212
os:
1313
- ubuntu-latest
14-
python: [ 2.7, 3.7 ]
14+
python: [3.7]
1515
splunk-version:
1616
- "8.1"
1717
- "8.2"
@@ -20,13 +20,13 @@ jobs:
2020

2121
steps:
2222
- name: Checkout code
23-
uses: actions/checkout@v2
23+
uses: actions/checkout@v3
2424

2525
- name: Run docker-compose
2626
run: SPLUNK_VERSION=${{matrix.splunk-version}} docker-compose up -d
2727

2828
- name: Setup Python
29-
uses: actions/setup-python@v2
29+
uses: actions/setup-python@v4
3030
with:
3131
python-version: ${{ matrix.python }}
3232

CHANGELOG.md

+9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# Splunk Enterprise SDK for Python Changelog
22

3+
## Version 1.7.4
4+
5+
### Bug fixes
6+
* [#532](https://github.com/splunk/splunk-sdk-python/pull/532) update encoding errors mode to 'replace' [[issue#505](https://github.com/splunk/splunk-sdk-python/issues/505)]
7+
* [#507](https://github.com/splunk/splunk-sdk-python/pull/507) masked sensitive data in logs [[issue#506](https://github.com/splunk/splunk-sdk-python/issues/506)]
8+
9+
### Minor changes
10+
* [#530](https://github.com/splunk/splunk-sdk-python/pull/530) Update GitHub CI build status in README and removed RTD(Read The Docs) reference
11+
312
## Version 1.7.3
413

514
### Bug fixes

README.md

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
[![Build Status](https://travis-ci.org/splunk/splunk-sdk-python.svg?branch=master)](https://travis-ci.org/splunk/splunk-sdk-python)
2-
[![Documentation Status](https://readthedocs.org/projects/splunk-python-sdk/badge/?version=latest)](https://splunk-python-sdk.readthedocs.io/en/latest/?badge=latest)
1+
[![Build Status](https://github.com/splunk/splunk-sdk-python/actions/workflows/test.yml/badge.svg?branch=master)](https://github.com/splunk/splunk-sdk-python/actions/workflows/test.yml)
2+
3+
[Reference Docs](https://dev.splunk.com/enterprise/reference)
34

45
# The Splunk Enterprise Software Development Kit for Python
56

6-
#### Version 1.7.3
7+
#### Version 1.7.4
78

89
The Splunk Enterprise Software Development Kit (SDK) for Python contains library code designed to enable developers to build applications using the Splunk platform.
910

@@ -127,7 +128,7 @@ The Splunk Enterprise SDK for Python contains a collection of unit tests. To run
127128

128129
You can also run individual test files, which are located in **/splunk-sdk-python/tests**. To run a specific test, enter:
129130

130-
make specific_test_name
131+
make test_specific
131132

132133
The test suite uses Python's standard library, the built-in `unittest` library, `pytest`, and `tox`.
133134

scripts/test_specific.sh

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
echo "To run a specific test:"
2-
echo " tox -e py27,py37 [test_file_path]::[test_name]"
2+
echo " tox -e py27,py37 [test_file_path]::[TestClassName]::[test_method]"
3+
echo "For Example, To run 'test_autologin' testcase from 'test_service.py' file run"
4+
echo " tox -e py37 -- tests/test_service.py::ServiceTestCase::test_autologin"

splunklib/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,5 @@ def setup_logging(level, log_format=DEFAULT_LOG_FORMAT, date_format=DEFAULT_DATE
3131
format=log_format,
3232
datefmt=date_format)
3333

34-
__version_info__ = (1, 7, 3)
34+
__version_info__ = (1, 7, 4)
3535
__version__ = ".".join(map(str, __version_info__))

splunklib/binding.py

+32-10
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from __future__ import absolute_import
2828

2929
import io
30+
import json
3031
import logging
3132
import socket
3233
import ssl
@@ -60,12 +61,17 @@
6061
"HTTPError"
6162
]
6263

64+
SENSITIVE_KEYS = ['Authorization', 'Cookie', 'action.email.auth_password', 'auth', 'auth_password', 'clear_password', 'clientId',
65+
'crc-salt', 'encr_password', 'oldpassword', 'passAuth', 'password', 'session', 'suppressionKey',
66+
'token']
67+
6368
# If you change these, update the docstring
6469
# on _authority as well.
6570
DEFAULT_HOST = "localhost"
6671
DEFAULT_PORT = "8089"
6772
DEFAULT_SCHEME = "https"
6873

74+
6975
def _log_duration(f):
7076
@wraps(f)
7177
def new_f(*args, **kwargs):
@@ -77,6 +83,28 @@ def new_f(*args, **kwargs):
7783
return new_f
7884

7985

86+
def mask_sensitive_data(data):
87+
'''
88+
Masked sensitive fields data for logging purpose
89+
'''
90+
if not isinstance(data, dict):
91+
try:
92+
data = json.loads(data)
93+
except Exception as ex:
94+
return data
95+
96+
# json.loads will return "123"(str) as 123(int), so return the data if it's not 'dict' type
97+
if not isinstance(data, dict):
98+
return data
99+
mdata = {}
100+
for k, v in data.items():
101+
if k in SENSITIVE_KEYS:
102+
mdata[k] = "******"
103+
else:
104+
mdata[k] = mask_sensitive_data(v)
105+
return mdata
106+
107+
80108
def _parse_cookies(cookie_str, dictionary):
81109
"""Tries to parse any key-value pairs of cookies in a string,
82110
then updates the the dictionary with any key-value pairs found.
@@ -631,7 +659,7 @@ def delete(self, path_segment, owner=None, app=None, sharing=None, **query):
631659
"""
632660
path = self.authority + self._abspath(path_segment, owner=owner,
633661
app=app, sharing=sharing)
634-
logger.debug("DELETE request to %s (body: %s)", path, repr(query))
662+
logger.debug("DELETE request to %s (body: %s)", path, mask_sensitive_data(query))
635663
response = self.http.delete(path, self._auth_headers, **query)
636664
return response
637665

@@ -694,7 +722,7 @@ def get(self, path_segment, owner=None, app=None, headers=None, sharing=None, **
694722

695723
path = self.authority + self._abspath(path_segment, owner=owner,
696724
app=app, sharing=sharing)
697-
logger.debug("GET request to %s (body: %s)", path, repr(query))
725+
logger.debug("GET request to %s (body: %s)", path, mask_sensitive_data(query))
698726
all_headers = headers + self.additional_headers + self._auth_headers
699727
response = self.http.get(path, all_headers, **query)
700728
return response
@@ -773,12 +801,7 @@ def post(self, path_segment, owner=None, app=None, sharing=None, headers=None, *
773801

774802
path = self.authority + self._abspath(path_segment, owner=owner, app=app, sharing=sharing)
775803

776-
# To avoid writing sensitive data in debug logs
777-
endpoint_having_sensitive_data = ["/storage/passwords"]
778-
if any(endpoint in path for endpoint in endpoint_having_sensitive_data):
779-
logger.debug("POST request to %s ", path)
780-
else:
781-
logger.debug("POST request to %s (body: %s)", path, repr(query))
804+
logger.debug("POST request to %s (body: %s)", path, mask_sensitive_data(query))
782805
all_headers = headers + self.additional_headers + self._auth_headers
783806
response = self.http.post(path, all_headers, **query)
784807
return response
@@ -845,8 +868,7 @@ def request(self, path_segment, method="GET", headers=None, body={},
845868

846869
all_headers = headers + self.additional_headers + self._auth_headers
847870
logger.debug("%s request to %s (headers: %s, body: %s)",
848-
method, path, str(all_headers), repr(body))
849-
871+
method, path, str(mask_sensitive_data(dict(all_headers))), mask_sensitive_data(body))
850872
if body:
851873
body = _encode(**body)
852874

splunklib/modularinput/event_writer.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ def write_xml_document(self, document):
7777
7878
:param document: An ``ElementTree`` object.
7979
"""
80-
self._out.write(ensure_str(ET.tostring(document)))
80+
self._out.write(ensure_str(ET.tostring(document), errors="replace"))
8181
self._out.flush()
8282

8383
def close(self):

splunklib/searchcommands/search_command.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -934,7 +934,7 @@ def _read_chunk(istream):
934934
except Exception as error:
935935
raise RuntimeError('Failed to read body of length {}: {}'.format(body_length, error))
936936

937-
return metadata, six.ensure_str(body)
937+
return metadata, six.ensure_str(body, errors="replace")
938938

939939
_header = re.compile(r'chunked\s+1.0\s*,\s*(\d+)\s*,\s*(\d+)\s*\n')
940940

tests/searchcommands/test_csc_apps.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515
# under the License.
1616

1717
import unittest
18+
import pytest
19+
1820
from tests import testlib
1921
from splunklib import results
2022

21-
23+
@pytest.mark.smoke
2224
class TestCSC(testlib.SDKTestCase):
2325

2426
def test_eventing_app(self):

tests/test_binding.py

+2
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,7 @@ def test_got_updated_cookie_with_get(self):
641641
self.assertEqual(list(new_cookies.values())[0], list(old_cookies.values())[0])
642642
self.assertTrue(found)
643643

644+
@pytest.mark.smoke
644645
def test_login_fails_with_bad_cookie(self):
645646
# We should get an error if using a bad cookie
646647
try:
@@ -649,6 +650,7 @@ def test_login_fails_with_bad_cookie(self):
649650
except AuthenticationError as ae:
650651
self.assertEqual(str(ae), "Login failed.")
651652

653+
@pytest.mark.smoke
652654
def test_login_with_multiple_cookies(self):
653655
# We should get an error if using a bad cookie
654656
new_context = binding.Context()

tests/test_event_type.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,10 @@ def tearDown(self):
6363
except KeyError:
6464
pass
6565

66-
def test_delete(self):
67-
self.assertTrue(self.event_type_name in self.service.event_types)
68-
self.service.event_types.delete(self.event_type_name)
69-
self.assertFalse(self.event_type_name in self.service.event_types)
66+
# def test_delete(self):
67+
# self.assertTrue(self.event_type_name in self.service.event_types)
68+
# self.service.event_types.delete(self.event_type_name)
69+
# self.assertFalse(self.event_type_name in self.service.event_types)
7070

7171
def test_update(self):
7272
kwargs = {}

tests/test_job.py

+2
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ def test_oneshot_with_garbage_fails(self):
5757
jobs = self.service.jobs
5858
self.assertRaises(TypeError, jobs.create, "abcd", exec_mode="oneshot")
5959

60+
@pytest.mark.smoke
6061
def test_oneshot(self):
6162
jobs = self.service.jobs
6263
stream = jobs.oneshot("search index=_internal earliest=-1m | head 3", output_mode='json')
@@ -382,6 +383,7 @@ def test_search_invalid_query_as_json(self):
382383
except Exception as e:
383384
self.fail("Got some unexpected error. %s" % e.message)
384385

386+
@pytest.mark.smoke
385387
def test_v1_job_fallback(self):
386388
self.assertEventuallyTrue(self.job.is_done)
387389
self.assertLessEqual(int(self.job['eventCount']), 3)

tests/test_service.py

+3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
# under the License.
1616

1717
from __future__ import absolute_import
18+
import pytest
19+
1820
from tests import testlib
1921
import unittest
2022

@@ -168,6 +170,7 @@ def _create_unauthenticated_service(self):
168170
})
169171

170172
# To check the HEC event endpoint using Endpoint instance
173+
@pytest.mark.smoke
171174
def test_hec_event(self):
172175
import json
173176
service_hec = client.connect(host='localhost', scheme='https', port=8088,

0 commit comments

Comments
 (0)