The branch master has been updated via 3a3d8929cfab681d3807983a584fb4d7042df4b2 (commit) via 0d8b3195d26d3382e4580633b49e0626225dfdad (commit) from ed754fa33f1d80887e953a9cd849752d41775401 (commit)
- Log ----------------------------------------------------------------- commit 3a3d8929cfab681d3807983a584fb4d7042df4b2 Author: Richard Levitte <levi...@openssl.org> Date: Thu Apr 23 12:23:34 2020 +0200 Move release-tools/do-release.pl to omc-tools This is an infrastructure tool rather than a developer tool. commit 0d8b3195d26d3382e4580633b49e0626225dfdad Author: Richard Levitte <levi...@openssl.org> Date: Thu Apr 23 11:26:23 2020 +0200 Move a set of directories to omc-tools, as per vote concluded 2020-03-04 These directories are moved: OpenSSL-Query QueryApp clacheck github-approve-label-workflow license reports ----------------------------------------------------------------------- Summary of changes: OpenSSL-Query/MANIFEST | 10 - OpenSSL-Query/Makefile.PL | 44 ----- OpenSSL-Query/README.md | 70 ------- OpenSSL-Query/lib/OpenSSL/Query.pm | 151 --------------- OpenSSL-Query/lib/OpenSSL/Query/ClaREST.pm | 44 ----- OpenSSL-Query/lib/OpenSSL/Query/PersonREST.pm | 125 ------------ OpenSSL-Query/lib/OpenSSL/Query/REST.pm | 15 -- OpenSSL-Query/t/00-load.t | 13 -- OpenSSL-Query/t/query.t | 140 -------------- QueryApp/MANIFEST | 13 -- QueryApp/Makefile.PL | 42 ---- QueryApp/README.md | 82 -------- QueryApp/RESTAPI.txt | 50 ----- QueryApp/bin/query.psgi | 161 ---------------- QueryApp/lib/OpenSSL/Query/ClaDB.pm | 60 ------ QueryApp/lib/OpenSSL/Query/DB.pm | 15 -- QueryApp/lib/OpenSSL/Query/PersonDB.pm | 118 ------------ QueryApp/lib/OpenSSL/Query/Role/OMC.pm | 37 ---- QueryApp/public/dispatch.cgi | 22 --- QueryApp/public/dispatch.fcgi | 22 --- QueryApp/t/query.t | 176 ----------------- QueryApp/t/query_data/cdb.txt | 1 - QueryApp/t/query_data/pdb.yaml | 19 -- QueryApp/t/query_direct.t | 137 ------------- clacheck/README | 14 -- clacheck/clacheck.py | 113 ----------- github-approve-label-workflow/README.md | 20 -- .../github-approve-label-workflow.py | 171 ---------------- license/.htaccess | 5 - license/README | 30 --- license/add-counts | 41 ---- license/add-lastchance | 92 --------- license/approved | 55 ------ license/cgi-bin/authors.py | 90 --------- license/cgi-bin/lookup.py | 98 ---------- license/cgi-bin/receive-reply.py | 72 ------- license/cgi-bin/reply.py | 73 ------- license/cgi-bin/search.py | 101 ---------- license/cgi-bin/send-email.py | 113 ----------- license/createdb | 96 --------- license/devteam.py | 25 --- license/finduser | 53 ----- license/get-authors | 35 ---- license/get-followups | 53 ----- license/get-summary | 48 ----- license/git-import | 127 ------------ license/git-import-all | 7 - license/index.html | 72 ------- license/mailuser | 87 --------- license/request-approval.txt | 40 ---- license/rmcommit | 52 ----- license/rmuser | 23 --- license/style.css | 17 -- license/whattoremove | 58 ------ release-tools/do-release.pl | 214 --------------------- reports/.gitignore | 13 -- reports/LICENSE | 201 ------------------- reports/Makefile | 93 --------- reports/README | 3 - reports/bugs2csv.py | 89 --------- reports/ghstats | 26 --- reports/makereport | 55 ------ reports/rt2csv.py | 79 -------- reports/stats2csv.py | 28 --- 64 files changed, 4249 deletions(-) delete mode 100644 OpenSSL-Query/MANIFEST delete mode 100644 OpenSSL-Query/Makefile.PL delete mode 100644 OpenSSL-Query/README.md delete mode 100644 OpenSSL-Query/lib/OpenSSL/Query.pm delete mode 100644 OpenSSL-Query/lib/OpenSSL/Query/ClaREST.pm delete mode 100644 OpenSSL-Query/lib/OpenSSL/Query/PersonREST.pm delete mode 100644 OpenSSL-Query/lib/OpenSSL/Query/REST.pm delete mode 100644 OpenSSL-Query/t/00-load.t delete mode 100644 OpenSSL-Query/t/query.t delete mode 100644 QueryApp/MANIFEST delete mode 100644 QueryApp/Makefile.PL delete mode 100644 QueryApp/README.md delete mode 100644 QueryApp/RESTAPI.txt delete mode 100644 QueryApp/bin/query.psgi delete mode 100644 QueryApp/lib/OpenSSL/Query/ClaDB.pm delete mode 100644 QueryApp/lib/OpenSSL/Query/DB.pm delete mode 100644 QueryApp/lib/OpenSSL/Query/PersonDB.pm delete mode 100644 QueryApp/lib/OpenSSL/Query/Role/OMC.pm delete mode 100755 QueryApp/public/dispatch.cgi delete mode 100644 QueryApp/public/dispatch.fcgi delete mode 100644 QueryApp/t/query.t delete mode 100644 QueryApp/t/query_data/cdb.txt delete mode 100644 QueryApp/t/query_data/pdb.yaml delete mode 100644 QueryApp/t/query_direct.t delete mode 100644 clacheck/README delete mode 100755 clacheck/clacheck.py delete mode 100644 github-approve-label-workflow/README.md delete mode 100644 github-approve-label-workflow/github-approve-label-workflow.py delete mode 100644 license/.htaccess delete mode 100644 license/README delete mode 100755 license/add-counts delete mode 100755 license/add-lastchance delete mode 100755 license/approved delete mode 100755 license/cgi-bin/authors.py delete mode 100755 license/cgi-bin/lookup.py delete mode 100755 license/cgi-bin/receive-reply.py delete mode 100755 license/cgi-bin/reply.py delete mode 100755 license/cgi-bin/search.py delete mode 100755 license/cgi-bin/send-email.py delete mode 100755 license/createdb delete mode 100755 license/devteam.py delete mode 100755 license/finduser delete mode 100755 license/get-authors delete mode 100755 license/get-followups delete mode 100755 license/get-summary delete mode 100755 license/git-import delete mode 100755 license/git-import-all delete mode 100644 license/index.html delete mode 100755 license/mailuser delete mode 100644 license/request-approval.txt delete mode 100755 license/rmcommit delete mode 100755 license/rmuser delete mode 100644 license/style.css delete mode 100755 license/whattoremove delete mode 100644 release-tools/do-release.pl delete mode 100644 reports/.gitignore delete mode 100644 reports/LICENSE delete mode 100644 reports/Makefile delete mode 100644 reports/README delete mode 100644 reports/bugs2csv.py delete mode 100755 reports/ghstats delete mode 100755 reports/makereport delete mode 100644 reports/rt2csv.py delete mode 100644 reports/stats2csv.py diff --git a/OpenSSL-Query/MANIFEST b/OpenSSL-Query/MANIFEST deleted file mode 100644 index fec46d4..0000000 --- a/OpenSSL-Query/MANIFEST +++ /dev/null @@ -1,10 +0,0 @@ -lib/OpenSSL/Query.pm -lib/OpenSSL/Query/PersonREST.pm -lib/OpenSSL/Query/REST.pm -lib/OpenSSL/Query/ClaREST.pm -Makefile.PL -MANIFEST -META.yml -README.md -t/query.t -t/00-load.t diff --git a/OpenSSL-Query/Makefile.PL b/OpenSSL-Query/Makefile.PL deleted file mode 100644 index a98f4e6..0000000 --- a/OpenSSL-Query/Makefile.PL +++ /dev/null @@ -1,44 +0,0 @@ -use 5.006; -use strict; -use warnings; -use inc::Module::Install; - -name 'OpenSSL-Query'; -module_name 'OpenSSL::Query'; -version '1.1'; -abstract ''; -author q{Richard Levitte <levi...@openssl.org>}; -license 'apache'; - -perl_version 5.006; - -tests_recursive('t'); - -resources ( - license => 'http://www.apache.org/licenses/LICENSE-2.0', - repository => 'https://github.com/openssl/tools.git', - bugtracker => 'https://github.com/openssl/tools/issues', -); - -configure_requires ( - 'Module::Install' => 0, -); - -build_requires ( - 'Test::More' => 0, -); - -requires ( - 'Module::Load::Conditional' => 0, - 'Class::Method::Modifiers' => 0, - 'File::Spec' => 0, - 'URI::Encode' => 0, - Moo => 0, - Carp => 0, - 'LWP::UserAgent' => 0, - 'LWP::Protocol::https' =>0, -); - -install_as_site; -auto_install; -WriteAll; diff --git a/OpenSSL-Query/README.md b/OpenSSL-Query/README.md deleted file mode 100644 index 817a390..0000000 --- a/OpenSSL-Query/README.md +++ /dev/null @@ -1,70 +0,0 @@ -OpenSSL::Query -============== - -A module to query certain information about OpenSSL committers as well -as members of the OMC (OpenSSL Management Committee). These data are -usually interesting for other programs that need to verify identities, -whether a certain person holds a CLA, that sort of thing. - -OpenSSL::Query is built to be able to handle several implementations -for access to the databases that hold the data. The default -implementation uses a RESTful API with JSON encoded responses, -OpenSSL::Query::REST. - -Requirements ------------- - -OpenSSL::Query requires the following modules to build: - -- Module::Install (debian package libmodule-install-perl) - -OpenSSL::Query requires these extra modules to run: - -- Class::Method::Modifiers (debian package libclass-method-modifiers-perl) -- Moo (debian package libmoo-perl) -- URI::Encode (debian package liburi-encode-perl) -- LWP::UserAgent -- LWP::Protocol::https - -Any other module OpenSSL::Query depends on should be part of core -perl. - -Installation ------------- - - perl Makefile.PL - make && make install - -Local installation ------------- - -For a local installation, you might want to consider using local::lib -(debian package liblocal-lib-perl). In that case, running Makefile.PL -is slightly different: - - perl -Mlocal::lib Makefile.PL - -Other than that, follow the instructions in "Installation" above. - -To get the paths right permanently, you might want to consider adding -this in your `.bash_profile`, `.bashrc` och corresponding shell init -script: - - eval "`perl -I$HOME/perl5/lib/perl5 -Mlocal::lib`" - -Testing -------- - -Testing is done like this: - - make test - -However, it requires the additional Perl module Dancer2 and -plackup (debian packages libdancer2-perl and libplack-perl) -and that a temporary query service is started as well. -This is part of QueryApp, and is started like this: - - here=`pwd` # the directory OpenSSL-Query/ - cd ../QueryApp # Or wherever you have it checked out - PERSONDB=./t/query_data/pdb.yaml CLADB=./t/query_data/cdb.txt \ - PERL5LIB=./lib:$here/lib plackup bin/query.psgi diff --git a/OpenSSL-Query/lib/OpenSSL/Query.pm b/OpenSSL-Query/lib/OpenSSL/Query.pm deleted file mode 100644 index 727c77b..0000000 --- a/OpenSSL-Query/lib/OpenSSL/Query.pm +++ /dev/null @@ -1,151 +0,0 @@ -#! /usr/bin/env perl -# -# Copyright 2017 The OpenSSL Project Authors. All Rights Reserved. -# -# Licensed under the OpenSSL license (the "License"). You may not use -# this file except in compliance with the License. You can obtain a copy -# in the file LICENSE in the source distribution or at -# https://www.openssl.org/source/license.html - -use strict; - -package OpenSSL::Query; -use Carp; - -our %register_impl = (); - -sub import { - my $class = shift; - my $regtype = undef; - my $regname = undef; - my $regprio = 999; # Bottom feeders - - while (scalar @_ > 0) { - my $arg = shift; - if ($arg eq '-register-cla') { - $regtype = 'cla'; - $regname = shift; - } elsif ($arg eq '-register-person') { - $regtype = 'person'; - $regname = shift; - } elsif ($arg eq '-priority') { - $regprio = shift; - } else { - croak "Unknown argument $arg"; - return; - } - } - if (!defined($regtype) || !defined($regname)) { - croak "No proper module registration"; - } - $register_impl{$regtype}->{$regprio}->{$regname} = 1; -} - -sub _new_type { - my $self = shift; - my $type = shift; - my @args = @_; - - my @packages = - map { (sort keys %{$register_impl{$type}->{$_}}) } - sort keys %{$register_impl{$type}}; - my @objs = (); - while (@packages) { - my $obj = (shift @packages)->new(@args); - push @objs, $obj if $obj; - } - - croak "No implementation for $type queries" unless @objs; - - return @objs; -} - -sub new { - my $class = shift; - my @args = @_; - - my $self = {}; - bless $self, $class; - - foreach (('person', 'cla')) { - $self->{$_} = [ $self->_new_type($_, @args) ]; - } - - return $self; -} - -sub _perform { - my $self = shift; - my $type = shift; - my $sub = shift; - - my @errors = (); - foreach (@{$self->{$type}}) { - my @result = eval { $sub->($_, @_); }; - return wantarray ? @result : $result[0] unless $@; - push @errors, $@; - } - - croak join("\n", @errors); -} - -# Person methods -sub list_people { - my $self = shift; - - $self->_perform('person', - sub { my $obj = shift; - return $obj->list_people(@_) }, - @_); -} - -sub find_person { - my $self = shift; - - $self->_perform('person', - sub { my $obj = shift; - return wantarray - ? ($obj->find_person(@_)) - : $obj->find_person(@_); }, - @_); -} - -sub find_person_tag { - my $self = shift; - - $self->_perform('person', - sub { my $obj = shift; - return $obj->find_person_tag(@_) }, - @_); -} - -sub is_member_of { - my $self = shift; - - $self->_perform('person', - sub { my $obj = shift; - return $obj->is_member_of(@_) }, - @_); -} - -# Group methods -sub members_of { - my $self = shift; - - $self->_perform('person', - sub { my $obj = shift; - return $obj->members_of(@_) }, - @_); -} - -# Cla methods -sub has_cla { - my $self = shift; - - $self->_perform('cla', - sub { my $obj = shift; - return $obj->has_cla(@_) }, - @_); -} - -1; diff --git a/OpenSSL-Query/lib/OpenSSL/Query/ClaREST.pm b/OpenSSL-Query/lib/OpenSSL/Query/ClaREST.pm deleted file mode 100644 index fb1f256..0000000 --- a/OpenSSL-Query/lib/OpenSSL/Query/ClaREST.pm +++ /dev/null @@ -1,44 +0,0 @@ -#! /usr/bin/env perl -# -# Copyright 2017 The OpenSSL Project Authors. All Rights Reserved. -# -# Licensed under the OpenSSL license (the "License"). You may not use -# this file except in compliance with the License. You can obtain a copy -# in the file LICENSE in the source distribution or at -# https://www.openssl.org/source/license.html - -use strict; - -package OpenSSL::Query::ClaREST; -use Carp; -use Moo; -use OpenSSL::Query qw(-register-cla OpenSSL::Query::ClaREST -priority 1); -use HTTP::Status qw(:is); -use LWP::UserAgent; -use URI::Encode qw(uri_encode uri_decode); -use JSON::PP; -use Data::Dumper; - -has base_url => ( is => 'ro', default => 'https://api.openssl.org' ); -has _clahandler => ( is => 'ro', builder => 1 ); - -sub _build__clahandler { - my $ua = LWP::UserAgent->new( keep_alive => 1 ); - $ua->env_proxy; - return $ua; -} - -sub has_cla { - my $self = shift; - my $id = shift; - if ($id =~ m|<(\S+\@\S+)>|) { $id = $1; } - croak "Malformed input ID" unless $id =~ m|^\S+(\@\S+)$|; - - my $ua = $self->_clahandler; - my $json = $ua->get($self->base_url . '/0/HasCLA/' - . uri_encode($id, {encode_reserved => 1})); - croak "Server error: ", $json->message if is_server_error($json->code); - return $json->code == 200; -} - -1; diff --git a/OpenSSL-Query/lib/OpenSSL/Query/PersonREST.pm b/OpenSSL-Query/lib/OpenSSL/Query/PersonREST.pm deleted file mode 100644 index 0b9db66..0000000 --- a/OpenSSL-Query/lib/OpenSSL/Query/PersonREST.pm +++ /dev/null @@ -1,125 +0,0 @@ -#! /usr/bin/env perl -# -# Copyright 2017 The OpenSSL Project Authors. All Rights Reserved. -# -# Licensed under the OpenSSL license (the "License"). You may not use -# this file except in compliance with the License. You can obtain a copy -# in the file LICENSE in the source distribution or at -# https://www.openssl.org/source/license.html - -use strict; - -package OpenSSL::Query::PersonREST; -use Carp; -use Moo; -use OpenSSL::Query qw(-register-person OpenSSL::Query::PersonREST -priority 1); -use LWP::UserAgent; -use HTTP::Status qw(:is); -use URI::Encode qw(uri_encode uri_decode); -use JSON::PP; -use Data::Dumper; - -has base_url => ( is => 'ro', default => 'https://api.openssl.org' ); -has _personhandler => ( is => 'lazy', builder => 1 ); - -sub _build__personhandler { - my $ua = LWP::UserAgent->new( keep_alive => 1 ); - $ua->env_proxy; - return $ua; -} - -sub list_people { - my $self = shift; - - my $ua = $self->_personhandler; - my $json = $ua->get($self->base_url . '/0/People'); - croak "Server error: ", $json->message if is_server_error($json->code); - return () unless $json->code == 200; - - my $decoded = decode_json $json->decoded_content; - - return @$decoded; -} - -sub _id_encode { - my $id = shift; - - return $id if ref($id) eq ""; - croak "Malformed input ID" if ref($id) ne "HASH" || scalar keys %$id != 1; - - my $tag = (keys %$id)[0]; - return $tag . ':' . $id->{$tag}; -} - -sub find_person { - my $self = shift; - my $id = _id_encode(shift); - - my $ua = $self->_personhandler; - my $json = $ua->get($self->base_url . '/0/Person/' - . uri_encode($id, {encode_reserved => 1})); - croak "Server error: ", $json->message if is_server_error($json->code); - return () unless $json->code == 200; - - my $decoded = decode_json $json->decoded_content; - - return wantarray ? %$decoded : scalar keys %$decoded > 0; -} - -sub find_person_tag { - my $self = shift; - my $id = _id_encode(shift); - my $tag = shift; - - my $ua = $self->_personhandler; - my $json = $ua->get($self->base_url - . '/0/Person/' - . uri_encode($id, {encode_reserved => 1}) - . '/ValueOfTag/' - . uri_encode ($tag, {encode_reserved => 1})); - croak "Server error: ", $json->message if is_server_error($json->code); - return undef unless $json->code == 200; - - my $decoded = decode_json $json->decoded_content; - - return $decoded->[0]; -} - -sub is_member_of { - my $self = shift; - my $id = _id_encode(shift); - my $group = shift; - - my $ua = $self->_personhandler; - my $json = $ua->get($self->base_url - . '/0/Person/' - . uri_encode($id, {encode_reserved => 1}) - . '/IsMemberOf/' - . uri_encode ($group, {encode_reserved => 1})); - croak "Server error: ", $json->message if is_server_error($json->code); - return 0 unless $json->code == 200; - - my $decoded = decode_json $json->decoded_content; - - return $decoded->[0]; -} - -# Group methods -sub members_of { - my $self = shift; - my $group = shift; - - my $ua = $self->_personhandler; - my $json = $ua->get($self->base_url - . '/0/Group/' - . uri_encode($group, {encode_reserved => 1}) - . '/Members'); - croak "Server error: ", $json->message if is_server_error($json->code); - return () unless $json->code == 200; - - my $decoded = decode_json $json->decoded_content; - - return @$decoded; -} - -1; diff --git a/OpenSSL-Query/lib/OpenSSL/Query/REST.pm b/OpenSSL-Query/lib/OpenSSL/Query/REST.pm deleted file mode 100644 index 970ccaa..0000000 --- a/OpenSSL-Query/lib/OpenSSL/Query/REST.pm +++ /dev/null @@ -1,15 +0,0 @@ -#! /usr/bin/env perl -# -# Copyright 2017 The OpenSSL Project Authors. All Rights Reserved. -# -# Licensed under the OpenSSL license (the "License"). You may not use -# this file except in compliance with the License. You can obtain a copy -# in the file LICENSE in the source distribution or at -# https://www.openssl.org/source/license.html - -use strict; - -package OpenSSL::Query::REST; -use OpenSSL::Query::PersonREST; -use OpenSSL::Query::ClaREST; -1; diff --git a/OpenSSL-Query/t/00-load.t b/OpenSSL-Query/t/00-load.t deleted file mode 100644 index 29d6bc6..0000000 --- a/OpenSSL-Query/t/00-load.t +++ /dev/null @@ -1,13 +0,0 @@ -#!perl -T -use 5.006; -use strict; -use warnings; -use Test::More; - -plan tests => 1; - -BEGIN { - use_ok( 'OpenSSL::Query::REST' ) || print "Bail out!\n"; -} - -#note( "Testing OpenSSL::Query $OpenSSL::Query::VERSION, Perl $], $^X" ); diff --git a/OpenSSL-Query/t/query.t b/OpenSSL-Query/t/query.t deleted file mode 100644 index fd557e6..0000000 --- a/OpenSSL-Query/t/query.t +++ /dev/null @@ -1,140 +0,0 @@ -#! /usr/bin/env perl - -# This means that 'dance' at the end of query.psgi will not start a built in -# service, but will simply return a coderef. This is useful to run this with -# diverse dispatchers as well as tests. -BEGIN { $ENV{DANCER_APPHANDLER} = 'PSGI';} - -use strict; -use warnings; -use Test::More; -use OpenSSL::Query::REST; -use Data::Dumper; - -plan tests => 15; - -SKIP: { - my $query; - - skip "No object for further operations", 8 - unless ok( $query = eval { OpenSSL::Query->new(base_url => $ENV{BASE_URL} - // "http://localhost:5000") }, - 'Creating a OpenSSL::Query object' ); - - # print STDERR Dumper($query); - subtest 'Request of identity list' => sub { - plan tests => 1; - - my @res = $query->list_people(); - ok( scalar @res > 0, 'We got a list' ); - note( Dumper( [ @res ] ) ); - }; - - subtest 'Request of person data for Ray Bradbury' => sub { - plan tests => 2; - - my $res1 = $query->find_person( 'Ray Bradbury' ); - ok( $res1, 'Ray Bradbury is present' ); - note( $res1 ); - - my %res2 = $query->find_person( 'Ray Bradbury' ); - ok(scalar keys %res2 > 1, "Got Ray Bradbury's data" ); - note( Dumper( { %res2 } ) ); - }; - - subtest 'Request of person data for Ray Bradbury as full name' => sub { - plan tests => 2; - - my $res1 = $query->find_person( { fullname => 'Ray Bradbury' } ); - ok( $res1, 'Ray Bradbury is present' ); - note( $res1 ); - - my %res2 = $query->find_person( 'Ray Bradbury' ); - ok(scalar keys %res2 > 1, "Got Ray Bradbury's data" ); - note( Dumper( { %res2 } ) ); - }; - - subtest 'Request of membership in specific group for Ray Bradbury' => sub { - plan tests => 1; - my $res = $query->is_member_of( 'Ray Bradbury', 'scifi' ); - ok( $res, "Ray Bradbury is member of scifi since ".( $res ? $res : "(unknown)" ) ); - note( $res ); - }; - - subtest 'Request of membership in specific group for Ray Bradbury as full name' => sub { - plan tests => 1; - my $res = $query->is_member_of( { fullname => 'Ray Bradbury' }, 'scifi' ); - ok( $res, "Ray Bradbury is member of scifi since ".( $res ? $res : "(unknown)" ) ); - note( $res ); - }; - - subtest 'Request of "author" tag value for Ray Bradbury' => sub { - plan tests => 1; - my $res = $query->find_person_tag( 'Ray Bradbury', 'author' ); - ok( $res, "The 'author' tag for Ray Bradbury is ".( $res ? $res : "(unknown)" ) ); - note( Dumper $res ); - }; - - subtest 'Request of "author" tag value for Ray Bradbury as full name' => sub { - plan tests => 1; - my $res = $query->find_person_tag( { fullname => 'Ray Bradbury' }, 'author' ); - ok( $res, "The 'author' tag for Ray Bradbury is ".( $res ? $res : "(unknown)" ) ); - note( Dumper $res ); - }; - - subtest 'Request of CLA status for Ray Bradbury' => sub { - plan tests => 1; - my $res = $query->has_cla( 'r...@ourplace.com' ); - ok( $res, 'Ray Bradbury has CLA as r...@ourplace.com' ); - note( $res ); - }; - - subtest 'Request of membership in the group "writers"' => sub { - plan tests => 1; - my @res = $query->members_of( 'writers' ); - ok( @res, 'Finding members of "writers"' ); - note( Dumper @res ); - }; - - subtest 'Request of person data for Jay Luser' => sub { - plan tests => 2; - - my $res1 = $query->find_person( 'Jay Luser' ); - ok( !$res1, 'Jay Luser is not present' ); - note( $res1 ); - - my %res2 = $query->find_person( 'Jay Luser' ); - ok( !%res2, "Failed getting Jay Luser's data" ); - }; - - subtest 'Request of membership in specific group for Jay Luser' => sub { - plan tests => 1; - my $res = $query->is_member_of( 'Jay Luser', 'scifi' ); - ok( !$res, 'Jay Luser is not member of scifi' ); - note( $res ); - }; - - subtest 'Request of "author" tag value for Jay Luser' => sub { - plan tests => 1; - my $res = $query->find_person_tag( 'Jay Luser', 'author' ); - ok( !$res, "No 'author' tag for Jay Luser" ); - note( $res ); - }; - - subtest 'Request of CLA status for Jay Luser' => sub { - plan tests => 1; - my $res = $query->has_cla( 'jlu...@ourplace.com' ); - ok( !$res, 'Jay Luser has no CLA' ); - note( $res ); - }; - - subtest 'Request of membership in the group "couchpotatoes"' => sub { - plan tests => 1; - my @res = $query->members_of( 'couchpotatoes' ); - ok( !@res, 'No members in "couchpotatoes"' ); - note( @res ); - }; - -} - -1; diff --git a/QueryApp/MANIFEST b/QueryApp/MANIFEST deleted file mode 100644 index d9f0654..0000000 --- a/QueryApp/MANIFEST +++ /dev/null @@ -1,13 +0,0 @@ -bin/query.psgi -lib/OpenSSL/Query/ClaDB.pm -lib/OpenSSL/Query/DB.pm -lib/OpenSSL/Query/Role/OMC.pm -lib/OpenSSL/Query/PersonDB.pm -Makefile.PL -MANIFEST -META.yml -public/dispatch.fcgi -public/dispatch.cgi -t/query.t -t/query_data/pdb.yaml -t/query_data/cdb.txt diff --git a/QueryApp/Makefile.PL b/QueryApp/Makefile.PL deleted file mode 100644 index 56d57ca..0000000 --- a/QueryApp/Makefile.PL +++ /dev/null @@ -1,42 +0,0 @@ -use 5.006; -use strict; -use warnings; -use inc::Module::Install; - -name 'QueryApp'; -version '2.0'; -abstract 'An OpenSSL query web app'; -author q{Richard Levitte <levi...@openssl.org>}; -license 'apache'; - -perl_version 5.006; - -tests_recursive('t'); - -resources ( - license => 'http://www.apache.org/licenses/LICENSE-2.0', - repository => 'https://github.com/openssl/tools.git', - bugtracker => 'https://github.com/openssl/tools/issues', -); - -configure_requires ( - 'Module::Install' => 0, -); - -build_requires ( - 'Test::More' => 0, -); - -requires ( - 'File::Spec' => 0, - 'YAML::XS' => 0, - Moo => 0, - Carp => 0, - Dancer2 => 0, - Plack => 0, - 'OpenSSL::Query' => 0, -); - -install_as_site; -auto_install; -WriteAll; diff --git a/QueryApp/README.md b/QueryApp/README.md deleted file mode 100644 index c0018f6..0000000 --- a/QueryApp/README.md +++ /dev/null @@ -1,82 +0,0 @@ -QueryApp -======== - -A web app to answer OpenSSL queries, primarely to serve anything that -uses the OpenSSL::Query modules. - -This includes an OpenSSL::Query implementation that looks directly at -the databases, OpenSSL::Query::DB. - -This also includes a query.psgi that is used to serve the data, and a -couple of dispatchers for CGI and FCGI. These are designed to be used -directly in the checkout, but will work if copied elsewhere as well, -as long as the OpenSSL::Query::DB module is installed. - -REST API --------- - -RESTAPI.txt documents the details of the REST API provided by QueryApp. - -Requirements ------------- - -OpenSSL::Query requires the following modules to build: - -- Module::Install (debian package libmodule-install-perl) - -OpenSSL::Query requires these extra modules to run: - -- YAML::XS (debian package libyaml-libyaml-perl) -- Moo (debian package libmoo-perl) -- Dancer2 (debian package libdancer2-perl) -- Plack (debian package libplack-perl) -- URI::Encode (debian package liburi-encode-perl) -- Clone (debian package libclone-perl) -- OpenSSL::Query (from ../OpenSSL-Query) - -Any other module OpenSSL::Query depends on should be part of core -perl. - -Installation ------------- - - $ perl Makefile.PL - $ make - $ make install - -Local installation ------------- - -For a local installation, you might want to consider using local::lib -(debian package liblocal-lib-perl). In that case, running Makefile.PL -is slightly different: - - $ perl -Mlocal::lib Makefile.PL - -Other than that, follow the instructions in "Installation" above. - -The local installation method works best if the `PERL5LIB` environment variable -(among others) is set correctly in the shell profile. A comprehensive guide how -to do it correctly can be found in the manual page (`perldoc local::lib`, -or online at [local::lib](https://metacpan.org/pod/local::lib)). - -Essentially, it boils down to adding the following line to your shell profile -(e.g. `.bash_profile`, `.bashrc` for bash): - - eval "$(perl -I$HOME/perl5/lib/perl5 -Mlocal::lib)" - -The inner perl command will print roughly the following output, which then gets -evaluated by the shell to update the environment accordingly. - - PATH="/home/<user>/perl5/bin${PATH:+:${PATH}}"; export PATH; - PERL5LIB="/home/<user>/perl5/lib/perl5${PERL5LIB:+:${PERL5LIB}}"; export PERL5LIB; - PERL_LOCAL_LIB_ROOT="/home/<user>/perl5${PERL_LOCAL_LIB_ROOT:+:${PERL_LOCAL_LIB_ROOT}}"; export PERL_LOCAL_LIB_ROOT; - PERL_MB_OPT="--install_base \"/home/<user>/perl5\""; export PERL_MB_OPT; - PERL_MM_OPT="INSTALL_BASE=/home/<user>/perl5"; export PERL_MM_OPT; - -Testing -------- - -Testing is done like this: - - $ make test diff --git a/QueryApp/RESTAPI.txt b/QueryApp/RESTAPI.txt deleted file mode 100644 index 1cecba0..0000000 --- a/QueryApp/RESTAPI.txt +++ /dev/null @@ -1,50 +0,0 @@ -QueryApp REST API -================= - -Supported versions: - -/0 : Version 0 - - -Version 0 API: --------------- - -/0/People - - Fetches the list of known people. Each item of this list is a - list of identities for each person. - -/0/Person/:name - - Fetches the complete set of database information on :name. - -/0/Person/:name/Membership - - Fetches the groups (omc, omc-alumni or commit) that :name is - member of, with the date they became or were reinstated in the group - -/0/Person/:name/IsMemberOf/:group - - Fetches from what date :name became or was reinstated as member - of :group - -/0/Person/:name/ValueOfTag/:tag - - Fetches the value of :tag associated with :name. This tag is - usually application specific. - -/0/Person/:name/HasCLA - - Fetches the identity under which :name has a CLA, if any. - -/0/Group/:group/Members - - Fetches the list of identities belonging to the group :group. - -/0/HasCLA/:id - - Checks if there is a CLA under the precise identity :id. This - differs from /0/Person/:name/HasCLA in that it demands the precise - identity (email address or committer id) that the CLA is registered - under, while /0/Person/:name/HasCLA checks for any CLA associated - with any of :name's identities and returns a list of what it finds. diff --git a/QueryApp/bin/query.psgi b/QueryApp/bin/query.psgi deleted file mode 100644 index 523fb8f..0000000 --- a/QueryApp/bin/query.psgi +++ /dev/null @@ -1,161 +0,0 @@ -#! /usr/bin/env perl -# -# Copyright 2017 The OpenSSL Project Authors. All Rights Reserved. -# -# Licensed under the OpenSSL license (the "License"). You may not use -# this file except in compliance with the License. You can obtain a copy -# in the file LICENSE in the source distribution or at -# https://www.openssl.org/source/license.html - -use strict; -use warnings; -use Carp; - -# Currently supported API versions:</p> -# -# /0 : Version 0 -# -# Version 0 API: -# -# /0/Person/:name -# -# Fetches the complete set of database information on :name. -# -# /0/Person/:name/Membership -# -# Fetches the groups (omc, omc-alumni or commit) that :name is -# member of, with the date they became or were reinstated in the group -# -# /0/Person/:name/IsMemberOf/:group -# -# Fetches from what date :name became or was reinstated as member -# of :group -# -# /0/Person/:name/ValueOfTag/:tag -# -# Fetches the value of :tag associated with :name. This tag is -# usually application specific. -# -# /0/Person/:name/HasCLA -# -# Fetches the identity under which :name has a CLA, if any. -# -# /0/HasCLA/:id -# -# Checks if there is a CLA under the precise identity :id. This -# differs from /0/Person/:name/HasCLA in that it demands the precise -# identity (email address or committer id) that the CLA is registered -# under, while /0/Person/:name/HasCLA checks for any CLA associated -# with any of :name's identities and returns a list of what it finds. - -package query; -use Dancer2; -use HTTP::Status qw(:constants); -use OpenSSL::Query::DB; -use URI::Encode qw(uri_decode); - -set serializer => 'JSON'; -set omc => '/var/cache/openssl/checkouts/omc'; - -# Version 0 API. -# Feel free to add new routes, but never to change them or remove them, -# or to change their response. For such changes, add a new version at -# the end - -prefix '/0'; - -sub name_decode { - my $name = shift; - if ($name =~ m|^([^:]+):(.+)$|) { - return { $1 => $2 }; - } - return $name; -} - -get '/People' => sub { - my $query = OpenSSL::Query->new(omc => config->{omc}); - my @response = $query->list_people(); - - return [ @response ] if @response; - send_error('Not found', HTTP_NO_CONTENT); -}; - -get '/Person/:name' => sub { - my $query = OpenSSL::Query->new(omc => config->{omc}); - my $name = name_decode(uri_decode(param('name'))); - my %response = $query->find_person($name); - - return { %response } if %response; - send_error('Not found', HTTP_NO_CONTENT); -}; - -get '/Person/:name/Membership' => sub { - my $query = OpenSSL::Query->new(omc => config->{omc}, REST => 0); - my $name = name_decode(uri_decode(param('name'))); - my %response = $query->find_person($name); - - return $response{memberof} if %response; - send_error('Not found', HTTP_NO_CONTENT); -}; - -get '/Person/:name/IsMemberOf/:group' => sub { - my $query = OpenSSL::Query->new(omc => config->{omc}, REST => 0); - my $name = name_decode(uri_decode(param('name'))); - my $group = uri_decode(param('group')); - my $response = $query->is_member_of($name, $group); - - return [ $response ] if $response; - send_error('Not found', HTTP_NO_CONTENT); -}; - -get '/Person/:name/ValueOfTag/:tag' => sub { - my $query = OpenSSL::Query->new(omc => config->{omc}, REST => 0); - my $name = name_decode(uri_decode(param('name'))); - my $tag = uri_decode(param('tag')); - my $response = $query->find_person_tag($name, $tag); - - return [ $response ] if $response; - send_error('Not found', HTTP_NO_CONTENT); -}; - -get '/Person/:name/HasCLA' => sub { - my $query = OpenSSL::Query->new(omc => config->{omc}, REST => 0); - my $name = name_decode(uri_decode(param('name'))); - my %person = $query->find_person($name); - my @response = (); - - foreach (@{$person{ids}}) { - next if (ref $_ eq "HASH"); - next unless $_ =~ m|^\S+\@\S+$|; - push @response, $_ if $query->has_cla($_); - } - return [ @response ] if @response; - send_error('Not found', HTTP_NO_CONTENT); -}; - -get '/Group/:group/Members' => sub { - my $query = OpenSSL::Query->new(omc => config->{omc}, REST => 0); - my $group = uri_decode(param('group')); - my @response = $query->members_of($group); - - return [ @response ] if @response; - send_error('Not found', HTTP_NO_CONTENT); -}; - -get '/HasCLA/:id' => sub { - my $query = OpenSSL::Query->new(omc => config->{omc}, REST => 0); - my $id = uri_decode(param('id')); - if ($id =~ m|^\S+\@\S+$|) { - my $response = $query->has_cla($id); - - return [ $response ] if $response; - send_error('Not found', HTTP_NO_CONTENT); - } else { - send_error('Malformed identity', HTTP_BAD_REQUEST); - } -}; - -# End of version 0 API. To create a new version, start with `prefix '1';' -# below. - -dance; diff --git a/QueryApp/lib/OpenSSL/Query/ClaDB.pm b/QueryApp/lib/OpenSSL/Query/ClaDB.pm deleted file mode 100644 index bcd6daf..0000000 --- a/QueryApp/lib/OpenSSL/Query/ClaDB.pm +++ /dev/null @@ -1,60 +0,0 @@ -#! /usr/bin/env perl -# -# Copyright 2017 The OpenSSL Project Authors. All Rights Reserved. -# -# Licensed under the OpenSSL license (the "License"). You may not use -# this file except in compliance with the License. You can obtain a copy -# in the file LICENSE in the source distribution or at -# https://www.openssl.org/source/license.html - -use strict; - -package OpenSSL::Query::ClaDB; -use Carp; -use Moo; -use OpenSSL::Query qw(-register-cla OpenSSL::Query::ClaDB -priority 0); - -with q(OpenSSL::Query::Role::OMC); - -has clafile => ( is => 'ro', default => 'cladb.txt' ); -has _cladb => ( is => 'lazy', builder => 1 ); - -sub _build__cladb { - my $self = shift; - - my $path = $self->_find_file($self->clafile, 'CLADB'); - my $cladb = {}; - - open my $clafh, $path - or croak "Trying to open $path: $!"; - while (my $line = <$clafh>) { - $line =~ s|\R$||; # Better chomp - next if $line =~ m|^#|; - next if $line =~ m|^\s*$|; - croak "Malformed CLADB line: $line" - unless $line =~ m|^(\S+\@\S+)\s+([ICR])\s+(.+)$|; - - my $email = lc $1; - my $status = $2; - my $name = $3; - croak "Duplicate email address: $email" - if exists $cladb->{$email}; - - $cladb->{$email} = { status => $status, name => $name }; - } - close $clafh; - - return $cladb; -} - -sub has_cla { - my $self = shift; - my $id = lc shift; - if ($id =~ m|<(\S+\@\S+)>|) { $id = $1; } - croak "Malformed input ID" unless $id =~ m|^\S+(\@\S+)$|; - my $starid = '*' . $1; - - return exists $self->_cladb->{$id} || exists $self->_cladb->{$starid}; -} - -1; diff --git a/QueryApp/lib/OpenSSL/Query/DB.pm b/QueryApp/lib/OpenSSL/Query/DB.pm deleted file mode 100644 index a5a53d4..0000000 --- a/QueryApp/lib/OpenSSL/Query/DB.pm +++ /dev/null @@ -1,15 +0,0 @@ -#! /usr/bin/env perl -# -# Copyright 2017 The OpenSSL Project Authors. All Rights Reserved. -# -# Licensed under the OpenSSL license (the "License"). You may not use -# this file except in compliance with the License. You can obtain a copy -# in the file LICENSE in the source distribution or at -# https://www.openssl.org/source/license.html - -use strict; - -package OpenSSL::Query::DB; -use OpenSSL::Query::PersonDB; -use OpenSSL::Query::ClaDB; -1; diff --git a/QueryApp/lib/OpenSSL/Query/PersonDB.pm b/QueryApp/lib/OpenSSL/Query/PersonDB.pm deleted file mode 100644 index c26164b..0000000 --- a/QueryApp/lib/OpenSSL/Query/PersonDB.pm +++ /dev/null @@ -1,118 +0,0 @@ -#! /usr/bin/env perl -# -# Copyright 2017 The OpenSSL Project Authors. All Rights Reserved. -# -# Licensed under the OpenSSL license (the "License"). You may not use -# this file except in compliance with the License. You can obtain a copy -# in the file LICENSE in the source distribution or at -# https://www.openssl.org/source/license.html - -use strict; - -package OpenSSL::Query::PersonDB; - -use Carp; -use Clone qw(clone); -use Moo; -use OpenSSL::Query qw(-register-person OpenSSL::Query::PersonDB -priority 0); - -with q(OpenSSL::Query::Role::OMC); - -has personfile => ( is => 'ro', default => 'persondb.yaml' ); -has _persondb => ( is => 'lazy', builder => 1 ); - -use YAML::XS qw(LoadFile); - -sub _build__persondb { - my $self = shift; - - my $yaml = - LoadFile( $self->_find_file($self->personfile, 'PERSONDB') ); - - croak "Malformed PersonDB" unless ref($yaml) eq "ARRAY"; - foreach (@{$yaml}) { - croak "Malformed PersonDB" - unless (defined($_->{ids}) and defined($_->{memberof}) - and ref($_->{ids}) eq "ARRAY" and ref($_->{memberof}) eq "HASH"); - } - - return $yaml; -} - -sub list_people { - my $self = shift; - - my @list = (); - foreach my $record (@{$self->_persondb}) { - push @list, clone($record->{ids}); - } - - return @list; -} - -sub find_person { - my $self = shift; - my $id = shift; - - if (ref($id) eq "" && $id =~ m|<(\S+\@\S+)>|) { $id = $1; } - croak "Malformed input ID" if ref($id) eq "HASH" and scalar keys %$id != 1; - - my $found = 0; - foreach my $record (@{$self->_persondb}) { - foreach my $rid (@{$record->{ids}}) { - if (ref($id) eq "") { - if (ref($rid) eq "HASH") { - foreach (keys %$rid) { - last if $found = $id eq $rid->{$_}; - } - } else { - $found = $id eq $rid; - } - } elsif (ref($id) eq "HASH" && ref($rid) eq "HASH") { - foreach (keys %$rid) { - last if $found = exists $id->{$_} && $id->{$_} eq $rid->{$_}; - } - } - - return (wantarray ? %$record : 1) if $found; - } - } - return wantarray ? () : 0; -} - -sub find_person_tag { - my $self = shift; - my $id = shift; - my $tag = shift; - - my %record = $self->find_person($id); - return $record{tags}->{$tag}; -} - -sub is_member_of { - my $self = shift; - my $id = shift; - my $group = shift; - - if ($id =~ m|<(\S+\@\S+)>|) { $id = $1; } - - my %record = $self->find_person($id); - return $record{memberof}->{$group} - if exists $record{memberof}->{$group}; - return 0; -} - -sub members_of { - my $self = shift; - my $group = shift; - - my @ids = (); - foreach my $record (@{$self->_persondb}) { - if (grep { $_ eq $group } keys %{$record->{memberof}}) { - push @ids, [ @{$record->{ids}} ]; - } - } - return @ids; -} - -1; diff --git a/QueryApp/lib/OpenSSL/Query/Role/OMC.pm b/QueryApp/lib/OpenSSL/Query/Role/OMC.pm deleted file mode 100644 index 6cce602..0000000 --- a/QueryApp/lib/OpenSSL/Query/Role/OMC.pm +++ /dev/null @@ -1,37 +0,0 @@ -#! /usr/bin/env perl -# -# Copyright 2017 The OpenSSL Project Authors. All Rights Reserved. -# -# Licensed under the OpenSSL license (the "License"). You may not use -# this file except in compliance with the License. You can obtain a copy -# in the file LICENSE in the source distribution or at -# https://www.openssl.org/source/license.html - -use strict; -use warnings; - -package OpenSSL::Query::Role::OMC; - -use Carp; -use File::Spec::Functions; -use Moo::Role; - -has omc => ( is => 'ro' ); -has bureau => ( is => 'ro' ); # Backward compat, omc takes precedense - -sub _find_file { - my $self = shift; - my $filename = shift; - my $envvar = shift; - - my $omc = $ENV{OMC} // $self->omc // $ENV{BUREAU} // $self->bureau; - my @paths = ( $ENV{$envvar} // (), - $omc ? catfile($omc, $filename) : (), - catfile('.', $filename) ); - foreach (@paths) { - return $_ if -r $_; - } - croak "$filename not found in any of ", join(", ", @paths), "\n"; -} - -1; diff --git a/QueryApp/public/dispatch.cgi b/QueryApp/public/dispatch.cgi deleted file mode 100755 index 55661df..0000000 --- a/QueryApp/public/dispatch.cgi +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env perl - -# This means that 'dance' at the end of query.psgi will not start a built in -# service, but will simply return a coderef. This is useful to run this with -# diverse dispatchers as well as tests. -BEGIN { $ENV{DANCER_APPHANDLER} = 'PSGI';} - -use Dancer2; -use FindBin '$Bin'; -use lib path($Bin, '..', '..', 'lib'), path($Bin, '..', 'lib'); -use Plack::Handler::CGI; -use Plack::Util; - -# For some reason Apache SetEnv directives dont propagate -# correctly to the dispatchers, so forcing PSGI and env here -# is safer. -set apphandler => 'PSGI'; -set environment => 'production'; - -my $app = Plack::Util::load_psgi( path($Bin, '..', 'bin', 'query.psgi') ); -die "Unable to read startup script: $@" if $@; -Plack::Handler::CGI->new()->run($app); diff --git a/QueryApp/public/dispatch.fcgi b/QueryApp/public/dispatch.fcgi deleted file mode 100644 index 11ab853..0000000 --- a/QueryApp/public/dispatch.fcgi +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env perl - -# This means that 'dance' at the end of query.psgi will not start a built in -# service, but will simply return a coderef. This is useful to run this with -# diverse dispatchers as well as tests. -BEGIN { $ENV{DANCER_APPHANDLER} = 'PSGI';} - -use Dancer2; -use FindBin '$Bin'; -use lib path($Bin, '..', '..', 'lib'), path($Bin, '..', 'lib'); -use Plack::Handler::FCGI; -use Plack::Util; - -# For some reason Apache SetEnv directives dont propagate -# correctly to the dispatchers, so forcing PSGI and env here -# is safer. -set apphandler => 'PSGI'; -set environment => 'production'; - -my $app = Plack::Util::load_psgi( path($Bin, '..', 'bin', 'query.psgi') ); -die "Unable to read startup script: $@" if $@; -Plack::Handler::FCGI->new(nproc => 5, detach => 1)->run($app); diff --git a/QueryApp/t/query.t b/QueryApp/t/query.t deleted file mode 100644 index c570707..0000000 --- a/QueryApp/t/query.t +++ /dev/null @@ -1,176 +0,0 @@ -#! /usr/bin/env perl - -# This means that 'dance' at the end of query.psgi will not start a built in -# service, but will simply return a coderef. This is useful to run this with -# diverse dispatchers as well as tests. -BEGIN { $ENV{DANCER_APPHANDLER} = 'PSGI';} - -use strict; -use warnings; -use Test::More tests => 19; -use Plack::Test; -use Plack::Util; -use HTTP::Request::Common; -use FindBin; - -# This picks up if this is part of a checkout with OpenSSL-Query -use if -r $FindBin::Bin.'/../../OpenSSL-Query/lib/OpenSSL/Query.pm', - lib => $FindBin::Bin.'/../../OpenSSL-Query/lib'; - -$ENV{PERSONDB} = $FindBin::Bin.'/query_data/pdb.yaml'; -$ENV{CLADB} = $FindBin::Bin.'/query_data/cdb.txt'; - -my $app = Plack::Util::load_psgi( $FindBin::Bin.'/../bin/query.psgi' ); -my $test = Plack::Test->create( $app ); - -subtest 'Request of identity list' => sub { - my $res = $test->request( GET '/0/People' ); - plan tests => 2; - ok( $res->is_success, 'Successful request' ); - note( $res->content ); - is( $res->code, 200, 'We have content' ); -}; - -subtest 'A empty request' => sub { - my $res = $test->request( GET '/' ); - plan tests => 1; - ok( $res->is_error, 'Successfuly failed request' ); - note( $res->content ); -}; - -subtest 'A empty Person request' => sub { - my $res = $test->request( GET '/0/Person' ); - plan tests => 1; - ok( $res->is_error, 'Successfully failed request' ); - note( $res->content ); -}; - -subtest 'Request of person data for Ray Bradbury' => sub { - my $res = $test->request( GET '/0/Person/Ray Bradbury' ); - plan tests => 2; - ok( $res->is_success, 'Successful request' ); - note( $res->content ); - is( $res->code, 200, 'We have content' ); -}; - -subtest 'Request of person data for Ray Bradbury as full name' => sub { - my $res = $test->request( GET '/0/Person/fullname:Ray Bradbury' ); - plan tests => 2; - ok( $res->is_success, 'Successful request' ); - note( $res->content ); - is( $res->code, 200, 'We have content' ); -}; - -subtest 'Request of membership for Ray Bradbury' => sub { - my $res = $test->request( GET '/0/Person/Ray Bradbury/Membership' ); - plan tests => 2; - ok( $res->is_success, 'Successful request' ); - note( $res->content ); - is( $res->code, 200, 'We have content' ); -}; - -subtest 'Request of membership for Ray Bradbury as fullname' => sub { - my $res = $test->request( GET '/0/Person/fullname:Ray Bradbury/Membership' ); - plan tests => 2; - ok( $res->is_success, 'Successful request' ); - note( $res->content ); - is( $res->code, 200, 'We have content' ); -}; - -subtest 'Request of membership in specific group for Ray Bradbury' => sub { - my $res = $test->request( GET '/0/Person/Ray Bradbury/IsMemberOf/scifi' ); - plan tests => 2; - ok( $res->is_success, 'Successful request' ); - note( $res->content ); - is( $res->code, 200, 'We have content' ); -}; - -subtest 'Request of membership in specific group for Ray Bradbury as fullname' => sub { - my $res = $test->request( GET '/0/Person/fullname:Ray Bradbury/IsMemberOf/scifi' ); - plan tests => 2; - ok( $res->is_success, 'Successful request' ); - note( $res->content ); - is( $res->code, 200, 'We have content' ); -}; - -subtest 'Request of "author" tag value for Ray Bradbury' => sub { - my $res = $test->request( GET '/0/Person/Ray Bradbury/ValueOfTag/author' ); - plan tests => 2; - ok( $res->is_success, 'Successful request' ); - note( $res->content ); - is( $res->code, 200, 'We have content' ); -}; - -subtest 'Request of "author" tag value for Ray Bradbury as fullname' => sub { - my $res = $test->request( GET '/0/Person/fullname:Ray Bradbury/ValueOfTag/author' ); - plan tests => 2; - ok( $res->is_success, 'Successful request' ); - note( $res->content ); - is( $res->code, 200, 'We have content' ); -}; - -subtest 'Request of CLA status for Ray Bradbury' => sub { - my $res = $test->request( GET '/0/HasCLA/r...@ourplace.com' ); - plan tests => 2; - ok( $res->is_success, 'Successful request' ); - note( $res->content ); - is( $res->code, 200, 'We have content' ); -}; - -subtest 'Request of membership in the group "writers"' => sub { - my $res = $test->request( GET '/0/Group/writers/Members' ); - plan tests => 2; - ok( $res->is_success, 'Successful request' ); - note( $res->content ); - is( $res->code, 200, 'We have content' ); -}; - -subtest 'Request of person data for Jay Luser' => sub { - my $res = $test->request( GET '/0/Person/Jay Luser' ); - plan tests => 2; - ok( $res->is_success, 'Successful request' ); - note( $res->content ); - isnt( $res->code, 200, 'We have no content' ); -}; - -subtest 'Request of membership for Jay Luser' => sub { - my $res = $test->request( GET '/0/Person/Jay Luser/Membership' ); - plan tests => 2; - ok( $res->is_success, 'Successful request' ); - note( $res->content ); - isnt( $res->code, 200, 'We have no content' ); -}; - -subtest 'Request of membership in specific group for Jay Luser' => sub { - my $res = $test->request( GET '/0/Person/Jay Luser/IsMemberOf/scifi' ); - plan tests => 2; - ok( $res->is_success, 'Successful request' ); - note( $res->content ); - isnt( $res->code, 200, 'We have no content' ); -}; - -subtest 'Request of "author" tag value for Jay Luser' => sub { - my $res = $test->request( GET '/0/Person/Jay Luser/ValueOfTag/author' ); - plan tests => 2; - ok( $res->is_success, 'Successful request' ); - note( $res->content ); - isnt( $res->code, 200, 'We have no content' ); -}; - -subtest 'Request of CLA status for Jay Luser' => sub { - my $res = $test->request( GET '/0/HasCLA/jlu...@ourplace.com' ); - plan tests => 2; - ok( $res->is_success, 'Successful request' ); - note( $res->content ); - isnt( $res->code, 200, 'We have no content' ); -}; - -subtest 'Request of membership in the group "couchpotatoes"' => sub { - my $res = $test->request( GET '/0/Group/couchpotatoes/Members' ); - plan tests => 2; - ok( $res->is_success, 'Successful request' ); - note( $res->content ); - isnt( $res->code, 200, 'We have no content' ); -}; - -1; diff --git a/QueryApp/t/query_data/cdb.txt b/QueryApp/t/query_data/cdb.txt deleted file mode 100644 index 14fc6c3..0000000 --- a/QueryApp/t/query_data/cdb.txt +++ /dev/null @@ -1 +0,0 @@ -r...@ourplace.com I Ray Bradbury diff --git a/QueryApp/t/query_data/pdb.yaml b/QueryApp/t/query_data/pdb.yaml deleted file mode 100644 index 9be3211..0000000 --- a/QueryApp/t/query_data/pdb.yaml +++ /dev/null @@ -1,19 +0,0 @@ -- - ids: - - fullname: Ray Bradbury - - Ray - - r...@ourplace.com - - Burn paper burn - memberof: - writers: 1950 - scifi: 1950 - tags: - author: Ray Bradbury <r...@ourplace.com> - -- - ids: - - fullname: Selma Lagerlöf - - Selma - memberof: - writers: [ 1891, 1940 ] - diff --git a/QueryApp/t/query_direct.t b/QueryApp/t/query_direct.t deleted file mode 100644 index 2687fd6..0000000 --- a/QueryApp/t/query_direct.t +++ /dev/null @@ -1,137 +0,0 @@ -#! /usr/bin/env perl - -# This means that 'dance' at the end of query.psgi will not start a built in -# service, but will simply return a coderef. This is useful to run this with -# diverse dispatchers as well as tests. -BEGIN { $ENV{DANCER_APPHANDLER} = 'PSGI';} - -use strict; -use warnings; -use Test::More tests => 14; -use Data::Dumper; -use FindBin; - -# This picks up if this is part of a checkout with OpenSSL-Query -use if -r $FindBin::Bin.'/../../OpenSSL-Query/lib/OpenSSL/Query.pm', - lib => $FindBin::Bin.'/../../OpenSSL-Query/lib'; -require OpenSSL::Query::DB; OpenSSL::Query::DB->import(); - -$ENV{PERSONDB} = $FindBin::Bin.'/query_data/pdb.yaml'; -$ENV{CLADB} = $FindBin::Bin.'/query_data/cdb.txt'; - -my $query = OpenSSL::Query->new(); - -subtest 'Request of identity list' => sub { - plan tests => 1; - - my @res = $query->list_people(); - ok( scalar @res > 0, 'We got a list' ); - note( Dumper( [ @res ] ) ); -}; - -subtest 'Request of person data for Ray Bradbury' => sub { - plan tests => 2; - - my $res1 = $query->find_person( 'Ray Bradbury' ); - ok( $res1, 'Ray Bradbury is present' ); - note( $res1 ); - - my %res2 = $query->find_person( 'Ray Bradbury' ); - ok(scalar keys %res2 > 1, "Got Ray Bradbury's data" ); - note( Dumper( { %res2 } ) ); -}; - -subtest 'Request of person data for Ray Bradbury as full name' => sub { - plan tests => 2; - - my $res1 = $query->find_person( { fullname => 'Ray Bradbury' } ); - ok( $res1, 'Ray Bradbury is present' ); - note( $res1 ); - - my %res2 = $query->find_person( 'Ray Bradbury' ); - ok(scalar keys %res2 > 1, "Got Ray Bradbury's data" ); - note( Dumper( { %res2 } ) ); -}; - -subtest 'Request of membership in specific group for Ray Bradbury' => sub { - plan tests => 1; - my $res = $query->is_member_of( 'Ray Bradbury', 'scifi' ); - ok( $res, "Ray Bradbury is member of scifi since ".( $res ? $res : "(unknown)" ) ); - note( $res ); -}; - -subtest 'Request of membership in specific group for Ray Bradbury as fullname' => sub { - plan tests => 1; - my $res = $query->is_member_of( { fullname => 'Ray Bradbury' }, 'scifi' ); - ok( $res, "Ray Bradbury is member of scifi since ".( $res ? $res : "(unknown)" ) ); - note( $res ); -}; - -subtest 'Request of "author" tag value for Ray Bradbury' => sub { - plan tests => 1; - my $res = $query->find_person_tag( 'Ray Bradbury', 'author' ); - ok( $res, "The 'author' tag for Ray Bradbury is ".( $res ? $res : "(unknown)" ) ); - note( Dumper $res ); -}; - -subtest 'Request of "author" tag value for Ray Bradbury as full name' => sub { - plan tests => 1; - my $res = $query->find_person_tag( { fullname => 'Ray Bradbury' }, 'author' ); - ok( $res, "The 'author' tag for Ray Bradbury is ".( $res ? $res : "(unknown)" ) ); - note( Dumper $res ); -}; - -subtest 'Request of CLA status for Ray Bradbury' => sub { - plan tests => 1; - my $res = $query->has_cla( 'r...@ourplace.com' ); - ok( $res, 'Ray Bradbury has CLA as r...@ourplace.com' ); - note( $res ); -}; - -subtest 'Request of membership in the group "writers"' => sub { - plan tests => 1; - my @res = $query->members_of( 'writers' ); - ok( @res, 'Finding members of "writers"' ); - note( Dumper @res ); -}; - -subtest 'Request of person data for Jay Luser' => sub { - plan tests => 2; - - my $res1 = $query->find_person( 'Jay Luser' ); - ok( !$res1, 'Jay Luser is not present' ); - note( $res1 ); - - my %res2 = $query->find_person( 'Jay Luser' ); - ok( !%res2, "Failed getting Jay Luser's data" ); -}; - -subtest 'Request of membership in specific group for Jay Luser' => sub { - plan tests => 1; - my $res = $query->is_member_of( 'Jay Luser', 'scifi' ); - ok( !$res, 'Jay Luser is not member of scifi' ); - note( $res ); -}; - -subtest 'Request of "author" tag value for Jay Luser' => sub { - plan tests => 1; - my $res = $query->find_person_tag( 'Jay Luser', 'author' ); - ok( !$res, "No 'author' tag for Jay Luser" ); - note( $res ); -}; - -subtest 'Request of CLA status for Jay Luser' => sub { - plan tests => 1; - my $res = $query->has_cla( 'jlu...@ourplace.com' ); - ok( !$res, 'Jay Luser has no CLA' ); - note( $res ); -}; - -subtest 'Request of membership in the group "couchpotatoes"' => sub { - plan tests => 1; - my @res = $query->members_of( 'couchpotatoes' ); - ok( !@res, 'No members in "couchpotatoes"' ); - note( @res ); -}; - -1; diff --git a/clacheck/README b/clacheck/README deleted file mode 100644 index 1edb8ff..0000000 --- a/clacheck/README +++ /dev/null @@ -1,14 +0,0 @@ - -CLACHECK - -A cgi-bin script to verify GitHub pull requests and see that the author -is in the CLA database. - -Create a GH machine account, get an OAUTH token for it. -Create a GH webhook that gets pull requests and point it to -this script. - - ghpass.txt -- A github OAuth token - - clacheck.py -- GitHub hook to check for CLA license - diff --git a/clacheck/clacheck.py b/clacheck/clacheck.py deleted file mode 100755 index 2dbb6fd..0000000 --- a/clacheck/clacheck.py +++ /dev/null @@ -1,113 +0,0 @@ -#! /usr/bin/env python -"""GitHub web hook. Take PullRequest messages, and check the authors -for the CLA. - -Look for <EDIT> comments for pointers on where to customize -""" - -import cgi, cgitb -import json, urllib, os, re, sys, httplib - -cgitb.enable() - -env = os.environ -textplain = "Content-type: text/plain\n\n" -what = env.get('HTTP_X_GITHUB_EVENT', 'ping') -From = re.compile("^From:.*<(.*)>") -Trivial = re.compile("^\s*CLA\s*:\s*TRIVIAL", re.IGNORECASE) -URLpattern = re.compile("https?://([^/]*)/(.*)") -SUCCESS = 'success' -FAILURE = 'failure' -CLAFILE = "/var/cache/openssl/checkouts/omc/cladb.txt" #<EDIT> - -CLA_LABEL = 'hold: cla required' - -null_actions = ( - 'assigned', 'unassigned', 'labeled', 'unlabeled', 'closed', - 'review_requested', 'review_request_removed', - ) - -#<EDIT> target_url value -statusbody = """ -{ - "state": "%(state)s", - "target_url": "https://www.openssl.org/policies/cla.html", - "description": "%(description)s", - "context": "cla-check" -} -""" - -def url_split(url): - m = URLpattern.match(url) - return (m.group(1), '/' + m.group(2)) - -def update_status(pr, state, description): - d = { 'state': state, 'description': description } - token = open('../ghpass.txt').read().strip() #<EDIT> password file - headers = { - 'Authorization': 'token ' + token, - 'User-Agent': 'richsalz', #<EDIT> some other name - 'Content-Type': 'application/json; charset=utf-8', - 'Accept': 'application/json', - } - host,url = url_split(pr['_links']['statuses']['href']) - print textplain, "CLA check", state, description - conn = httplib.HTTPSConnection(host) - conn.request('POST', url, statusbody % d, headers) - conn.getresponse().read() - host,url = url_split(pr['issue_url']) - if state == SUCCESS: - url = url + '/labels/' + urllib.quote(CLA_LABEL) - print 'Delete', url - conn.request('DELETE', url, None, headers) - elif state == FAILURE: - url = url + '/labels' - print 'Add need-cla', url - conn.set_debuglevel(99) - conn.request('POST', url, '[ "{}" ]'.format(CLA_LABEL), headers) - reply = conn.getresponse().read() - print "--\n", reply - -def have_cla(name): - """Is |name| in the cladb?""" - for line in open(CLAFILE): - line = line.strip() - if not line or line[0] == '#': - continue - n = line.split() - if len(n) and n[0] == name.lower(): - return 1 - return 0 - -def process(): - if what != 'pull_request': - print textplain, "Request", what - return - data = json.loads(sys.stdin.read()) - action = data.get('action', None) - if action is None or action in null_actions: - print textplain, "No-op action", action - return - pr = data.get('pull_request', None) - if pr is None: - print textplain, "PR data missing" - return - patch_url = pr.get('patch_url', None) - if patch_url is None: - print textplain, "patch_url missing" - return - missing = {} - for line in urllib.urlopen(patch_url): - m = Trivial.match(line) - if m: - update_status(pr, SUCCESS, "Trivial") - return - m = From.match(line) - if m and not have_cla(m.group(1)): - missing[m.group(1)] = 1 - if len(missing) == 0: - update_status(pr, SUCCESS, 'CLA on file') - else: - update_status(pr, FAILURE, "CLA missing: " + str(missing.keys())) - -process() diff --git a/github-approve-label-workflow/README.md b/github-approve-label-workflow/README.md deleted file mode 100644 index 6acf928..0000000 --- a/github-approve-label-workflow/README.md +++ /dev/null @@ -1,20 +0,0 @@ -Do we have any open openssl PR requests that have the label -"approval: done" that are over 24 hours old? If so if there -have been no other comments added since then we can automatically -move them to "approval: ready to merge" - -You need a token to make label changes and to ensure you don't -hit rate limiting if you just want a dry run. Get one from -https://github.com/settings/tokens/new select 'repo' only -then put it in token.txt (prefix with the string "token ", i.e. -echo "token 12903413aaaaaa" > token.txt - -to see what it would do: - -python github-approve-label-workflow --debug --token token.txt - -or to also actually change any labels - -python github-approve-label-workflow --debug --token token.txt --commit - -Requires Python 3 diff --git a/github-approve-label-workflow/github-approve-label-workflow.py b/github-approve-label-workflow/github-approve-label-workflow.py deleted file mode 100644 index ecacdf5..0000000 --- a/github-approve-label-workflow/github-approve-label-workflow.py +++ /dev/null @@ -1,171 +0,0 @@ -#! /usr/bin/env python -# requires python 3 -# -# Do we have any open PR's that have label "Approval: done" -# that are over 24 hours without any other comments? -# -# get a token.... https://github.com/settings/tokens/new -- just repo is fine -# pop it in token.txt or you'll get a bad API limit -# -# note that we'd use pyGithub but we can't as it doesn't fully handle the timeline objects -# as of Feb 2020 -# -# m...@openssl.org Feb 2020 -# -import requests -import json -from datetime import datetime, timezone -from optparse import OptionParser - -api_url = "https://api.github.com/repos/openssl/openssl" - -def convertdate(date): - return datetime.strptime(date.replace('Z',"+0000"), "%Y-%m-%dT%H:%M:%S%z") - -# Get all the open pull requests, filtering by approval: done label - -def getpullrequests(): - url = api_url + "/pulls?per_page=100&page=1" # defaults to open - res = requests.get(url, headers=headers) - repos = res.json() - prs = [] - while 'next' in res.links.keys(): - res = requests.get(res.links['next']['url'], headers=headers) - repos.extend(res.json()) - - # Let's filter by label if we're just looking to move things, we can parse - # everything for statistics in another script - - try: - for pr in repos: - if 'labels' in pr: - for label in pr['labels']: - if label['name'] == 'approval: done': - prs.append(pr['number']) - except: - print("failed", repos['message']) - return prs - -# Change the labels on an issue from approval: done to approval: ready to merge - -def movelabeldonetoready(issue): - url = api_url + "/issues/" + str(issue) + "/labels/approval:%20done" - res = requests.delete(url, headers=headers) - if (res.status_code != 200): - print("Error removing label", res.status_code, res.content) - return - url = api_url + "/issues/" + str(issue) + "/labels" - newlabel = {"labels": ["approval: ready to merge"]} - res = requests.post(url, data=json.dumps(newlabel), headers=headers) - if (res.status_code != 200): - print("Error adding label", res.status_code, res.content) - return - newcomment = {"body":"This pull request is ready to merge"} - url = api_url + "/issues/" + str(issue) + "/comments" - res = requests.post(url, data=json.dumps(newcomment), headers=headers) - if (res.status_code != 201): - print("Error adding comment", res.status_code, res.content) - return - -# Check through an issue and see if it's a candidate for moving - -def checkpr(pr): - url = api_url + "/issues/" + str(pr) + "/timeline?per_page=100&page=1" - res = requests.get(url, headers=headers) - repos = res.json() - while 'next' in res.links.keys(): - res = requests.get(res.links['next']['url'], headers=headers) - repos.extend(res.json()) - - comments = [] - approvallabel = {} - readytomerge = 0 - - for event in repos: - try: - if (event['event'] == "commented"): - comments.append(convertdate(event["updated_at"])) - if debug: - print("debug: commented at ", - convertdate(event["updated_at"])) - if (event['event'] == "committed"): - comments.append(convertdate(event["author"]["date"])) - if debug: - print("debug: created at ", - convertdate(event["author"]["date"])) - elif (event['event'] == "labeled"): - if debug: - print("debug: labelled with ", event['label']['name'], - "at", convertdate(event["created_at"])) - approvallabel[event['label']['name']] = convertdate( - event["created_at"]) - elif (event['event'] == "unlabeled"): - if (debug): - print("debug: unlabelled with ", event['label']['name'], - "at", convertdate(event["created_at"])) - if event['label'][ - 'name'] in approvallabel: # have to do this for if labels got renamed in the middle - del approvallabel[event['label']['name']] - elif (event['event'] == "reviewed" - and event['state'] == "approved"): - if debug: - print("debug: approved at", - convertdate(event['submitted_at'])) - except: - return (repos['message']) - - if 'approval: ready to merge' in approvallabel: - return ("issue already has label approval: ready to merge") - if 'approval: done' not in approvallabel: - return ("issue did not get label approval: done") - approvedone = approvallabel['approval: done'] - - if max(comments) > approvedone: - return ("issue had comments after approval: done label was given") - - now = datetime.now(timezone.utc) - hourssinceapproval = (now - approvedone).total_seconds() / 3600 - if debug: - print("Now: ", now) - print("Last comment: ", max(comments)) - print("Approved since: ", approvedone) - print("hours since approval", hourssinceapproval) - - if (hourssinceapproval < 24): - return ("not yet 24 hours since labelled approval:done hours:" + - str(int(hourssinceapproval))) - - if (options.commit): - print("Moving issue ", pr, " to approval: ready to merge") - movelabeldonetoready(pr) - else: - print("use --commit to actually change the labels") - return ( - "this issue was candidate to move to approval: ready to merge hours:" + - str(int(hourssinceapproval))) - -# main - -parser = OptionParser() -parser.add_option("-d","--debug",action="store_true",help="be noisy",dest="debug") -parser.add_option("-t","--token",help="file containing github authentication token for example 'token 18asdjada...'",dest="token") -parser.add_option("-c","--commit",action="store_true",help="actually change the labels",dest="commit") -(options, args) = parser.parse_args() -if (options.token): - fp = open(options.token, "r") - git_token = fp.readline().strip('\n') -else: - git_token = "" # blank token is fine, but you can't change labels and you hit API rate limiting -debug = options.debug -# since timeline is a preview feature we have to enable access to it with an accept header -headers = { - "Accept": "application/vnd.github.mockingbird-preview", - "Authorization": git_token -} - -if debug: - print("Getting list of PRs") -prs = getpullrequests() -print("There were", len(prs), "open PRs with approval:done ") -for pr in prs: - print(pr, checkpr(pr)) diff --git a/license/.htaccess b/license/.htaccess deleted file mode 100644 index 7ff120e..0000000 --- a/license/.htaccess +++ /dev/null @@ -1,5 +0,0 @@ -Redirect 404 /adpass.txt -Redirect 404 /ghpass.txt -Redirect 404 /ropass.txt -Redirect 404 /rwpass.txt -Redirect 404 /.git diff --git a/license/README b/license/README deleted file mode 100644 index 3db5742..0000000 --- a/license/README +++ /dev/null @@ -1,30 +0,0 @@ -Tools - approved -- Mark specified email addresses as approving - createdb -- Create the license approval database - finduser -- List specified email or names - devteam.py -- List of dev team members; edit this for your project - get-followups -- Make list of people who have not replied - git-import -- Import specified commits - git-import-all -- Script to import all git commits - mailuser -- Send license mail to specified addresses (SQL patterns) - rmcommit -- Remove a set of commits from a user's activity - rmuser -- Remove specified email authors from database - whattoremove -- Commits to remove for folks who said no - add-counts -- add commit data to output of get-followups - add-lastchance -- "last chance trying to reach" version of add-counts - -Passwords; create these files. One line per each - adpass.txt -- HTTP password for admin functions - ropass.txt -- A mysql read-only password - rwpass.txt -- A mysql read-write password - -Web - index.html -- Main license page - request-approval.txt -- Email template to send requesting approval - style.css -- Webpage styling; deliberately minimal - cgi-bin/authors.py -- List of authors - cgi-bin/lookup.py -- Lookup an author, get list of commits - cgi-bin/receive-reply.py -- Handler for link sent via email - cgi-bin/reply.py -- Destination of send-email; form to reply - cgi-bin/search.py -- Search for an author - cgi-bin/send-email.py -- Send email to an author diff --git a/license/add-counts b/license/add-counts deleted file mode 100755 index 4a796fe..0000000 --- a/license/add-counts +++ /dev/null @@ -1,41 +0,0 @@ -#! /usr/bin/env perl -# Annotate the output of "get-followups -d" to show the stats -# of each commit. -use strict; -use warnings; - -die "Feed this the output of 'get-followups -d'\n" if -t 0; - -while ( <> ) { - unless ( /([0-da-f]{8}) .*/ ) { - print; - next; - } - my $cid = $1; - my $line = $_; - $line =~ s/^\s*//; - if ( $cid eq 'd02b48c6' ) { - print "931 +17534 -0 ", $_; - next; - } - my $pattern = "$cid^..$cid"; - my $files = 0; - my $adds = 0; - my $dels = 0; - my $name = ''; - open my $F, "git diff --numstat $pattern|" - || die "Can't open git diff, $!\n"; - while ( <$F> ) { - $files++; - next unless /(\d+)\s+(\d+)\s+(.*)/; - $adds += int($1); - $dels += int($2); - $name = $3 if $name eq ''; - } - close $F || die "Can't close git diff, $!\n"; - if ( $files == 1 ) { - print "$name +$adds -$dels $line"; - } else { - print "$files +$adds -$dels $line"; - } -} diff --git a/license/add-lastchance b/license/add-lastchance deleted file mode 100755 index e763b6e..0000000 --- a/license/add-lastchance +++ /dev/null @@ -1,92 +0,0 @@ -#! /usr/bin/env perl -# Annotate the output of "get-followups -d" to show the stats -# of each commit for a "last chance trying to find" page. -use strict; -use warnings; - -die "Feed this the output of 'get-followups -d'\n" if -t 0; - -my $blog = 'https://www.openssl.org//blog/blog/2017/03/22/license'; -print <<EOF; -<html> - <head> - <title>Help find these people</title> - <link rel="stylesheet" type="text/css" href="/style.css"> - </head> - <body> - <h1>Help find these people</h1> - <p>We are looking for some people who have previously contributed - to OpenSSL. See <a href="$blog">$blog</a> for some background. - If you know where to find any of the following people, please - email their current address to - <a href="mailto:license\@openssl.org">license\@openssl.org</a>, - or ask them to get in touch. - </p> - <p>Each contributor is separated by a blank line. The first - line is the last known email we have, and the full name if known. - Each following line has the number of files changed, lines added - and deleted, the commit ID and date, and then the commit subject line. - </p> - <p>Thank you! - </p> - <p><a href="/">Main page</a></p> - </p> -EOF - -my $users = 0; -my $commits = 0; -my $base = 'https://github.com/openssl/openssl/commit'; -while ( <> ) { - unless ( /([0-da-f]{8}) .*/ ) { - $users++ if /https:/; - s/.*uid.[0-9]+, //; - s/, \d, /, /; - s/"//g; - if ( /([^,]*), (.*)/ ) { - if ( $1 eq $2 ) { - print "<$1>\n"; - } else { - print "$2 <$1>\n"; - } - } else { - print; - } - print "<br/>\n"; - next; - } - $commits++; - my $cid = $1; - chop; - my $line = $_; - $line =~ s/^\s*//; - $line =~ s/</</; - if ( $cid eq 'd02b48c6' ) { - print "- +0/-0 ", $_; - print "<br/>\n"; - next; - } - my $pattern = "$cid^..$cid"; - my $files = 0; - my $adds = 0; - my $dels = 0; - open my $F, "git diff --numstat $pattern|" - || die "Can't open git diff, $!\n"; - while ( <$F> ) { - next if /CHANGES/; - $files++; - next unless /(\d+)\s+(\d+)\s+(.*)/; - $adds += int($1); - $dels += int($2); - } - close $F || die "Can't close git diff, $!\n"; - print " $files +$adds -$dels <a href='$base/$cid'>$line</a><br/>\n"; -} -print <<EOF; - - $users contributors, $commits commits - <p> - - <a href="/">Main page</a></p> - </body> -</html> -EOF diff --git a/license/approved b/license/approved deleted file mode 100755 index c501bf8..0000000 --- a/license/approved +++ /dev/null @@ -1,55 +0,0 @@ -#! /usr/bin/env python -"""approved [flags] args... - -Flags: - -c text... Comment to use - -m Use email+date as the comment - -r Reject not approve - -h This help - -v List emails as processed - -Args is a list of email addresses. -""" - -import datetime, mysql.connector, os, re, subprocess, sys -import string, random -import getopt - -dbconfig = { - 'user': 'license', - 'password': open('rwpass.txt').read().strip(), - 'database': 'license' - } -conn = mysql.connector.connect(**dbconfig) -cursor = conn.cursor() - -# Parse JCL -comment = 'From CLI'; -reply = 'y' -verbose = 0 -opts, args = getopt.getopt(sys.argv[1:], "c:hrvm") -for o,a in opts: - if o == '-c': - comment = a - elif o == '-r': - reply = 'n' - elif o == '-v': - verbose = 1 - elif o == '-m': - comment = datetime.date.today().strftime('Email %Y-%m-%d') - else: - print __doc__ - raise SystemExit - -q = 'SELECT uid FROM users WHERE email = %s' -update = ("UPDATE users SET date_replied=%s, reply=%s, comment=%s" - " WHERE uid=%s") -today = datetime.datetime.today().date() - -for email in args: - cursor.execute(q, (email,)) - for uid in cursor: - cursor.execute(update, (today, reply, comment, uid[0])) - conn.commit() - if verbose: - print email, uid[0] diff --git a/license/cgi-bin/authors.py b/license/cgi-bin/authors.py deleted file mode 100755 index 827199d..0000000 --- a/license/cgi-bin/authors.py +++ /dev/null @@ -1,90 +0,0 @@ -#! /usr/bin/env python - -import cgi -import cgitb -import mysql.connector - -cgitb.enable() - -urlbase = 'https://github.com/openssl/openssl/commit/' - -dbconfig = { - 'user': 'licensereader', - 'password': open('../ropass.txt').read().strip(), - 'database': 'license' - } -conn = mysql.connector.connect(**dbconfig) -cursor = conn.cursor() - -header = """Content-Type: text/html - -<html> - <head> - <title>Authors - OpenSSL License Change Agreement</title> - <link rel="stylesheet" type="text/css" href="/style.css"> - </head> - <body> - <h1>List of Authors</h1> - <p><a href="/">Main page</a></p> - - <p>Names appear multiple times because of multiple email addresses.</p> -""" - -trailer = """ - <a href="/">Main page</a> - </body> -</html> -""" - -def summary(): - print header - q = "SELECT name, uid FROM users WHERE reply = '-' ORDER BY name" - cursor.execute(q) - print "<p>We are still seeking responses from the following:</p>" - print "<p class='cw'>" - for row in cursor: - name, uid = row - name = name.encode('ascii', errors='xmlcharrefreplace') - print '<a href="lookup.py?uid=%d">%s</a><br>' % (uid,name) - print "</p>" - print trailer - -def details(): - print header - print "<table border='1' class='cw'>" - print "<tr><th>Name</th><th>Reply</th><th>Date</th><th>Comment</th></tr>" - q = ("SELECT name,uid,reply,date_replied,comment" - " FROM users ORDER BY reply,name") - cursor.execute(q) - counts = {} - for row in cursor: - name,uid,reply,date_replied,comment = row - if comment is None or comment is '': - comment = "--" - if date_replied == None: - date_replied = '' - counts[reply] = counts.get(reply, 0) + 1 - print ("<tr>" - "<td><a href='lookup.py?uid=%d'>%s</td>" - "<td>%s</td>" - "<td>%s</td>" - "<td>%s</td></tr>") % (uid,name,reply,date_replied,comment) - print "</table>" - print "<p>Counts by response:</p>" - print "<table border='1' class='cw'>" - print "<tr><th>Reply</th><th>Count</th></tr>" - total = 0 - for k in counts: - print "<tr><td>%s</td><td>%d</td></tr>" % (k, counts[k]) - total += counts[k] - print "<tr><td>%s</td><td>%d</td></tr>" % ("Total", total) - print "</table>" - print trailer - -form = cgi.FieldStorage() - -dpass = open('../adpass.txt').read().strip() -if 'd' in form and form['d'].value == dpass: - details() -else: - summary() diff --git a/license/cgi-bin/lookup.py b/license/cgi-bin/lookup.py deleted file mode 100755 index 762ed31..0000000 --- a/license/cgi-bin/lookup.py +++ /dev/null @@ -1,98 +0,0 @@ -#! /usr/bin/env python - -import cgi -import cgitb -import mysql.connector - -cgitb.enable() - -# Open links in newpage? -target = 'target="_blank"' -where = ' (commits open in a new window)' - -urlbase = 'https://github.com/openssl/openssl/commit/' - -dbconfig = { - 'user': 'licensereader', - 'password': open('../ropass.txt').read().strip(), - 'database': 'license' - } - -print """Content-Type: text/html - -<html> - <head> - <title>Search results - OpenSSL License Change Agreement</title> - <link rel="stylesheet" type="text/css" href="/style.css"> - </head> - <body> - <h1>Search results</h1> - - <p><a href="/">Main page</a></p> - - <p>""" - -def show_log(uid, email): - """Ouput HTML for all commits from |uid| or |email|. If uid is None - then look up email. Returns the uid.""" - conn = mysql.connector.connect(**dbconfig) - cursor = conn.cursor() - if uid: - q = "SELECT email, reply FROM users WHERE uid = %s" - cursor.execute(q, (uid,)) - row = cursor.fetchone() - if not row: - print "No commits by id %s: No such developer</p>" % (uid,) - return None - email, reply = row - else: - q = "SELECT uid, reply FROM users WHERE email = %s" - cursor.execute(q, (email,)) - row = cursor.fetchone() - if not row: - print "No commits by %s: No such developer</p>" % (email,) - return None - uid, reply = row - q = "SELECT count(cid) FROM log WHERE uid = %s" - cursor.execute(q, (uid,)) - row = cursor.fetchone() - if not row or not row[0]: - print "No commits by", email - return None - count = row[0] - q = ("SELECT commit, date, descrip FROM commits" - " LEFT JOIN log ON commits.cid = log.cid" - " WHERE uid = %s ORDER BY date, commit") - cursor.execute(q, (uid,)) - print "Found %d commits by %s%s:\n</p>" % (count, email, where) - print "<p class='cw'>" - print "<table>" - for row in cursor: - commit, cdate, descrip = row - print '<tr><td><a href="%s%s" %s>%s</a> </td>' % \ - (urlbase, commit, target, commit) - print '<td>%s </td><td>%s </td></tr>' % (cdate, descrip) - print "</table></p>" - return uid - -form = cgi.FieldStorage() -if 'onepage' in form: - where = target = '' -if 'uid' in form: - uid = show_log(form['uid'].value.replace('<', '<'), None) -elif 'email' in form: - uid = show_log(None, form['email'].value.replace('<', '<')) -else: - uid = None - print "No email specified" - -print '<p>' -if uid != None: - print '<a href="/cgi-bin/send-email.py?uid=%s">' \ - 'Send agreement email</a><br>' % (uid,) - -print """ - <a href="/">Main page</a></p> - </body> -</html> -""" diff --git a/license/cgi-bin/receive-reply.py b/license/cgi-bin/receive-reply.py deleted file mode 100755 index add2dc9..0000000 --- a/license/cgi-bin/receive-reply.py +++ /dev/null @@ -1,72 +0,0 @@ -#! /usr/bin/env python - -import cgi, cgitb -import mysql.connector -import datetime, os, re, subprocess, sys, string, random - -cgitb.enable() - -dbconfig = { - 'user': 'license', - 'password': open('../rwpass.txt').read().strip(), - 'database': 'license' - } - -print """Content-Type: text/html - -<html> - <head> - <title>Reply Recorded - OpenSSL License Change Agreement</title> - <link rel="stylesheet" type="text/css" href="/style.css"> - </head> - <body> - <h1>Reply Recorded</h1> - <p><a href="/">Main page</a></p> - <p>""" - -trailer = """ - <p><a href="/">Main page</a></p> - </body> -</html> -""" - -form = cgi.FieldStorage() -if 'uid' not in form or 'p' not in form or 'agree' not in form: - print "Missing parameters. Please check the link.\n", trailer - raise SystemExit -uid = form['uid'].value -secret = form['p'].value -reply = form['agree'].value -comment = "" -if 'comment' in form: - comment = form['comment'].value.replace('<', '<') - -conn = mysql.connector.connect(**dbconfig) -cursor = conn.cursor() -q = "SELECT secret,reply FROM users WHERE uid = %s" -cursor.execute(q, (uid,)) -row = cursor.fetchone() -if not row: - print "No such user. Please check the link.\n", trailer - raise SystemExit -dbsecret, dbreply = row -if secret != dbsecret: - print "Password does not match. Please check the link or\n" - print '<a href="/cgi-bin/send-email.py?uid=%s">re-send' % (uid,) - print "the agreement email</a>" - print trailer - raise SystemExit -if dbreply != '-': - print "Already replied. If you wish to change your answer, please" - print "send email to" - print "<a href='mailto:lice...@openssl.org'>lice...@openssl.org</a>" - print "describing your change." - raise SystemExit - -today = datetime.datetime.today().date() -t = ("UPDATE users SET date_replied=%s, reply=%s, comment=%s" - " WHERE uid=%s") -cursor.execute(t, (today, reply, comment, uid)) -conn.commit() - -print "Your reply has been recorded, thank you!", trailer diff --git a/license/cgi-bin/reply.py b/license/cgi-bin/reply.py deleted file mode 100755 index 93625d9..0000000 --- a/license/cgi-bin/reply.py +++ /dev/null @@ -1,73 +0,0 @@ -#! /usr/bin/env python - -import cgi, cgitb -import mysql.connector -import datetime, os, re, subprocess, sys, string, random - -cgitb.enable() - -dbconfig = { - 'user': 'licensereader', - 'password': open('../ropass.txt').read().strip(), - 'database': 'license' - } - -print """Content-Type: text/html - -<html> - <head> - <title>Reply - OpenSSL License Change Agreement</title> - <link rel="stylesheet" type="text/css" href="/style.css"> - </head> - <body> - <h1>Reply</h1> - <p><a href="/">Main page</a></p> - """ - -trailer = """ - <p><a href="/">Main page</a></p> - </body> -</html> -""" - -form = cgi.FieldStorage() -if 'uid' not in form or 'p' not in form: - print "Missing parameters. Please check the link.\n", trailer - raise SystemExit -uid = form['uid'].value -secret = form['p'].value - -conn = mysql.connector.connect(**dbconfig) -cursor = conn.cursor() -q = "SELECT secret FROM users WHERE uid = %s" -cursor.execute(q, (uid,)) -row = cursor.fetchone() -if not row: - print "No such user. Please check the link.\n", trailer - raise SystemExit -if secret != row[0]: - print "Password does not match. Please check the link.\n", trailer - raise SystemExit - -print """ - <form action="/cgi-bin/receive-reply.py" method="GET"> - - <p> - I give permission for my contributions to be licensed under - the Apache License (version 2):</br> - <input type="radio" name="agree" value="y" checked>Yes<br> - <input type="radio" name="agree" value="n" >No<br> - <input type="hidden" name="uid" value="%s"> - <input type="hidden" name="p" value="%s"> - </p> - - <p> - Additional comments (optional):<br> - <input type="text" name='comment' maxlength='80' size='40'> - </p> - - <button action="submit">Send answer</button> - </form> -""" % (uid, secret) - -print trailer diff --git a/license/cgi-bin/search.py b/license/cgi-bin/search.py deleted file mode 100755 index 10409a2..0000000 --- a/license/cgi-bin/search.py +++ /dev/null @@ -1,101 +0,0 @@ -#! /usr/bin/env python - -import cgi -import cgitb -import mysql.connector - -cgitb.enable() - -# Open links in newpage? -target = 'target="_blank"' -where = ' (commits open in a new window)' - -urlbase = 'https://github.com/openssl/openssl/commit/' - -dbconfig = { - 'user': 'licensereader', - 'password': open('../ropass.txt').read().strip(), - 'database': 'license' - } - -print """Content-Type: text/html - -<html> - <head> - <title>Author Search results - OpenSSL License Change Agreement</title> - <link rel="stylesheet" type="text/css" href="/style.css"> - </head> - <body> - <h1>Author Search results</h1> - <p><a href="/">Main page</a></p> - <p>""" - -def show_log(uid, email): - """Ouput HTML for all commits from |uid| or |email|. If uid is None - then look up email. Returns the uid.""" - conn = mysql.connector.connect(**dbconfig) - cursor = conn.cursor() - if uid: - q = "SELECT email, reply FROM users WHERE uid = %s" - cursor.execute(q, (uid,)) - row = cursor.fetchone() - if not row: - print "No commits by id %s: No such developer</p>" % (uid,) - return None - email, reply = row - else: - q = "SELECT uid, reply FROM users WHERE email = %s" - cursor.execute(q, (email,)) - row = cursor.fetchone() - if not row: - print "No commits by %s: No such developer</p>" % (email,) - return None - uid, reply = row - q = "SELECT count(cid) FROM log WHERE uid = %s" - cursor.execute(q, (uid,)) - row = cursor.fetchone() - if not row or not row[0]: - print "No commits by", email - return None - count = row[0] - q = ("SELECT commit, date, descrip FROM commits" - " LEFT JOIN log ON commits.cid = log.cid" - " WHERE uid = %s ORDER BY date, commit") - cursor.execute(q, (uid,)) - print "Found %d commits by %s%s:\n</p>" % (count, email, where) - print "<p class='cw'>" - print "<table>" - for row in cursor: - commit, cdate, descrip = row - print '<tr><td><a href="%s%s" %s>%s</a> </td>' % \ - (urlbase, commit, target, commit) - print '<td>%s </td><td>%s </td></tr>' % (cdate, descrip) - print "</table></p>" - return uid - -form = cgi.FieldStorage() -if 'text' in form: - pattern = '%' + form['text'].value + '%' - conn = mysql.connector.connect(**dbconfig) - cursor = conn.cursor() - q = ("SELECT name, uid FROM users WHERE" - " name LIKE %s OR email LIKE %s ORDER BY name") - cursor.execute(q, (pattern,pattern)) - - print "<p class='cw'>" - for row in cursor: - name, uid = row - name = name.encode('ascii', errors='xmlcharrefreplace') - print '<a href="lookup.py?uid=%d">%s</a><br>' % (uid,name) - #print '<a href="lookup.py?uid=%d">' % (uid,) + name + '</a><br>' - print "</p>" -else: - print "No text specified" - -print '<p>' - -print """ - <a href="/">Main page</a></p> - </body> -</html> -""" diff --git a/license/cgi-bin/send-email.py b/license/cgi-bin/send-email.py deleted file mode 100755 index 04753c8..0000000 --- a/license/cgi-bin/send-email.py +++ /dev/null @@ -1,113 +0,0 @@ -#! /usr/bin/env python - -import cgi, cgitb -import mysql.connector -import datetime, os, re, subprocess, sys, string, random - -cgitb.enable() - -dbconfig = { - 'user': 'license', - 'password': open('../rwpass.txt').read().strip(), - 'database': 'license' - } - -print """Content-Type: text/html - -<html> - <head> - <title>Send email - OpenSSL License Change Agreement</title> - <link rel="stylesheet" type="text/css" href="/style.css"> - </head> - <body> - <h1>Send email</h1> - <p><a href="/">Main page</a></p> - <p>""" - -trailer = """ - </p> - <p><a href="/">Main page</a></p> - </body> -</html> -""" - -whitelist = ( - "m...@awe.com", - "openssl-us...@dukhovni.org", - "t...@cryptsoft.com", - "l...@lutz-jaenicke.de", - "b...@links.org", - "marqu...@openssl.com", - "marqu...@veridicalsystems.com", - "k...@roeckx.be", - "rich...@levitte.org", - "levi...@lp.se", - ) - -def okay_to_resend(email, last_asked): - """Return 1 if okay to resend email.""" - if email[-12:] == '@openssl.org' or email in whitelist: - return 1 - return 0 - -form = cgi.FieldStorage() -if 'uid' not in form: - print "No user specified.\n", trailer - raise SystemExit -uid = form['uid'].value - -conn = mysql.connector.connect(**dbconfig) -cursor = conn.cursor() -q = "SELECT email, reply, last_asked, secret FROM users WHERE uid = %s" -cursor.execute(q, (uid,)) -row = cursor.fetchone() -if not row: - print "No such user.\n", trailer - raise SystemExit -email, reply, last_asked, secret = row - -#if reply == 'd': -# print "Dev team, not sending.\n", trailer -# raise SystemExit - -if 1: - # This is why we can't have nice things :( - print "Mail contact lice...@openssl.org" - print "People are using this to spam other folks. :(" - raise SystemExit - -if last_asked and not okay_to_resend(email, last_asked): - diff = datetime.datetime.today().date() - last_asked - days = diff.days - print "Mail to", email, "was sent", str(last_asked) + "," - if days == 0: - print "earlier today.\n" - print "Please wait a day before requesting again.", trailer - raise SystemExit - if days <= 2: - print "recently.\n" - print "Please wait a day before requesting again.", trailer - raise SystemExit - -d = { 'uid': uid, 'secret': secret } -raw = open("../request-approval.txt").read() - -args = ('mail', '-s', 'OpenSSL License change', - '-r', 'lice...@openssl.org', email) -f = subprocess.Popen(args, stdin=subprocess.PIPE).stdin -print >>f, raw % d -f.close() - -today = datetime.datetime.today().date() -t = 'UPDATE users SET last_asked=%s WHERE uid=%s' -cursor.execute(t, (today, uid)) -conn.commit() - -print "Mail sent (with the fields filled in):</p>" -print "<pre>" -print raw -print "</pre>" -print "<p>" - -print trailer -raise SystemExit diff --git a/license/createdb b/license/createdb deleted file mode 100755 index 2a9dc81..0000000 --- a/license/createdb +++ /dev/null @@ -1,96 +0,0 @@ -#! /usr/bin/env python -"""Create the database tables for recording license change replies. -""" - -import datetime, mysql.connector, os -import string, random - -try: - execfile("devteam.py") -except: - devteam = () - -dbconfig = { - 'user': 'license', - 'password': open('rwpass.txt').read().strip(), - 'database': 'license' - } - -alphabet = string.uppercase + string.lowercase + string.digits - -tables = {} - -# The table of everyone whose name is in a commit. -tables['users'] = ( - "CREATE TABLE `users` (" - " `email` varchar(80) NOT NULL," - " `name` varchar(80) DEFAULT NULL," - " `secret` varchar(20) DEFAULT NULL," - " `last_asked` date DEFAULT NULL," - " `date_replied` date DEFAULT NULL," - " `reply` varchar(1) DEFAULT '?'," - " `comment` TINYTEXT DEFAULT NULL," - " `uid` int(11) NOT NULL AUTO_INCREMENT," - " PRIMARY KEY (`uid`)," - " UNIQUE KEY `email` (`email`)" - " )") - -# The table of all commits. -tables['commits'] = ( - "CREATE TABLE `commits` (" - " `commit` varchar(40) NOT NULL," - " `date` date DEFAULT NULL," - " `descrip` TINYTEXT DEFAULT NULL," - " `cid` int(11) NOT NULL AUTO_INCREMENT," - " PRIMARY KEY (`cid`)" - " )") - -# The log of each commit and involved user. -tables['log'] = ( - "CREATE TABLE `log` (" - " `cid` int," - " `uid` int," - " FOREIGN KEY (uid) REFERENCES users(uid)," - " FOREIGN KEY (cid) REFERENCES commits(cid)," - " UNIQUE INDEX (uid,cid)" - ")") - -table_order = [ 'users', 'commits', 'log' ] - -conn = mysql.connector.connect(**dbconfig) -cursor = conn.cursor() - -def makesecret(): - return "".join( [ random.choice(alphabet) for i in xrange(20) ] ) - -def maketables(): - drop_order = table_order[:] - drop_order.reverse() - for t in drop_order: - try: - cursor.execute("DROP TABLE %s" % (t,)) - print "Dropped table", t - except: - pass - for t in table_order: - print "Creating table", t - cursor.execute(tables[t]) - -def add_devteam(devteam): - print "Adding", len(devteam), "to devteam" - now = datetime.datetime.today() - for email,name in devteam: - data = { 'email': email, 'name': name, 'secret': makesecret(), - 'reply': 'd' - } - t = ("INSERT INTO users (email, name, secret, reply) " - " VALUES ( %(email)s, %(name)s, %(secret)s, %(reply)s )") - cursor.execute(t, data) - - -maketables() -if len(devteam) > 0: - add_devteam(devteam) - conn.commit() - -conn.close() diff --git a/license/devteam.py b/license/devteam.py deleted file mode 100755 index 40f1ce7..0000000 --- a/license/devteam.py +++ /dev/null @@ -1,25 +0,0 @@ -#! /usr/bin/env python - -devteam = ( - ( "m...@openssl.org", "Matt Caswell" ), - ( "m...@awe.com", "Mark Cox" ), - ( "vik...@openssl.org", "Viktor Duchovni" ), - ( "openssl-us...@dukhovni.org", "Viktor Duchovni" ), - ( "st...@openssl.org", "Dr. Stephen Henson" ), - ( "t...@cryptsoft.com", "Tim Hudson" ), - ( "t...@openssl.org", "Tim Hudson" ), - ( "l...@lutz-jaenicke.de", "Dr. Lutz Janicke" ), - ( "emi...@openssl.org", "Emilia Kasper" ), - ( "b...@links.org", "Ben Laurie" ), - ( "marqu...@openssl.com", "Steve Marquess" ), - ( "marqu...@openssl.org", "Steve Marquess" ), - ( "marqu...@veridicalsystems.com", "Steve Marquess" ), - ( "levi...@openssl.org", "Richard Levitte" ), - ( "b...@openssl.org", "Bodo Moeller" ), - ( "ap...@openssl.org", "Andy Polyakov" ), - ( "k...@roeckx.be", "Kurt Roeckx" ), - ( "rs...@openssl.org", "Rich Salz" ), - ( "ge...@openssl.org", "Geoff Thorpe" ), - ( "rich...@levitte.org", "Richard Levitte" ), - ( "levi...@lp.se", "Levitte Programming (Richard Levitte)" ) -) diff --git a/license/finduser b/license/finduser deleted file mode 100755 index 481c04b..0000000 --- a/license/finduser +++ /dev/null @@ -1,53 +0,0 @@ -#! /usr/bin/env python -"""finduser [flags] pattern... - -Flags: - -1 Print just email - -f Also print the comment - -Arguments is a list of SQL paterns (will get wrapped in wildcards, %), -by default display full information as CSV. -""" - -import mysql.connector -import datetime, os, re, subprocess, sys, string, random -import getopt - -dbconfig = { - 'user': 'licensereader', - 'password': open('ropass.txt').read().strip(), - 'database': 'license' - } -conn = mysql.connector.connect(**dbconfig) -cursor = conn.cursor() - -single = 0 -full = 0 -try: - opts, args = getopt.getopt(sys.argv[1:], "1f") -except: - print __doc__ - raise SystemExit - -for o,a in opts: - if o == '-1': - single = 1 - elif o == '-f': - full = 1 - -q = ('SELECT users.uid,email,reply,name,count(log.uid),comment FROM users' - ' LEFT JOIN log ON log.uid = users.uid' - ' WHERE email like %s GROUP BY email' ) -for email in args: - pat = '%' + email + '%' - cursor.execute(q, (pat,)) - for row in cursor: - uid,email,reply,name,count,comment = row - if reply == None: - reply = '-' - if single: - print email - else: - print '%d, %s, %s, %d, "%s"' % (uid, email, reply, count, name) - if full: - print '# ', comment diff --git a/license/get-authors b/license/get-authors deleted file mode 100755 index 32c6bd1..0000000 --- a/license/get-authors +++ /dev/null @@ -1,35 +0,0 @@ -#! /usr/bin/env python -"""get-authors - -Outputs text for an AUTHORS file. No parameters. -""" - -import mysql.connector -import datetime, os, re, subprocess, sys, string, random -import getopt - -dbconfig = { - 'user': 'licensereader', - 'password': open('ropass.txt').read().strip(), - 'database': 'license' - } -conn = mysql.connector.connect(**dbconfig) -cursor = conn.cursor() - -try: - opts, args = getopt.getopt(sys.argv[1:], "") -except: - print __doc__ - raise SystemExit - -for o,a in opts: - pass - -q = "SELECT name,email FROM users WHERE reply='y' OR reply='d' ORDER BY name" -cursor.execute(q) -for row in cursor: - name,email = row - if name == email: - print "<%s>" % (name,) - else: - print "%s <%s>" % (name, email) diff --git a/license/get-followups b/license/get-followups deleted file mode 100755 index 1d9472c..0000000 --- a/license/get-followups +++ /dev/null @@ -1,53 +0,0 @@ -#! /usr/bin/env python -"""get-followups [flags] - -Flags: - -d List details (commits) per user - -Get list of users (in CSV format) who have not been reached. -""" - -import mysql.connector -import datetime, os, re, subprocess, sys, string, random -import getopt - -dbconfig = { - 'user': 'licensereader', - 'password': open('ropass.txt').read().strip(), - 'database': 'license' - } -conn = mysql.connector.connect(**dbconfig) -cursor = conn.cursor() - -urlbase = 'https://license.openssl.org/cgi-bin/lookup.py?uid=' -fmtstring = urlbase + '%d, %s, %d, "%s"' - -details = 0 -opts, args = getopt.getopt(sys.argv[1:], "dh") -for o,a in opts: - if o == '-d': - details = 1 - else: - print __doc__ - raise SystemExit - -rows = [] -q = ('SELECT users.uid,email,reply,name,count(log.uid) FROM users' - ' LEFT JOIN log ON log.uid = users.uid' - ' WHERE reply = "-" GROUP BY email ORDER BY count(log.uid), email' ) -cursor.execute(q) -for row in cursor: - uid,email,reply,name,count = row - rows.append((uid, email, reply, name, count)) - -q = ('SELECT commit,date,descrip FROM commits' - ' LEFT JOIN log ON log.cid=commits.cid WHERE log.uid=%s') -for row in rows: - uid,email,reply,name,count = row - print fmtstring % (uid, email, count, name) - if details and count > 0: - cursor.execute(q, (uid,)) - for c in cursor: - commit,date,descrip = c - print "\t", commit[0:8],date,descrip - print diff --git a/license/get-summary b/license/get-summary deleted file mode 100755 index 3e0089c..0000000 --- a/license/get-summary +++ /dev/null @@ -1,48 +0,0 @@ -#! /usr/bin/env perl -# Annotate the output of "get-followups -d" to show the summary -# of all outstanding commits. -use strict; -use warnings; - -open my $FH, "./get-followups -d|" || die "Can't pipe, $!,"; - -my $total = 0; -my $tot_adds = 0; -my $tot_files = 0; -my $tot_dels = 0; -my $authors = 0; -while ( <$FH> ) { - if ( /https:/ ) { - $authors++; - next; - } - next unless /([0-da-f]{8}) .*/; - my $cid = $1; - my $pattern = "$cid^..$cid"; - my $files = 0; - my $adds = 0; - my $dels = 0; - $total++; - open my $F, "git diff --numstat $pattern|" - || die "Can't open git diff, $!\n"; - while ( <$F> ) { - next if /CHANGES/; - $files++; - next unless /(\d+)\s+(\d+)\s+(.*)/; - $adds += int($1); - $dels += int($2); - } - $tot_files += $files; - $tot_adds += $adds; - $tot_dels += $dels; - close $F || die "Can't close git diff, $!\n"; -} -close $FH || die "Can't close, $!,"; - -printf "Authors : %4d\n", $authors; -printf "Commits : %4d\n", $total; -printf "Files : %4d (%.2f average)\n", $tot_files, $tot_files / $total; -printf "Added lines : %4d (%.2f average)\n", $tot_adds, $tot_adds / $total; -printf "Deleted lines: %4d (%.2f average)\n", $tot_dels, $tot_dels / $total; -my $tot = $tot_adds - $tot_dels; -printf "Net change : %4d (%.2f average)\n", $tot, $tot / $total; diff --git a/license/git-import b/license/git-import deleted file mode 100755 index 496210b..0000000 --- a/license/git-import +++ /dev/null @@ -1,127 +0,0 @@ -#! /usr/bin/env python -"""Import a list of commits specified on the commandline into the license -database tables.""" - -import mysql.connector, os, re, subprocess, sys -import string, random - -if not os.environ.has_key('GIT_DIR'): - raise SystemExit, '$GIT_DIR not set' - -Author = re.compile("Author: (.*) <(.*)>") -ReviewedBy = re.compile(" *Reviewed-by:") -Email = re.compile(".*?([_0-9a-z.-]+@[0-9a-z.-]+).*", re.I) - -# Accented/multi-byte characters we just filter out. -Stripchars = ''.join([chr(x) for x in range(128,255)]) - -def hackfilter(s): - """Gross hack to just filter out the highbit chars we've seen in - our commit logs. :(""" - return s.translate(None, Stripchars) - -alphabet = string.uppercase + string.lowercase + string.digits - -def makesecret(): - """Make a password/secret.""" - return "".join( [ random.choice(alphabet) for i in xrange(20) ] ) - -def parse(commit): - """Parse a commit message and return a tuple of the email - addresses involved, the date of the commit, and the abbreviated - text description.""" - args = ('git', 'log', '-1', '--format=%cI %s', commit) - # 0 1 2 - # 012345678901234567890123456 - # 2015-05-22T16:15:08+00:00 Commit message text...\n - proc = subprocess.Popen(args, stdout=subprocess.PIPE) - l = proc.stdout.read() - cdate = l[0:10] - descrip = hackfilter(l[26:-1]) - descrip = descrip[:60] - proc.wait() - names = {} - proc = subprocess.Popen(('git', 'show', commit), stdout=subprocess.PIPE) - for l in proc.stdout: - if ReviewedBy.match(l): - # Reviewers are not contributors, skip them. - continue - m = Author.match(l) - if m and m.group(2) not in names: - names[hackfilter(m.group(2))] = hackfilter(m.group(1)) - continue - m = Email.match(l) - # If matched, and has a domain, and not seen before. - if m and m.group(1).find('.') != -1 and m.group(1) not in names: - names[hackfilter(m.group(1))] = hackfilter(m.group(1)) - continue - proc.wait() - return (names, cdate, descrip) - -#def execute(q, t): -# try: -# cusor.execute(q, t) -# except: -# print "Execute failed. SQL = |", q, '|' -# print "Data follows:\n", t - -dbconfig = { - 'user': 'license', - 'password': open('rwpass.txt').read().strip(), - 'database': 'license' - } -conn = mysql.connector.connect(**dbconfig) -cursor = conn.cursor() -userids = {} - -for commit in sys.argv[1:]: - names, cdate, descrip = parse(commit) - q = 'SELECT cid FROM commits WHERE commit = %s LIMIT 1' - cursor.execute(q, (commit,)) - row = cursor.fetchone() - if row and row[0]: - sys.stdout.write(commit[:7] + ', ') - cid = row[0] - else: - sys.stdout.write(commit[:7] + '. ') - data = { 'commit': commit, 'date': cdate, 'descrip': descrip } - t = ("INSERT IGNORE INTO commits (commit, date, descrip) " - " VALUES (%(commit)s, %(date)s, %(descrip)s)") - try: - cursor.execute(t, data) - except: - print "FAILED\n", "|" + t + "|\n", data - cid = cursor.lastrowid - q = 'SELECT uid FROM users WHERE email = %s LIMIT 1' - for email in names: - uid = userids.get(email, None) - if not uid: - # Not already seen -- try the database - try: - cursor.execute(q, (email,)) - row = cursor.fetchone() - except: - row = None - if row: - uid = userids[email] = row[0] - if not uid: - # Create the user - secret = makesecret(); - data = { 'email': email, 'name': names[email], - 'reply': '-', 'secret': secret } - t = ("INSERT INTO users (email, name, reply, secret)" - " VALUES (%(email)s, %(name)s, %(reply)s, %(secret)s)") - cursor.execute(t, data) - conn.commit() - cursor.execute(q, (email,)) - row = cursor.fetchone() - if row: - uid = row[0] - if not uid: - print "Can't find or add", email - continue - data = { 'cid': cid, 'uid': uid } - t = ("INSERT IGNORE INTO log (cid, uid)" - " VALUES (%(cid)s, %(uid)s)") - cursor.execute(t, data) - conn.commit() diff --git a/license/git-import-all b/license/git-import-all deleted file mode 100755 index 705db75..0000000 --- a/license/git-import-all +++ /dev/null @@ -1,7 +0,0 @@ -#! /bin/sh - -# Get all commits and import them. - -export GIT_DIR=/opt/openssl/checkouts/openssl/.git -#CLA_DATE='--before=2015-08-25' -git rev-list --all $CLA_DATE | xargs ./git-import diff --git a/license/index.html b/license/index.html deleted file mode 100644 index 300f223..0000000 --- a/license/index.html +++ /dev/null @@ -1,72 +0,0 @@ -<html> - <head> - <title>OpenSSL License Change Agreement</title> - <link rel="stylesheet" type="text/css" href="/style.css"> - </head> - <body> - <h1>OpenSSL License Change Agreement</h1> - <p> - This is the server for collecting agreements to the OpenSSL - license change. - We want to move from the - <a href="https://www.openssl.org/source/license.html">current license</a> - (which can also be found in the file LICENSE in any download), - to the - <a href="https://www.apache.org/licenses/LICENSE-2.0.txt"> Apache License - Version 2.0</a>. - </p> - <p> - <b>Update:</b> We are looking for the last few contributors, please - see the <a - href="/trying-to-find">https://license.openssl.org/trying-to-find</a> - page. Share it with your friends and colleagues who might have worked - on or with OpenSSL. - </p> - <ul> - <li> - If you received an email from us, please visit that link in a - browser (for safety, cut and paste it). - </li> - <li> - If you did not receive an email, perhaps it got lost. If so, you can - search the database to see which commits we found that contain - your email; see below. - If you might have used an old address that no longer works, you can - see the <a href="cgi-bin/authors.py">full list of authors</a> or - search on name or email, below. - </li> - <li> - If you did not receive an email, and think you should have done so, - please email - <a - href="mailto:lice...@openssl.org">lice...@openssl.org</a> - and be as specific as possible. Please allow some time for us to get back - to you. - </li> - </ul> - - <p>We are grateful to all the contributors who have contributed to - OpenSSL and look forward to their help and support in this effort. - For some background information, please see our <a - href="https://www.openssl.org/blog/blog/categories/license/">blog postings</a> - on this effort. - </p> - - <p> - <hr> - <form action="cgi-bin/lookup.py" method="GET"> - Search for commits with this email - (exact match): - <input name="email" type="TEXT"> - <button action="submit">Search</button> - </form> - <form action="cgi-bin/search.py" method="GET"> - Search for authors with this text in their name or email - (substring match): - <input name="text" TYPE="TEXT"> - <button action="submit">Author Search</button> - </form> - <hr> - </p> - </body> -</html> diff --git a/license/mailuser b/license/mailuser deleted file mode 100755 index 02f6e92..0000000 --- a/license/mailuser +++ /dev/null @@ -1,87 +0,0 @@ -#! /usr/bin/env python -"""mailuser [flags] args... - -Flags: - -a all users, even if already agreed - -f file File to use for message text - -n No date check - -l Just list who would get mail - -h This help - -d N Only if sent more than N days ago - -Arguments is a list of SQL paterns (will get wrapped in wildcards, %) -and send them license agreement email. -""" - -import mysql.connector -import datetime, os, re, subprocess, sys, string, random -import getopt - -dbconfig = { - 'user': 'license', - 'password': open('rwpass.txt').read().strip(), - 'database': 'license' - } -conn = mysql.connector.connect(**dbconfig) -cursor = conn.cursor() - -# Parse JCL. -today = datetime.datetime.today().date() -justlist = 0 -checkdate = 1 -cutoff = 2 -allusers = 0 -raw = open("request-approval.txt").read() -opts, args = getopt.getopt(sys.argv[1:], 'af:hnld:') -for o, a in opts: - if o == '-l': - justlist = 1 - elif o == '-a': - allusers = 1 - elif o == '-n': - checkdate = 0 - elif o == '-d': - cutoff = int(a) - elif o == '-f': - raw = open(a).read() - else: - print __doc__ - raise SystemExit - -# Get dict of matching users -who = {} -for email in args: - q = ("SELECT email,last_asked,uid,secret FROM users" - " WHERE email LIKE %s") - if not allusers: - q = q + " and reply = '-'" - pat = '%' + email + '%' - cursor.execute(q, (pat,)) - for row in cursor: - email,last_asked,uid,secret = row - if checkdate == 0 or last_asked is None: - who[email] = (uid,secret) - if last_asked: - diff = today - last_asked - days = diff.days - if days >= cutoff: - who[email] = (uid,secret) - -if justlist: - for email in who: - print email - raise SystemExit - -for email in who: - print email - uid, secret = who[email] - d = { 'uid': uid, 'secret': secret } - args = ('mail', '-s', 'OpenSSL License change', - '-r', 'lice...@openssl.org', email) - f = subprocess.Popen(args, stdin=subprocess.PIPE).stdin - print >>f, raw % d - f.close() - today = datetime.datetime.today().date() - t = 'UPDATE users SET last_asked=%s WHERE uid=%s' - cursor.execute(t, (today, uid)) - conn.commit() diff --git a/license/request-approval.txt b/license/request-approval.txt deleted file mode 100644 index bbab451..0000000 --- a/license/request-approval.txt +++ /dev/null @@ -1,40 +0,0 @@ -Hello! - -This mail is coming from the OpenSSL development team. - -We are working to change the license for OpenSSL. We want to move from -the current license (which is custom-written and has some uncommon -requirements on end-users), to the widely-accepted and common -Apache License (version 2). You can find some explanation in -our blog entries: - - https://www.openssl.org/blog/blog/2017/03/20/license/ - https://www.openssl.org/blog/blog/2015/08/01/cla/ - -We wrote some tools to look through every version of our files, and -our scripts found your email address. You can see what we found: - - https://license.openssl.org/cgi-bin/lookup.py?uid=%(uid)s - -We are asking for your permission to change the licence for your -contribution. Please visit this link to respond; you will have a chance -to accept or decline, and enter a brief comment (you can use the comment -to give the names of other people we should contact, for example): - - https://license.openssl.org/cgi-bin/reply.py?uid=%(uid)s&p=%(secret)s - -If you have any questions or concerns, send email to lice...@openssl.org; -please be patient for a response. You can also post to the public mailing -list, openssl-...@openssl.org; details about that list can be found at this -site: - - https://mta.openssl.org/mailman/listinfo/openssl-dev - -If we do not hear from you, we will assume that you have no objection. - -We are grateful to all the contributors who have contributed to -OpenSSL and look forward to their help and support in this effort. - -Thank you! - --The OpenSSL Development Team diff --git a/license/rmcommit b/license/rmcommit deleted file mode 100755 index 02bc769..0000000 --- a/license/rmcommit +++ /dev/null @@ -1,52 +0,0 @@ -#! /usr/bin/env python -"""Remove commits from the log. - -Flags: - -m X Just the specified commits from the user X - -Arguments is a list of commit prefixes. -""" - -import mysql.connector, os, re, subprocess, sys -import getopt, string, random -dbconfig = { - 'user': 'license', - 'password': open('rwpass.txt').read().strip(), - 'database': 'license' - } -conn = mysql.connector.connect(**dbconfig) -cursor = conn.cursor() - -email = None -try: - opts, args = getopt.getopt(sys.argv[1:], "hm:") -except: - print __doc__ - raise SystemExit -for o,a in opts: - if o == '-h': - print __doc__ - raise SystemExit - elif o == '-m': - cursor.execute('SELECT uid FROM users WHERE email = %s', (a,)) - for c in cursor: - email = c[0] - if not email: - print a, "not found" - raise SystemExit - -for cids in args: - pat = cids + '%' - cursor.execute('SELECT cid FROM commits WHERE commit LIKE %s', (pat,)) - cid = None - for c in cursor: - cid = c[0] - if cid: - if email: - cursor.execute('DELETE FROM log WHERE uid=%s AND cid=%s', - (email, cid)) - else: - cursor.execute('DELETE FROM log WHERE cid=%s', (cid,)) - conn.commit() - else: - print "Commit", cids, "not found" diff --git a/license/rmuser b/license/rmuser deleted file mode 100755 index 5274de9..0000000 --- a/license/rmuser +++ /dev/null @@ -1,23 +0,0 @@ -#! /usr/bin/env python -"""Remove users (specified on commandline) who were mistakenly added. -""" - -import mysql.connector, os, re, subprocess, sys -import string, random -dbconfig = { - 'user': 'license', - 'password': open('rwpass.txt').read().strip(), - 'database': 'license' - } -conn = mysql.connector.connect(**dbconfig) -cursor = conn.cursor() - -d1 = 'DELETE from log where uid = %s' -d2 = 'DELETE from users where uid = %s' -q = 'select uid from users where email = %s' -for email in sys.argv[1:]: - cursor.execute(q, (email,)) - for uid in cursor: - cursor.execute(d1, uid) - cursor.execute(d2, uid) - conn.commit() diff --git a/license/style.css b/license/style.css deleted file mode 100644 index 62395f8..0000000 --- a/license/style.css +++ /dev/null @@ -1,17 +0,0 @@ -body { - background-color: linen; - font-size: 1.25em; - font-family: "Arial", "Verdana"; -} -h1 { - font-size: 2em; - font-family: "Times New Roman", "Georgia"; -} -p.cw { - font-family: Monospace; - margin-left: 4em; -} - -ul li { - padding: .5em; -} diff --git a/license/whattoremove b/license/whattoremove deleted file mode 100755 index 57cd1ef..0000000 --- a/license/whattoremove +++ /dev/null @@ -1,58 +0,0 @@ -#! /usr/bin/env python -"""whattoremove [arguments] - -Flags: - -i file File of commits to include - -h This help - -Outputs CSV list of the commits that people who rejected -the license were involved in. The exclude file can be -generated by a command like this: - git log --pretty=fomat:%h -""" - -import mysql.connector -import datetime, os, re, subprocess, sys, string, random -import getopt - -# Parse JCL -include = None -opts, args = getopt.getopt(sys.argv[1:], "hi:") -for o,a in opts: - if o == '-i': - f = open(a) - include = [ c.strip() for c in f ] - f.close() - else: - print __doc__ - raise SystemExit - -dbconfig = { - 'user': 'licensereader', - 'password': open('ropass.txt').read().strip(), - 'database': 'license' - } -conn = mysql.connector.connect(**dbconfig) -cursor = conn.cursor() - -# Get those who said no and all the commits the did -q = ( 'SELECT log.cid,users.email FROM log' - ' LEFT JOIN users ON log.uid = users.uid' - ' WHERE users.reply = "n" ORDER BY log.cid' ) -cursor.execute(q) -cids = [] -emails = {} -for row in cursor: - cid,email = row - cids.append(cid) - emails[cid] = str(email) - -q = 'SELECT commit,date,descrip FROM commits WHERE cid=%s' -for cid in cids: - cursor.execute(q, (cid,)) - for row in cursor: - commit,date,descrip = row - commit = commit[0:7] - descrip = descrip.replace('"', '\'').replace(',', '') - if include == None or commit in include: - print '%s, %s, "%s"' % (commit, emails[cid], descrip) diff --git a/release-tools/do-release.pl b/release-tools/do-release.pl deleted file mode 100644 index 9bc7137..0000000 --- a/release-tools/do-release.pl +++ /dev/null @@ -1,214 +0,0 @@ -#! /usr/bin/env perl -# Copyright 2010-2018 The OpenSSL Project Authors. All Rights Reserved. -# -# Licensed under the OpenSSL license (the "License"). You may not use -# this file except in compliance with the License. You can obtain a copy -# in the file LICENSE in the source distribution or at -# https://www.openssl.org/source/license.html - -use strict; -use warnings; - -use File::Basename; - -my $homedir = glob("~openssl"); -my $tmpdir = $ENV{"OPENSSL_TMP_DIR"} // $homedir . "/dist/new"; -my $olddir = $ENV{"OPENSSL_OLD_DIR"} // $homedir . "/dist/old"; -my $srcdir = $ENV{"OPENSSL_SRC_DIR"} // "/var/www/openssl/source"; -my $ftpdir = $ENV{"OPENSSL_FTP_DIR"} // "/srv/ftp/source"; -my $mail = $ENV{"OPENSSL_MAIL"} // "mutt -s SUBJECT RECIP < BODY"; - -my $do_mail = 0; -my $do_copy = 0; -my $do_move = 0; -my $mail_only = 0; - -foreach (@ARGV) { - if (/--tmpdir=(.*)$/) { - $tmpdir = $1; - } elsif (/^--copy$/) { - $do_copy = 1; - } - elsif (/^--move$/) { - $do_move = 1; - } elsif (/^--mail$/) { - $do_mail = 1; - } elsif (/^--mail-only$/) { - $mail_only = 1; - $do_mail = 1; - } elsif (/^--full-release$/) { - $do_mail = 1; - $do_copy = 1; - $do_move = 1; - } else { - print STDERR "Unknown command line argument $_"; - exit 1; - } -} - -if ( getpwuid($<) ne "openssl" && !exists $ENV{"OPENSSL_RELEASE_TEST"} ) { - print "This script must be run as the \"openssl\" user\n"; - exit 1; -} - -die "Can't find distribution directory $tmpdir" unless -d $tmpdir; -die "Can't find old distribution directory $olddir" unless -d $olddir; -die "Can't find source directory $srcdir" unless -d $srcdir; -die "Can't find ftp directory $ftpdir" unless -d $ftpdir; - -my @versions; -my @series; -my @files = glob("$tmpdir/*.txt.asc"); - -foreach (@files) { - if (/^.*\/openssl-(\d+\.\d+\.\d+[a-z]*-pre\d+)\..*$/) { - push @versions, $1; - } elsif (/^.*\/openssl-(\d+\.\d+\.\d+[a-z]*)\..*$/) { - push @versions, $1; - } else { - die "Unexpected filename $_"; - } -} -foreach (@versions) { - if (/^(\d+\.\d+\.\d+)[a-z]*(?:-pre\d+)$/) { - my $serie = $1; - push @series, $serie unless grep /^$serie/, @series; - } -} -die "No distribution in temp directory!" if ( scalar @versions == 0 ); -print "OpenSSL versions to be released:\n"; -foreach (@versions) { - print "$_\n"; -} -print "OK? (y/n)\n"; -$_ = <STDIN>; -exit 1 unless /^y/i; - -my @distfiles; -my @announce; - -foreach (@versions) { - push @distfiles, "openssl-$_.tar.gz"; - push @distfiles, "openssl-$_.tar.gz.sha1"; - push @distfiles, "openssl-$_.tar.gz.sha256"; - push @distfiles, "openssl-$_.tar.gz.asc"; - push @announce, "openssl-$_.txt.asc"; -} - -$do_copy = 0 if $mail_only; - -my $bad = 0; -if ($do_copy) { - foreach (@distfiles) { - if ( !-f "$tmpdir/$_" ) { - print STDERR "File $_ not found in temp directory!\n"; - $bad = 1; - } - if ( -e "$srcdir/$_" ) { - print STDERR "File $_ already present in source directory!\n"; - $bad = 1; - } - if ( -e "$ftpdir/$_" ) { - print STDERR "File $_ already present in ftp directory!\n"; - $bad = 1; - } - if ( -e "$olddir/$_" ) { - print STDERR - "File $_ already present in old distributions directory!\n"; - $bad = 1; - } - } -} - -exit 1 if $bad; - -print "Directory sanity check OK\n"; - -print "Starting release for OpenSSL @versions\n"; - -if ($do_copy) { - foreach my $serie (@series) { - my @glob_patterns = ( - "openssl-$serie.tar.gz", - "openssl-$serie?.tar.gz", - "openssl-$serie-pre[0-9].tar.gz", - "openssl-$serie?-pre[0-9].tar.gz", - "openssl-$serie-pre[0-9][0-9].tar.gz", - "openssl-$serie?-pre[0-9][0-9].tar.gz", - ); - my $tomove_oldsrc = "$srcdir/old/$serie"; - my @tomove_src = - map { basename ($_) } - grep { -f $_ } - map { glob("$srcdir/$_") } - @glob_patterns; - my $tomove_oldftp = "$ftpdir/old/$serie"; - my @tomove_ftp = - map { basename ($_) } - grep { -f $_ } - map { glob("$ftpdir/$_") } - @glob_patterns; - - mkdir $tomove_oldsrc - or die "Couldn't mkdir $tomove_oldsrc : $!" - if !-d $tomove_oldsrc; - mkdir $tomove_oldftp - or die "Couldn't mkdir $tomove_oldftp : $!" - if !-d $tomove_oldftp; - foreach (@tomove_src) { - system("mv $srcdir/$_* $tomove_oldsrc/"); - die "Error moving $_* to old source directory!" if $?; - } - foreach (@tomove_ftp) { - system("mv $ftpdir/$_* $tomove_oldftp/"); - die "Error moving $_* to old ftp directory!" if $?; - } - } - print - "Moved old distributions files to source/old and ftp/old directories\n"; - - foreach (@distfiles) { - system("cp $tmpdir/$_ $srcdir/$_"); - die "Error copying $_ to source directory!" if $?; - system("cp $tmpdir/$_ $ftpdir/$_"); - die "Error copying $_ to ftp directory!" if $?; - } - print "Copied distributions files to source and ftp directories\n"; -} -else { - print "Test mode: no files copied\n"; -} - -foreach (@versions) { - my $announce = "openssl-$_.txt.asc"; - my $annversion = $_; - $annversion =~ s/-pre(\d+$)/ pre release $1/; - my $annmail = $mail; - $annmail =~ s/SUBJECT/"OpenSSL version $annversion published"/; - $annmail =~ s/RECIP/openssl-project openssl-users openssl-announce/; - $annmail =~ s|BODY|$tmpdir/$announce|; - - if ($do_mail) { - print "Sending announcement email for OpenSSL $_...\n"; - system("$annmail"); - die "Error sending announcement email!" if $?; - print "Don't forget to authorise the openssl-announce email.\n"; - push @distfiles, $announce if $do_move; - } else { - print "Announcement email not sent automatically\n"; - print "\nSend announcement mail manually with command:\n\n$annmail\n\n"; - print -"When done, move the announcement file away with command:\n\nmv $tmpdir/$announce $olddir/$announce\n\n" - if $do_move; - } -} - -if ($do_move) { - foreach (@distfiles) { - rename( "$tmpdir/$_", "$olddir/$_" ) || die "Can't move $_: $!"; - } - print "Moved distribution files to old directory\n"; -} - -print "Successful!\n"; - diff --git a/reports/.gitignore b/reports/.gitignore deleted file mode 100644 index e89b957..0000000 --- a/reports/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -bugs.csv -bugs.full -cve.txt -cve.xsl -issues.csv -issues/*.js -pulls.csv -pulls/*.js -releases.txt -team -team.counts -team.full - diff --git a/reports/LICENSE b/reports/LICENSE deleted file mode 100644 index 8dada3e..0000000 --- a/reports/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/reports/Makefile b/reports/Makefile deleted file mode 100644 index dfee4b1..0000000 --- a/reports/Makefile +++ /dev/null @@ -1,93 +0,0 @@ - -GITURL = https://api.github.com/repos/openssl/openssl -WWWREPO = ../www.openssl.org -SRCREPO = ../gitlab - -SINCE ?= $(shell date +%Y-%m) -#SINCE = 2016-01 -SINCE2 =$(subst -,,$(SINCE))01 - -VULN = $(WWWREPO)/news/vulnerabilities.xml - -REFRESH = bugs.full pulls issues - -ALL = cve.txt releases.txt \ - bugs.csv \ - team.full team.counts \ - pulls.csv issues.csv - -all: $(ALL) - -.PHONY: refresh -refresh: - @rm -rf $(REFRESH) - $(MAKE) $(REFRESH) - -.PHONY: report -report: - ./makereport $(SINCE) - -check: - test -d $(WWWREPO) -o -d $(WWWREPO)/.git || exit 1 - test -f $(VULN) || exit 1 - test -f $(VULN) || exit 1 - test -d $(SRCREPO) -o -d $(SRCREPO)/.git || exit 1 - -.PHONY: clean -clean: - rm -f $(ALL) - rm -rf issues pulls - - -cve.txt: cve.xsl $(VULN) - @rm -f $@ - ( cd $(WWWREPO) ; git pull ) - xsltproc cve.xsl $(VULN) | sed -e 's/^ //' -e '/^$$/d' | \ - awk '$$1 >= $(SINCE2) { print; }' >$@ - -releases.txt: cve.txt - @rm -f $@ - awk -F, '{print $$4; print $$5; print $$6; }' <cve.txt | \ - sort -u | sed -e 1d -e 's/ //' | sort -r >$@ - - -bugs.full: - @rm -f $@ - ssh rt.openssl.org 'rt ls -f status,created,resolved "id>1"' >$@ - -bugs.csv: bugs.full bugs2csv.py - @rm -f $@ - python bugs2csv.py $(SINCE2) <bugs.full >$@ - -.PHONY: team.full -team.full: - @rm -f $@ - ( cd $(SRCREPO) && git log '--since=$(SINCE)-01' '--format=%ce' ) | \ - sed -e s/k...@roeckx.be/k...@openssl.org/ \ - -e s/openssl-us...@dukhovni.org/vik...@openssl.org/ \ - -e s/b...@links.org/b...@openssl.org/ \ - -e s/rs...@akamai.com/rs...@openssl.org/ \ - -e s/rich...@levitte.org/levi...@openssl.org/ \ - | grep @openssl.org | sort >$@ - -team.counts: team.full - @rm -f $@ - uniq -c team.full | sort -n >$@ - -.PHONY: pulls.csv -pulls.csv: - @rm -f $@ - python stats2csv.py pulls $(SINCE2) >$@ - -.PHONY: issues.csv -issues.csv: - @rm -f $@ - python stats2csv.py issues $(SINCE2) >$@ - -pulls: - @rm -f $@ - ./ghstats pulls '$(GITURL)' - -issues: - @rm -f $@ - ./ghstats issues '$(GITURL)' diff --git a/reports/README b/reports/README deleted file mode 100644 index 781bb2c..0000000 --- a/reports/README +++ /dev/null @@ -1,3 +0,0 @@ - -This collection of scripts is used to generate the OpenSSL activity -reports for the Core Infrastructure Initiative. diff --git a/reports/bugs2csv.py b/reports/bugs2csv.py deleted file mode 100644 index 88a0151..0000000 --- a/reports/bugs2csv.py +++ /dev/null @@ -1,89 +0,0 @@ -#! /usr/bin/env python -'''Create a CSV file from RT output. - -Parse the output an RT buglist: - rt ls -f status,created,resolved 'id>1' -aggregate statistics per-month. Output a CSV file that shows, for -each month, the number of new bugs report, resolved, or rejected, -and the cumulative totals for each category.''' - -import sys - -weekly = 0 -opened, resolved, rejected = {}, {}, {} -keys = [] - -months = { - 'Jan': '01', 'Feb': '02', 'Mar': '03', - 'Apr': '04', 'May': '05', 'Jun': '06', - 'Jul': '07', 'Aug': '08', 'Sep': '09', - 'Oct': '10', 'Nov': '11', 'Dec': '12', - } - -def parsedate(datestr): - '''Parse a string like "Wed Apr 24 17:38:26 2002" - into a key "2001-04" (year month week).''' - fields = datestr.split(' ') - if fields is None or len(fields) != 5: - return "?" - week = 0 - try: - week = int(fields[2]) / 7 - except: - week = 0 - week += 1 - if weekly: - return '%s-%s-%d' % (fields[4], months.get(fields[1], "?"), week) - else: - return '%s-%s' % (fields[4], months.get(fields[1], "?")) - -records = 0 -for line in sys.stdin: - line = line[:-1] - fields = line.split('\t') - if fields is None or len(fields) != 4 or fields[0] == 'id': - continue - records += 1 - key = parsedate(fields[2]) - if key not in keys: - keys.append(key) - if not opened.has_key(key): - opened[key] = 0; - opened[key] += 1 - if fields[3] == 'Not set': - continue - key = parsedate(fields[3]) - if key not in keys: - keys.append(key) - if not resolved.has_key(key): - resolved[key] = 0; - if not rejected.has_key(key): - rejected[key] = 0; - if fields[1] == 'resolved': - resolved[key] += 1 - else: - rejected[key] += 1 - -# Open, resolved, rejected cumulative totals -ocum, rcum, xcum = 0, 0, 0 -lines = [] -dates = [] -keys.sort() -for k in keys: - o = opened.get(k, 0) - ocum += o - r = resolved.get(k, 0) - rcum += r - x = rejected.get(k, 0) - xcum += x - lines.append("%s, %d, %d, %d" % (k, o, r+x, ocum - rcum - xcum)) - dates.append(k.replace('-','')) - -when=sys.argv[1].replace('-','') - -print 'date,opened,closed,num-open' -lines.reverse() -dates.reverse() -for d,l in zip(dates, lines): - if d >= when: - print l diff --git a/reports/ghstats b/reports/ghstats deleted file mode 100755 index 01579e5..0000000 --- a/reports/ghstats +++ /dev/null @@ -1,26 +0,0 @@ -#! /bin/sh - -AUTH='-n' -# Fetch all " -rm -rf $1 -mkdir $1 - -curl $AUTH -sD $1.tmp "$2/$1?state=all&per_page=100" >$1/01.js -LAST=`grep '^Link:' $1.tmp | sed -e 's/.*page=\([0-9]*\)>.*/\1/'` -rm -f $1.tmp - -echo Fetching \"$LAST\" pages - -CURR=2 -while test $CURR -le $LAST ; do - case $CURR in - [1-9]) - O=$1/0$CURR.js - ;; - *) - O=$1/$CURR.js - ;; - esac - curl $AUTH -s "$2/$1?page=$CURR&state=all&per_page=100" >$O - CURR=`expr $CURR + 1` -done diff --git a/reports/makereport b/reports/makereport deleted file mode 100755 index 9c845ec..0000000 --- a/reports/makereport +++ /dev/null @@ -1,55 +0,0 @@ -#! /bin/sh - -echo "This is an automated activity report from OpenSSL." -echo "A follow-up, if any, will call out particular highlights." - -echo "" -echo Since $1, the team has made `wc -l <team.full` commits. - -( -echo "" -echo We have made the following releases. Note that there are sometimes -echo gaps, because some CVE notices reference old releases which had -echo already gone out. -) | fmt -for R in 1.1.0 1.0.2 1.0.1 ; do - grep $R <releases.txt | fmt | sed -e 's/^/ /' -done - -WC=`cat issues.csv pulls.csv | awk -F, '{print $6;}' | sort -u | wc -l` -ISS=`grep -c open <issues.csv` -PR=`grep -c open <pulls.csv` -( -echo "" -echo On GitHub, $WC unique users created $ISS new issues and $PR new pull requests. - -ISS=`grep -c closed <issues.csv` -PR=`grep -c closed <pulls.csv` -echo "The team closed $ISS issues and closed (usually merged) $PR PRs." -echo "(Note that the we often create our own PR's in order to leverage the" -echo "CI tools we available there.)" -) | fmt - -( -echo "" -echo "The tables below are CSV format so that they can easily be cut and pasted" -echo "into a spreadsheet." -) | fmt - -( -echo "" -echo We have addressed the following CVE\'s. We remind you that -echo 1.0.1 goes end of life at the end of 2016. -) | fmt -echo "date, name, sev, rel110, rel102, rel101" -cat cve.txt - -( -echo "" -echo Here are the number of bugs opened and closed, and the total open bugs -echo on a monthly basis: -) | fmt -cat bugs.csv - -echo "This report was generated by the tools found here:" -echo " https://github.com/richsalz/activityreports" diff --git a/reports/rt2csv.py b/reports/rt2csv.py deleted file mode 100644 index 6465ad1..0000000 --- a/reports/rt2csv.py +++ /dev/null @@ -1,79 +0,0 @@ -#! /usr/bin/env python -'''Create a CSV file from RT output. OBSOLETE - -Parse the output an RT buglist: - rt ls -f status,created,resolved 'id>1' -aggregate statistics per-week. Output a CSV file that shows, for -each month, the number of new bugs report, resolved, or rejected, -and the cumulative totals for each category.''' - -import sys - -weekly = 1 -opened, resolved, rejected = {}, {}, {} -keys = [] - -months = { - 'Jan': '01', 'Feb': '02', 'Mar': '03', - 'Apr': '04', 'May': '05', 'Jun': '06', - 'Jul': '07', 'Aug': '08', 'Sep': '09', - 'Oct': '10', 'Nov': '11', 'Dec': '12', - } - -def parsedate(datestr): - '''Parse a string like "Wed Apr 24 17:38:26 2002" - into a key "2001-04" (year month week).''' - fields = datestr.split(' ') - if fields is None or len(fields) != 5: - return "?" - week = 0 - try: - week = int(fields[2]) / 7 - except: - week = 0 - week += 1 - if weekly: - return '%s-%s-%d' % (fields[4], months.get(fields[1], "?"), week) - else: - return '%s-%s' % (fields[4], months.get(fields[1], "?")) - -records = 0 -for line in sys.stdin: - line = line[:-1] - fields = line.split('\t') - if fields is None or len(fields) != 4 or fields[0] == 'id': - continue - records += 1 - key = parsedate(fields[2]) - if key not in keys: - keys.append(key) - if not opened.has_key(key): - opened[key] = 0; - opened[key] += 1 - if fields[3] == 'Not set': - continue - key = parsedate(fields[3]) - if key not in keys: - keys.append(key) - if not resolved.has_key(key): - resolved[key] = 0; - if not rejected.has_key(key): - rejected[key] = 0; - if fields[1] == 'resolved': - resolved[key] += 1 - else: - rejected[key] += 1 - -# Open, resolved, rejected cumulative totals -ocum, rcum, xcum = 0, 0, 0 -print 'date,opened,tot-opened,resolved,tot-res,rejected,tot-rej,tot-closed,num-open' -keys.sort() -for k in keys: - o = opened.get(k, 0) - ocum += o - r = resolved.get(k, 0) - rcum += r - x = rejected.get(k, 0) - xcum += x - print "%s, %d, %d, %d, %d, %d, %d, %d, %d" % \ - (k, o, ocum, r, rcum, x, xcum, rcum+xcum, ocum - rcum - xcum) diff --git a/reports/stats2csv.py b/reports/stats2csv.py deleted file mode 100644 index 5d3211f..0000000 --- a/reports/stats2csv.py +++ /dev/null @@ -1,28 +0,0 @@ -#! /usr/bin/env python - -import datetime, glob, json, sys - -dtparse = datetime.datetime.strptime - -def parse(d): - return dtparse(d, '%Y%m%d') - -files = glob.glob(sys.argv[1]+ "/*.js") -files.sort() -when = sys.argv[2] - -print "open, closed, duration, #, state, user" -for f in files: - items = json.load(open(f)) - for i in items: - created = i["created_at"][:10].replace('-', '') - closed = i["closed_at"]; - if closed is None: - closed = '-' - duration = 0 - else: - closed = closed[:10].replace('-', '') - duration = (parse(closed) - parse(created)).days - if created >= when: - print "%s, %s, %d, %s, %s, %s" % \ - ( created, closed, duration, i["number"], i["state"], i["user"]["login"])