Skip to content
Merged
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
32 changes: 31 additions & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,52 @@ permissions:
contents: read

jobs:
release-checks:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
with:
persist-credentials: false

- name: Set up uv
uses: astral-sh/setup-uv@v4
with:
python-version: "3.10"
enable-cache: true

Comment on lines +16 to +25

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate and print the relevant workflow
echo "== publish.yml =="
sed -n '1,120p' .github/workflows/publish.yml

# Check if other workflows reference these actions unpinned
echo
echo "== Other unpinned actions/checkout@v4 or setup-uv@v4 usages =="
rg -n --hidden --glob '!.git/*' "uses:\s*actions/checkout@v4|uses:\s*astral-sh/setup-uv@v4" .github/workflows || true

# Check whether persist-credentials is set anywhere in the workflow
echo
echo "== persist-credentials occurrences in publish.yml =="
rg -n "persist-credentials" .github/workflows/publish.yml || true

Repository: MaxApiTeam/PyMax

Length of output: 2134


🌐 Web query:

actions/checkout@v4 persist-credentials default value

💡 Result:

The default value for the persist-credentials input in actions/checkout@v4 is true [1][2]. When this option is set to true (the default), the action configures the Git repository with the provided authentication token (such as GITHUB_TOKEN) or SSH key in the local.git/config file [1][3]. This allows subsequent steps in the workflow to perform authenticated Git commands [1]. The token is removed during the post-job cleanup process [1]. To disable this behavior and prevent the credentials from being persisted in the local Git configuration, you must explicitly set the input to false: - uses: actions/checkout@v4 with: persist-credentials: false

Citations:


Harden third-party action usage in publish workflow.

  • actions/checkout@v4 and astral-sh/setup-uv@v4 are used unpinned (appears in both release-checks and release-build jobs).
  • actions/checkout@v4 credential persistence is not disabled (no persist-credentials: false in workflow; default is true), weakening release supply-chain hardening.
🔒 Suggested hardening diff
-      - uses: actions/checkout@v4
+      - uses: actions/checkout@<FULL_LENGTH_COMMIT_SHA>
+        with:
+          persist-credentials: false

       - name: Set up uv
-        uses: astral-sh/setup-uv@v4
+        uses: astral-sh/setup-uv@<FULL_LENGTH_COMMIT_SHA>
🧰 Tools
🪛 zizmor (1.25.2)

[warning] 16-16: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 16-16: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 19-19: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 19-19: runtime artifacts potentially vulnerable to a cache poisoning attack (cache-poisoning): this step

(cache-poisoning)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/publish.yml around lines 16 - 23, The workflow uses
third-party actions unpinned and leaves credentials persisted; update both jobs
(release-checks and release-build) to pin actions/checkout@v4 and
astral-sh/setup-uv@v4 to immutable references (commit SHAs or fully-qualified
tags) instead of floating tags, and add persist-credentials: false to the
actions/checkout invocation(s) to prevent leaking workflow tokens; ensure you
update every occurrence of the actions (actions/checkout and astral-sh/setup-uv)
in the workflow file so all uses are pinned and credential persistence is
disabled.

- name: Check lint
run: uv run ruff check src tests

- name: Check formatting
run: uv run ruff format --check src tests

- name: Run tests
run: uv run pytest
Comment on lines +26 to +33

@m-xim m-xim May 26, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Лучше запускать formatting, lint и тесты на любой PR, чтобы не пропускать проблемы до мержа. В отдельный action их перенести.
Также стоит явно указать src и tests в конфигурации ruff.


- name: Build docs
run: uv run sphinx-build -b html docs /tmp/pymax-docs

release-build:
runs-on: ubuntu-latest
needs: release-checks

steps:
- uses: actions/checkout@v4
with:
persist-credentials: false

- name: Set up uv
uses: astral-sh/setup-uv@v4
with:
python-version: "3.10"
enable-cache: true

- name: Build release distributions
run: uv build

- name: Check distributions
run: uvx twine check dist/*
run: uv run twine check dist/*

- name: Upload distributions
uses: actions/upload-artifact@v4
Expand Down
14 changes: 14 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
repos:
- repo: local
hooks:
- id: ruff-check
name: ruff check
entry: uv run ruff check --fix
language: system
types_or: [python, pyi]

- id: ruff-format
name: ruff format
entry: uv run ruff format
language: system
types_or: [python, pyi]
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ client.include_router(router)

```bash
uv sync --all-groups
uv run pre-commit install
uv run pre-commit run --all-files
uv run pytest
uv run python -c "import pymax; print(pymax.__all__)"
uv run sphinx-build -b html docs docs/_build/html
```
Expand Down
6 changes: 6 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ PyMax - асинхронная Python-библиотека для Max API. Он
минимальный рабочий пример с авторизацией, обработчиком сообщений и запуском
клиента.

.. toctree::
:maxdepth: 1
:caption: Новости

release-2-1-0

.. toctree::
:maxdepth: 2
:caption: Руководство
Expand Down
43 changes: 43 additions & 0 deletions docs/release-2-1-0.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
PyMax 2.1.0
===========

Изменения относительно ``2.0.1``.

Добавлено
---------

* Заявки на вступление в группы и каналы: ``get_join_requests()``,
``confirm_join_request()`` /
``confirm_join_requests()`` и отклонить их через ``decline_join_request()`` /
``decline_join_requests()``.
* Доменные типы ``Member`` и ``Presence`` для заявок.
* 2FA: ``check_2fa()`` и ``change_password()``.
* QR-вход: ``authorize_qr_login(qr_link)``.
* Web app-боты: ``get_bot_init_data(bot_id, chat_id, start_param=None)``.

Исправлено
----------

* TCP-заголовок приведен к схеме Max: ``ver:1``, ``cmd:1``, ``seq:2``,
``opcode:2``, ``len/cof:4``. ``seq`` больше не падает после ``255``.
* Upload фото, видео и файлов использует ``ExtraConfig.proxy`` для HTTP-отправки
на upload URL.
* ``MaxApiError.title`` и ``MaxApiError.localized_message`` могут быть ``None``.

Изменилось
----------

* ``check_2fa()`` возвращает ``False``, если профиль еще не загружен или сервер
не прислал ``profile_options``.
* При заданном ``ExtraConfig.proxy`` upload-запросы тоже идут через proxy.
Proxy должен выдерживать большие HTTP POST-запросы.
* ``Capability`` разделен на ``ProfileOptions`` и ``TwoFactorAction``.
* ``ApiFacade`` получил ``bots``-сервис.

Миграция
--------

* Код на ``Client`` и ``WebClient`` обычно менять не нужно.
* Импорт ``pymax.api.auth.enums.Capability`` замените на ``TwoFactorAction`` или
``ProfileOptions``.
* Если код ждал строку в ``MaxApiError.title``, теперь нужно учитывать ``None``.
32 changes: 17 additions & 15 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "maxapi-python"
version = "2.0.1"
version = "2.1.0"
description = "Python wrapper для API мессенджера Max"
readme = "README.md"
requires-python = ">=3.10"
Expand Down Expand Up @@ -89,37 +89,39 @@ dev = [
{include-group = "docs"},
{include-group = "test"},
"build>=1.2.0",
"pre-commit>=4.0.0",
"twine>=5.0.0",
"pyright>=1.1.390",
"black>=24.0.0",
"isort>=5.13.0",
"flake8>=7.0.0",
"ruff>=0.8.0",
]

[tool.pyright]
venv = ".venv"
venvPath = "."

[tool.black]
[tool.ruff]
line-length = 79
target-version = ["py310"]
target-version = "py310"

[tool.flake8]
max-line-length = 79
max-complexity = 10
[tool.ruff.lint]
select = ["E", "F", "I"]
ignore = ["E501"]

[tool.ruff.lint.per-file-ignores]
"src/pymax/**/__init__.py" = ["F401", "F403"]
"tests/**" = ["F401"]

[tool.ruff.format]
quote-style = "double"
indent-style = "space"
line-ending = "auto"

[tool.mypy]
python_version = "3.10"
warn_return_any = true
warn_unused_configs = true
plugins = ["pydantic.mypy"]

[tool.isort]
profile = "black"
line_length = 79
multi_line_output = 3
include_trailing_comma = true

[tool.pytest.ini_options]
asyncio_mode = "auto"
testpaths = ["tests"]
Expand Down
2 changes: 1 addition & 1 deletion src/pymax/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "2.0.1"
__version__ = "2.1.0"


from .auth import (
Expand Down
15 changes: 13 additions & 2 deletions src/pymax/api/auth/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,21 @@ class AuthType(str, Enum):
RESEND = "RESEND"


class Capability(int, Enum):
DEFAULT = 0 # В душе не чаю что это такое но при первой установке 2фа там 0 3 4 так что пусть будет дефолт
class ProfileOptions(int, Enum):
"""Битовые/числовые признаки профиля, связанные с 2FA."""

ESIA_VERIFIED_FLAG = 1
SECOND_FACTOR_PASSWORD_ENABLED = 2
SECOND_FACTOR_HAS_EMAIL = 3
SECOND_FACTOR_HAS_HINT = 4


class TwoFactorAction(int, Enum):
"""Действия 2FA, передаваемые в expectedCapabilities."""

SET_PASSWORD = 0
UPDATE_PASSWORD = 1
RESTORE_PASSWORD = 2
HINT = 3
EMAIL = 4
REMOVE_2FA = 5
16 changes: 10 additions & 6 deletions src/pymax/api/auth/payloads.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from pydantic import Field, field_serializer
from pydantic import Field

from pymax.api.models import CamelModel
from pymax.api.session.payloads import MobileUserAgentPayload
from pymax.types.domain.sync import DEFAULT_CONFIG_HASH, ConfigHash, SyncState

from .enums import AuthType, Capability
from .enums import AuthType, TwoFactorAction


class RequestCodePayload(CamelModel):
Expand Down Expand Up @@ -115,15 +115,19 @@ class SetHintPayload(CamelModel):


class SetTwoFactorPayload(CamelModel):
expected_capabilities: list[Capability]
expected_capabilities: list[TwoFactorAction]
track_id: str
password: str
hint: str | None = None


class RemoveTwoFactorPayload(CamelModel):
track_id: str
remove2fa: bool = True
expected_capabilities: list[Capability] = Field(
default_factory=lambda: [Capability.REMOVE_2FA]
remove2fa: bool = Field(default=True, alias="remove2fa")
expected_capabilities: list[TwoFactorAction] = Field(
default_factory=lambda: [TwoFactorAction.REMOVE_2FA]
)


class ApproveQrLoginPayload(CamelModel):
qr_link: str
Loading