Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package openQA for openSUSE:Factory checked in at 2025-10-27 14:39:25 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/openQA (Old) and /work/SRC/openSUSE:Factory/.openQA.new.1980 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "openQA" Mon Oct 27 14:39:25 2025 rev:771 rq:1313591 version:5.1761296552.ae7c17aa Changes: -------- --- /work/SRC/openSUSE:Factory/openQA/openQA.changes 2025-10-24 17:25:38.028962434 +0200 +++ /work/SRC/openSUSE:Factory/.openQA.new.1980/openQA.changes 2025-10-27 14:41:01.241881545 +0100 @@ -1,0 +2,12 @@ +Fri Oct 24 16:35:40 UTC 2025 - [email protected] + +- Update to version 5.1761296552.ae7c17aa: + * Add tests for file_security_policy + * Pass parameter $is_userfile to log_url + * Remove redirect and serve files as attachments if necessary + * Serve files uploaded by tests via asset domain + * Use direct link to subdomain for the test assets + * Revert "Don't redirect to asset domain via /needles/ID/(image|json) route" + * Revert "Don't redirect screenshots, thumbs and needles to files_domain" + +------------------------------------------------------------------- Old: ---- openQA-5.1761228068.a3a7f84d.obscpio New: ---- openQA-5.1761296552.ae7c17aa.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ openQA-client-test.spec ++++++ --- /var/tmp/diff_new_pack.2FrhAp/_old 2025-10-27 14:41:02.817948108 +0100 +++ /var/tmp/diff_new_pack.2FrhAp/_new 2025-10-27 14:41:02.821948277 +0100 @@ -18,7 +18,7 @@ %define short_name openQA-client Name: %{short_name}-test -Version: 5.1761228068.a3a7f84d +Version: 5.1761296552.ae7c17aa Release: 0 Summary: Test package for %{short_name} License: GPL-2.0-or-later ++++++ openQA-devel-test.spec ++++++ --- /var/tmp/diff_new_pack.2FrhAp/_old 2025-10-27 14:41:02.869950304 +0100 +++ /var/tmp/diff_new_pack.2FrhAp/_new 2025-10-27 14:41:02.873950473 +0100 @@ -18,7 +18,7 @@ %define short_name openQA-devel Name: %{short_name}-test -Version: 5.1761228068.a3a7f84d +Version: 5.1761296552.ae7c17aa Release: 0 Summary: Test package for %{short_name} License: GPL-2.0-or-later ++++++ openQA-test.spec ++++++ --- /var/tmp/diff_new_pack.2FrhAp/_old 2025-10-27 14:41:02.909951993 +0100 +++ /var/tmp/diff_new_pack.2FrhAp/_new 2025-10-27 14:41:02.913952163 +0100 @@ -18,7 +18,7 @@ %define short_name openQA Name: %{short_name}-test -Version: 5.1761228068.a3a7f84d +Version: 5.1761296552.ae7c17aa Release: 0 Summary: Test package for openQA License: GPL-2.0-or-later ++++++ openQA-worker-test.spec ++++++ --- /var/tmp/diff_new_pack.2FrhAp/_old 2025-10-27 14:41:02.953953852 +0100 +++ /var/tmp/diff_new_pack.2FrhAp/_new 2025-10-27 14:41:02.957954021 +0100 @@ -18,7 +18,7 @@ %define short_name openQA-worker Name: %{short_name}-test -Version: 5.1761228068.a3a7f84d +Version: 5.1761296552.ae7c17aa Release: 0 Summary: Test package for %{short_name} License: GPL-2.0-or-later ++++++ openQA.spec ++++++ --- /var/tmp/diff_new_pack.2FrhAp/_old 2025-10-27 14:41:03.009956217 +0100 +++ /var/tmp/diff_new_pack.2FrhAp/_new 2025-10-27 14:41:03.013956386 +0100 @@ -99,7 +99,7 @@ %define devel_requires %devel_no_selenium_requires chromedriver Name: openQA -Version: 5.1761228068.a3a7f84d +Version: 5.1761296552.ae7c17aa Release: 0 Summary: The openQA web-frontend, scheduler and tools License: GPL-2.0-or-later ++++++ openQA-5.1761228068.a3a7f84d.obscpio -> openQA-5.1761296552.ae7c17aa.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1761228068.a3a7f84d/lib/OpenQA/WebAPI/Controller/File.pm new/openQA-5.1761296552.ae7c17aa/lib/OpenQA/WebAPI/Controller/File.pm --- old/openQA-5.1761228068.a3a7f84d/lib/OpenQA/WebAPI/Controller/File.pm 2025-10-23 16:01:08.000000000 +0200 +++ new/openQA-5.1761296552.ae7c17aa/lib/OpenQA/WebAPI/Controller/File.pm 2025-10-24 11:02:32.000000000 +0200 @@ -64,7 +64,7 @@ push @{$self->static->paths}, $needledir; # name is an URL parameter and can't contain slashes, so it should be safe - return $self->_serve_static($name . $format, 1); + return $self->_serve_static($name . $format); } sub _needle_by_id_and_extension ($self, $extension) { @@ -75,7 +75,7 @@ my $needle_filename = $needle->name . $extension; push @{$self->static->paths}, $needle_dir; - return $self->_serve_static($needle_filename, 1); + return $self->_serve_static($needle_filename); } sub needle_image_by_id ($self) { @@ -101,11 +101,6 @@ return $self->_serve_static($self->param('filename')); } -sub test_image ($self) { - return $self->reply->not_found unless $self->_set_test; - return $self->_serve_static($self->param('filename'), 1); -} - sub download_asset ($self) { # we handle this in apache, but need it in tests for asset cache # so minimal security is good enough @@ -114,7 +109,6 @@ my $file = path(assetdir(), $path)->to_string; my $is_text = $self->_set_headers($file); - return if $self->_redirect_if_configured($is_text); return $self->reply->not_found unless -f $file && -r _; $self->reply->file($file); } @@ -145,10 +139,6 @@ # map to URL - mojo will canonicalize my $url = $self->url_for('download_asset', assetpath => $path); - # redirect to file domain if configured - my $file_domain = $self->app->config->{global}->{file_domain}; - $url->host($file_domain) if ($file_domain); - $self->app->log->debug("redirect to $url"); # pass the redirect to the reverse proxy - might come back to use # in case there is no proxy (e.g. in tests) @@ -169,7 +159,12 @@ $headers->header('X-Content-Type-Options', 'nosniff'); $is_text = 1; } - my $allow_insecure = $self->app->config->{global}->{file_security_policy} ne 'download-prompt'; + my $file_security_policy = $self->app->config->{global}->{file_security_policy}; + my $allow_insecure = $file_security_policy eq 'insecure-browsing'; + if ($file_security_policy =~ m/^domain:/ and my $file_domain = $self->app->config->{global}->{file_domain}) + { + $allow_insecure = 1 if $file_domain eq $self->req->url->to_abs->host_port; + } $as_attachment = 0 if ($allow_insecure || $filetype !~ m/(html|svg)/) && $ext ne 'iso'; } # force saveAs @@ -181,18 +176,7 @@ return $is_text; } -sub _redirect_if_configured ($self, $is_text) { - # skip harmless text files as the viewer doesn't follow redirects and those files are not problematic anyway - return 0 if $is_text || !defined(my $domain = $self->app->config->{global}->{file_domain}); - # redirect to configured domain so potentially dangerious HTML files cannot use the current session - my $url = $self->req->url->to_abs; - return 0 if $url->host eq $domain; # skip if already redirected - $url->host($domain); - $self->redirect_to($url); - return 1; -} - -sub _serve_static ($self, $asset, $noredirect = 0) { +sub _serve_static ($self, $asset) { my $static = $self->static; my $log = $self->log; @@ -201,11 +185,7 @@ return $self->reply->not_found unless $asset; $log->debug('found ' . pp($asset)); - unless ($noredirect) { - my $is_text = blessed $asset && $asset->isa('Mojo::Asset::File') && $self->_set_headers($asset->path); - return 1 if $self->_redirect_if_configured($is_text); - } - + blessed $asset && $asset->isa('Mojo::Asset::File') && $self->_set_headers($asset->path); $static->serve_asset($self, $asset); return !!$self->rendered; } @@ -215,7 +195,7 @@ return $self->reply->not_found unless $self->_set_test; my $asset = $self->static->file('.thumbs/' . $self->param('filename')); - return $self->_serve_static($asset, 1); + return $self->_serve_static($asset); } # this is the agnostic route to images - usually served by apache directly @@ -224,7 +204,7 @@ # name is an URL parameter and can't contain slashes, so it should be safe my $dir = $self->param('md5_dirname') || ($self->param('md5_1') . '/' . $self->param('md5_2')); - return $self->_serve_static("$dir/.thumbs/" . $self->param('md5_basename'), 1); + return $self->_serve_static("$dir/.thumbs/" . $self->param('md5_basename')); } 1; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1761228068.a3a7f84d/lib/OpenQA/WebAPI/Plugin/Helpers.pm new/openQA-5.1761296552.ae7c17aa/lib/OpenQA/WebAPI/Plugin/Helpers.pm --- old/openQA-5.1761228068.a3a7f84d/lib/OpenQA/WebAPI/Plugin/Helpers.pm 2025-10-23 16:01:08.000000000 +0200 +++ new/openQA-5.1761296552.ae7c17aa/lib/OpenQA/WebAPI/Plugin/Helpers.pm 2025-10-24 11:02:32.000000000 +0200 @@ -381,6 +381,20 @@ } return $regex_problem && $context ? "$context: $regex_problem" : $regex_problem; }); + + $app->helper( + log_url => sub ($c, $testid, $resultfile, $is_userfile = 1) { + my $url = $c->url_for('test_file', testid => $testid, filename => $resultfile); + return _domain_url_for($c, $url, $is_userfile); + }); +} + +sub _domain_url_for ($c, $url, $is_userfile) { + if ($is_userfile and my $file_domain = $c->app->config->{global}->{file_domain}) { + $url->host($file_domain); + $url->scheme($c->req->url->scheme // 'http'); + } + return $url; } # returns the search args for the job overview according to the parameter of the specified controller diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1761228068.a3a7f84d/lib/OpenQA/WebAPI.pm new/openQA-5.1761296552.ae7c17aa/lib/OpenQA/WebAPI.pm --- old/openQA-5.1761228068.a3a7f84d/lib/OpenQA/WebAPI.pm 2025-10-23 16:01:08.000000000 +0200 +++ new/openQA-5.1761296552.ae7c17aa/lib/OpenQA/WebAPI.pm 2025-10-24 11:02:32.000000000 +0200 @@ -162,7 +162,7 @@ $test_r->get('/edit')->name('edit_test')->to('running#edit'); $test_r->get('/badge')->name('test_result_badge')->to('test#badge'); - $test_r->get('/images/#filename')->name('test_img')->to('file#test_image'); + $test_r->get('/images/#filename')->name('test_img')->to('file#test_file'); $test_r->get('/images/thumb/#filename')->name('test_thumbnail')->to('file#test_thumbnail'); $test_r->get('/file/#filename')->name('test_file')->to('file#test_file'); $test_r->get('/settings/:dir/*link_path')->name('filesrc')->to('test#show_filesrc'); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1761228068.a3a7f84d/t/api/04-jobs.t new/openQA-5.1761296552.ae7c17aa/t/api/04-jobs.t --- old/openQA-5.1761228068.a3a7f84d/t/api/04-jobs.t 2025-10-23 16:01:08.000000000 +0200 +++ new/openQA-5.1761296552.ae7c17aa/t/api/04-jobs.t 2025-10-24 11:02:32.000000000 +0200 @@ -1215,7 +1215,8 @@ $t->get_ok('/api/v1/jobs/99938/details')->status_is(200); $t->json_is('/job/logs/0', 'video.ogv', 'Test result logs are present'); - $t->json_is('/job/ulogs/0', 'y2logs.tar.bz2', 'Test result uploaded logs are present'); + $t->json_is('/job/ulogs/0', 'report.html', 'Test result uploaded logs are present (report.html)'); + $t->json_is('/job/ulogs/1', 'y2logs.tar.bz2', 'Test result uploaded logs are present (y2logs.tar.bz2)'); }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1761228068.a3a7f84d/t/testresults/00099/00099938-opensuse-Factory-DVD-x86_64-Build0048-doc/ulogs/report.html new/openQA-5.1761296552.ae7c17aa/t/testresults/00099/00099938-opensuse-Factory-DVD-x86_64-Build0048-doc/ulogs/report.html --- old/openQA-5.1761228068.a3a7f84d/t/testresults/00099/00099938-opensuse-Factory-DVD-x86_64-Build0048-doc/ulogs/report.html 1970-01-01 01:00:00.000000000 +0100 +++ new/openQA-5.1761296552.ae7c17aa/t/testresults/00099/00099938-opensuse-Factory-DVD-x86_64-Build0048-doc/ulogs/report.html 2025-10-24 11:02:32.000000000 +0200 @@ -0,0 +1,4 @@ +<html> +<head><title>Some HTML report generated by a test</title></head> +<body>HELLO WORLD</body> +</html> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1761228068.a3a7f84d/t/ui/07-file.t new/openQA-5.1761296552.ae7c17aa/t/ui/07-file.t --- old/openQA-5.1761228068.a3a7f84d/t/ui/07-file.t 2025-10-23 16:01:08.000000000 +0200 +++ new/openQA-5.1761296552.ae7c17aa/t/ui/07-file.t 2025-10-24 11:02:32.000000000 +0200 @@ -141,22 +141,59 @@ $t->get_ok('/assets/hdd/foo.qcow2')->status_is(200)->content_type_is('application/octet-stream'); $t->get_ok('/assets/repo/testrepo/doesnotexist')->status_is(404); -subtest 'redirection to different domain' => sub { - my $config = $t->app->config->{global}; - $config->{file_security_policy} = 'domain:openqa-files'; - $config->{file_domain} = 'openqa-files'; - $t->get_ok('/assets/repo/testrepo/README.html')->status_is(302); - $t->header_like(Location => qr|^http://openqa-files(:\d+)?/assets/repo/testrepo/README.html$|); - - $t->get_ok('/tests/99961/asset/repo/testrepo/README')->status_is(302); - $t->header_like(Location => qr|^//openqa-files(:\d+)?/assets/repo/testrepo/README$|); - - # no redirect for images and thumbs - $t->get_ok('/tests/99938/images/logpackages-1.png')->status_is(200)->content_type_is('image/png') - ->header_is('Content-Length' => '48019'); - $t->get_ok('/tests/99938/images/thumb/logpackages-1.png')->status_is(200)->content_type_is('image/png') - ->header_is('Content-Length' => '6769'); - $t->get_ok('/image/347/da6/.thumbs/61d0c3faf37d49d33b6fc308f2.png')->status_is(200)->content_type_is('image/png'); +subtest 'file security policy' => sub { + + subtest 'file domain' => sub { + my $config = $t->app->config->{global}; + $config->{file_security_policy} = 'domain:openqa-files'; + $config->{file_domain} = 'openqa-files'; + $t->get_ok('/tests/99938/downloads_ajax')->status_is(200); + my $link = $t->tx->res->dom->find('a')->grep(qr/vars.json/)->map(attr => 'href')->first; + like $link, qr{^/}, 'link to vars.json points to same domain'; + $link = $t->tx->res->dom->find('a')->grep(qr/report.html/)->map(attr => 'href')->first; + like $link, qr{^http://openqa-files/}, 'link to user HTML file points to file domain subdomain'; + + for my $url (qw(/assets/repo/testrepo/README.html /tests/99938/file/report.html)) { + $t->get_ok($url)->status_is(200); + $t->header_like( + 'Content-Disposition', + qr/attachment; filename=.*.html;/, + "$url - HTML under original domain served as attachment" + ); + } + + $t->get_ok('/tests/99961/asset/repo/testrepo/README')->status_is(302, 'asset is redirected to asset url'); + $t->header_like(Location => qr|^/assets/repo/testrepo/README$|); + }; + + subtest 'insecure-browsing' => sub { + my $config = $t->app->config->{global}; + delete $config->{file_domain}; + $config->{file_security_policy} = 'insecure-browsing'; + $t->get_ok('/tests/99938/downloads_ajax')->status_is(200); + my $link = $t->tx->res->dom->find('a')->grep(qr/report.html/)->map(attr => 'href')->first; + like $link, qr{^/}, 'link to HTML file points to same domain'; + + for my $url (qw(/assets/repo/testrepo/README.html /tests/99938/file/report.html)) { + $t->get_ok($url)->status_is(200); + $t->header_is('Content-Disposition', undef, "$url - Not served as attachment"); + } + }; + + subtest 'download-prompt' => sub { + my $config = $t->app->config->{global}; + $config->{file_security_policy} = 'download-prompt'; + $t->get_ok('/tests/99938/downloads_ajax')->status_is(200); + my $link = $t->tx->res->dom->find('a')->grep(qr/report.html/)->map(attr => 'href')->first; + like $link, qr{^/}, 'link to HTML file points to same domain'; + + $t->get_ok('/assets/repo/testrepo/README.html')->status_is(200); + $t->header_is( + 'Content-Disposition', + 'attachment; filename=README.html;', + 'HTML under original domain served as attachment' + ); + }; }; done_testing(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1761228068.a3a7f84d/templates/webapi/test/downloads.html.ep new/openQA-5.1761296552.ae7c17aa/templates/webapi/test/downloads.html.ep --- old/openQA-5.1761228068.a3a7f84d/templates/webapi/test/downloads.html.ep 2025-10-23 16:01:08.000000000 +0200 +++ new/openQA-5.1761296552.ae7c17aa/templates/webapi/test/downloads.html.ep 2025-10-24 11:02:32.000000000 +0200 @@ -1,10 +1,10 @@ % if(@$resultfiles) { <h5>Result files</h5> - %= include 'test/result_file_list', resultfiles => $resultfiles + %= include 'test/result_file_list', resultfiles => $resultfiles, is_userfile => 0 % } % if (@$ulogs) { <h6>Uploaded logs</h6> - %= include 'test/result_file_list', resultfiles => $ulogs + %= include 'test/result_file_list', resultfiles => $ulogs, is_userfile => 1 % } % my $assets = $job->jobs_assets; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1761228068.a3a7f84d/templates/webapi/test/result_file_list.html.ep new/openQA-5.1761296552.ae7c17aa/templates/webapi/test/result_file_list.html.ep --- old/openQA-5.1761228068.a3a7f84d/templates/webapi/test/result_file_list.html.ep 2025-10-23 16:01:08.000000000 +0200 +++ new/openQA-5.1761296552.ae7c17aa/templates/webapi/test/result_file_list.html.ep 2025-10-24 11:02:32.000000000 +0200 @@ -17,14 +17,14 @@ % } % else { <i class="fa fa-file-o"></i> - <a href="<%= url_for('test_file', testid => $testid, filename => $resultfile) %>"> + <a href="<%= log_url($testid, $resultfile, $is_userfile) %>"> <%= $resultfile %> </a> % next; % } - <a href="<%= url_for('test_file', testid => $testid, filename => $resultfile) %>" target="blank" title="Raw/download"> + <a href="<%= log_url($testid, $resultfile, $is_userfile) %>" target="blank" title="Raw/download"> <i class="fa fa-download"></i> </a> </li> % } -</ul> \ No newline at end of file +</ul> ++++++ openQA.obsinfo ++++++ --- /var/tmp/diff_new_pack.2FrhAp/_old 2025-10-27 14:41:27.162976280 +0100 +++ /var/tmp/diff_new_pack.2FrhAp/_new 2025-10-27 14:41:27.206978138 +0100 @@ -1,5 +1,5 @@ name: openQA -version: 5.1761228068.a3a7f84d -mtime: 1761228068 -commit: a3a7f84d0a22e2b1efdda0d319b7b14ccc1584ab +version: 5.1761296552.ae7c17aa +mtime: 1761296552 +commit: ae7c17aa933783d60ea30f148fe82043d564fe5b
