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 %] の修正が含まれます:
+
+
+
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 @@
モジュールがインストールされているかどうかを検出し通知します。
+
新機能と改善点