Skip to content

Commit daad249

Browse files
authored
Merge pull request #77 from PaperMtn/release/4.4.2
Release/4.4.2
2 parents 0986aaa + c4eb324 commit daad249

8 files changed

Lines changed: 73 additions & 56 deletions

File tree

.github/dependabot.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,4 @@ updates:
1212
insecure-external-code-execution: "deny"
1313
ignore:
1414
- dependency-name: "*"
15-
security-updates-only: true
1615
versioning-strategy: increase

CHANGELOG.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,18 @@
1-
## [4.4.2] - 2025-xx-xx
1+
## [4.4.2] - 2025-07-05
22
### Added
33
- Added `.github/dependabot.yml` with configuration for Dependabot:
44
- Use `develop` as target branch
55
- Update both `pyproject.toml` and `poetry.lock`
6+
- README updated to recommend using `pipx` for installation
7+
8+
### Fixed
9+
- Fixed issue with Poetry build arguments in Dockerfile, which was causing the build to fail.
10+
11+
### Changed
12+
- Modified signature download process to use `requests` instead of `urllib`, which is more robust and provides better SSL handling. This addresses the issue raised in [#74](https://github.com/PaperMtn/slack-watchman/issues/74)
13+
- Dependabot updates
14+
- `urllib3` updated to `2.5.0`
15+
- `requests` updated to `2.32.4`
616

717
## [4.4.1] - 2024-12-18
818
### Fixed

Dockerfile

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,15 @@ WORKDIR /opt/slack-watchman
44
COPY . .
55
RUN pip install poetry
66
RUN poetry config virtualenvs.create false && \
7-
poetry install --no-dev && \
7+
poetry install --only main && \
88
poetry build
99

1010
FROM python:3.12-slim-bullseye
1111
WORKDIR /opt/slack-watchman
1212
COPY --from=builder /opt/slack-watchman/dist/*.whl /opt/slack-watchman/dist/
1313
COPY --from=builder /opt/slack-watchman/pyproject.toml /opt/slack-watchman/poetry.lock /opt/slack-watchman/
14-
ENV PYTHONPATH=/opt/slack-watchman \
15-
SLACK_WATCHMAN_TOKEN="" \
16-
SLACK_WATCHMAN_COOKIE="" \
17-
SLACK_WATCHMAN_URL=""
18-
RUN pip install dist/*.whl && \
19-
chmod -R 700 .
14+
ENV PYTHONPATH=/opt/slack-watchman
15+
RUN pip install dist/*.whl && rm -rf ./dist
16+
RUN chmod -R 700 .
2017
STOPSIGNAL SIGINT
2118
ENTRYPOINT ["slack-watchman"]

README.md

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -165,16 +165,24 @@ An example file is in `docs/example.conf`
165165
**Note**: Cookie and URL values are optional, and not required if not using cookie authentication.
166166

167167
## Installation
168-
You can install the latest stable version via pip:
169168

170-
```commandline
169+
The recommended way to install Slack Watchman is via [`pipx`](https://pypa.github.io/pipx/), which installs the app in an isolated environment and makes it available on your system `PATH`:
170+
171+
```bash
172+
pipx install slack-watchman
173+
```
174+
175+
**Alternative: Install via pip**
176+
177+
You can also install Slack Watchman using pip:
178+
```bash
171179
python3 -m pip install slack-watchman
172180
```
173181

174-
Or build from source yourself:
182+
**Alternative: Build from Source**
175183

176-
Download the release source files, then from the top level repository run:
177-
```commandline
184+
Download the release source files, then from the top-level directory of the repository, run:
185+
```bash
178186
python3 -m pip build
179187
python3 -m pip install --force-reinstall dist/*.whl
180188
```

poetry.lock

Lines changed: 15 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "slack-watchman"
3-
version = "4.4.1"
3+
version = "4.4.2"
44
description = "Monitoring and enumerating Slack for exposed secrets"
55
authors = ["PaperMtn <papermtn@protonmail.com>"]
66
license = "GPL-3.0"
@@ -20,8 +20,8 @@ classifiers = [
2020
python = ">=3.10"
2121
colorama = "^0.4.6"
2222
pyyaml = "^6.0.2"
23-
requests = "^2.32.3"
24-
beautifulsoup4 = "^4.12.3"
23+
requests = "^2.32.4"
24+
beautifulsoup4 = "^4.13.4"
2525

2626
[tool.poetry.group.dev.dependencies]
2727
pytest = "^8.3.3"

src/slack_watchman/signature_downloader.py

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
import traceback
55
import zipfile
66
from typing import List
7-
from urllib.request import urlopen
87

98
import yaml
9+
import requests
1010

1111
from slack_watchman.loggers import JSONLogger, StdoutLogger
1212
from slack_watchman.models.signature import Signature, create_from_dict
@@ -34,28 +34,29 @@ def download_signatures(self) -> List[Signature]:
3434
List[Signature]: A list of processed Signature objects.
3535
"""
3636
try:
37-
with urlopen(SIGNATURE_URL) as response:
38-
with zipfile.ZipFile(io.BytesIO(response.read())) as signatures_zip_file:
39-
signature_objects = []
37+
response = requests.get(SIGNATURE_URL, stream=True, timeout=10)
38+
response.raise_for_status()
39+
with zipfile.ZipFile(io.BytesIO(response.content)) as signatures_zip_file:
40+
signature_objects = []
4041

41-
for file_path in signatures_zip_file.namelist():
42-
if file_path.endswith('/'): # Skip directories
43-
continue
42+
for file_path in signatures_zip_file.namelist():
43+
if file_path.endswith('/'): # Skip directories
44+
continue
4445

45-
signature_name = os.path.basename(file_path)
46-
self.logger.log('DEBUG', f'Processing {file_path}...')
46+
signature_name = os.path.basename(file_path)
47+
self.logger.log('DEBUG', f'Processing {file_path}...')
4748

48-
with signatures_zip_file.open(file_path) as source:
49-
file_content = source.read()
49+
with signatures_zip_file.open(file_path) as source:
50+
file_content = source.read()
5051

51-
if file_path.endswith('.yaml'):
52-
processed_signatures = self._process_signature(file_content)
53-
signature_objects.extend(processed_signatures)
54-
self.logger.log('INFO', f'Downloaded and processed signature file: {signature_name}')
55-
else:
56-
self.logger.log('DEBUG', f'Skipping unrecognized file: {file_path}')
52+
if file_path.endswith('.yaml'):
53+
processed_signatures = self._process_signature(file_content)
54+
signature_objects.extend(processed_signatures)
55+
self.logger.log('INFO', f'Downloaded and processed signature file: {signature_name}')
56+
else:
57+
self.logger.log('DEBUG', f'Skipping unrecognized file: {file_path}')
5758

58-
return signature_objects
59+
return signature_objects
5960

6061
except Exception as e:
6162
self.logger.log('CRITICAL', f"Error processing signature files: {e}")

tests/unit/test_unit_signature_downloader.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,15 @@ def downloader(mock_logger):
1919
return SignatureDownloader(logger=mock_logger)
2020

2121

22-
@patch('slack_watchman.signature_downloader.urlopen')
22+
@patch('slack_watchman.signature_downloader.requests.get')
2323
@patch('slack_watchman.signature_downloader.zipfile.ZipFile')
24-
def test_download_signatures(mock_zipfile, mock_urlopen, downloader, mock_logger):
24+
def test_download_signatures(mock_zipfile, mock_get, downloader, mock_logger):
2525
"""Test the download_signatures method."""
26-
# Mock response from urlopen
26+
# Set up mock response
2727
mock_response = MagicMock()
28-
mock_response.read.return_value = b'mock_zip_content'
29-
mock_urlopen.return_value.__enter__.return_value = mock_response
28+
mock_response.status_code = 200
29+
mock_response.content = b'zipfile-bytes'
30+
mock_get.return_value = mock_response
3031

3132
# Mock a zip file structure
3233
mock_zip = MagicMock()
@@ -116,8 +117,8 @@ def test_process_signature():
116117
})
117118

118119

119-
@patch('slack_watchman.signature_downloader.urlopen', side_effect=Exception('Mocked Exception'))
120-
def test_download_signatures_exception(mock_urlopen, downloader, mock_logger):
120+
@patch('slack_watchman.signature_downloader.requests.get', side_effect=Exception('Mocked Exception'))
121+
def test_download_signatures_exception(mock_get, downloader, mock_logger):
121122
"""Test that download_signatures handles exceptions correctly."""
122123
with pytest.raises(SystemExit): # sys.exit(1) triggers SystemExit
123124
downloader.download_signatures()

0 commit comments

Comments
 (0)