Skip to content

Commit 7a6a61a

Browse files
authored
Introduce new states for XML Validation (#2804)
Change the name of the environment variable from VALIDATE_XML_SUBMISSIONS to VALIDATE_SUBMISSIONS Change the handling of the XML validation in the environment to be a string setting instead of a boolean. The new state should be as follows No Value or "SILENT": Log a message in the CDash logs and attempt to parse XML "WARN" : Log, return a message with a warning label in the http response of the submission, and attempt to parse XML "REJECT" : Log and return 400 to prevent further submissions and do not attempt to process the XML
1 parent 6b6284a commit 7a6a61a

File tree

9 files changed

+82
-46
lines changed

9 files changed

+82
-46
lines changed

.env.example

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,16 @@ DB_PASSWORD=secret
118118
# to some value other than 'sync'.
119119
#REMOTE_WORKERS=false
120120

121-
# Whether or not submission XML files are validated before being processed.
122-
# Enabling this setting will trigger a scan through XML files uploaded in
123-
# each submission in order to preemptively reject malformed files.
124-
#VALIDATE_XML_SUBMISSIONS=true
121+
# Whether or not submission files are validated before being processed.
122+
# CDash will trigger a scan through certain files uploaded in
123+
# each submission in order to reject malformed files. This setting controls
124+
# how much the user is made aware of issues found with the files.
125+
# Valid values:
126+
# SILENT <--- This is the default
127+
# WARN
128+
# REJECT
129+
130+
#VALIDATE_SUBMISSIONS=SILENT
125131

126132
# Should we show the most recent submission time for a project or subproject?
127133
# Disabling this feature can improve rendering performance of index.php
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace App\Enums;
4+
5+
enum SubmissionValidationType: int
6+
{
7+
case SILENT = 0;
8+
case WARN = 1;
9+
case REJECT = 2;
10+
}

app/Http/Controllers/SubmissionController.php

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace App\Http\Controllers;
44

5+
use App\Enums\SubmissionValidationType;
56
use App\Exceptions\BadSubmissionException;
67
use App\Jobs\ProcessSubmission;
78
use App\Models\Site;
@@ -73,7 +74,7 @@ private function submitProcess(): Response
7374
@set_time_limit(0);
7475

7576
$statusarray = [];
76-
77+
$responseMessage = '';
7778
$projectname = $_GET['project'] ?? '';
7879

7980
if (strlen($projectname) === 0) {
@@ -146,34 +147,29 @@ private function submitProcess(): Response
146147
// Figure out what type of XML file this is.
147148
$stored_filename = 'inbox/' . $filename;
148149
$xml_info = [];
149-
try {
150-
$xml_info = SubmissionUtils::get_xml_type(Storage::readStream($stored_filename), $stored_filename);
151-
} catch (BadSubmissionException $e) {
152-
$xml_info['xml_handler'] = '';
153-
$message = "Could not determine submission file type for: '{$stored_filename}'";
154-
Log::warning($message);
155-
if ((bool) config('cdash.validate_xml_submissions') === true) {
156-
$this->failProcessing($filename, 400, $message);
157-
}
158-
}
150+
$xml_info = SubmissionUtils::get_xml_type(Storage::readStream($stored_filename), $stored_filename);
151+
159152
if ($xml_info['xml_handler'] !== '') {
160153
// If validation is enabled and if this file has a corresponding schema, validate it
161154
$validation_errors = [];
162155
try {
163156
$validation_errors = $xml_info['xml_handler']::validate($stored_filename);
164157
} catch (FileNotFoundException|UnableToReadFile $e) {
165-
Log::warning($e->getMessage());
166-
if ((bool) config('cdash.validate_xml_submissions') === true) {
167-
$this->failProcessing($filename, 400, "XML validation failed for $filename:" . PHP_EOL . $e->getMessage());
168-
}
158+
$message = $e->getMessage();
159+
report($message);
160+
$this->failProcessing($filename, 500, "Unable to read file for validation $filename:" . PHP_EOL . $message);
169161
}
170162
if (count($validation_errors) > 0) {
171163
$error_string = implode(PHP_EOL, $validation_errors);
172-
164+
$message = "XML validation failed: Found issues with file $filename:";
173165
// We always log validation failures, but we only send messages back to the client if configured to do so
174-
Log::warning("Submission validation failed for file '$filename':" . PHP_EOL);
175-
if ((bool) config('cdash.validate_xml_submissions') === true) {
176-
$this->failProcessing($filename, 400, "XML validation failed: rejected file $filename:" . PHP_EOL . $error_string);
166+
Log::info($message);
167+
$fullMessage = $message . PHP_EOL . $error_string;
168+
if (config('cdash.validate_submissions') === SubmissionValidationType::REJECT) {
169+
$this->failProcessing($filename, 400, $fullMessage);
170+
}
171+
if (config('cdash.validate_submissions') === SubmissionValidationType::WARN) {
172+
$responseMessage .= $fullMessage;
177173
}
178174
}
179175
}
@@ -219,8 +215,12 @@ private function submitProcess(): Response
219215
Artisan::call('submission:queue');
220216
}
221217

222-
$statusarray['status'] = 'OK';
223218
$statusarray['message'] = '';
219+
if ($responseMessage !== '') {
220+
$statusarray['message'] = $responseMessage;
221+
}
222+
223+
$statusarray['status'] = 'OK';
224224
if ($buildid !== null) {
225225
$statusarray['buildId'] = $buildid;
226226
}

app/Jobs/ProcessSubmission.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use AbstractSubmissionHandler;
66
use ActionableBuildInterface;
7+
use App\Exceptions\BadSubmissionException;
78
use App\Models\SuccessfulJob;
89
use App\Utils\UnparsedSubmissionProcessor;
910
use BuildPropertiesJSONHandler;
@@ -133,6 +134,8 @@ private function requeueSubmissionFile($buildid): bool
133134
* Execute the job.
134135
*
135136
* @return void
137+
*
138+
* @throws BadSubmissionException
136139
*/
137140
public function handle()
138141
{
@@ -197,6 +200,7 @@ public function failed(Throwable $exception): void
197200
* This method could be running on a worker that is either remote or local, so it accepts
198201
* a file handle or a filename that it can query the CDash API for.
199202
*
203+
* @throws BadSubmissionException
200204
**/
201205
private function doSubmit($filename, $projectid, $buildid = null, $expected_md5 = ''): AbstractSubmissionHandler|UnparsedSubmissionProcessor|false
202206
{

app/cdash/include/ctestparser.php

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ function parse_put_submission(string $filename, int $projectid, ?string $expecte
150150

151151
/**
152152
* Main function to parse the incoming xml from ctest
153+
*
154+
* @throws BadSubmissionException
153155
*/
154156
function ctest_parse($filehandle, string $filename, $projectid, $expected_md5 = '', ?int $buildid = null): AbstractSubmissionHandler|false
155157
{
@@ -163,19 +165,8 @@ function ctest_parse($filehandle, string $filename, $projectid, $expected_md5 =
163165
$Project->Id = $projectid;
164166
$xml_info = [];
165167
// Figure out what type of XML file this is.
166-
try {
167-
$xml_info = SubmissionUtils::get_xml_type($filehandle, $filename);
168-
} catch (BadSubmissionException $e) {
169-
$xml_info['file_handle'] = $filehandle;
170-
$xml_info['xml_handler'] = null;
171-
$xml_info['xml_type'] = '';
172-
$message = "Could not determine submission file type for: '{$filename}'";
173-
Log::warning($message);
174-
if ((bool) config('cdash.validate_xml_submissions') === true) {
175-
abort(400, $message);
176-
}
177-
}
178-
$filehandle = $xml_info['file_handle'];
168+
$xml_info = SubmissionUtils::get_xml_type($filehandle, $filename);
169+
179170
$handler_ref = $xml_info['xml_handler'];
180171
$file = $xml_info['xml_type'];
181172
$handler = isset($handler_ref) ? new $handler_ref($Project) : null;

app/cdash/xml_handlers/abstract_xml_handler.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public static function validate(string $path): array
9393
$validation_errors = libxml_get_errors();
9494
foreach ($validation_errors as $error) {
9595
if ($error->level === LIBXML_ERR_ERROR || $error->level === LIBXML_ERR_FATAL) {
96-
$errors[] = "ERROR: {$error->message} in {$error->file}, line: {$error->line}, column: {$error->column}";
96+
$errors[] = "WARNING: {$error->message} in {$error->file}, line: {$error->line}, column: {$error->column}";
9797
}
9898
}
9999
libxml_clear_errors();

config/cdash.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
<?php
22

3+
use App\Enums\SubmissionValidationType;
4+
use Illuminate\Support\Str;
5+
36
$cdash_directory_name = env('CDASH_DIRECTORY', 'cdash');
47
$cdash = realpath(app_path($cdash_directory_name));
58

@@ -64,7 +67,12 @@
6467
'show_last_submission' => env('SHOW_LAST_SUBMISSION', true),
6568
'slow_page_time' => env('SLOW_PAGE_TIME', 10),
6669
'token_duration' => env('TOKEN_DURATION', 15811200),
67-
'validate_xml_submissions' => env('VALIDATE_XML_SUBMISSIONS', false),
70+
'validate_submissions' => match (Str::upper((string) env('VALIDATE_SUBMISSIONS'))) {
71+
'SILENT' => SubmissionValidationType::SILENT,
72+
'WARN' => SubmissionValidationType::WARN,
73+
'REJECT' => SubmissionValidationType::REJECT,
74+
default => SubmissionValidationType::SILENT,
75+
},
6876
// Specify whether users are allowed to create "full access" authentication tokens
6977
'allow_full_access_tokens' => env('ALLOW_FULL_ACCESS_TOKENS', true),
7078
// Specify whether users are allowed to create "submit only" tokens which are valid for all projects

docs/submissions.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,10 @@ CDash automatically detects when its database is unavailable and stores submissi
7979

8080
## Submission files validation
8181

82-
CDash can be configured to validate submitted XML files before attempting to process them, in order to preemptively reject malformed files. If enabled, once a submission is moved out of the queue, its XML files will be scanned for valid syntax and validated against the [XML schemas](../app/Validators/Schemas/) CDash supports. To use this feature, set `VALIDATE_XML_SUBMISSIONS=true` in your `.env` file.
82+
CDash can be configured to validate submitted XML files before attempting to process them, in order to preemptively reject malformed files. If enabled, once a submission is moved out of the queue, its XML files will be scanned for valid syntax and validated against the [XML schemas](../app/Validators/Schemas/) CDash supports. To use this feature, set `VALIDATE_SUBMISSIONS` in your `.env` file.
83+
84+
No Value or "SILENT": Log a message in the CDash logs and attempt to parse XML
85+
"WARN" : Log, return a message with a warning label in the
86+
http response of the submission, and attempt to parse XML
87+
"REJECT" : Log and return 400 to prevent further submissions and do not attempt
88+
to process the XML

tests/Feature/SubmissionValidation.php

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public function setUp(): void
2727

2828
public function writeEnvEntry(string $value): void
2929
{
30-
file_put_contents($this->ConfigFile, "VALIDATE_XML_SUBMISSIONS={$value}\n", FILE_APPEND | LOCK_EX);
30+
file_put_contents($this->ConfigFile, "VALIDATE_SUBMISSIONS={$value}\n", FILE_APPEND | LOCK_EX);
3131
}
3232

3333
public function submit(string $fileName): bool
@@ -54,20 +54,31 @@ public function testSubmissionValidationNoEnv(): void
5454
/** Check that error messages are logged but submission succeeds
5555
* when the environment variable is set but to false
5656
*/
57-
public function testSubmissionValidationFalse(): void
57+
public function testSubmissionValidationSilent(): void
5858
{
59-
$this->writeEnvEntry('false');
59+
$this->writeEnvEntry('SILENT');
60+
$this::assertTrue($this->submit('invalid_Configure.xml'), 'Submission of invalid_Configure.xml was not successful when it should have passed.');
61+
$this::assertTrue($this->submit('invalid_syntax_Build.xml'), 'Submission of invalid_syntax_Build.xml was not successful when it should have passed.');
62+
$this::assertTrue($this->submit('valid_Build.xml'), 'Submission of valid_Build.xml was not successful when it should have passed.');
63+
}
64+
65+
/** Check that error messages are logged but submission succeeds
66+
* when the environment variable is set but to WARN
67+
*/
68+
public function testSubmissionValidationWarn(): void
69+
{
70+
$this->writeEnvEntry('WARN');
6071
$this::assertTrue($this->submit('invalid_Configure.xml'), 'Submission of invalid_Configure.xml was not successful when it should have passed.');
6172
$this::assertTrue($this->submit('invalid_syntax_Build.xml'), 'Submission of invalid_syntax_Build.xml was not successful when it should have passed.');
6273
$this::assertTrue($this->submit('valid_Build.xml'), 'Submission of valid_Build.xml was not successful when it should have passed.');
6374
}
6475

6576
/** Check that the submission is dependent upon passing validation
66-
* when the environment variable is set
77+
* when the environment variable is set to REJECT
6778
*/
68-
public function testSubmissionValidationTrue(): void
79+
public function testSubmissionValidationReject(): void
6980
{
70-
$this->writeEnvEntry('true');
81+
$this->writeEnvEntry('REJECT');
7182
$this::assertFalse($this->submit('invalid_Configure.xml'), 'Submission of invalid_Configure.xml was successful when it should have failed.');
7283
$this::assertFalse($this->submit('invalid_syntax_Build.xml'), 'Submission of invalid_syntax_Build.xml was successful when it should have failed.');
7384
$this::assertTrue($this->submit('valid_Build.xml'), 'Submission of valid_Build.xml was not successful when it should have passed.');

0 commit comments

Comments
 (0)