Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
0b9f655
some webui messages typos
hasan7n Mar 8, 2026
610bb25
add association signing
hasan7n Mar 9, 2026
1bcd289
fix circular imports for signing assocs
hasan7n Mar 9, 2026
7ed505b
better apis for cc
hasan7n Mar 9, 2026
374002b
validation for input cc config
hasan7n Mar 9, 2026
d2a949a
change required fields
hasan7n Mar 9, 2026
322409e
update cc setup to checks only
hasan7n Mar 10, 2026
c0c5085
add webui for cc
hasan7n Mar 10, 2026
a4ce142
add notes for users setup
hasan7n Mar 10, 2026
a97001d
update base image to test writing results before benchmark run
hasan7n Mar 11, 2026
56b3dc2
remove account from required fields
hasan7n Mar 11, 2026
f08a047
change policy for model owner
hasan7n Mar 11, 2026
b13cd17
make run_script available as metrics container in web ui
hasan7n Mar 11, 2026
43dc4ac
add skip compatiblity tests in web ui
hasan7n Mar 11, 2026
839451e
add key location as required field for cc asset
hasan7n Mar 11, 2026
dd90619
some readme updates
hasan7n Mar 11, 2026
e482202
use proper exceptions
hasan7n Mar 11, 2026
3129e73
fix check utils
hasan7n Mar 11, 2026
e98344f
make setup cc interactive
hasan7n Mar 11, 2026
163a67a
update how workloads are retrieved for model owner
hasan7n Mar 11, 2026
a8d8e30
update webui
hasan7n Mar 11, 2026
72805c3
add file exists api for cc
hasan7n Mar 11, 2026
92e2433
add is_script api for containers
hasan7n Mar 11, 2026
5d6521c
add script execution without metrics
hasan7n Mar 11, 2026
3c1c90c
fix docker.io prefix problem
hasan7n Mar 11, 2026
4fb74dd
update how tar works in cc base image
hasan7n Mar 12, 2026
7a0f62c
expect wip_provider in gcp config in cc base image
hasan7n Mar 12, 2026
cedf40b
make wip_provider required in client
hasan7n Mar 12, 2026
1eb5492
prevent an unsupported option for execution
hasan7n Mar 12, 2026
07f1753
add model-only rano container
hasan7n Mar 12, 2026
2e3e8f1
fix json yaml issue in dev data
hasan7n Mar 12, 2026
c2523f1
don't require buckets to be public
hasan7n Mar 12, 2026
232e970
fix cc design
mhmdk0 Mar 12, 2026
0e4aaa1
fix operator cc design
mhmdk0 Mar 12, 2026
6b4a44b
enhance submit_as_prepared design in dataset registration
mhmdk0 Mar 12, 2026
ca01add
don't require creating VMs from medperf
hasan7n Mar 12, 2026
7efb101
update chestxray cc example
hasan7n Mar 12, 2026
b1e4054
allow only local certs for data owner and operator
hasan7n Mar 13, 2026
29b4dd5
fix set gcs iam policy
hasan7n Mar 13, 2026
8cbb39a
add another reason for model cc not ready
hasan7n Mar 13, 2026
032ae14
fix route typo
hasan7n Mar 13, 2026
6270cdb
remove sa impersonation
hasan7n Mar 13, 2026
9831a45
typo in vm role check
hasan7n Mar 13, 2026
0e39a02
remove vm role check
hasan7n Mar 13, 2026
fda8b80
typo in confientialmodel execution
hasan7n Mar 13, 2026
11f4415
proper handling of vm start
hasan7n Mar 13, 2026
819541d
fix errors in workload uid
hasan7n Mar 13, 2026
3ac0b32
fix vm_name usage
hasan7n Mar 13, 2026
49fb738
know when cc workload fails
hasan7n Mar 13, 2026
9d66b8b
add gpu
hasan7n Mar 13, 2026
2727e5a
refactor gcp utils
hasan7n Mar 14, 2026
05fa6e3
fix cc operator required fields
hasan7n Mar 14, 2026
c01326c
add wip_provider as required input
hasan7n Mar 14, 2026
02e19af
add dataset hash mismatch
hasan7n Mar 14, 2026
a4b6c84
move all gcp logic to one place
hasan7n Mar 14, 2026
7e0723b
don't use gcloud cli with storage
hasan7n Mar 14, 2026
8d95a86
don't use gcloud cli for wip
hasan7n Mar 14, 2026
2f0b043
don't use gcloud cli in kms, fix how sensitive keys are handled
hasan7n Mar 14, 2026
6e23f69
update requirements
hasan7n Mar 14, 2026
e0e0ed9
Revert "fix circular imports for signing assocs"
hasan7n Mar 14, 2026
1118574
Revert "add association signing"
hasan7n Mar 14, 2026
6fa133f
fix bug in check_hash
hasan7n Mar 14, 2026
abc0e2a
refactor
hasan7n Mar 14, 2026
7d89728
fix failing unit test
hasan7n Mar 14, 2026
0b9d4fd
make checkbox border better
hasan7n Mar 15, 2026
9b10154
ui fixes
hasan7n Mar 15, 2026
04cb996
allow certificate delete always
hasan7n Mar 15, 2026
793bde0
scripts/instructions for gcp admins
hasan7n Mar 15, 2026
5656f60
edit scripts
hasan7n Mar 15, 2026
1dff53b
modify attribute condition to accept gpu workload
hasan7n Mar 15, 2026
cf493cf
ui/ux enhancements
hasan7n Mar 15, 2026
1f8e88a
update admin readme
hasan7n Mar 15, 2026
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

Large diffs are not rendered by default.

42 changes: 42 additions & 0 deletions cli/medperf/asset_management/asset_check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from medperf.asset_management.gcp_utils import checks, get_user_credentials


def verify_asset_owner_setup(bucket_name, kms_key_resource, wip_resource):
base_creds = get_user_credentials()
result = checks.check_user_role_on_bucket(
"user",
base_creds,
bucket_name,
"roles/storage.admin",
)
if result:
return False, result

result = checks.check_user_role_on_kms_key(
base_creds,
kms_key_resource,
"roles/cloudkms.cryptoKeyEncrypter",
)

if result:
return False, result

result = checks.check_user_role_on_kms_key(
base_creds,
kms_key_resource,
"roles/cloudkms.admin",
)

if result:
return False, result

result = checks.check_user_role_on_wip(
base_creds,
wip_resource,
"roles/iam.workloadIdentityPoolAdmin",
)

if result:
return False, result

return True, ""
150 changes: 73 additions & 77 deletions cli/medperf/asset_management/asset_management.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
from medperf.asset_management.gcp_utils import CCWorkloadID
from medperf.asset_management.gcp_utils import (
CCWorkloadID,
GCPAssetConfig,
GCPOperatorConfig,
)
from medperf.entities.dataset import Dataset
from medperf.entities.model import Model
from medperf.entities.user import User
Expand All @@ -7,134 +11,117 @@
from medperf.asset_management.cc_operator import OperatorManager
from medperf.utils import tar, generate_tmp_path
import secrets
import os
from medperf import config
from medperf.exceptions import MedperfException
from medperf import config as medperf_config


def generate_encryption_key(encryption_key_file: str):
with open(encryption_key_file, "wb") as f:
pass
os.chmod(encryption_key_file, 0o700)
with open(encryption_key_file, "ab") as f:
f.write(secrets.token_bytes(32))
def generate_encryption_key():
return secrets.token_bytes(32)


def validate_cc_config(cc_config: dict, asset_name_prefix: str):
if cc_config == {}:
return

cc_config["encrypted_asset_bucket_file"] = asset_name_prefix + ".enc"
cc_config["encrypted_key_bucket_file"] = asset_name_prefix + "_key.enc"

GCPAssetConfig(**cc_config)


def validate_cc_operator_config(cc_config: dict):
if cc_config == {}:
return
GCPOperatorConfig(**cc_config)


def setup_dataset_for_cc(dataset: Dataset):
if not dataset.is_cc_configured():
return
cc_config = dataset.get_cc_config()
cc_policy = dataset.get_cc_policy()
if not cc_config:
raise ValueError(
f"Dataset {dataset.id} does not have a configuration for confidential computing."
)
if cc_policy is None:
raise ValueError(
f"Dataset {dataset.id} does not have a policy for confidential computing."
)
__verify_cloud_environment(cc_config)

# create dataset asset
medperf_config.ui.text = "Compressing dataset"
asset_path = generate_tmp_path()
tar(asset_path, [dataset.data_path, dataset.labels_path])

# create encryption key
encryption_key_folder = os.path.join(
config.cc_artifacts_dir, "dataset" + str(dataset.id)
)
os.makedirs(encryption_key_folder, exist_ok=True)
encryption_key_file = os.path.join(encryption_key_folder, "encryption_key.bin")
generate_encryption_key(encryption_key_file)

__setup_asset_for_cc(cc_config, cc_policy, asset_path, encryption_key_file)
__setup_asset_for_cc(cc_config, cc_policy, asset_path)


def setup_model_for_cc(model: Model):
if not model.is_cc_configured():
return
cc_config = model.get_cc_config()
cc_policy = model.get_cc_policy()
if not cc_config:
raise ValueError(
f"Model {model.id} does not have a configuration for confidential computing."
)
if cc_policy is None:
raise ValueError(
f"Model {model.id} does not have a policy for confidential computing."
)
if model.type != "ASSET":
raise ValueError(
raise MedperfException(
f"Model {model.id} is not a file-based asset and cannot be set up for confidential computing."
)

asset = model.asset_obj
# create model asset
asset_path = asset.get_archive_path()

# create encryption key
encryption_key_folder = os.path.join(
config.cc_artifacts_dir, "model" + str(model.id)
)
os.makedirs(encryption_key_folder, exist_ok=True)
encryption_key_file = os.path.join(encryption_key_folder, "encryption_key.bin")
generate_encryption_key(encryption_key_file)
__verify_cloud_environment(cc_config)
__setup_asset_for_cc(cc_config, cc_policy, asset_path, for_model=True)

__setup_asset_for_cc(cc_config, cc_policy, asset_path, encryption_key_file)

def __verify_cloud_environment(cc_config: dict):
AssetStorageManager(cc_config, None, None).setup()


def __setup_asset_for_cc(
cc_config: dict, cc_policy: dict, asset_path: str, encryption_key_file: str
cc_config: dict,
cc_policy: dict,
asset_path: str,
for_model: bool = False,
):
# asset storage setup
asset_storage_manager = AssetStorageManager(
cc_config, asset_path, encryption_key_file
)
asset_storage_manager.setup()
# create encryption key
encryption_key = generate_encryption_key()

asset_storage_manager = AssetStorageManager(cc_config, asset_path, encryption_key)
asset_policy_manager = AssetPolicyManager(cc_config, for_model=for_model)

# storage
asset_storage_manager.store_asset()

# policy setup
asset_policy_manager = AssetPolicyManager(cc_config, encryption_key_file)
asset_policy_manager.setup()
asset_policy_manager.setup_policy(cc_policy)
asset_policy_manager.setup_policy(cc_policy, encryption_key)
del encryption_key


def update_dataset_cc_policy(dataset: Dataset, permitted_workloads: list[CCWorkloadID]):
cc_config = dataset.get_cc_config()
if not cc_config:
raise ValueError(
if not dataset.is_cc_configured():
raise MedperfException(
f"Dataset {dataset.id} does not have a configuration for confidential computing."
)

encryption_key_folder = os.path.join(
config.cc_artifacts_dir, "dataset" + str(dataset.id)
)
encryption_key_file = os.path.join(encryption_key_folder, "encryption_key.bin")

asset_policy_manager = AssetPolicyManager(cc_config, encryption_key_file)
cc_config = dataset.get_cc_config()
asset_policy_manager = AssetPolicyManager(cc_config)
asset_policy_manager.configure_policy(permitted_workloads)


def update_model_cc_policy(model: Model, permitted_workloads: list[CCWorkloadID]):
cc_config = model.get_cc_config()
if not cc_config:
raise ValueError(
if not model.is_cc_configured():
raise MedperfException(
f"Model {model.id} does not have a configuration for confidential computing."
)
cc_config = model.get_cc_config()
if model.type != "ASSET":
raise ValueError(
raise MedperfException(
f"Model {model.id} is not a file-based asset and cannot be set up for confidential computing."
)

encryption_key_folder = os.path.join(
config.cc_artifacts_dir, "model" + str(model.id)
)
encryption_key_file = os.path.join(encryption_key_folder, "encryption_key.bin")

asset_policy_manager = AssetPolicyManager(cc_config, encryption_key_file)
asset_policy_manager = AssetPolicyManager(cc_config, for_model=True)
asset_policy_manager.configure_policy(permitted_workloads)


def setup_operator(user: User):
cc_config = user.get_cc_config()
if not cc_config:
raise ValueError(
"User does not have a configuration for confidential computing."
)
if not user.is_cc_configured():
return

cc_config = user.get_cc_config()
operator_manager = OperatorManager(cc_config)
operator_manager.setup()

Expand All @@ -156,6 +143,10 @@ def run_workload(
model_cc_config,
result_collector_public_key,
)


def wait_for_workload(workload: CCWorkloadID, operator_cc_config: dict):
operator_manager = OperatorManager(operator_cc_config)
operator_manager.wait_for_workload_completion(workload)


Expand All @@ -168,3 +159,8 @@ def download_results(
operator_manager = OperatorManager(operator_cc_config)

operator_manager.download_results(workload, private_key_bytes, results_path)


def workload_results_exists(operator_cc_config: dict, workload: CCWorkloadID) -> bool:
operator_manager = OperatorManager(operator_cc_config)
return operator_manager.results_exist(workload)
Loading
Loading