From b3e38a5468ad8f9cb4239dd4121db792981b9854 Mon Sep 17 00:00:00 2001 From: saikumarvasa100-hash Date: Thu, 13 Nov 2025 14:28:34 +0530 Subject: [PATCH 1/4] feat: use OS port selection for OAuth server - Replace manual port range iteration with OS port selection (port 0) - Remove USABLE_PORT_RANGE constant as it's no longer needed - Simplify code by letting OS automatically assign available port Fixes #913 --- ggshield/verticals/auth/oauth.py | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/ggshield/verticals/auth/oauth.py b/ggshield/verticals/auth/oauth.py index 73fc4f91e5..ed6d652db8 100644 --- a/ggshield/verticals/auth/oauth.py +++ b/ggshield/verticals/auth/oauth.py @@ -28,11 +28,6 @@ CLIENT_ID = "ggshield_oauth" SCAN_SCOPE = "scan" -# potential port range to be used to run local server -# to handle authorization code callback -# this is the largest band of not commonly occupied ports -# https://stackoverflow.com/questions/10476987/best-tcp-port-number-range-for-internal-applications -USABLE_PORT_RANGE = (29170, 29998) logger = logging.getLogger(__name__) @@ -71,7 +66,7 @@ def __init__(self, config: Config, instance: str) -> None: self._access_token: Optional[str] = None # If the PAT expiration date has been enforced to respect the workspace policy self._expire_at_downsized: bool = False - self._port = USABLE_PORT_RANGE[0] + self._port = 0 self.server: Optional[HTTPServer] = None self._generate_pkce_pair() @@ -163,19 +158,14 @@ def _redirect_to_login(self) -> None: webbrowser.open_new_tab(request_uri) def _prepare_server(self) -> None: - for port in range(*USABLE_PORT_RANGE): - try: - self.server = HTTPServer( - # only consider requests from localhost on the predetermined port - ("127.0.0.1", port), - functools.partial(RequestHandler, self), - ) - self._port = port - break - except OSError: - continue - else: - raise UnexpectedError("Could not find unoccupied port.") + try: + self.server = HTTPServer( + ("127.0.0.1", 0), # Let OS choose an available port + functools.partial(RequestHandler, self), + ) + self._port = self.server.server_port # Get the assigned port + except OSError as e: + raise UnexpectedError(f"Could not create local server: {e}") def _wait_for_callback(self) -> None: """ From baacc4a3cf4b49eb3f55ba345eb9f021c76ecf1c Mon Sep 17 00:00:00 2001 From: saikumarvasa100-hash Date: Fri, 14 Nov 2025 09:56:40 +0530 Subject: [PATCH 2/4] fix: move server_port assignment inside try block Fixes AttributeError by ensuring server_port is accessed only after successful HTTPServer creation --- ggshield/verticals/auth/oauth.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ggshield/verticals/auth/oauth.py b/ggshield/verticals/auth/oauth.py index ed6d652db8..a3dffdc5db 100644 --- a/ggshield/verticals/auth/oauth.py +++ b/ggshield/verticals/auth/oauth.py @@ -164,6 +164,7 @@ def _prepare_server(self) -> None: functools.partial(RequestHandler, self), ) self._port = self.server.server_port # Get the assigned port + except OSError as e: raise UnexpectedError(f"Could not create local server: {e}") From 9b6eded5976c6c01e7b26881e0c799a85ba3fcf6 Mon Sep 17 00:00:00 2001 From: saikumarvasa100-hash Date: Fri, 14 Nov 2025 10:00:13 +0530 Subject: [PATCH 3/4] docs: add changelog fragment for OAuth port fix Add changelog entry documenting the fix for OAuth server port allocation issue --- changelog.d/20241114_oauth_port_fix.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changelog.d/20241114_oauth_port_fix.md diff --git a/changelog.d/20241114_oauth_port_fix.md b/changelog.d/20241114_oauth_port_fix.md new file mode 100644 index 0000000000..f2e32e092e --- /dev/null +++ b/changelog.d/20241114_oauth_port_fix.md @@ -0,0 +1,3 @@ +### Fixed + +- Fixed OAuth server initialization that caused AttributeError when OS could not allocate a port. The server_port is now accessed only after successful HTTPServer creation. From 86bd0c1f30304a2387666ab464757c7d7a6f20c9 Mon Sep 17 00:00:00 2001 From: saikumarvasa100-hash Date: Fri, 21 Nov 2025 22:17:17 +0530 Subject: [PATCH 4/4] fix: remove blank line to fix black formatting --- ggshield/verticals/auth/oauth.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ggshield/verticals/auth/oauth.py b/ggshield/verticals/auth/oauth.py index a3dffdc5db..64ba286a66 100644 --- a/ggshield/verticals/auth/oauth.py +++ b/ggshield/verticals/auth/oauth.py @@ -165,7 +165,6 @@ def _prepare_server(self) -> None: ) self._port = self.server.server_port # Get the assigned port - except OSError as e: raise UnexpectedError(f"Could not create local server: {e}") def _wait_for_callback(self) -> None: