Skip to content

Commit f5bfcdc

Browse files
committed
fix: mnist test RHOAI 3.0
1 parent 67df4f5 commit f5bfcdc

File tree

2 files changed

+83
-12
lines changed

2 files changed

+83
-12
lines changed

src/codeflare_sdk/ray/cluster/config.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,8 @@ def _validate_types(self):
226226
"""Validate the types of all fields in the ClusterConfiguration dataclass."""
227227
errors = []
228228
for field_info in fields(self):
229+
if field_info.name == "appwrapper":
230+
continue
229231
value = getattr(self, field_info.name)
230232
expected_type = field_info.type
231233
if not self._is_type(value, expected_type):

tests/e2e/mnist_raycluster_sdk_oauth_test.py

Lines changed: 81 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,18 @@ def run_mnist_raycluster_sdk_oauth(self):
7676

7777
def assert_jobsubmit_withoutLogin(self, cluster):
7878
dashboard_url = cluster.cluster_dashboard_uri()
79+
80+
# Verify that job submission is actually blocked by attempting to submit without auth
81+
# The endpoint path depends on whether we're using HTTPRoute (with path prefix) or not
82+
if "/ray/" in dashboard_url:
83+
# HTTPRoute format: https://hostname/ray/namespace/cluster-name
84+
# API endpoint is at the same base path
85+
api_url = dashboard_url + "/api/jobs/"
86+
else:
87+
# OpenShift Route format: https://hostname
88+
# API endpoint is directly under the hostname
89+
api_url = dashboard_url + "/api/jobs/"
90+
7991
jobdata = {
8092
"entrypoint": "python mnist.py",
8193
"runtime_env": {
@@ -84,26 +96,83 @@ def assert_jobsubmit_withoutLogin(self, cluster):
8496
"env_vars": get_setup_env_variables(),
8597
},
8698
}
87-
try:
88-
response = requests.post(
89-
dashboard_url + "/api/jobs/", verify=False, json=jobdata
90-
)
91-
if response.status_code == 403:
92-
assert True
99+
100+
# Try to submit a job without authentication
101+
# Follow redirects to see the final response - if it redirects to login, that's still a failure
102+
response = requests.post(api_url, verify=False, json=jobdata, allow_redirects=True)
103+
104+
# Check if the submission was actually blocked
105+
# Success indicators that submission was blocked:
106+
# 1. Status code 403 (Forbidden)
107+
# 2. Status code 302 (Redirect to login) - but we need to verify the final response after redirect
108+
# 3. Status code 200 but with HTML content (login page) instead of JSON (job submission response)
109+
# 4. Status code 401 (Unauthorized)
110+
111+
submission_blocked = False
112+
113+
if response.status_code == 403:
114+
submission_blocked = True
115+
elif response.status_code == 401:
116+
submission_blocked = True
117+
elif response.status_code == 302:
118+
# Redirect happened - check if final response after redirect is also a failure
119+
# If we followed redirects, check the final status
120+
submission_blocked = True # Redirect to login means submission failed
121+
elif response.status_code == 200:
122+
# Check if response is HTML (login page) instead of JSON (job submission response)
123+
content_type = response.headers.get('Content-Type', '')
124+
if 'text/html' in content_type or 'application/json' not in content_type:
125+
# Got HTML (likely login page) instead of JSON - submission was blocked
126+
submission_blocked = True
93127
else:
94-
response.raise_for_status()
95-
assert False
96-
97-
except Exception as e:
98-
print(f"An unexpected error occurred. Error: {e}")
99-
assert False
128+
# Got JSON response - check if it's an error or actually a successful submission
129+
try:
130+
json_response = response.json()
131+
# If it's a successful job submission, it should have a 'job_id' or 'submission_id'
132+
# If it's an error, it might have 'error' or 'message'
133+
if 'job_id' in json_response or 'submission_id' in json_response:
134+
# Job was actually submitted - this is a failure!
135+
submission_blocked = False
136+
else:
137+
# Error response - submission was blocked
138+
submission_blocked = True
139+
except ValueError:
140+
# Not JSON - likely HTML login page
141+
submission_blocked = True
142+
143+
if not submission_blocked:
144+
assert False, f"Job submission succeeded without authentication! Status: {response.status_code}, Response: {response.text[:200]}"
145+
146+
# Also verify that RayJobClient cannot be used without authentication
147+
try:
148+
client = RayJobClient(address=dashboard_url, verify=False)
149+
# Try to call a method to trigger the connection and authentication check
150+
client.list_jobs()
151+
assert False, "RayJobClient succeeded without authentication - this should not be possible"
152+
except (requests.exceptions.JSONDecodeError, requests.exceptions.HTTPError, Exception):
153+
# Any exception is expected when trying to use the client without auth
154+
pass
155+
156+
assert True, "Job submission without authentication was correctly blocked"
100157

101158
def assert_jobsubmit_withlogin(self, cluster):
102159
auth_token = run_oc_command(["whoami", "--show-token=true"])
103160
ray_dashboard = cluster.cluster_dashboard_uri()
104161
header = {"Authorization": f"Bearer {auth_token}"}
105162
client = RayJobClient(address=ray_dashboard, headers=header, verify=False)
106163

164+
# Verify that no jobs were submitted during the previous unauthenticated test
165+
# This ensures that the authentication check in assert_jobsubmit_withoutLogin actually worked
166+
existing_jobs = client.list_jobs()
167+
if existing_jobs:
168+
job_ids = [job.job_id if hasattr(job, 'job_id') else str(job) for job in existing_jobs]
169+
assert False, (
170+
f"Found {len(existing_jobs)} existing job(s) before authenticated submission: {job_ids}. "
171+
"This indicates that the unauthenticated job submission test failed to properly block submission."
172+
)
173+
else:
174+
print("Verified: No jobs exist from the previous unauthenticated submission attempt.")
175+
107176
submission_id = client.submit_job(
108177
entrypoint="python mnist.py",
109178
runtime_env={

0 commit comments

Comments
 (0)