Skip to content

Commit c6ea75c

Browse files
authored
Merge pull request #460 from OperationCode/irving/202610-security-patches
October 2026 security patches
2 parents 2c58334 + 4cbbc40 commit c6ea75c

8 files changed

Lines changed: 1015 additions & 1045 deletions

File tree

‎.github/workflows/ci.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ on:
77
branches: [master]
88

99
env:
10-
POETRY_VERSION: "2.3.0"
10+
POETRY_VERSION: "2.5.1"
1111
POETRY_VIRTUALENVS_IN_PROJECT: true
1212

1313
jobs:

‎docker/Dockerfile‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
1-
FROM python:3.14-slim AS base
1+
# Pin the exact patch release and Debian suite. A new tag invalidates the CI
2+
# build cache, so the apt-get upgrade below runs again and picks up security fixes.
3+
FROM python:3.14.9-slim-trixie AS base
24

3-
RUN apt-get update && apt-get upgrade -y && apt-get install -y --no-install-recommends wget && rm -rf /var/lib/apt/lists/*
5+
RUN apt-get update && apt-get upgrade -y && apt-get install -y --no-install-recommends ca-certificates wget && rm -rf /var/lib/apt/lists/*
46

57
FROM base AS builder
68

79
ENV PIP_DISABLE_PIP_VERSION_CHECK=on \
810
PYTHONUNBUFFERED=1 \
9-
POETRY_VERSION=2.4.0 \
11+
POETRY_VERSION=2.5.1 \
1012
POETRY_HOME="/opt/poetry" \
1113
POETRY_NO_INTERACTION=1 \
1214
POETRY_VIRTUALENVS_IN_PROJECT=true \
1315
POETRY_VIRTUALENVS_CREATE=true \
16+
POETRY_VIRTUALENVS_OPTIONS_NO_PIP=true \
1417
POETRY_CACHE_DIR=/tmp/poetry_cache
1518

1619
# Install build dependencies
@@ -43,6 +46,9 @@ ENV PIP_DISABLE_PIP_VERSION_CHECK=on \
4346

4447
WORKDIR /app
4548

49+
# pip is not used at runtime, and its vendored packages carry CVEs
50+
RUN python -m pip uninstall -y pip
51+
4652
# Copy application and virtual environment from builder
4753
COPY --from=builder /app ./
4854

‎poetry.lock‎

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

‎pybot/endpoints/slack/message_templates/tech.py‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,7 @@ def _compile_regex_from_parts(self) -> Pattern[str]:
4848

4949
return re.compile(regex_string)
5050

51-
def _filter_matches(
52-
self, lines: list[str], two_col_org_row: Pattern[str]
53-
) -> Generator[dict, None, None]:
51+
def _filter_matches(self, lines: list[str], two_col_org_row: Pattern[str]) -> Generator[dict]:
5452
for line in lines:
5553
match = two_col_org_row.match(line).groupdict()
5654
if match.get("term") and match.get("definition"):

‎pybot/plugins/api/request.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def __len__(self):
7171
def __repr__(self):
7272
return "API Request: " + str(self.request)
7373

74-
def clone(self) -> "SlackApiRequest":
74+
def clone(self) -> SlackApiRequest:
7575
return self.__class__(
7676
copy.deepcopy(self.request),
7777
copy.deepcopy(self.resource),

‎pyproject.toml‎

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,19 @@ readme = "README.md"
88
packages = [{include = "pybot"}]
99

1010
[tool.poetry.dependencies]
11-
python = "^3.12"
11+
python = "^3.14"
1212
aiohttp = "^3.9"
1313
python-dotenv = "^1.0"
1414
pyyaml = "^6.0"
1515
sentry-sdk = "^2.0"
1616
zipcodes = "^1.2"
17+
multidict = "^6.9.1"
1718

1819
[tool.poetry.group.dev.dependencies]
1920
pytest = "^9.0"
2021
pytest-asyncio = "^1.0"
2122
pytest-aiohttp = "^1.0"
2223
pytest-mock = "^3.12"
23-
black = "^26.0"
2424
ruff = "^0.15"
2525
requests = "^2.31"
2626
pytest-cov = "^7.0.0"
@@ -39,13 +39,9 @@ testpaths = ["tests"]
3939

4040
[tool.ruff]
4141
line-length = 100
42-
target-version = "py312"
42+
target-version = "py314"
4343
extend-exclude = ["pybot/_vendor"]
4444

4545
[tool.ruff.lint]
4646
select = ["E", "F", "I", "UP"]
4747
ignore = ["F401", "E501"] # Allow re-exports and longer lines for now
48-
49-
[tool.black]
50-
line-length = 100
51-
target-version = ["py312"]

‎tests/fixtures/__init__.py‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ def setup_user_info(
103103
email: str | None = None,
104104
name: str = "Test User",
105105
real_name: str = "Test User",
106-
) -> "SlackMock":
106+
) -> SlackMock:
107107
"""Configure response for users.info API call."""
108108
profile = {"real_name": real_name}
109109
if email:
@@ -120,17 +120,17 @@ def setup_user_info(
120120
}
121121
return self
122122

123-
def setup_method_response(self, method: str, response: Any) -> "SlackMock":
123+
def setup_method_response(self, method: str, response: Any) -> SlackMock:
124124
"""Configure response for a specific Slack API method."""
125125
self._method_responses[method] = response
126126
return self
127127

128-
def setup_error_response(self, method: str, error: Exception) -> "SlackMock":
128+
def setup_error_response(self, method: str, error: Exception) -> SlackMock:
129129
"""Configure an error to be raised for a specific method."""
130130
self._error_responses[method] = error
131131
return self
132132

133-
def setup_lookup_by_email(self, email: str, user_id: str) -> "SlackMock":
133+
def setup_lookup_by_email(self, email: str, user_id: str) -> SlackMock:
134134
"""Configure users.lookupByEmail response."""
135135
self._email_lookup[email] = user_id
136136
return self
@@ -287,7 +287,7 @@ async def _handle_get_all_records(self, table: str, field: str) -> list[str]:
287287
return [m.get(field) for m in self._mentors.values() if m.get(field)]
288288
return []
289289

290-
def setup_service(self, name: str, record_id: str | None = None) -> "AirtableMock":
290+
def setup_service(self, name: str, record_id: str | None = None) -> AirtableMock:
291291
"""Add a service to the mock."""
292292
record_id = record_id or f"recsvc{len(self._services)}"
293293
self._services[record_id] = {"Name": name}
@@ -300,7 +300,7 @@ def setup_mentor(
300300
skillsets: list[str] | None = None,
301301
record_id: str | None = None,
302302
slack_name: str | None = None,
303-
) -> "AirtableMock":
303+
) -> AirtableMock:
304304
"""Add a mentor to the mock."""
305305
record_id = record_id or f"recmentor{len(self._mentors)}"
306306
self._mentors[record_id] = {
@@ -311,7 +311,7 @@ def setup_mentor(
311311
}
312312
return self
313313

314-
def setup_error(self, table: str, operation: str, error: Exception | str) -> "AirtableMock":
314+
def setup_error(self, table: str, operation: str, error: Exception | str) -> AirtableMock:
315315
"""Configure an error for a specific table/operation combination."""
316316
if isinstance(error, str):
317317
error = Exception(error)
@@ -388,7 +388,7 @@ async def _handle_query(self, method: str, data: dict | None = None, **kwargs) -
388388

389389
return {"ok": True}
390390

391-
def setup_invite_error(self, error: Exception) -> "AdminSlackMock":
391+
def setup_invite_error(self, error: Exception) -> AdminSlackMock:
392392
"""Configure an error for channel invites."""
393393
from pybot._vendor.slack import methods
394394

‎tests/unit/test_roll_command.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def test_roll_input_validation(self, input_text, expected_valid):
2828
text = input_text.lower()
2929
numdice, typedice = [int(num) for num in text.split("d")]
3030
valid = 0 < numdice <= 10 and 0 < typedice <= 20
31-
except (ValueError, IndexError):
31+
except ValueError, IndexError:
3232
valid = False
3333

3434
assert valid == expected_valid

0 commit comments

Comments
 (0)