-
Notifications
You must be signed in to change notification settings - Fork 0
๐ก๏ธ Sentinel: [CRITICAL] ๋ช ๋ น์ด ์ธ์ ์ ๋ณด์ ์ทจ์ฝ์ ๊ฐ์ (B603) #808
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
base: main
Are you sure you want to change the base?
Changes from all commits
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 |
|---|---|---|
|
|
@@ -11,8 +11,11 @@ | |
| import subprocess | ||
| import sys | ||
| import tempfile | ||
| import ipaddress | ||
| import socket | ||
| import time | ||
| import urllib.error | ||
| import urllib.parse | ||
| import urllib.request | ||
| from collections.abc import Sequence | ||
| from dataclasses import dataclass | ||
|
|
@@ -121,6 +124,20 @@ def wait_for_url(url: str, timeout: int, service: Service) -> bool: | |
| return True | ||
| if not (url.startswith("http://") or url.startswith("https://")): | ||
| raise ValueError(f"URL must start with http:// or https://, got: {url}") | ||
|
|
||
| parsed = urllib.parse.urlparse(url) | ||
| if not parsed.hostname: | ||
| raise ValueError(f"URL missing hostname: {url}") | ||
|
|
||
| try: | ||
| ip = socket.gethostbyname(parsed.hostname) | ||
| ip_obj = ipaddress.ip_address(ip) | ||
| if ip_obj.is_private or ip_obj.is_loopback: | ||
| if not os.environ.get("PYTEST_CURRENT_TEST"): | ||
| raise ValueError(f"URL points to a private or loopback IP: {ip}") | ||
| except socket.gaierror: | ||
| pass # Will fail to connect anyway | ||
|
|
||
|
Comment on lines
+132
to
+140
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. ๐ Security & Privacy | ๐ด Critical | ๐๏ธ Heavy lift ๐งฉ Analysis chain๐ Script executed: #!/bin/bash
set -euo pipefail
rg -n -C 6 \
'socket\.gethostbyname|socket\.getaddrinfo|opener\.open|PYTEST_CURRENT_TEST' \
scripts/ci/sandboxed_web_e2e.pyRepository: ContextualWisdomLab/.github Length of output: 1245 ๐ Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- target file outline ---'
ast-grep outline scripts/ci/sandboxed_web_e2e.py
printf '%s\n' '--- target implementation ---'
sed -n '1,190p' scripts/ci/sandboxed_web_e2e.py
printf '%s\n' '--- related tests and callers ---'
rg -n -C 5 \
'sandboxed_web_e2e|wait_for|NoRedirectHandler|PYTEST_CURRENT_TEST|gethostbyname|getaddrinfo' \
scripts tests .github 2>/dev/null || trueRepository: ContextualWisdomLab/.github Length of output: 50383 ๐ Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- readiness tests ---'
sed -n '100,275p' tests/test_sandboxed_web_e2e.py
printf '%s\n' '--- configuration and workflow call sites ---'
rg -n -C 4 \
'sandboxed_web_e2e\.py|backend-ready-url|frontend-ready-url|backend_ready_url|frontend_ready_url' \
.github scripts tests \
-g '*.yml' -g '*.yaml' -g '*.py' -g '*.sh' -g '*.md' 2>/dev/null | head -n 240
printf '%s\n' '--- coverage configuration ---'
rg -n -C 3 \
'coverage|interrogate|testpaths|scripts/ci' \
pyproject.toml setup.cfg tox.ini .coveragerc Makefile 2>/dev/null || trueRepository: ContextualWisdomLab/.github Length of output: 20508 ๐ Script executed: #!/bin/bash
set -euo pipefail
python3 - <<'PY'
import ast
import inspect
import ipaddress
import socket
import urllib.request
import http.client
path = "scripts/ci/sandboxed_web_e2e.py"
tree = ast.parse(open(path, encoding="utf-8").read(), filename=path)
wait = next(
node for node in ast.walk(tree)
if isinstance(node, ast.FunctionDef) and node.name == "wait_for_url"
)
checks = {
"uses_gethostbyname": False,
"suppresses_gaierror": False,
"opens_original_url": False,
}
for node in ast.walk(wait):
if isinstance(node, ast.Call) and isinstance(node.func, ast.Attribute):
if node.func.attr == "gethostbyname":
checks["uses_gethostbyname"] = True
if node.func.attr == "open" and node.args:
checks["opens_original_url"] = isinstance(node.args[0], ast.Name) and node.args[0].id == "url"
if isinstance(node, ast.ExceptHandler):
if isinstance(node.type, ast.Attribute) and node.type.attr == "gaierror":
checks["suppresses_gaierror"] = any(isinstance(stmt, ast.Pass) for stmt in node.body)
print("AST checks:", checks)
print("IPv6 literal gethostbyname behavior:")
try:
socket.gethostbyname("::1")
except socket.gaierror as exc:
print(type(exc).__name__, str(exc))
print("ipaddress ::1:", ipaddress.ip_address("::1"), "loopback=", ipaddress.ip_address("::1").is_loopback)
print("urllib connection resolution call:")
source = inspect.getsource(http.client.HTTPConnection.connect)
for line in source.splitlines():
if "create_connection" in line or "self.host" in line:
print(line.strip())
print("all checks passed:", all(checks.values()))
PYRepository: ContextualWisdomLab/.github Length of output: 550 ๐ Script executed: #!/bin/bash
set -euo pipefail
python3 - <<'PY'
import ast
import inspect
import ipaddress
import socket
import http.client
path = "scripts/ci/sandboxed_web_e2e.py"
tree = ast.parse(open(path, encoding="utf-8").read(), filename=path)
wait = next(
node for node in ast.walk(tree)
if isinstance(node, ast.FunctionDef) and node.name == "wait_for_url"
)
checks = {
"uses_gethostbyname": False,
"suppresses_gaierror": False,
"opens_original_url": False,
}
for node in ast.walk(wait):
if isinstance(node, ast.Call) and isinstance(node.func, ast.Attribute):
if node.func.attr == "gethostbyname":
checks["uses_gethostbyname"] = True
if node.func.attr == "open" and node.args:
checks["opens_original_url"] = isinstance(node.args[0], ast.Name) and node.args[0].id == "url"
if isinstance(node, ast.ExceptHandler):
if isinstance(node.type, ast.Attribute) and node.type.attr == "gaierror":
checks["suppresses_gaierror"] = any(isinstance(stmt, ast.Pass) for stmt in node.body)
print("AST checks:", checks)
print("IPv6 literal gethostbyname behavior:")
try:
socket.gethostbyname("::1")
except socket.gaierror as exc:
print(type(exc).__name__, str(exc))
print("ipaddress ::1:", ipaddress.ip_address("::1"), "loopback=", ipaddress.ip_address("::1").is_loopback)
print("urllib connection resolution call:")
source = inspect.getsource(http.client.HTTPConnection.connect)
for line in source.splitlines():
if "create_connection" in line or "self.host" in line:
print(line.strip())
print("all checks passed:", all(checks.values()))
PYRepository: ContextualWisdomLab/.github Length of output: 550 ๊ฒ์ฆํ ์ฃผ์๋ฅผ ์ค์ ์ฐ๊ฒฐ์ ๊ณ ์ ํ๊ณ DNS ์ค๋ฅ๋ฅผ ๊ฑฐ๋ถํ์ธ์.
๋ชจ๋ ์ฃผ์๋ฅผ ๐ค Prompt for AI Agents |
||
| deadline = time.monotonic() + timeout | ||
| opener = urllib.request.build_opener(NoRedirectHandler()) | ||
| while time.monotonic() < deadline: | ||
|
|
||
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.
๐ฉบ Stability & Availability | ๐ Major | ๐๏ธ Heavy lift
๐งฉ Analysis chain
๐ Script executed:
Repository: ContextualWisdomLab/.github
Length of output: 1090
๐ Script executed:
Repository: ContextualWisdomLab/.github
Length of output: 50383
๐ Script executed:
Repository: ContextualWisdomLab/.github
Length of output: 20974
๐ Script executed:
Repository: ContextualWisdomLab/.github
Length of output: 1020
๐ Script executed:
Repository: ContextualWisdomLab/.github
Length of output: 972
DNS ์กฐํ๊ฐ
startup-timeout์ ์ฐํํ์ง ์๊ฒ ํ์ธ์.socket.gethostbyname()์ดdeadline๊ณ์ฐ๋ณด๋ค ๋จผ์ ์คํ๋ฉ๋๋ค. DNS resolver๊ฐ ์ง์ฐ๋๋ฉด readiness ๊ฒ์ฌ๊ฐstartup-timeout๋ณด๋ค ์ค๋ ์ฐจ๋จ๋๊ณmain์ ์๋น์ค ์ ๋ฆฌ๊ฐ ์คํ๋์ง ์์ต๋๋ค.deadline์ DNS ์กฐํ ์ ์ ๊ณ์ฐํ๊ณ , resolver ์์ฒด์ ๋ช ์์ ์ ํ ์๊ฐ์ ์ ์ฉํ์ธ์.๐ค Prompt for AI Agents