diff --git a/Bugzilla/CGI.pm b/Bugzilla/CGI.pm index 44c089a2..9b1ff923 100644 --- a/Bugzilla/CGI.pm +++ b/Bugzilla/CGI.pm @@ -288,6 +288,69 @@ sub close_standby_message { } } +our $ALLOW_UNSAFE_RESPONSE = 0; +# responding to text/plain or text/html is safe +# responding to any request with a referer header is safe +# some things need to have unsafe responses (attachment.cgi) +# everything else should get a 403. +sub _prevent_unsafe_response { + my ($self, $headers) = @_; + my $safe_content_type_re = qr{ + ^ (*COMMIT) # COMMIT makes the regex faster + # by preventing back-tracking. see also perldoc pelre. + # application/x-javascript, xml, atom+xml, rdf+xml, xml-dtd, and json + (?: application/ (?: x(?: -javascript | ml (?: -dtd )? ) + | (?: atom | rdf) \+ xml + | json ) + # text/csv, text/calendar, text/plain, and text/html + | text/ (?: c (?: alendar | sv ) + | plain + | html ) + # used for HTTP push responses + | multipart/x-mixed-replace) + }sx; + my $safe_referer_re = do { + # Note that urlbase must end with a /. + # It almost certainly does, but let's be extra careful. + my $urlbase = correct_urlbase(); + $urlbase =~ s{/$}{}; + qr{ + # Begins with literal urlbase + ^ (*COMMIT) + \Q$urlbase\E + # followed by a slash or end of string + (?: / + | $ ) + }sx + }; + + return if $ALLOW_UNSAFE_RESPONSE; + + if (Bugzilla->usage_mode == USAGE_MODE_BROWSER) { + # Safe content types are ones that arn't images. + # For now let's assume plain text and html are not valid images. + my $content_type = $headers->{'-type'} // $headers->{'-content_type'} // 'text/html'; + my $is_safe_content_type = $content_type =~ $safe_content_type_re; + + # Safe referers are ones that begin with the urlbase. + my $referer = $self->referer; + my $is_safe_referer = $referer && $referer =~ $safe_referer_re; + + if (!$is_safe_referer && !$is_safe_content_type) { + print $self->SUPER::header(-type => 'text/html', -status => '403 Forbidden'); + if ($content_type ne 'text/html') { + print "Untrusted Referer Header\n"; + if ($ENV{MOD_PERL}) { + my $r = $self->r; + $r->rflush; + $r->status(200); + } + } + exit; + } + } +} + # Override header so we can add the cookies in sub header { my $self = shift; @@ -302,6 +365,7 @@ sub header { else { %headers = @_; } + $self->_prevent_unsafe_response(\%headers); if ($self->{'_content_disp'}) { $headers{'-content_disposition'} = $self->{'_content_disp'}; diff --git a/Bugzilla/Config.pm b/Bugzilla/Config.pm index 1c02d9dd..45861670 100644 --- a/Bugzilla/Config.pm +++ b/Bugzilla/Config.pm @@ -16,10 +16,9 @@ use autodie qw(:default); use Bugzilla::Constants; use Bugzilla::Hook; -use Bugzilla::Util qw(trick_taint); +use Bugzilla::Util qw(trick_taint read_text write_text); use JSON::XS; -use File::Slurp; use File::Temp; use File::Basename; @@ -284,7 +283,7 @@ sub write_params { my $param_file = bz_locations()->{'datadir'} . '/params.json'; my $json_data = JSON::XS->new->canonical->pretty->encode($param_data); - write_file($param_file, { binmode => ':utf8', atomic => 1 }, \$json_data); + write_text($param_file, $json_data); # It's not common to edit parameters and loading # Bugzilla::Install::Filesystem is slow. @@ -301,8 +300,8 @@ sub read_param_file { my $file = bz_locations()->{'datadir'} . '/params.json'; if (-e $file) { - my $data; - read_file($file, binmode => ':utf8', buf_ref => \$data); + my $data = read_text($file); + trick_taint($data); # If params.json has been manually edited and e.g. some quotes are # missing, we don't want JSON::XS to leak the content of the file diff --git a/Bugzilla/Constants.pm b/Bugzilla/Constants.pm index 8b2eeac2..b4d22f8b 100644 --- a/Bugzilla/Constants.pm +++ b/Bugzilla/Constants.pm @@ -200,7 +200,7 @@ use Memoize; # CONSTANTS # # Bugzilla version -use constant BUGZILLA_VERSION => "5.0.3"; +use constant BUGZILLA_VERSION => "5.0.4"; # A base link to the current REST Documentation. We place it here # as it will need to be updated to whatever the current release is. diff --git a/Bugzilla/DB/Sqlite.pm b/Bugzilla/DB/Sqlite.pm index ddafc169..a56ed31a 100644 --- a/Bugzilla/DB/Sqlite.pm +++ b/Bugzilla/DB/Sqlite.pm @@ -219,6 +219,7 @@ sub sql_date_format { my ($self, $date, $format) = @_; $format = "%Y.%m.%d %H:%M:%S" if !$format; $format =~ s/\%i/\%M/g; + $format =~ s/\%s/\%S/g; return "STRFTIME(" . $self->quote($format) . ", $date)"; } diff --git a/Bugzilla/Install/Filesystem.pm b/Bugzilla/Install/Filesystem.pm index 4f133d86..d30ae18d 100644 --- a/Bugzilla/Install/Filesystem.pm +++ b/Bugzilla/Install/Filesystem.pm @@ -31,7 +31,6 @@ use File::Path; use File::Basename; use File::Copy qw(move); use File::Spec; -use File::Slurp; use IO::File; use POSIX (); @@ -536,7 +535,7 @@ sub update_filesystem { # Remove old assets htaccess file to force recreation with correct values. if (-e "$assetsdir/.htaccess") { - if (read_file("$assetsdir/.htaccess") =~ //) { + if (read_text("$assetsdir/.htaccess") =~ //) { unlink("$assetsdir/.htaccess"); } } @@ -782,22 +781,21 @@ sub _update_old_charts { # to product IDs. sub _update_old_mining_filenames { my ($miningdir) = @_; + my $dbh = Bugzilla->dbh; my @conversion_errors; - require Bugzilla::Product; - # We use a dummy product instance with ID 0, representing all products my $product_all = {id => 0, name => '-All-'}; - bless($product_all, 'Bugzilla::Product'); print "Updating old charting data file names..."; - my @products = Bugzilla::Product->get_all(); + my @products = @{ $dbh->selectall_arrayref('SELECT id, name FROM products + ORDER BY name', {Slice=>{}}) }; push(@products, $product_all); foreach my $product (@products) { - if (-e File::Spec->catfile($miningdir, $product->id)) { + if (-e File::Spec->catfile($miningdir, $product->{id})) { push(@conversion_errors, { product => $product, - message => 'A file named "' . $product->id . + message => 'A file named "' . $product->{id} . '" already exists.' }); } } @@ -805,8 +803,8 @@ sub _update_old_mining_filenames { if (! @conversion_errors) { # Renaming mining files should work now without a hitch. foreach my $product (@products) { - if (! rename(File::Spec->catfile($miningdir, $product->name), - File::Spec->catfile($miningdir, $product->id))) { + if (! rename(File::Spec->catfile($miningdir, $product->{name}), + File::Spec->catfile($miningdir, $product->{id}))) { push(@conversion_errors, { product => $product, message => $! }); @@ -822,7 +820,7 @@ sub _update_old_mining_filenames { print " FAILED:\n"; foreach my $error (@conversion_errors) { printf "Cannot rename charting data file for product %d (%s): %s\n", - $error->{product}->id, $error->{product}->name, + $error->{product}->{id}, $error->{product}->{name}, $error->{message}; } print "You need to empty the \"$miningdir\" directory, then run\n", diff --git a/Bugzilla/Install/Requirements.pm b/Bugzilla/Install/Requirements.pm index a688a0ff..61496d84 100644 --- a/Bugzilla/Install/Requirements.pm +++ b/Bugzilla/Install/Requirements.pm @@ -155,11 +155,6 @@ sub REQUIRED_MODULES { module => 'Math::Random::ISAAC', version => '1.0.1', }, - { - package => 'File-Slurp', - module => 'File::Slurp', - version => '9999.13', - }, { package => 'JSON-XS', module => 'JSON::XS', diff --git a/Bugzilla/JobQueue.pm b/Bugzilla/JobQueue.pm index d5ceda8e..6ff85d84 100644 --- a/Bugzilla/JobQueue.pm +++ b/Bugzilla/JobQueue.pm @@ -14,8 +14,8 @@ use warnings; use Bugzilla::Constants; use Bugzilla::Error; use Bugzilla::Install::Util qw(install_string); +use Bugzilla::Util qw(read_text); use File::Basename; -use File::Slurp; use base qw(TheSchwartz); use fields qw(_worker_pidfile); @@ -124,7 +124,7 @@ sub subprocess_worker { # And poll the PID to detect when the working has finished. # We do this instead of system() to allow for the INT signal to # interrup us and trigger kill_worker(). - my $pid = read_file($self->{_worker_pidfile}, err_mode => 'quiet'); + my $pid = read_text($self->{_worker_pidfile}, err_mode => 'quiet'); if ($pid) { sleep(3) while(kill(0, $pid)); } @@ -139,7 +139,7 @@ sub subprocess_worker { sub kill_worker { my $self = Bugzilla->job_queue(); if ($self->{_worker_pidfile} && -e $self->{_worker_pidfile}) { - my $worker_pid = read_file($self->{_worker_pidfile}); + my $worker_pid = read_text($self->{_worker_pidfile}); if ($worker_pid && kill(0, $worker_pid)) { $self->debug("Stopping worker process"); system "$0 -f -p '" . $self->{_worker_pidfile} . "' stop"; diff --git a/Bugzilla/Migrate.pm b/Bugzilla/Migrate.pm index 0731d4fe..7865c842 100644 --- a/Bugzilla/Migrate.pm +++ b/Bugzilla/Migrate.pm @@ -403,7 +403,7 @@ sub parse_date { } my $tz; if ($time[6]) { - $tz = Bugzilla->local_timezone->offset_as_string($time[6]); + $tz = DateTime::TimeZone->offset_as_string($time[6]); } else { $tz = $self->config('timezone'); diff --git a/Bugzilla/Template.pm b/Bugzilla/Template.pm index 41b9265c..decffe1e 100644 --- a/Bugzilla/Template.pm +++ b/Bugzilla/Template.pm @@ -32,7 +32,6 @@ use Digest::MD5 qw(md5_hex); use File::Basename qw(basename dirname); use File::Find; use File::Path qw(rmtree mkpath); -use File::Slurp; use File::Spec; use IO::Dir; use List::MoreUtils qw(firstidx); @@ -502,7 +501,7 @@ sub _concatenate_css { next unless -e "$cgi_path/$files{$source}"; my $file = $skins_path . '/' . md5_hex($source) . '.css'; if (!-e $file) { - my $content = read_file("$cgi_path/$files{$source}"); + my $content = read_text("$cgi_path/$files{$source}"); # minify $content =~ s{/\*.*?\*/}{}sg; # comments @@ -512,7 +511,7 @@ sub _concatenate_css { # rewrite urls $content =~ s{url\(([^\)]+)\)}{_css_url_rewrite($source, $1)}eig; - write_file($file, "/* $files{$source} */\n" . $content . "\n"); + write_text($file, "/* $files{$source} */\n" . $content . "\n"); } push @minified, $file; } @@ -522,9 +521,9 @@ sub _concatenate_css { if (!-e $file) { my $content = ''; foreach my $source (@minified) { - $content .= read_file($source); + $content .= read_text($source); } - write_file($file, $content); + write_text($file, $content); } $file =~ s/^\Q$cgi_path\E\///o; @@ -563,7 +562,7 @@ sub _concatenate_js { next unless -e "$cgi_path/$files{$source}"; my $file = $skins_path . '/' . md5_hex($source) . '.js'; if (!-e $file) { - my $content = read_file("$cgi_path/$files{$source}"); + my $content = read_text("$cgi_path/$files{$source}"); # minimal minification $content =~ s#/\*.*?\*/##sg; # block comments @@ -572,7 +571,7 @@ sub _concatenate_js { $content =~ s#\n{2,}#\n#g; # blank lines $content =~ s#(^\s+|\s+$)##g; # whitespace at the start/end of file - write_file($file, ";/* $files{$source} */\n" . $content . "\n"); + write_text($file, ";/* $files{$source} */\n" . $content . "\n"); } push @minified, $file; } @@ -582,9 +581,9 @@ sub _concatenate_js { if (!-e $file) { my $content = ''; foreach my $source (@minified) { - $content .= read_file($source); + $content .= read_text($source); } - write_file($file, $content); + write_text($file, $content); } $file =~ s/^\Q$cgi_path\E\///o; diff --git a/Bugzilla/Util.pm b/Bugzilla/Util.pm index bbf4261c..57ce5f6b 100644 --- a/Bugzilla/Util.pm +++ b/Bugzilla/Util.pm @@ -24,7 +24,7 @@ use parent qw(Exporter); validate_email_syntax check_email_syntax clean_text get_text template_var display_value disable_utf8 detect_encoding email_filter - join_activity_entries); + join_activity_entries read_text write_text); use Bugzilla::Constants; use Bugzilla::RNG qw(irand); @@ -39,6 +39,8 @@ use Scalar::Util qw(tainted blessed); use Text::Wrap; use Encode qw(encode decode resolve_alias); use Encode::Guess; +use File::Basename qw(dirname); +use File::Temp qw(tempfile); sub trick_taint { require Carp; @@ -106,6 +108,29 @@ sub html_quote { return $var; } +sub read_text { + my ($filename) = @_; + open my $fh, '<:encoding(utf-8)', $filename; + local $/ = undef; + my $content = <$fh>; + close $fh; + return $content; +} + +sub write_text { + my ($filename, $content) = @_; + my ($tmp_fh, $tmp_filename) = tempfile('.tmp.XXXXXXXXXX', + DIR => dirname($filename), + UNLINK => 0, + ); + binmode $tmp_fh, ':encoding(utf-8)'; + print $tmp_fh $content; + close $tmp_fh; + # File::Temp tries for secure files, but File::Slurp used the umask. + chmod(0666 & ~umask, $tmp_filename); + rename $tmp_filename, $filename; +} + sub html_light_quote { my ($text) = @_; # admin/table.html.tmpl calls |FILTER html_light| many times. @@ -588,7 +613,7 @@ sub datetime_from { second => defined($time[0]) ? int($time[0]) : undef, # If a timezone was specified, use it. Otherwise, use the # local timezone. - time_zone => Bugzilla->local_timezone->offset_as_string($time[6]) + time_zone => DateTime::TimeZone->offset_as_string($time[6]) || Bugzilla->local_timezone, ); diff --git a/attachment.cgi b/attachment.cgi index 40b0c9d3..4cd9229f 100755 --- a/attachment.cgi +++ b/attachment.cgi @@ -35,6 +35,7 @@ use Encode::MIME::Header; # Required to alter Encode::Encoding{'MIME-Q'}. local our $cgi = Bugzilla->cgi; local our $template = Bugzilla->template; local our $vars = {}; +local $Bugzilla::CGI::ALLOW_UNSAFE_RESPONSE = 1; # All calls to this script should contain an "action" variable whose # value determines what the user wants to do. The code below checks diff --git a/contrib/jb2bz.py b/contrib/jb2bz.py index 85f95423..caaa0c5e 100755 --- a/contrib/jb2bz.py +++ b/contrib/jb2bz.py @@ -17,8 +17,8 @@ Share and enjoy. """ -import rfc822, mimetools, multifile, mimetypes, email.utils -import sys, re, glob, StringIO, os, stat, time +import email, mimetypes, email.utils +import sys, re, glob, os, stat, time import MySQLdb, getopt # mimetypes doesn't include everything we might encounter, yet. @@ -89,10 +89,24 @@ def process_notes_file(current, fname): def process_reply_file(current, fname): new_note = {} reply = open(fname, "r") - msg = rfc822.Message(reply) - new_note['text'] = "%s\n%s" % (msg['From'], msg.fp.read()) - new_note['timestamp'] = email.utils.parsedate_tz(msg['Date']) - current["notes"].append(new_note) + msg = email.message_from_file(reply) + + # Add any attachments that may have been in a followup or reply + msgtype = msg.get_content_maintype() + if msgtype == "multipart": + for part in msg.walk(): + new_note = {} + if part.get_filename() is None: + if part.get_content_type() == "text/plain": + new_note['timestamp'] = time.gmtime(email.utils.mktime_tz(email.utils.parsedate_tz(msg['Date']))) + new_note['text'] = "%s\n%s" % (msg['From'], part.get_payload()) + current["notes"].append(new_note) + else: + maybe_add_attachment(part, current) + else: + new_note['text'] = "%s\n%s" % (msg['From'], msg.get_payload()) + new_note['timestamp'] = time.gmtime(email.utils.mktime_tz(email.utils.parsedate_tz(msg['Date']))) + current["notes"].append(new_note) def add_notes(current): """Add any notes that have been recorded for the current bug.""" @@ -104,51 +118,48 @@ def add_notes(current): for f in glob.glob("%d.followup.*" % current['number']): process_reply_file(current, f) -def maybe_add_attachment(current, file, submsg): +def maybe_add_attachment(submsg, current): """Adds the attachment to the current record""" - cd = submsg["Content-Disposition"] - m = re.search(r'filename="([^"]+)"', cd) - if m == None: + attachment_filename = submsg.get_filename() + if attachment_filename is None: return - attachment_filename = m.group(1) - if (submsg.gettype() == 'application/octet-stream'): + + if (submsg.get_content_type() == 'application/octet-stream'): # try get a more specific content-type for this attachment - type, encoding = mimetypes.guess_type(m.group(1)) - if type == None: - type = submsg.gettype() + mtype, encoding = mimetypes.guess_type(attachment_filename) + if mtype == None: + mtype = submsg.get_content_type() else: - type = submsg.gettype() + mtype = submsg.get_content_type() - try: - data = StringIO.StringIO() - mimetools.decode(file, data, submsg.getencoding()) - except: + if mtype == 'application/x-pkcs7-signature': + return + + if mtype == 'application/pkcs7-signature': + return + + if mtype == 'application/pgp-signature': return - current['attachments'].append( ( attachment_filename, type, data.getvalue() ) ) + if mtype == 'message/rfc822': + return -def process_mime_body(current, file, submsg): - data = StringIO.StringIO() try: - mimetools.decode(file, data, submsg.getencoding()) - current['description'] = data.getvalue() + data = submsg.get_payload(decode=True) except: return + current['attachments'].append( ( attachment_filename, mtype, data ) ) + def process_text_plain(msg, current): - current['description'] = msg.fp.read() - -def process_multi_part(file, msg, current): - mf = multifile.MultiFile(file) - mf.push(msg.getparam("boundary")) - while mf.next(): - submsg = mimetools.Message(file) - if submsg.has_key("Content-Disposition"): - maybe_add_attachment(current, mf, submsg) + current['description'] = msg.get_payload() + +def process_multi_part(msg, current): + for part in msg.walk(): + if part.get_filename() is None: + process_text_plain(part, current) else: - # This is the message body itself (always?), so process - # accordingly - process_mime_body(current, mf, submsg) + maybe_add_attachment(part, current) def process_jitterbug(filename): current = {} @@ -158,39 +169,37 @@ def process_jitterbug(filename): current['description'] = '' current['date-reported'] = () current['short-description'] = '' - - print "Processing: %d" % current['number'] - file = open(filename, "r") - create_date = os.fstat(file.fileno()) - msg = mimetools.Message(file) + print "Processing: %d" % current['number'] - msgtype = msg.gettype() + mfile = open(filename, "r") + create_date = os.fstat(mfile.fileno()) + msg = email.message_from_file(mfile) - add_notes(current) - current['date-reported'] = email.utils.parsedate_tz(msg['Date']) + current['date-reported'] = time.gmtime(email.utils.mktime_tz(email.utils.parsedate_tz(msg['Date']))) if current['date-reported'] is None: current['date-reported'] = time.gmtime(create_date[stat.ST_MTIME]) if current['date-reported'][0] < 1900: current['date-reported'] = time.gmtime(create_date[stat.ST_MTIME]) - if msg.getparam('Subject') is not None: + if msg.has_key('Subject') is not False: current['short-description'] = msg['Subject'] else: current['short-description'] = "Unknown" - if msgtype[:5] == 'text/': + msgtype = msg.get_content_maintype() + if msgtype == 'text': process_text_plain(msg, current) - elif msgtype[:5] == 'text': - process_text_plain(msg, current) - elif msgtype[:10] == "multipart/": - process_multi_part(file, msg, current) + elif msgtype == "multipart": + process_multi_part(msg, current) else: # Huh? This should never happen. print "Unknown content-type: %s" % msgtype sys.exit(1) + add_notes(current) + # At this point we have processed the message: we have all of the notes and # attachments stored, so it's time to add things to the database. # The schema for JitterBug 2.14 can be found at: @@ -219,6 +228,7 @@ def process_jitterbug(filename): try: cursor.execute( "INSERT INTO bugs SET " \ "bug_id=%s," \ + "priority='---'," \ "bug_severity='normal'," \ "bug_status=%s," \ "creation_ts=%s," \ @@ -242,7 +252,7 @@ def process_jitterbug(filename): version, component, resolution] ) - + # This is the initial long description associated with the bug report cursor.execute( "INSERT INTO longdescs SET " \ "bug_id=%s," \ @@ -253,7 +263,7 @@ def process_jitterbug(filename): reporter, time.strftime("%Y-%m-%d %H:%M:%S", current['date-reported'][:9]), current['description'] ] ) - + # Add whatever notes are associated with this defect for n in current['notes']: cursor.execute( "INSERT INTO longdescs SET " \ @@ -265,15 +275,15 @@ def process_jitterbug(filename): reporter, time.strftime("%Y-%m-%d %H:%M:%S", n['timestamp'][:9]), n['text']]) - + # add attachments associated with this defect for a in current['attachments']: cursor.execute( "INSERT INTO attachments SET " \ - "bug_id=%s, creation_ts=%s, description='', mimetype=%s," \ + "bug_id=%s, creation_ts=%s, description=%s, mimetype=%s," \ "filename=%s, submitter_id=%s", [ current['number'], time.strftime("%Y-%m-%d %H:%M:%S", current['date-reported'][:9]), - a[1], a[0], reporter ]) + a[0], a[1], a[0], reporter ]) cursor.execute( "INSERT INTO attach_data SET " \ "id=LAST_INSERT_ID(), thedata=%s", [ a[2] ]) diff --git a/docs/en/rst/conf.py b/docs/en/rst/conf.py index a758fd24..34acb477 100644 --- a/docs/en/rst/conf.py +++ b/docs/en/rst/conf.py @@ -44,7 +44,7 @@ # General information about the project. project = u'Bugzilla' -copyright = u'2014, The Bugzilla Team' +copyright = u'2016, The Bugzilla Team' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -387,7 +387,7 @@ on_rtd = os.environ.get('READTHEDOCS', None) == 'True' if on_rtd: - base_api_url = 'https://www.bugzilla.org/docs/5.0/en/html/api/' + base_api_url = 'https://www.bugzilla.org/docs/5.0/en/html/integrating/api/' else: base_api_url = '../integrating/api/' diff --git a/docs/en/rst/installing/linux.rst b/docs/en/rst/installing/linux.rst index 22d0bf73..e2e05c31 100644 --- a/docs/en/rst/installing/linux.rst +++ b/docs/en/rst/installing/linux.rst @@ -49,7 +49,7 @@ graphviz patchutils gcc 'perl(Apache2::SizeLimit)' 'perl(Authen::Radius)' 'perl(Daemon::Generic)' 'perl(Date::Format)' 'perl(DateTime)' 'perl(DateTime::TimeZone)' 'perl(DBI)' 'perl(Digest::SHA)' 'perl(Email::MIME)' 'perl(Email::Reply)' 'perl(Email::Sender)' 'perl(Encode)' 'perl(Encode::Detect)' -'perl(File::MimeInfo::Magic)' 'perl(File::Slurp)' 'perl(GD)' 'perl(GD::Graph)' +'perl(File::MimeInfo::Magic)' 'perl(GD)' 'perl(GD::Graph)' 'perl(GD::Text)' 'perl(HTML::FormatText::WithLinks)' 'perl(HTML::Parser)' 'perl(HTML::Scrubber)' 'perl(IO::Scalar)' 'perl(JSON::RPC)' 'perl(JSON::XS)' 'perl(List::MoreUtils)' 'perl(LWP::UserAgent)' 'perl(Math::Random::ISAAC)' @@ -117,7 +117,7 @@ Bugzilla The best way to get Bugzilla is to check it out from git: -:command:`git clone --branch release-X.X-stable https://git.mozilla.org/bugzilla/bugzilla` +:command:`git clone --branch release-X.X-stable https://github.com/bugzilla/bugzilla` Run the above command in your home directory, replacing "X.X" with the 2-digit version number of the stable release of Bugzilla that you want - e.g. "4.4". diff --git a/docs/en/rst/installing/mac-os-x.rst b/docs/en/rst/installing/mac-os-x.rst index b18a5ec3..37a1d361 100644 --- a/docs/en/rst/installing/mac-os-x.rst +++ b/docs/en/rst/installing/mac-os-x.rst @@ -28,7 +28,7 @@ Bugzilla The best way to get Bugzilla is to check it out from git: -:command:`git clone --branch release-X.X-stable https://git.mozilla.org/bugzilla/bugzilla` +:command:`git clone --branch release-X.X-stable https://github.com/bugzilla/bugzilla` Run the above command in your home directory, replacing "X.X" with the 2-digit version number of the stable release of Bugzilla that you want - e.g. "4.4". diff --git a/docs/en/rst/installing/migrating-from-2.inc.rst b/docs/en/rst/installing/migrating-from-2.inc.rst index c9328077..889e5c3d 100644 --- a/docs/en/rst/installing/migrating-from-2.inc.rst +++ b/docs/en/rst/installing/migrating-from-2.inc.rst @@ -21,7 +21,7 @@ Mac OS X, you can Once git is installed, run these commands to pull a copy of Bugzilla: -:command:`git clone https://git.mozilla.org/bugzilla/bugzilla bugzilla-new` +:command:`git clone https://github.com/bugzilla/bugzilla bugzilla-new` :command:`cd bugzilla-new` diff --git a/docs/en/rst/installing/migrating.rst b/docs/en/rst/installing/migrating.rst index 5b842dd3..8fc0de5f 100644 --- a/docs/en/rst/installing/migrating.rst +++ b/docs/en/rst/installing/migrating.rst @@ -4,8 +4,7 @@ Migrating From Other Bug-Tracking Systems ######################################### Bugzilla has a framework you can use for migrating from other bug-tracking -systems - -`Bugzilla::Migrate `_. +systems - :api:`Bugzilla::Migrate `. It provides the infrastructure you will need, but requires a module to be written to define the specifics of the system you are coming from. One exists for diff --git a/docs/en/rst/installing/quick-start.rst b/docs/en/rst/installing/quick-start.rst index 64a88e55..7ea5ed58 100644 --- a/docs/en/rst/installing/quick-start.rst +++ b/docs/en/rst/installing/quick-start.rst @@ -64,7 +64,7 @@ Get it from our Git repository: :command:`cd /var/www/html` -:command:`git clone --branch release-X.X-stable https://git.mozilla.org/bugzilla/bugzilla bugzilla` +:command:`git clone --branch release-X.X-stable https://github.com/bugzilla/bugzilla bugzilla` (where "X.X" is the 2-digit version number of the stable release of Bugzilla that you want - e.g. 5.0) diff --git a/docs/en/rst/installing/upgrading-with-git.rst b/docs/en/rst/installing/upgrading-with-git.rst index 075ff890..85595134 100644 --- a/docs/en/rst/installing/upgrading-with-git.rst +++ b/docs/en/rst/installing/upgrading-with-git.rst @@ -9,6 +9,18 @@ intermediate steps. There is a script named :file:`checksetup.pl` included with Bugzilla that will automatically do all of the database migration for you. +Bugzilla is now hosted on Github, but we used to be hosted on git.mozilla.org. +If you got the code from git.mozilla.org, you need to point your +checkout at Github instead. To find out, run: + +:command:`git remote -v` + +If you see "git.mozilla.org" anywhere in the output, then run: + +:command:`git remote set-url origin https://github.com/bugzilla/bugzilla` + +This change will only ever need to be done once. + .. include:: upgrading-with-1.inc.rst You can see if you have local code customizations using: diff --git a/docs/en/rst/installing/windows.rst b/docs/en/rst/installing/windows.rst index adc1728c..d756077b 100644 --- a/docs/en/rst/installing/windows.rst +++ b/docs/en/rst/installing/windows.rst @@ -40,7 +40,7 @@ Bugzilla The best way to get Bugzilla is to check it out from git. Download and install git from the `git website `_, and then run: -:command:`git clone --branch release-X.X-stable https://git.mozilla.org/bugzilla/bugzilla C:\\bugzilla` +:command:`git clone --branch release-X.X-stable https://github.com/bugzilla/bugzilla C:\\bugzilla` where "X.X" is the 2-digit version number of the stable release of Bugzilla that you want (e.g. 5.0). @@ -85,7 +85,6 @@ Install the following mandatory modules with: * URI * List-MoreUtils * Math-Random-ISAAC -* File-Slurp * JSON-XS * Win32 * Win32-API diff --git a/docs/en/rst/integrating/extensions.rst b/docs/en/rst/integrating/extensions.rst index 18c5341d..6a3fd8d3 100644 --- a/docs/en/rst/integrating/extensions.rst +++ b/docs/en/rst/integrating/extensions.rst @@ -11,8 +11,8 @@ versions of Bugzilla with minimal effort. We maintain a written by other people on our wiki. You would need to make sure that the extension in question works with your version of Bugzilla. -Or, you can write your own extension. See the `Bugzilla Extension -documentation `_ +Or, you can write your own extension. See the :api:`Bugzilla Extension +documentation ` for the core documentation on how to do that. It would make sense to read the section on :ref:`templates`. There is also a sample extension in :file:`$BUGZILLA_HOME/extensions/Example/` which gives examples of how to @@ -183,8 +183,8 @@ bugs, except to comment and add themselves to the CC list. Because this kind of change is such a common request, we have added a specific hook for it that :ref:`extensions` can call. It's called -``bug_check_can_change_field``, and it's documented `in the Hooks -documentation `_. +``bug_check_can_change_field``, and it's documented :api:`in the Hooks +documentation `. Checking Syntax =============== diff --git a/docs/en/rst/integrating/skins.rst b/docs/en/rst/integrating/skins.rst index 2cd08b4c..4c1d8e25 100644 --- a/docs/en/rst/integrating/skins.rst +++ b/docs/en/rst/integrating/skins.rst @@ -8,7 +8,7 @@ its underlying structure. It ships with two - "Classic" and "Dusk". You can find some more listed `on the wiki `_, and there are a couple more which are part of -`bugzilla.mozilla.org `_. +`bugzilla.mozilla.org `_. However, in each case you may need to check that the skin supports the version of Bugzilla you have. diff --git a/editflagtypes.cgi b/editflagtypes.cgi index d0b9443b..71f7cb65 100755 --- a/editflagtypes.cgi +++ b/editflagtypes.cgi @@ -453,7 +453,7 @@ sub get_products_and_components { # Let's sort the list by classifications. @products = (); - push(@products, @{$class{$_->id}}) foreach Bugzilla::Classification->get_all; + push(@products, @{$class{$_->id} || []}) foreach Bugzilla::Classification->get_all; } } diff --git a/taskgraph.json b/taskgraph.json index 7433db6f..ba1d1f3e 100644 --- a/taskgraph.json +++ b/taskgraph.json @@ -17,8 +17,8 @@ "provisionerId": "aws-provisioner-v1", "workerType": "b2gtest", "payload": { - "image": "dklawren/docker-bugzilla", - "command": ["/runtests.sh"], + "image": "bugzilla/bugzilla-ci", + "command": ["runtests.sh"], "env": { "TEST_SUITE": "sanity" }, @@ -54,8 +54,8 @@ "provisionerId": "aws-provisioner-v1", "workerType": "b2gtest", "payload": { - "image": "dklawren/docker-bugzilla", - "command": ["/runtests.sh"], + "image": "bugzilla/bugzilla-ci", + "command": ["runtests.sh"], "env": { "TEST_SUITE": "docs" }, @@ -91,8 +91,8 @@ "provisionerId": "aws-provisioner-v1", "workerType": "b2gtest", "payload": { - "image": "dklawren/docker-bugzilla", - "command": ["/runtests.sh"], + "image": "bugzilla/bugzilla-ci", + "command": ["runtests.sh"], "env": { "TEST_SUITE": "webservices" }, @@ -133,15 +133,15 @@ "provisionerId": "aws-provisioner-v1", "workerType": "b2gtest", "payload": { - "image": "dklawren/docker-bugzilla", - "command": ["/runtests.sh"], + "image": "bugzilla/bugzilla-ci", + "command": ["runtests.sh"], "env": { "TEST_SUITE": "selenium" }, "artifacts": { "public/runtests_log": { "type": "file", - "path": "/runtests.log", + "path": "/tmp/runtests.log", "expires": "2018-02-17T17:33:38.806Z" }, "public/httpd_error_log": { @@ -151,7 +151,7 @@ }, "public/selenium_log": { "type": "file", - "path": "/selenium.log", + "path": "/tmp/selenium.log", "expires": "2018-02-17T17:33:38.806Z" } } @@ -180,15 +180,16 @@ "provisionerId": "aws-provisioner-v1", "workerType": "b2gtest", "payload": { - "image": "dklawren/docker-bugzilla:pgsql", - "command": ["/runtests.sh"], + "image": "bugzilla/bugzilla-ci", + "command": ["runtests.sh"], "env": { + "BUGS_DB_DRIVER": "pg", "TEST_SUITE": "webservices" }, "artifacts": { "public/runtests_log": { "type": "file", - "path": "/runtests.log", + "path": "/tmp/runtests.log", "expires": "2018-02-17T17:33:38.806Z" }, "public/httpd_error_log": { @@ -222,15 +223,16 @@ "provisionerId": "aws-provisioner-v1", "workerType": "b2gtest", "payload": { - "image": "dklawren/docker-bugzilla:pgsql", - "command": ["/runtests.sh"], + "image": "bugzilla/bugzilla-ci", + "command": ["runtests.sh"], "env": { + "BUGS_DB_DRIVER": "pg", "TEST_SUITE": "selenium" }, "artifacts": { "public/runtests_log": { "type": "file", - "path": "/runtests.log", + "path": "/tmp/runtests.log", "expires": "2018-02-17T17:33:38.806Z" }, "public/httpd_error_log": { @@ -240,7 +242,7 @@ }, "public/selenium_log": { "type": "file", - "path": "/selenium.log", + "path": "/tmp/selenium.log", "expires": "2018-02-17T17:33:38.806Z" } } diff --git a/template/en/default/pages/release-notes.html.tmpl b/template/en/default/pages/release-notes.html.tmpl index 358298bc..b89e3a61 100644 --- a/template/en/default/pages/release-notes.html.tmpl +++ b/template/en/default/pages/release-notes.html.tmpl @@ -43,6 +43,27 @@

Updates in this 5.0.x Release

+

5.0.4

+ +

This release fixes one security issue. See the + Security Advisory + for details.

+ +

This release also contains the following [% terms.bug %] fixes:

+ +
    +
  • checksetup.pl would fail to update Chart storage during pre-3.6 to 5.0 upgrade. + ([% terms.Bug %] 1273846)
  • +
  • editflagtypes.cgi would crash when classifications are enabled and + the user did not have global editcomponents privileges. + ([% terms.Bug %] 1310728)
  • +
  • The File::Slurp would trigger warnings on perl 5.24. + ([% terms.Bug %] 1301887)
  • +
  • All the time entries in the 'when' column had the correct date but the time + was fixed to 00:00 when using Sqlite. + ([% terms.Bug %] 1303702)
  • +
+

5.0.3

This release fixes one security issue. See the @@ -69,7 +90,7 @@ ([% terms.Bug %] 1259881)

  • An extension which allows user-controlled data to be used as a link in tabs could trigger XSS if the data is not correctly sanitized. - [%+ terms. Bugzilla %] no longer relies on the extension to do the sanity + [%+ terms.Bugzilla %] no longer relies on the extension to do the sanity check. A vanilla installation is not affected as no tab is user-controlled. ([% terms.Bug %] 1250114)
  • Extensions can now easily override the favicon used for the @@ -174,7 +195,7 @@

    Required Perl Modules

    [% INCLUDE req_table reqs = REQUIRED_MODULES - new = ['File-Slurp','JSON-XS', 'Email-Sender'] + new = ['JSON-XS', 'Email-Sender'] updated = ['DateTime', 'DateTime-TimeZone', 'Template-Toolkit', 'URI'] %] @@ -205,6 +226,7 @@ you.

    +

    New Features and Improvements

      diff --git a/template/ja/default/pages/release-notes.html.tmpl b/template/ja/default/pages/release-notes.html.tmpl index 8f269c37..efad17df 100644 --- a/template/ja/default/pages/release-notes.html.tmpl +++ b/template/ja/default/pages/release-notes.html.tmpl @@ -42,6 +42,28 @@

      5.0.x リリースでの更新点

      +

      5.0.4

      + +

      このリリースでは一つのセキュリティー問題の修正が含まれます。詳細は + セキュリティーアドバイザリ + をご覧ください。

      + +

      このリリースでは以下の [% terms.bug %] の修正が含まれます:

      + +
        +
      • checksetup.pl が pre-3.6 から 5.0 へのアップグレードの際に Chart 用の領域のアップグ + レードに失敗することがあります。 + ([% terms.Bug %] 1273846)
      • +
      • editflagtypes.cgi が classification を有効にしている環境下で editcomponents + 権限を持たないユーザが実行した場合にクラッシュする可能性があります。 + ([% terms.Bug %] 1310728)
      • +
      • File::Slurp モジュールが perl 5.24 上で警告を発生させていました。 + ([% terms.Bug %] 1301887)
      • +
      • Sqlite 環境下において 'when' カラムのすべての日時入力が日付は正しいながら時間が + 00:00 になっていました。 + ([% terms.Bug %] 1303702)
      • +
      +

      5.0.3

      このリリースでは一つのセキュリティー問題の修正が含まれます。詳細は @@ -65,7 +87,7 @@ を Excel で数式として評価されなくするために空白でエスケープされるようになりました。 ([% terms.Bug %] 1259881)

    • ユーザ制御のデータを利用する拡張におけるリンクにサニタイズされていないデータに対するXSSの可能性が - ありました。[%+ terms. Bugzilla %] は拡張機能の中でのサニタイズに依存しなくなりました。ユーザによる + ありました。[%+ terms.Bugzilla %] は拡張機能の中でのサニタイズに依存しなくなりました。ユーザによる タブについても標準で対処するようになりました。 ([% terms.Bug %] 1250114)
    • 拡張で [%+ terms.Bugzilla %] サイトの favicon のオーバーライドが簡単にできるようになりました。 @@ -167,7 +189,7 @@

      必須 Perl モジュール

      [% INCLUDE req_table reqs = REQUIRED_MODULES - new = ['File-Slurp','JSON-XS', 'Email-Sender'] + new = ['JSON-XS', 'Email-Sender'] updated = ['DateTime', 'DateTime-TimeZone', 'Template-Toolkit', 'URI'] %] @@ -196,6 +218,7 @@ モジュールがインストールされているかどうかを検出し通知します。

      +

      新機能と改善点