-
-
Notifications
You must be signed in to change notification settings - Fork 5.9k
security: default Studio host to 127.0.0.1 and prompt before auto-start #4864
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
Closed
Closed
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
b4cae48
security: default Studio host to 127.0.0.1 and prompt before auto-start
claude e445b0d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] 9b6bc70
Merge branch 'main' into main
rolandtannous 7156253
Merge branch 'main' into main
Bedrovelsen 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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| # SPDX-License-Identifier: AGPL-3.0-only | ||
| # Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0 | ||
|
|
||
| """Tests that Unsloth Studio defaults to 127.0.0.1 (loopback) not 0.0.0.0. | ||
|
|
||
| TDD: these tests should FAIL before the host default changes are applied, | ||
| and PASS afterwards. | ||
|
|
||
| Uses AST parsing to inspect source-level defaults without requiring the | ||
| full studio venv (run.py has heavy dependencies like structlog/uvicorn). | ||
|
|
||
| Run with: | ||
| cd studio/backend | ||
| python -m pytest tests/test_host_defaults.py -v | ||
| """ | ||
|
|
||
| import ast | ||
| from pathlib import Path | ||
|
|
||
| import pytest | ||
|
|
||
| _RUN_PY = Path(__file__).resolve().parent.parent / "run.py" | ||
|
|
||
|
|
||
| def _parse_function_param_defaults(source: str, func_name: str) -> dict: | ||
| """Return {param_name: default_value} for a named function in *source*. | ||
|
|
||
| Only handles ast.Constant defaults (strings, ints, bools). | ||
| """ | ||
| tree = ast.parse(source) | ||
| for node in ast.walk(tree): | ||
| if ( | ||
| isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)) | ||
| and node.name == func_name | ||
| ): | ||
| result = {} | ||
| all_args = node.args.args | ||
| defaults = node.args.defaults | ||
| # Defaults are right-aligned against the args list | ||
| offset = len(all_args) - len(defaults) | ||
| for i, default in enumerate(defaults): | ||
| arg_name = all_args[offset + i].arg | ||
| if isinstance(default, ast.Constant): | ||
| result[arg_name] = default.value | ||
| return result | ||
| return {} | ||
|
|
||
|
|
||
| def _parse_argparse_add_argument_default(source: str, option_name: str) -> "str | None": | ||
| """Return the 'default' kwarg value for add_argument(option_name, ...) in *source*. | ||
|
|
||
| Only handles ast.Constant defaults. | ||
| """ | ||
| tree = ast.parse(source) | ||
| for node in ast.walk(tree): | ||
| if not isinstance(node, ast.Call): | ||
| continue | ||
| # Match: parser.add_argument("--host", ...) | ||
| func = node.func | ||
| if not (isinstance(func, ast.Attribute) and func.attr == "add_argument"): | ||
| continue | ||
| if not node.args: | ||
| continue | ||
| first_arg = node.args[0] | ||
| if not (isinstance(first_arg, ast.Constant) and first_arg.value == option_name): | ||
| continue | ||
| for kw in node.keywords: | ||
| if kw.arg == "default" and isinstance(kw.value, ast.Constant): | ||
| return kw.value.value | ||
| return None | ||
|
|
||
|
|
||
| def test_run_server_default_host_is_loopback(): | ||
| """run_server() parameter default for 'host' must be 127.0.0.1, not 0.0.0.0. | ||
|
|
||
| Binding to 0.0.0.0 by default exposes the service on all network | ||
| interfaces, contradicting the documented "privacy first / 100% local" | ||
| guarantee. Loopback (127.0.0.1) is the least-permissive default; | ||
| users who need network access can pass -H 0.0.0.0 explicitly. | ||
| """ | ||
| source = _RUN_PY.read_text() | ||
| defaults = _parse_function_param_defaults(source, "run_server") | ||
| assert ( | ||
| "host" in defaults | ||
| ), "run_server() must have a 'host' parameter with a default" | ||
| host_default = defaults["host"] | ||
| assert host_default == "127.0.0.1", ( | ||
| f"run_server() host default must be '127.0.0.1' (loopback) " | ||
| f"but got '{host_default}'. Binding to '{host_default}' by default " | ||
| f"exposes the service beyond localhost." | ||
| ) | ||
|
|
||
|
|
||
| def test_argparse_default_host_is_loopback(): | ||
| """_make_argument_parser() --host add_argument default must be 127.0.0.1. | ||
|
|
||
| When run.py is invoked directly (python run.py), the argparse default | ||
| should match the function default so direct execution is equally safe. | ||
| """ | ||
| source = _RUN_PY.read_text() | ||
| host_default = _parse_argparse_add_argument_default(source, "--host") | ||
| assert host_default is not None, ( | ||
| "Could not find add_argument('--host', ...) in run.py; " | ||
| "ensure _make_argument_parser() contains it." | ||
| ) | ||
| assert ( | ||
| host_default == "127.0.0.1" | ||
| ), f"run.py argparse --host default must be '127.0.0.1', got '{host_default}'" |
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.
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.
The manual command hint correctly suggests adding
-H 0.0.0.0for network access. However, there is an inconsistency in theNew-StudioShortcutsfunction (specifically the$launcherContenthere-string at line 381), which still has-H 0.0.0.0hardcoded in the$studioCommandvariable. This should be updated to match the new security defaults so that the desktop shortcut also binds to127.0.0.1by default, ensuring consistency with the changes made to theinstall.shlauncher template.