-
Notifications
You must be signed in to change notification settings - Fork 2
fix(bot): מספר קבצים בהודעות ZIP + שלב בחירת שם ל-ZIP #3194
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
Merged
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
4fdfcc7
feat(mcp): פתקים דביקים — צפייה, יצירה ועריכה דרך ה-MCP
claude fd6b706
feat(webapp): קיצור דרך לעריכת תיאור מתפריט ⋮ בעמוד הקובץ
claude e97bee5
Merge branch 'main' into claude/mcp-codekeeper-webapp-ldnzsg
amirbiron 9218b77
fix(webapp): תבנית חדשה מגיעה מיד אחרי deploy (ETag כולל גרסת deploy)
claude e745b7e
Merge branch 'main' into claude/mcp-codekeeper-webapp-ldnzsg
amirbiron 71e3264
feat(webapp): אייקון תיאור על קבצים באוסף + מודאל תצוגה
claude 7ea470a
feat(webapp): הזזת אייקון תיאור בכרטיס אוסף + ארכיון לאוספים
claude 26b25b6
Merge origin/main: יישור הענף מול main + פתרון קונפליקט collections.css
claude 991b1ad
fix(webapp): המרת צבעים קשיחים לטוקני ערכה במודאל התיאור ובכפתור הארכיון
claude afa7b6d
Merge origin/main: יישור מול main אחרי squash של #3192 + פתרון קונפלי…
claude c7c49a3
fix(bot): תיקון מספר קבצים בהודעות ZIP + שלב בחירת שם ל-ZIP
claude bab0701
Merge branch 'main' into claude/mcp-codekeeper-webapp-ldnzsg
amirbiron fd88aa0
fix(bot): הקשחת יצירת ZIP — ניקוי שמות (Zip-Slip), מגבלות איסוף, to_t…
claude 85bcfa9
fix(bot): הקשחת ZIP סבב 2 — מגבלות לפני הורדה, מניעת שמות כפולים, תיק…
claude File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| """טסטים לכלי בניית ה-ZIP המרוכז ב-utils (הגנת Zip-Slip + מגבלות איסוף). | ||
|
|
||
| חשוב אבטחתית: safe_zip_entry_name מנרמל שמות רשומה לשם בסיס בטוח (בלי נתיב מוחלט/ | ||
| מקונן/"..") ו-build_zip_bytes אוכף מגבלת מספר קבצים וגודל מצטבר. נבדק ע"י פענוח ה-ZIP. | ||
| """ | ||
|
|
||
| import zipfile | ||
| from io import BytesIO | ||
|
|
||
| from utils import ( | ||
| safe_zip_entry_name, | ||
| build_zip_bytes, | ||
| ZIP_CREATE_MAX_FILES, | ||
| ZIP_CREATE_MAX_TOTAL_BYTES, | ||
| ) | ||
|
|
||
|
|
||
| def _names(zip_bytes): | ||
| with zipfile.ZipFile(BytesIO(zip_bytes)) as z: | ||
| return z.namelist() | ||
|
|
||
|
|
||
| def test_safe_zip_entry_name_strips_paths(): | ||
| # basename בלבד — שום רכיב נתיב לא שורד | ||
| assert safe_zip_entry_name("../../etc/passwd") == "passwd" | ||
| assert safe_zip_entry_name("/abs/path/x.py") == "x.py" | ||
| assert safe_zip_entry_name("a\\b\\c.txt") == "c.txt" | ||
| assert safe_zip_entry_name("plain.md") == "plain.md" | ||
| # שמות מסוכנים "טהורים" נופלים ל-fallback | ||
| assert safe_zip_entry_name("..", fallback="f") == "f" | ||
| assert safe_zip_entry_name(".", fallback="f") == "f" | ||
| assert safe_zip_entry_name("", fallback="f") == "f" | ||
| assert safe_zip_entry_name(None, fallback="f") == "f" | ||
|
|
||
|
|
||
| def test_build_zip_sanitizes_entry_names(): | ||
| items = [ | ||
| {"filename": "../../etc/passwd", "bytes": b"x"}, | ||
| {"filename": "/abs/evil.sh", "bytes": b"y"}, | ||
| {"filename": "ok.txt", "bytes": b"z"}, | ||
| ] | ||
| names = _names(build_zip_bytes(items)) | ||
| # אף רשומה ללא מפריד נתיב או ".." | ||
| assert all("/" not in n and "\\" not in n and ".." not in n for n in names) | ||
| assert not any(n.startswith("/") for n in names) | ||
| assert set(names) == {"passwd", "evil.sh", "ok.txt"} | ||
|
|
||
|
|
||
| def test_build_zip_enforces_max_files(): | ||
| items = [{"filename": f"f{i}.txt", "bytes": b"x"} for i in range(10)] | ||
| names = _names(build_zip_bytes(items, max_files=3)) | ||
| assert len(names) == 3 | ||
|
|
||
|
|
||
| def test_build_zip_enforces_max_total_bytes(): | ||
| items = [ | ||
| {"filename": "a.bin", "bytes": b"0" * 600}, | ||
| {"filename": "b.bin", "bytes": b"1" * 600}, # 600+600=1200 > 1000 ⇒ נעצר לפני | ||
| {"filename": "c.bin", "bytes": b"2" * 600}, | ||
| ] | ||
| names = _names(build_zip_bytes(items, max_total_bytes=1000)) | ||
| assert names == ["a.bin"] | ||
|
|
||
|
|
||
| def test_build_zip_skips_missing_names_with_fallback(): | ||
| items = [ | ||
| {"filename": None, "bytes": b"content"}, # שם חסר ⇒ fallback file_1 | ||
| {"bytes": b"nofield"}, # ללא מפתח filename ⇒ fallback file_2 | ||
| ] | ||
| names = _names(build_zip_bytes(items)) | ||
| assert names == ["file_1", "file_2"] | ||
|
|
||
|
|
||
| def test_build_zip_disambiguates_duplicate_names(): | ||
| # מקורות שונים שמנורמלים לאותו שם — לא נדרסים; הבאים מקבלים סיומת ממספרת עם שמירת הסיומת | ||
| items = [ | ||
| {"filename": "a/x.txt", "bytes": b"1"}, | ||
| {"filename": "b/x.txt", "bytes": b"2"}, | ||
| {"filename": "c/x.txt", "bytes": b"3"}, | ||
| ] | ||
| names = _names(build_zip_bytes(items)) | ||
| assert names == ["x.txt", "x_2.txt", "x_3.txt"] | ||
| assert len(set(names)) == 3 | ||
|
|
||
|
|
||
| def test_defaults_are_sane(): | ||
| assert ZIP_CREATE_MAX_FILES == 50 | ||
| assert ZIP_CREATE_MAX_TOTAL_BYTES == 45 * 1024 * 1024 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.