Skip to content
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

WIP: Add ModelMesh test for CVE-2024-7557 #1861

Open
wants to merge 43 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
8ce98fd
Add tests
rnetser Sep 18, 2024
73b24a5
add modelmesh tests
rnetser Sep 18, 2024
98c215d
Merge branch 'master' of https://github.com/red-hat-data-services/ods…
rnetser Sep 19, 2024
8bb6f88
Merge branch 'master' of https://github.com/red-hat-data-services/ods…
rnetser Sep 22, 2024
3f83bc6
add modelmesh tests
rnetser Sep 23, 2024
a7121e4
Merge branch 'master' of https://github.com/red-hat-data-services/ods…
rnetser Sep 23, 2024
b82028d
add modelmesh tests
rnetser Sep 24, 2024
d5feec2
Merge branch 'master' of https://github.com/red-hat-data-services/ods…
rnetser Sep 24, 2024
8000cbb
add modelmesh tests
rnetser Sep 24, 2024
2c0720d
add modelmesh tests
rnetser Sep 24, 2024
118abdd
add modelmesh tests
rnetser Sep 24, 2024
cdbb779
Merge branch 'master' of https://github.com/red-hat-data-services/ods…
rnetser Sep 24, 2024
f7d526c
add modelmesh tests
rnetser Sep 25, 2024
4048abf
add modelmesh tests
rnetser Sep 25, 2024
4409b52
Merge branch 'master' of https://github.com/red-hat-data-services/ods…
rnetser Sep 25, 2024
1e8f59b
add modelmesh tests
rnetser Sep 26, 2024
4c2a0fa
Merge branch 'master' of https://github.com/red-hat-data-services/ods…
rnetser Sep 26, 2024
15c0e39
add modelmesh tests
rnetser Sep 26, 2024
35fe0d1
add modelmesh tests
rnetser Sep 26, 2024
62cb00e
add modelmesh tests
rnetser Sep 26, 2024
db2230e
Merge branch 'master' of https://github.com/red-hat-data-services/ods…
rnetser Sep 26, 2024
ccd8051
add modelmesh tests
rnetser Sep 26, 2024
a8d618a
add modelmesh tests
rnetser Sep 26, 2024
09f70d0
Merge branch 'master' of https://github.com/red-hat-data-services/ods…
rnetser Sep 29, 2024
bcabc3c
resolve robocop comments
rnetser Sep 29, 2024
dba77d1
fix comments
rnetser Sep 29, 2024
aad7b58
fix comments
rnetser Sep 29, 2024
a3b1727
fix assign
rnetser Sep 30, 2024
ad89501
add runtime to token from ui
rnetser Sep 30, 2024
d7bfab1
add runtime to token from ui
rnetser Sep 30, 2024
d4a4a38
add runtime to token from ui
rnetser Sep 30, 2024
08f2918
add runtime to token from ui
rnetser Sep 30, 2024
7891842
add runtime to token from ui
rnetser Sep 30, 2024
4f57e46
add runtime to token from ui
rnetser Sep 30, 2024
c3a830d
update paths in project
rnetser Sep 30, 2024
001b8c8
Merge branch 'master' of https://github.com/red-hat-data-services/ods…
rnetser Sep 30, 2024
2db9d62
address robocop comments
rnetser Sep 30, 2024
5827368
fix ui
rnetser Oct 1, 2024
dfe44cb
Merge branch 'master' of https://github.com/red-hat-data-services/ods…
rnetser Oct 1, 2024
846f459
fix ui
rnetser Oct 1, 2024
78fe13f
update 2.13
rnetser Oct 1, 2024
2cfb81d
update 2.13
rnetser Oct 1, 2024
6d29aef
update 2.13
rnetser Oct 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,15 @@
*** Keywords ***
Create Model Server
[Documentation] Keyword to create a Model Server in a Data Science Project
[Arguments] ${no_replicas}=1 ${server_size}=Small ${ext_route}=${TRUE}
... ${token}=${TRUE} ${runtime}=OpenVINO Model Server ${server_name}=Model Serving Test
... ${no_gpus}=0 ${existing_server}=${FALSE}
[Arguments] ${no_replicas}=1
Fixed Show fixed Hide fixed
... ${server_size}=Small
... ${ext_route}=${TRUE}
... ${token}=${TRUE}
... ${runtime}=OpenVINO Model Server
... ${server_name}=Model Serving Test
... ${no_gpus}=0
... ${existing_server}=${FALSE}
... ${service_account_name}=${NONE}
Move To Tab Models
IF ${existing_server}
${existing_server}= Run Keyword And Return Status Wait Until Page Contains Element //button[.="${server_name}"]
Expand Down Expand Up @@ -63,8 +69,9 @@
Log message=Token Auth should be enabled by default..(from v2.5)
SeleniumLibrary.Checkbox Should Be Selected ${TOKEN_AUTH_CHECKBOX_XP}
END
ELSE IF ${token}==${TRUE}
Enable Token Authentication
END
IF ${token}
Enable Token Authentication service_account_name=${service_account_name}
END
SeleniumLibrary.Wait Until Element Is Enabled //button[contains(text(),"Add")]
SeleniumLibrary.Click Button Add
Expand Down Expand Up @@ -181,9 +188,10 @@
[Documentation] Enables Token authentication to serving route
[Arguments] ${service_account_name}=${NONE}
SeleniumLibrary.Select Checkbox ${TOKEN_AUTH_CHECKBOX_XP}
IF "${service_account_name}" != "${NONE}"
Input Service Account Name ${service_account_name}
IF "${service_account_name}" == "${NONE}"
${service_account_name}=default-name
Fixed Show fixed Hide fixed
END
Input Service Account Name ${service_account_name}

Disable Token Authentication
[Documentation] Disable Token authentication to serving route
Expand Down Expand Up @@ -218,7 +226,8 @@
${token}= Get Single Model Token ${service_account_name}
ELSE
SeleniumLibrary.Wait Until Page Contains Element xpath://td[@data-label="Tokens"]/button
SeleniumLibrary.Click Element xpath://td[@data-label="Tokens"]/button
SeleniumLibrary.Click Button
Fixed Show fixed Hide fixed
... xpath://*[@id="expand-table-row-${model_name}-1-undefined-1"]/../../td[@data-label='Tokens']//button
${token}= SeleniumLibrary.Get Element Attribute
... xpath://div[.="${service_account_name} "]/../../td[@data-label="Token Secret"]//input value
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Xpath can be inproved

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mwaykole please advise how

END
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ Resource ./Workbenches.resource
${DS_PROJECT_TITLE}= Data Science Projects
${TITLE_INPUT_XP}= xpath=//input[@id="manage-project-modal-name"]
${DESCR_INPUT_XP}= xpath=//textarea[@id="manage-project-modal-description"]
${RESOURCE_EDIT_BTN_XP}= xpath=//button[.="Edit resource name"]
${RESOURCE_INPUT_XP}= css:[data-testid="manage-project-modal-resourceName"]
${RESOURCE_INPUT_XP}= css:[data-testid="resource-manage-project-modal-name"]
rnetser marked this conversation as resolved.
Show resolved Hide resolved
${GENERIC_CREATE_BTN_XP}= xpath=//button[text()="Create"]
${GENERIC_CANCEL_BTN_XP}= xpath=//button[text()="Cancel"]
# TODO: Update to latter option once the change is pulled from ODH into downstream!
Expand Down Expand Up @@ -137,8 +136,6 @@ Create Data Science Project
ELSE
Wait Until Page Contains Element ${PROJECT_CREATE_BTN_XP}
Click Button ${PROJECT_CREATE_BTN_XP}
Wait Until Page Contains Element ${RESOURCE_EDIT_BTN_XP}
Click Button ${RESOURCE_EDIT_BTN_XP}
Wait Until Page Contains Element ${TITLE_INPUT_XP}
Run Keyword And Warn On Failure Element Should Be Disabled ${GENERIC_CREATE_BTN_XP}
Input Text ${TITLE_INPUT_XP} ${title}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,26 +75,10 @@
SeleniumLibrary.Click Button ${DEPLOY_MODEL_BTN}
END
SeleniumLibrary.Wait Until Page Contains Element //div[@role="dialog"]
Set Model Name ${model_name}
Select Model Server ${model_server}
IF "${serving_runtime}" != "${NONE}" Set Model Server Runtime ${serving_runtime}
SeleniumLibrary.Wait Until Page Contains Element xpath://span[.="Model framework (name - version)"]
Select Framework ${framework}
IF ${existing_data_connection}==${TRUE}
# Select Radio Button group_name=radiogroup value=existing-data-connection-radio
# Selected by default, let's skip for now
Select Existing Data Connection ${data_connection_name}
Set Folder Path ${model_path}
ELSE
# Existing connection radio is selected by default; for now blindly click on new connection radio
SeleniumLibrary.Click Element //input[@id="new-data-connection-radio"]
# Select Radio Button group_name=radiogroup value=new-data-connection-radio
Set Up New Data Connection dc_name=${data_connection_name}
Set Folder Path ${model_path}
END
SeleniumLibrary.Wait Until Element Is Enabled //button[contains(text(),"Deploy")]
SeleniumLibrary.Click Button Deploy
SeleniumLibrary.Wait Until Page Does Not Contain xpath://h1[.="Deploy model"]
Fill Deploy Model Form model_name=${model_name} model_server=${model_server}
... serving_runtime=${serving_runtime} framework=${framework}
... data_connection_name=${data_connection_name} existing_data_connection=${existing_data_connection}
... model_path=${model_path}

Select Project
[Documentation] Selects a project in the "deploy model" modal.
Expand Down Expand Up @@ -387,18 +371,11 @@
[Documentation] Deletes all currently deployed models, if any are present.
# Returns an empty list if no matching elements found
Switch Model Serving Project project_name=All projects
${projects}= Get WebElements xpath://table/tbody/tr/td[@data-label="Project"]
FOR ${project} IN @{projects}
${project}= Get Text ${project}
@{project description}= Split String ${project}
Switch Model Serving Project ${project description}[0]
${models}= Get WebElements xpath://table/tbody/tr/td[@data-label="Name"]/div/a
FOR ${model} IN @{models}
${model}= Get Text ${model}
Delete Model Via UI ${model}
Sleep 1s
END
Switch Model Serving Project project_name=All projects
${models}= Get WebElements xpath://table/tbody/tr/td[@data-label="Name"]/div/a
FOR ${model} IN @{models}
${model}= Get Text ${model}
Delete Model Via UI ${model}
Sleep 1s
END

Add Namespace To ServiceMeshMemberRoll
Expand Down Expand Up @@ -643,3 +620,53 @@
ELSE
Log message=Skipping UserWorkloadMonitoring enablement.
END

Deploy Model From Models Tab
[Documentation] Deploys a model from the project's Models tab
[Arguments] ${project_name}
Fixed Show fixed Hide fixed
... ${data_connection_name}
... ${model_name}
... ${framework}
... ${existing_data_connection}
... ${model_path}
... ${model_server}
... ${serving_runtime}=${NONE}
Open Data Science Project Details Page ${project_name} tab_id=model-server
SeleniumLibrary.Click Button
Fixed Show fixed Hide fixed
... xpath://*[@id="expand-table-row-${model_name}-1-undefined-1"]/../../td[@class='pf-v5-c-table__td']//button
SeleniumLibrary.Wait Until Page Contains Element //div[@role="dialog"]
Fill Deploy Model Form model_name=${model_name} model_server=${model_server}
... serving_runtime=${serving_runtime} framework=${framework}
... data_connection_name=${data_connection_name} existing_data_connection=${existing_data_connection}
... model_path=${model_path}

Fill Deploy Model Form
Fixed Show fixed Hide fixed
[Documentation] Fills the deploy model form
[Arguments] ${model_name}
Fixed Show fixed Hide fixed
... ${model_server}
... ${serving_runtime}
... ${framework}
... ${data_connection_name}
... ${existing_data_connection}
... ${model_path}
Set Model Name ${model_name}
Select Model Server ${model_server}
IF "${serving_runtime}" != "${NONE}" Set Model Server Runtime ${serving_runtime}
SeleniumLibrary.Wait Until Page Contains Element
Fixed Show fixed Hide fixed
... xpath://span[.="Model framework (name - version)"]
Select Framework ${framework}
IF ${existing_data_connection}
# Select Radio Button group_name=radiogroup value=existing-data-connection-radio
# Selected by default, let's skip for now
Select Existing Data Connection ${data_connection_name}
Set Folder Path ${model_path}
ELSE
# Existing connection radio is selected by default; for now blindly click on new connection radio
SeleniumLibrary.Click Element //input[@id="new-data-connection-radio"]
# Select Radio Button group_name=radiogroup value=new-data-connection-radio
Set Up New Data Connection dc_name=${data_connection_name}
Set Folder Path ${model_path}
END
SeleniumLibrary.Wait Until Element Is Enabled //button[contains(text(),"Deploy")]
SeleniumLibrary.Click Button Deploy
SeleniumLibrary.Wait Until Page Does Not Contain xpath://h1[.="Deploy model"]

Check warning

Code scanning / Robocop

File has too many lines ({{ lines_count }}/{{max_allowed_count }}) Warning test

File has too many lines (674/400)
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# robocop: off=too-long-test-case,too-many-calls-in-test-case,wrong-case-in-keyword-name
*** Settings ***
Documentation Suite of test cases for OVMS in Kserve
Documentation Suite of test cases for OVMS in Kserve and ModelMesh
Library OperatingSystem
Library ../../../libs/Helpers.py
Resource ../../Resources/Page/ODH/JupyterHub/HighAvailability.robot
Expand All @@ -11,9 +11,8 @@
Resource ../../Resources/Page/ODH/Monitoring/Monitoring.resource
Resource ../../Resources/OCP.resource
Resource ../../Resources/CLI/ModelServing/modelmesh.resource
Suite Setup Cross Auth On Kserve Suite Setup
Suite Teardown Cross Auth On Kserve Suite Teardown
Test Tags Kserve Modelmesh
Test Teardown Cross Auth Test Teardown
Test Tags Sanity ProductBug


*** Variables ***
Expand All @@ -22,43 +21,58 @@
${PRJ_DESCRIPTION}= project used for validating cross-auth CVE
${MODEL_CREATED}= ${FALSE}
${MODEL_NAME}= test-model
${SECOND_MODEL_NAME}= test-model-second
${SECOND_MODEL_NAME}= ${MODEL_NAME}-second
${RUNTIME_NAME}= Model Serving Test
${EXPECTED_INFERENCE_OUTPUT}= {"model_name":"${MODEL_NAME}__isvc-83d6fab7bd","model_version":"1","outputs":[{"name":"Plus214_Output_0","datatype":"FP32","shape":[1,10],"data":[-8.233053,-7.7497034,-3.4236815,12.3630295,-12.079103,17.266596,-10.570976,0.7130762,3.321715,1.3621228]}]} #robocop: disable
${SECOND_EXPECTED_INFERENCE_OUTPUT}= {"model_name":"${SECOND_MODEL_NAME}__isvc-83d6fab7bd","model_version":"1","outputs":[{"name":"Plus214_Output_0","datatype":"FP32","shape":[1,10],"data":[-8.233053,-7.7497034,-3.4236815,12.3630295,-12.079103,17.266596,-10.570976,0.7130762,3.321715,1.3621228]}]} #robocop: disable
${FIRST_SERVICE_ACCOUNT}= first_account
${SECOND_SERVICE_ACCOUNT}= second_account


*** Test Cases ***
Test Cross Model Authentication On Kserve
[Documentation] Tests for the presence of CVE-2024-7557 when using Kserve
[Tags] Sanity ProductBug
... RHOAIENG-11007 RHOAIENG-12048
[Tags] Kserve RHOAIENG-11007 RHOAIENG-12048
Set Test Variable $serving_mode kserve

Check notice

Code scanning / Robocop

{{ set_variable_keyword }} can be replaced with VAR Note test

Set Test Variable can be replaced with VAR
Set Test Variable $project_name ${PRJ_TITLE}-${serving_mode}

Check notice

Code scanning / Robocop

{{ set_variable_keyword }} can be replaced with VAR Note test

Set Test Variable can be replaced with VAR
Template with embedded arguments

Test Cross Model Authentication On ModelMesh
[Documentation] Tests for the presence of CVE-2024-7557 when using ModelMesh
[Tags] ModelMesh RHOAIENG-11007 RHOAIENG-12853
Set Test Variable $serving_mode modelmeshserving

Check notice

Code scanning / Robocop

{{ set_variable_keyword }} can be replaced with VAR Note test

Set Test Variable can be replaced with VAR
Set Test Variable $project_name ${PRJ_TITLE}-${serving_mode}

Check notice

Code scanning / Robocop

{{ set_variable_keyword }} can be replaced with VAR Note test

Set Test Variable can be replaced with VAR
Template with embedded arguments


*** Keywords ***
Template with embedded arguments
Fixed Show fixed Hide fixed
[Documentation] Template for cross-auth test cases
Cross Auth Test Setup
${single_model}= Set Variable If "${serving_mode}" == "kserve" ${True} ${False}
Open Data Science Projects Home Page
Create Data Science Project title=${PRJ_TITLE} description=${PRJ_DESCRIPTION}
Create Data Science Project title=${project_name} description=${PRJ_DESCRIPTION}
... existing_project=${FALSE}
Recreate S3 Data Connection project_title=${PRJ_TITLE} dc_name=model-serving-connection
... aws_access_key=${S3.AWS_ACCESS_KEY_ID} aws_secret_access=${S3.AWS_SECRET_ACCESS_KEY}
... aws_bucket_name=ods-ci-s3
Deploy Kserve Model Via UI model_name=${MODEL_NAME} serving_runtime=OpenVINO Model Server
... data_connection=model-serving-connection path=test-dir model_framework=onnx
... service_account_name=first_account token=${TRUE}
Wait For Pods To Be Ready label_selector=serving.kserve.io/inferenceservice=${MODEL_NAME}
... namespace=${PRJ_TITLE}
${first_token}= Get Model Serving Access Token via UI service_account_name=first_account single_model=${TRUE}
... model_name=${MODEL_NAME}
Deploy Kserve Model Via UI model_name=${SECOND_MODEL_NAME} serving_runtime=OpenVINO Model Server
... data_connection=model-serving-connection path=test-dir model_framework=onnx
... service_account_name=second_account token=${TRUE}
Wait For Pods To Be Ready label_selector=serving.kserve.io/inferenceservice=${SECOND_MODEL_NAME}
... namespace=${PRJ_TITLE}
${second_token}= Get Model Serving Access Token via UI service_account_name=second_account
... single_model=${TRUE} model_name=${SECOND_MODEL_NAME}
Cross Auth Model Deployment single_model=${single_model}
... model_name=${MODEL_NAME} service_account_name=${FIRST_SERVICE_ACCOUNT}

${first_token}= Get Access Token Via UI service_account_name=${FIRST_SERVICE_ACCOUNT}
Fixed Show fixed Hide fixed
... single_model=${single_model} model_name=${MODEL_NAME} project_name=${project_name}

Cross Auth Model Deployment single_model=${single_model}
... model_name=${SECOND_MODEL_NAME} service_account_name=${SECOND_SERVICE_ACCOUNT}

${second_token}= Get Access Token Via UI service_account_name=${SECOND_SERVICE_ACCOUNT}
... single_model=${single_model} model_name=${SECOND_MODEL_NAME} project_name=${project_name}

Verify Model Inference model_name=${MODEL_NAME} inference_input=${INFERENCE_INPUT}
... expected_inference_output=${EXPECTED_INFERENCE_OUTPUT} token_auth=${TRUE} token=${first_token}
... project_title=${PRJ_TITLE}
... project_title=${project_name}

Verify Model Inference model_name=${SECOND_MODEL_NAME} inference_input=${INFERENCE_INPUT}
... expected_inference_output=${SECOND_EXPECTED_INFERENCE_OUTPUT} token_auth=${TRUE} token=${second_token}
... project_title=${PRJ_TITLE}
... project_title=${project_name}

# Should not be able to query first model with second token
# Will fail at this step until CVE is fixed from dashboard side
${inf_out}= Get Model Inference model_name=${MODEL_NAME} inference_input=${INFERENCE_INPUT}
Expand All @@ -67,33 +81,59 @@
${inf_out}= Get Model Inference model_name=${SECOND_MODEL_NAME} inference_input=${INFERENCE_INPUT}
... token_auth=${TRUE} token=${first_token}
Run Keyword And Warn On Failure Should Contain ${inf_out} Log in with OpenShift
[Teardown] Run Keywords Run Keyword If Test Failed Get Kserve Events And Logs
... model_name=${MODEL_NAME} project_title=${PRJ_TITLE} AND Clean All Models Of Current User

Cross Auth Model Deployment
Fixed Show fixed Hide fixed
[Documentation] Deploys a model with cross auth enabled
[Arguments] ${single_model} ${model_name} ${service_account_name}
${dc_name}= Set Variable model-serving-connection-${serving_mode}
Recreate S3 Data Connection project_title=${project_name} dc_name=${dc_name}
... aws_access_key=${S3.AWS_ACCESS_KEY_ID} aws_secret_access=${S3.AWS_SECRET_ACCESS_KEY}
... aws_bucket_name=ods-ci-s3
Open Data Science Project Details Page ${project_name} tab_id=model-server
IF ${single_model}
Deploy Kserve Model Via UI model_name=${model_name} serving_runtime=OpenVINO Model Server
... data_connection=${dc_name} path=test-dir model_framework=onnx
... service_account_name=${service_account_name} token=${TRUE}
Wait For Pods To Be Ready label_selector=serving.kserve.io/inferenceservice=${model_name}
... namespace=${project_name}
ELSE
Create Model Server token=${TRUE} server_name=${model_name} service_account_name=${service_account_name}
sleep 1m
Deploy Model From Models Tab project_name=${project_name} model_name=${model_name} framework=onnx
... existing_data_connection=${TRUE} data_connection_name=${dc_name} model_server=${model_name}
... model_path=mnist-8.onnx
Wait Until Keyword Succeeds 5 min 10 sec Verify Openvino Deployment runtime_name=${model_name}
... project_name=${project_name}
Wait Until Keyword Succeeds 5 min 10 sec Verify Serving Service project_name=${project_name}
Verify Model Status ${MODEL_NAME} success
Fixed Show fixed Hide fixed
END

*** Keywords ***
Cross Auth On Kserve Suite Setup
[Documentation] Suite setup steps for testing DSG. It creates some test variables
Cross Auth Test Setup
[Documentation] Test setup steps for testing DSG. It creates some test variables
... and runs RHOSi setup

Set Library Search Order SeleniumLibrary
Skip If Component Is Not Enabled kserve
Skip If Component Is Not Enabled ${serving_mode}
RHOSi Setup
Launch Dashboard ${TEST_USER.USERNAME} ${TEST_USER.PASSWORD} ${TEST_USER.AUTH_TYPE}
... ${ODH_DASHBOARD_URL} ${BROWSER.NAME} ${BROWSER.OPTIONS}
Fetch Knative CA Certificate filename=openshift_ca_istio_knative.crt
Clean All Models Of Current User

Cross Auth On Kserve Suite Teardown
[Documentation] Suite teardown steps after testing DSG. It Deletes
Cross Auth Test Teardown
[Documentation] Test teardown steps after testing DSG. It Deletes
... all the DS projects created by the tests and run RHOSi teardown
Run Keywords Run Keyword If Test Failed Get Kserve Events And Logs
... model_name=${MODEL_NAME} project_title=${project_name} AND Clean All Models Of Current User

# Even if kw fails, deleting the whole project will also delete the model
# Failure will be shown in the logs of the run nonetheless
IF ${MODEL_CREATED}
Clean All Models Of Current User
ELSE
Log Model not deployed, skipping deletion step during teardown console=true
END
${projects}= Create List ${PRJ_TITLE}
${projects}= Create List ${project_name}

Check notice

Code scanning / Robocop

{{ create_keyword }} can be replaced with VAR Note test

Create List can be replaced with VAR
Delete List Of Projects Via CLI ocp_projects=${projects}
# Will only be present on SM cluster runs, but keyword passes
# if file does not exist
Expand Down
Loading