-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
Some tweaks to is_in_or_equal #9020
Conversation
🪼 branch checks and previews
Install Gradio from this PR pip install https://gradio-pypi-previews.s3.amazonaws.com/8bc4c39139dd33fac41dce5e469886345407e165/gradio-4.40.0-py3-none-any.whl Install Gradio Python Client from this PR pip install "gradio-client @ git+https://github.com/gradio-app/gradio@8bc4c39139dd33fac41dce5e469886345407e165#subdirectory=client/python" Install Gradio JS Client from this PR npm install https://gradio-npm-previews.s3.amazonaws.com/8bc4c39139dd33fac41dce5e469886345407e165/gradio-client-1.4.0.tgz |
@@ -1466,3 +1459,23 @@ def __len__(self): | |||
|
|||
def as_list(self): | |||
return [v for _, v in self.data] | |||
|
|||
|
|||
def safe_join(directory: DeveloperPath, path: UserProvidedPath) -> str: |
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.
Using these custom types so that in the future user provided paths are not accidentally sanitized before being joined
* asd * asd * asd * asd * asd * asd * asd * asd * asd * asd * asd * asd * asd * asd
* asd * asd * asd * asd * asd * asd * asd * asd * asd * asd * asd * asd * asd * asd * :[
* add max/min-imize and zoom in and out to image preview * add full screen icon to gallery * add stories * add changeset * use native full screen api * remove zoom in/out * add changeset * tweaks * remove zoom prop * fix ui test * add annotated image btns * add changeset * format * ruff format * fix test * remove * tweak * fix test * format * amend bool check --------- Co-authored-by: gradio-pr-bot <[email protected]> Co-authored-by: pngwn <[email protected]>
* asd * asd * asd * asd * asd * asd * asd * asd * asd * asd * asd * asd * asd * asd * :[ * asd
* asd * asd * asd
* asd * asd * asd * asd
* asd * asd * asd * asd * adsa * asd
* asd * asd * asd * asd * adsa * asd * asd
* better header for mobile * add changeset * nicer border * style header * better search overlay * responsive changes * more mobile responsiveness * docs and guides mobile responsive * formatting * fix get started button * fix header * test without lite * formatting * secondary menu docs * fix type overflow in paramtable * playground header * playground on mobile * small changes * formatting * formatting --------- Co-authored-by: gradio-pr-bot <[email protected]>
* asd * asd * asd * asd * adsa * asd * asd * asd
* asd * asd * asd * asd * adsa * asd * asd * asd * fix
* fix * asd
🦄 change detectedThis Pull Request includes changes to the following packages.
With the following changelog entry.
Maintainers or the PR author can modify the PR title to modify this entry.
|
test/test_utils.py
Outdated
path_2=create_path_string(), | ||
) | ||
def test_is_in_or_equal_fuzzer(path_1, path_2): | ||
print(path_1, path_2) |
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.
print(path_1, path_2) |
gradio/routes.py
Outdated
] | ||
|
||
def routes_safe_join(directory: DeveloperPath, path: UserProvidedPath) -> str: | ||
"""Safely join the user path to the directory while performing some additional http-related checks.""" |
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.
Nice this makes sense. Perhaps worth mentioning the checks explicitly here:
"""Safely join the user path to the directory while performing some additional http-related checks.""" | |
"""Safely join the user path to the directory while performing some additional http-related checks, e.g. ensuring that the full path exists on the local file system and is not a directory.""" |
@@ -543,7 +559,7 @@ async def file(path_or_url: str, request: fastapi.Request): | |||
|
|||
is_dir = abs_path.is_dir() | |||
|
|||
if in_blocklist or is_dir: | |||
if is_dir or in_blocklist: |
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.
curious why :)
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.
Typo hehe. Originally moved is_blocklist
to be a separate check but realized we don't have to do that
gradio/routes.py
Outdated
temp_file.file.close() | ||
# we need to move the temp file to the cache directory | ||
# but that's possibly blocking and we're in an async function | ||
# but that's possibl y blocking and we're in an async function |
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.
# but that's possibl y blocking and we're in an async function | |
# but that's possibly blocking and we're in an async function |
test/test_routes.py
Outdated
import tempfile | ||
from pathlib import Path |
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.
nit: might as well put these imports at the top of the file?
gradio/utils.py
Outdated
@@ -1090,7 +1083,7 @@ def is_in_or_equal(path_1: str | Path, path_2: str | Path): | |||
return ".." not in str(relative_path) | |||
except ValueError: | |||
return False | |||
return True | |||
return False |
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.
When is this ever used? It seems like the function should terminate by lines 1083 or 1085 at the latest
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.
Yes this is right - I think we can remove but just kept because I figured it was there for a reason lol
|
||
if path.is_absolute(): | ||
return path | ||
return Path(os.path.abspath(str(path))) |
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.
Ok so the reason we used the convoluted symlink logic is because of this issue: #3024
Basically, we don't want to resolve symlinks but we do want to make them absolute. This fix might work, let me check
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.
Ok so this should work, nice! I would just add a test case in test_utils.py to confirm that symlinks are made absolute but not resolved.
gradio/components/file_explorer.py
Outdated
def _safe_join(self, folders: list[str]): | ||
if not folders or len(folders) == 0: | ||
return self.root_dir | ||
head, tail = folders[0], folders[1:] |
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.
What's the purpose of splitting head and tail? Why can't we do combined_path = UserProvidedPath(os.path.join(*folders))
directly
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.
It was originally like that but then I ran into errors in the functional tests. I thought it was because os.path.join
couldn't handle a single argument but it's actually because the list was empty.
So long story short, I think we can use the line you're suggesting since I added the empty list check right above.
gradio/components/file_explorer.py
Outdated
@@ -85,7 +86,7 @@ def __init__( | |||
) | |||
root_dir = root | |||
self._constructor_args[0]["root_dir"] = root | |||
self.root_dir = os.path.abspath(root_dir) | |||
self.root_dir = cast(DeveloperPath, os.path.abspath(root_dir)) |
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.
could we do DeveloperPath(os.path.abspath(root_dir))
instead of using casting?
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.
Also applies to casting in routes.py, can we replace all casting with just directly creating the DeveloperPath with a string?
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.
Awesome PR @freddyaboulton! I went through and reviewed it as thoroughly as I good and everything lgtm. Just a few nits above
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.
LGTM, some small comments but great work freddy
Thanks for the reviews! I've addressed all of the comments |
Description
DeveloperPath
andUserProvidedPath
type aliases to make it clearer what each argument of safe join should be🎯 PRs Should Target Issues
Before your create a PR, please check to see if there is an existing issue for this change. If not, please create an issue before you create this PR, unless the fix is very small.
Not adhering to this guideline will result in the PR being closed.
Tests
PRs will only be merged if tests pass on CI. To run the tests locally, please set up your Gradio environment locally and run the tests:
bash scripts/run_all_tests.sh
You may need to run the linters:
bash scripts/format_backend.sh
andbash scripts/format_frontend.sh