Skip to content

Commit c0ac139

Browse files
committed
Address review: SP-mediated uploads, login_required, platform binary, code smell fix
1 parent 1baab37 commit c0ac139

3 files changed

Lines changed: 142 additions & 99 deletions

File tree

install/ci-vm/ci-linux/ci/runCI

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -139,10 +139,11 @@ if [ -e "${dstDir}/ccextractor" ]; then
139139
#!/bin/bash
140140
COMBINED_LOG="/tmp/combined_stdout.log"
141141
REAL_BINARY="PLACEHOLDER_BINARY"
142-
EXIT_CODE_FILE="/tmp/.wrapper_exit_code"
142+
EXIT_CODE_FILE=$(mktemp)
143143
echo "=== TEST INVOCATION: $@ ===" >> "$COMBINED_LOG"
144144
{ "$REAL_BINARY" "$@" 2>&1; echo $? > "$EXIT_CODE_FILE"; } | tee -a "$COMBINED_LOG"
145145
exit_code=$(cat "$EXIT_CODE_FILE")
146+
rm -f "$EXIT_CODE_FILE"
146147
echo "=== EXIT CODE: ${exit_code} ===" >> "$COMBINED_LOG"
147148
echo "" >> "$COMBINED_LOG"
148149
exit $exit_code
@@ -153,37 +154,33 @@ WRAPPER_EOF
153154
executeCommand cd ${suiteDstDir}
154155
executeCommand ${tester} --debug --entries "${testFile}" --executable "${wrapper_path}" --tempfolder "${tempFolder}" --timeout 600 --reportfolder "${reportFolder}" --resultfolder "${resultFolder}" --samplefolder "${sampleFolder}" --method Server --url "${reportURL}"
155156

156-
# Upload AI artifacts to GCS
157-
gcs_bucket=$(curl -s "http://metadata/computeMetadata/v1/instance/attributes/bucket" -H "Metadata-Flavor: Google")
158-
test_id=$(curl -s "http://metadata/computeMetadata/v1/instance/attributes/testID" -H "Metadata-Flavor: Google")
159-
token=$(curl -s "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token" -H "Metadata-Flavor: Google" | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")
160-
157+
# Upload artifacts through the Sample Platform server
161158
upload_artifact() {
162159
local file_path="$1"
163-
local dest_path="$2"
160+
local artifact_name="$2"
164161
if [ -f "$file_path" ]; then
165162
local http_code
166-
http_code=$(curl -s -X POST --data-binary @"$file_path" \
167-
-H "Authorization: Bearer $token" \
168-
-H "Content-Type: application/octet-stream" \
169-
-w "%{http_code}" \
170-
-o /dev/null \
171-
"https://storage.googleapis.com/upload/storage/v1/b/${gcs_bucket}/o?uploadType=media&name=${dest_path}")
172-
if [ -z "$http_code" ] || [ "$http_code" -ne 200 ]; then
173-
echo "GCS upload failed for ${dest_path}: HTTP ${http_code:-no_response}" >> "${logFile}"
163+
http_code=$(curl -s -A "${userAgent}" \
164+
--form "type=artifact" \
165+
--form "name=${artifact_name}" \
166+
--form "file=@${file_path}" \
167+
-w "%{http_code}" -o /dev/null \
168+
"${reportURL}" 2>/dev/null)
169+
if [ -z "$http_code" ] || [ "$http_code" -lt 200 ] || [ "$http_code" -ge 300 ]; then
170+
echo "Artifact upload failed for ${artifact_name}: HTTP ${http_code:-no_response}" >> "${logFile}"
174171
fi
175172
fi
176173
}
177174

178-
upload_artifact "$ccextractor_path" "test_artifacts/${test_id}/ccextractor"
175+
upload_artifact "$ccextractor_path" "ccextractor"
179176

180177
# Upload combined stdout log
181-
upload_artifact "${combined_stdout}" "test_artifacts/${test_id}/combined_stdout.log"
178+
upload_artifact "${combined_stdout}" "combined_stdout.log"
182179

183180
# Upload coredumps if any
184181
for core_file in /tmp/coredumps/core.*; do
185182
if [ -f "$core_file" ]; then
186-
upload_artifact "$core_file" "test_artifacts/${test_id}/coredump"
183+
upload_artifact "$core_file" "coredump"
187184
break
188185
fi
189186
done

mod_ci/controllers.py

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,9 +1194,7 @@ def create_instance(compute, project, zone, test, reportURL) -> Dict:
11941194
startup_script = f.read()
11951195
metadata_items = [
11961196
{'key': 'startup-script', 'value': startup_script},
1197-
{'key': 'reportURL', 'value': reportURL},
1198-
{'key': 'bucket', 'value': config.get('GCS_BUCKET_NAME', '')},
1199-
{'key': 'testID', 'value': str(test.id)}
1197+
{'key': 'reportURL', 'value': reportURL}
12001198
]
12011199
elif test.platform == TestPlatform.windows:
12021200
image_response = compute.images().getFromFamily(project=config.get('WINDOWS_INSTANCE_PROJECT_NAME', ''),
@@ -1217,9 +1215,7 @@ def create_instance(compute, project, zone, test, reportURL) -> Dict:
12171215
{'key': 'windows-startup-script-ps1', 'value': startup_script},
12181216
{'key': 'service_account', 'value': service_account},
12191217
{'key': 'rclone_conf', 'value': rclone_conf},
1220-
{'key': 'reportURL', 'value': reportURL},
1221-
{'key': 'bucket', 'value': config.get('GCS_BUCKET_NAME', '')},
1222-
{'key': 'testID', 'value': str(test.id)}
1218+
{'key': 'reportURL', 'value': reportURL}
12231219
]
12241220
source_disk_image = image_response['selfLink']
12251221

@@ -2346,6 +2342,11 @@ def progress_reporter(test_id, token):
23462342
if not upload_type_request(log, test_id, repo_folder, test, request):
23472343
return "EMPTY"
23482344

2345+
elif request.form['type'] == 'artifact':
2346+
log.info(f'[PROGRESS_REPORTER][Test: {test_id}] Artifact upload')
2347+
if not artifact_upload_request(log, test_id, request):
2348+
return "EMPTY"
2349+
23492350
elif request.form['type'] == 'finish':
23502351
log.info(f'[PROGRESS_REPORTER][Test: {test_id}] Test finished')
23512352
finish_type_request(log, test_id, test, request)
@@ -2695,6 +2696,45 @@ def upload_type_request(log, test_id, repo_folder, test, request) -> bool:
26952696
return False
26962697

26972698

2699+
# Allowed artifact names that the VM can upload
2700+
ALLOWED_ARTIFACT_NAMES = {'ccextractor', 'ccextractor.exe', 'combined_stdout.log', 'coredump'}
2701+
2702+
2703+
def artifact_upload_request(log, test_id, request) -> bool:
2704+
"""
2705+
Handle artifact upload from the CI VM.
2706+
2707+
Validates the artifact name against an allow-list, then uploads
2708+
the file to GCS under test_artifacts/{test_id}/{name}.
2709+
2710+
:param log: logger
2711+
:type log: Logger
2712+
:param test_id: The id of the test to update.
2713+
:type test_id: int
2714+
:param request: Request parameters
2715+
:type request: Request
2716+
:return: True if upload succeeded, False otherwise.
2717+
:rtype: bool
2718+
"""
2719+
from run import storage_client_bucket
2720+
2721+
artifact_name = request.form.get('name', '')
2722+
if artifact_name not in ALLOWED_ARTIFACT_NAMES:
2723+
log.warning(f"[Test: {test_id}] Rejected artifact upload with disallowed name: {artifact_name}")
2724+
return False
2725+
2726+
if 'file' not in request.files:
2727+
log.warning(f"[Test: {test_id}] Artifact upload missing file")
2728+
return False
2729+
2730+
uploaded_file = request.files['file']
2731+
blob_path = f'test_artifacts/{test_id}/{artifact_name}'
2732+
blob = storage_client_bucket.blob(blob_path)
2733+
blob.upload_from_file(uploaded_file.stream)
2734+
log.info(f"[Test: {test_id}] Artifact '{artifact_name}' uploaded to {blob_path}")
2735+
return True
2736+
2737+
26982738
def finish_type_request(log, test_id, test, request):
26992739
"""
27002740
Handle finish request type for progress reporter.

0 commit comments

Comments
 (0)