-
Notifications
You must be signed in to change notification settings - Fork 44
Dev/2.1.2 #56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dev/2.1.2 #56
Changes from all commits
049768b
020c2d2
b21246f
9f208c3
540606d
f96aaeb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| PyMax 2.1.2 | ||
| =========== | ||
|
|
||
| Изменения относительно ``2.1.1``. | ||
|
|
||
| Добавлено | ||
| --------- | ||
|
|
||
| * ``get_bot_init_data()`` теперь можно вызвать без ``chat_id`` для сценариев, | ||
| где Max запускает web app вне конкретного чата. | ||
|
|
||
| Исправлено | ||
| ---------- | ||
|
|
||
| * ``ExtraConfig.request_timeout`` снова применяется к API-запросам по | ||
| умолчанию, а явный ``timeout`` в низкоуровневом вызове сохраняет приоритет. | ||
| * Login-ответ без нового ``token`` больше не ломает запуск клиента и не | ||
| перезаписывает сохраненный токен пустым значением. | ||
| * ``FolderList`` больше не переопределяет pydantic-итератор и не ломает | ||
| ``dict(...)`` / стандартную сериализацию модели. | ||
|
|
||
| Изменилось | ||
| ---------- | ||
|
|
||
| * Publish workflow упрощен: сборка, проверка дистрибутивов и публикация в PyPI | ||
| теперь разделены на понятные шаги с artifact handoff. | ||
|
|
||
| Миграция | ||
| -------- | ||
|
|
||
| * Если код итерировал ``FolderList`` напрямую, замените это на | ||
| ``folder_list.folders``. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| __version__ = "2.1.1" | ||
| __version__ = "2.1.2" | ||
|
|
||
|
|
||
| from .auth import ( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -33,9 +33,7 @@ def __init__( | |
| self.dispatcher: Dispatcher[ClientT] = Dispatcher(self, root_router) | ||
| self.api = ApiFacade(self) | ||
| self.config = config | ||
| self.store = self.config.store or SessionStore( | ||
| config.work_dir, config.session_name | ||
| ) | ||
| self.store = self.config.store or SessionStore(config.work_dir, config.session_name) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Preserve injected stores even when they are falsy. Line 36 now treats any falsy custom store as “missing” and replaces it with a new Suggested fix- self.store = self.config.store or SessionStore(config.work_dir, config.session_name)
+ self.store = (
+ self.config.store
+ if self.config.store is not None
+ else SessionStore(config.work_dir, config.session_name)
+ )🤖 Prompt for AI Agents |
||
| self.auth_flow = auth_flow | ||
|
|
||
| self.me: Profile | None = None | ||
|
|
@@ -76,18 +74,14 @@ async def start(self) -> None: | |
| await self.connection.open() | ||
|
|
||
| handshake_device_id = ( | ||
| session_data.device_id | ||
| if session_data | ||
| else self.config.device.device_id | ||
| session_data.device_id if session_data else self.config.device.device_id | ||
| ) | ||
| logger.debug("running handshake") | ||
| await self.handshake(handshake_device_id) | ||
| except (ConnectionError, EOFError, OSError, TimeoutError) as e: | ||
| logger.exception("failed to connect or handshake") | ||
| await self.connection.close() | ||
| raise ConnectionError( | ||
| f"Failed to connect and handshake: {e}" | ||
| ) from e | ||
| raise ConnectionError(f"Failed to connect and handshake: {e}") from e | ||
|
|
||
| self._ping_task = asyncio.create_task(self._ping_loop()) | ||
|
|
||
|
|
@@ -108,9 +102,7 @@ async def start(self) -> None: | |
|
|
||
| if not auth_result.token: | ||
| logger.error("authentication finished without token") | ||
| raise RuntimeError( | ||
| "Authentication failed: no token received" | ||
| ) | ||
| raise RuntimeError("Authentication failed: no token received") | ||
|
|
||
| await self.store.save_session( | ||
| session_data := SessionInfo( | ||
|
|
@@ -135,7 +127,7 @@ async def start(self) -> None: | |
| self.config.device.user_agent, | ||
| ) | ||
|
|
||
| if response.token != self.session.token: | ||
| if response.token is not None and response.token != self.session.token: | ||
| await self.store.update_token(self.session.token, response.token) | ||
| self.session.token = response.token | ||
|
|
||
|
|
@@ -189,7 +181,7 @@ async def invoke( | |
| opcode: int, | ||
| payload: dict[str, Any], | ||
| cmd: int = Command.REQUEST, | ||
| timeout: float | None = 30.0, | ||
| timeout: float | None = None, | ||
| compress: bool = False, | ||
| ) -> InboundFrame: | ||
| seq = self.connection.next_seq() | ||
|
|
@@ -211,10 +203,11 @@ async def invoke( | |
| payload_keys, | ||
| ) | ||
| logger.debug("Request data=%s", frame.model_dump()) | ||
| response = await self.connection.request(frame, timeout=timeout) | ||
| response_keys = ( | ||
| sorted(response.payload.keys()) if response.payload else [] | ||
| request_timeout = ( | ||
| self.config.request_timeout if timeout is None else timeout | ||
| ) | ||
| response = await self.connection.request(frame, timeout=request_timeout) | ||
| response_keys = sorted(response.payload.keys()) if response.payload else [] | ||
| logger.debug( | ||
| "response opcode=%s cmd=%s seq=%s payload_keys=%s", | ||
| response.opcode, | ||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: MaxApiTeam/PyMax
Length of output: 182
🏁 Script executed:
Repository: MaxApiTeam/PyMax
Length of output: 1772
🌐 Web query:
GitHub Actions security hardening pin actions to full commit SHA immutable only form movable tags💡 Result:
Pin GitHub Actions by full-length commit SHA (immutable), not by tags (movable). GitHub’s own guidance says pinning to a full-length commit SHA is currently the only way to treat an action reference as an immutable release, and warns that specifying a tag carries risk because tags can be moved or deleted if an attacker gains access to the action’s repository.[1][2] In a workflow, use this form: - uses: owner/repo@ For example, the docs’ guidance is that the reference should be a full-length commit SHA; the short/abbreviated SHA form is explicitly discouraged as insecure.[3] Also consider enforcing this via GitHub Actions policy: - GitHub introduced an “allowed actions policy” capability to enforce SHA pinning; workflows that attempt to use an action that isn’t pinned to a full commit SHA will fail the check.[4] Why “full commit SHA only” matters (vs tags): - GitHub explains that SHA pinning helps mitigate backdoors because an attacker would need to generate a SHA-1 collision for a valid Git object payload.[1] - GitHub also notes that pinning to tags is less secure and depends on trusting the creator; even then, tags can be moved/deleted.[1][2] Practical hardening tips (beyond pinning): - Audit the action’s source code and behavior with respect to how it handles repository contents and secrets.[2][5]
Citations:
Pin all GitHub Actions
uses:references to full commit SHAs in.github/workflows/publish.yml(including the OIDC publish job).This workflow trusts movable tags for:
actions/checkout@v6(line 22)astral-sh/setup-uv@v8.1.0(lines 25, 61)actions/upload-artifact@v4(line 36)actions/download-artifact@v4(line 55)Because the
publishjob hasid-token: write, a retagged action could tamper with whatuv publishpublishes. GitHub guidance recommends full-length commit SHAs for immutable action references. https://docs.github.com/en/actions/reference/security/secure-use🧰 Tools
🪛 zizmor (1.25.2)
[warning] 21-22: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 22-22: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[error] 25-25: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[error] 25-25: runtime artifacts potentially vulnerable to a cache poisoning attack (cache-poisoning): this step
(cache-poisoning)
🤖 Prompt for AI Agents