Skip to content

Commit 3e6d1c9

Browse files
committed
Always set member perms when unzipping
Re-create `t/root/dist/pair/0.1.1/pair-0.1.1.zip` with no permissions for groups or others to any file or directory and add tests to make sure they are readable by all and that directories are executable by all. This causes failures! Change `unzip` to *always* set file permissions, with different values for directories (which must be executable) and files (which need not be executable for serving by the API). Fixes #15. As a result of the re-organization of `pair-0.1.1.zip`, change the `find_docs` tests to sort results before comparing them. Apparently different zip files can index their members in different orders. So just avoid the problem for the future.
1 parent d69e0f4 commit 3e6d1c9

File tree

6 files changed

+46
-27
lines changed

6 files changed

+46
-27
lines changed

Changes

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ Revision history for Perl extension PGXN::API
1717
nor testing releases (#2).
1818
- Updated the SemVer regex when parsing rsync output to the official
1919
version published in https://regex101.com/r/vkijKf/ (#16).
20+
- Fix unzipping of distributions to ensure that all directories are
21+
readable and executable but not writeable by all, and that files are
22+
only readable by all (#15).
2023

2124
0.16.5 2016-06-22T18:03:05Z
2225
- Fixed a test failure on systems with a non-English locale, thanks to

lib/PGXN/API/Sync.pm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ sub unzip {
195195

196196
foreach my $member ($zip->members) {
197197
# Make sure the file is readable by everyone
198-
$member->unixFileAttributes($member->unixFileAttributes | 0444);
198+
$member->unixFileAttributes( $member->isDirectory ? 0755 : 0444 );
199199
my $fn = catfile $dist_dir, split m{/} => $member->fileName;
200200
say " $fn\n" if $self->verbose > 2;
201201
if ($member->extractToFileNamed($fn) != AZ_OK) {

t/indexer.t

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,57 +1147,57 @@ is_deeply \@called, [qw(update_user_lists _commit)],
11471147
# Test find_docs().
11481148
touch(catfile $indexer->doc_root_file_for(source => $params->{meta}), qw(sql hi.mkdn));
11491149
$params->{meta}{provides}{pair}{docfile} = 'sql/hi.mkdn';
1150-
is_deeply [ $indexer->find_docs($params)], [
1151-
{ filename => 'sql/hi.mkdn', extension => 'pair' },
1152-
{ filename => 'doc/pair.md' },
1150+
is_deeply [ sort { $a->{filename} cmp $b->{filename} } $indexer->find_docs($params)], [
11531151
{ filename => 'README.md' },
1152+
{ filename => 'doc/pair.md' },
1153+
{ filename => 'sql/hi.mkdn', extension => 'pair' },
11541154
], 'find_docs() should find specified and random doc files';
11551155

11561156
$params->{meta}{no_index} = { file => ['sql/hi.mkdn'] };
1157-
is_deeply [ $indexer->find_docs($params)], [
1158-
{ filename => 'sql/hi.mkdn', extension => 'pair' },
1159-
{ filename => 'doc/pair.md' },
1157+
is_deeply [ sort { $a->{filename} cmp $b->{filename} } $indexer->find_docs($params)], [
11601158
{ filename => 'README.md' },
1159+
{ filename => 'doc/pair.md' },
1160+
{ filename => 'sql/hi.mkdn', extension => 'pair' },
11611161
], 'find_docs() no_index should be ignored for specified doc file';
11621162

11631163
$params->{meta}{no_index} = { file => ['doc/pair.md'] };
1164-
is_deeply [ $indexer->find_docs($params)], [
1165-
{ filename => 'sql/hi.mkdn', extension => 'pair' },
1164+
is_deeply [ sort { $a->{filename} cmp $b->{filename} } $indexer->find_docs($params)], [
11661165
{ filename => 'README.md' },
1166+
{ filename => 'sql/hi.mkdn', extension => 'pair' },
11671167
], 'find_docs() should respect no_index for found docs';
11681168

11691169
$params->{meta}{no_index} = { directory => ['sql'] };
1170-
is_deeply [ $indexer->find_docs($params)], [
1171-
{ filename => 'sql/hi.mkdn', extension => 'pair' },
1172-
{ filename => 'doc/pair.md' },
1170+
is_deeply [ sort { $a->{filename} cmp $b->{filename} } $indexer->find_docs($params)], [
11731171
{ filename => 'README.md' },
1172+
{ filename => 'doc/pair.md' },
1173+
{ filename => 'sql/hi.mkdn', extension => 'pair' },
11741174
], 'find_docs() should ignore no_index directory for specified doc';
11751175

11761176
$params->{meta}{no_index} = { directory => ['doc'] };
1177-
is_deeply [ $indexer->find_docs($params)], [
1178-
{ filename => 'sql/hi.mkdn', extension => 'pair' },
1177+
is_deeply [ sort { $a->{filename} cmp $b->{filename} } $indexer->find_docs($params)], [
11791178
{ filename => 'README.md' },
1179+
{ filename => 'sql/hi.mkdn', extension => 'pair' },
11801180
], 'find_docs() should respect no_index directory for found docs';
11811181

11821182
delete $params->{meta}{no_index};
11831183
$params->{meta}{provides}{pair}{docfile} = 'foo/bar.txt';
1184-
is_deeply [ $indexer->find_docs($params)], [
1185-
{ filename => 'doc/pair.md' },
1184+
is_deeply [ sort { $a->{filename} cmp $b->{filename} } $indexer->find_docs($params)], [
11861185
{ filename => 'README.md' },
1186+
{ filename => 'doc/pair.md' },
11871187
], 'find_docs() should ignore non-existent specified file';
11881188

11891189
$params->{meta}{provides}{pair}{docfile} = 'doc/pair.md';
1190-
is_deeply [ $indexer->find_docs($params)], [
1191-
{ filename => 'doc/pair.md', extension => 'pair' },
1190+
is_deeply [ sort { $a->{filename} cmp $b->{filename} } $indexer->find_docs($params)], [
11921191
{ filename => 'README.md' },
1192+
{ filename => 'doc/pair.md', extension => 'pair' },
11931193
], 'find_docs() should not return dupes';
11941194

11951195
$params->{meta}{provides}{pair}{docfile} = 'doc/pair.pdf';
11961196
touch(catfile $indexer->doc_root_file_for(source => $params->{meta}), qw(doc pair.pdf));
11971197

1198-
is_deeply [ $indexer->find_docs($params)], [
1199-
{ filename => 'doc/pair.md' },
1198+
is_deeply [ sort { $a->{filename} cmp $b->{filename} } $indexer->find_docs($params)], [
12001199
{ filename => 'README.md' },
1200+
{ filename => 'doc/pair.md' },
12011201
], 'find_docs() should ignore doc files it does not know how to parse';
12021202

12031203
sub touch {

t/root/dist/pair/0.1.1/META.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"date": "2010-10-29T22:46:45Z",
1010
"release_status": "testing",
1111
"user": "theory",
12-
"sha1": "703c0c485166636317c3d4bc8a1a36d512761af7",
12+
"sha1": "443cbcf678a3c2f479c4c069bcb96054d9b25a32",
1313
"license": "postgresql",
1414
"provides": {
1515
"pair": {
0 Bytes
Binary file not shown.

t/sync.t

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

33
use strict;
44
use warnings;
5-
#use Test::More tests => 58;
6-
use Test::More 'no_plan';
5+
use Test::More tests => 65;
6+
# use Test::More 'no_plan';
77
use File::Spec::Functions qw(catfile catdir tmpdir);
88
use Test::MockModule;
99
use Test::Output;
@@ -282,7 +282,7 @@ is_deeply \@users, [qw(
282282
##############################################################################
283283
# digest_for()
284284
my $pgz = catfile qw(dist pair 0.1.1 pair-0.1.1.zip);
285-
is $sync->digest_for($pgz), '703c0c485166636317c3d4bc8a1a36d512761af7',
285+
is $sync->digest_for($pgz), '443cbcf678a3c2f479c4c069bcb96054d9b25a32',
286286
'Should get expected digest from digest_for()';
287287

288288
##############################################################################
@@ -323,19 +323,35 @@ my @files = (qw(
323323
catfile(qw(test expected base.out)),
324324
);
325325

326+
my @dirs = (
327+
'test',
328+
catfile(qw(test expected)),
329+
catfile(qw(test sql)),
330+
'doc',
331+
'sql',
332+
);
333+
326334
my $src_dir = PGXN::API->instance->source_dir;
327335
my $base = catdir $src_dir, 'pair', 'pair-0.1.1';
328-
329-
file_not_exists_ok catfile($base, $_), "$_ should not exist" for @files;
336+
file_not_exists_ok $base, "pair-0.1.1 directory should not exist";
330337

331338
# Unzip it.
332339
ok my $zip = $sync->unzip($pgz, {name => 'pair'}), "Unzip $pgz";
333340
isa_ok $zip, 'Archive::Zip';
334341
file_exists_ok catfile($base, $_), "$_ should now exist" for @files;
335342
my $readall = S_IRUSR | S_IRGRP | S_IROTH;
343+
my $dirall = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
344+
ok(
345+
((stat $base)[2] & $dirall) == $dirall,
346+
'Root directory should be writeable by owner and readable and executable by all'
347+
);
348+
ok(
349+
((stat catfile $base, $_)[2] & $dirall) == $dirall,
350+
"Directory $_ should be writeable by owner and readable and executable by all"
351+
) for @dirs;
336352
ok(
337353
((stat catfile $base, $_)[2] & $readall) == $readall,
338-
"$_ should be readable by all",
354+
"File $_ should be readable by all",
339355
) for @files;
340356

341357
# Now try a brokenated zip file.

0 commit comments

Comments
 (0)