Release verification script. (#257)

Add README sections for release verification and vote announcements.
diff --git a/docs/release_instructions.md b/docs/release_instructions.md
index cfdf9be..804ae49 100644
--- a/docs/release_instructions.md
+++ b/docs/release_instructions.md
@@ -88,12 +88,131 @@
 ### Release Approval
 
 These steps are **manual** and must be performed by the Release Manager.
+ - Starting the Vote: The Release manager for Apache OpenWhisk sends a release note to the OpenWhisk mailing for votes, and opens the mail for 72 hours. Apache requires a minimum of three positive votes and more positive than negative votes MUST be cast, in order to release.
 
-Apache requires a minimum of three positive votes and more positive than negative votes MUST be cast, in order to release.
+ - Wait for the Results
 
--The Release manager for Apache OpenWhisk sends a release note to the OpenWhisk mailing for votes, and opens the mail for 72 hours.
+#### Starting the Vote
+
+Propose a vote on the dev list. Here is an example:
+```
+To: "OpenWhisk Developers List" <dev@openwhisk.apache.org>
+Subject: [VOTE] Release Apache OpenWhisk {component} version {version}
+
+Hi,
+
+This is a call to vote on releasing version {version} release
+candidate {rc} of the following {N} project modules with artifacts
+built from the Git repositories and commit IDs listed below.
+
+* {YOUR REPOSITORY ID} : {GIT HASH}
+* {... list others if more than one}
+
+This release comprises of source code distribution only.
+
+You can use this UNIX script to download the release and verify the signatures:
+https://gitbox.apache.org/repos/asf?p=incubator-openwhisk-release.git;a=blob_plain;f=tools/rcverify.sh;hb=HEAD
+
+Usage:
+sh rcverify.sh {repository} {component} {version}
+
+Please vote to approve this release:
+
+  [ ] +1 Approve the release
+  [ ]  0 Don't care
+  [ ] -1 Don't release, because ...
+
+Release verification checklist for reference:
+  [ ] Download links are valid.
+  [ ] Checksums and PGP signatures are valid.
+  [ ] DISCLAIMER is included.
+  [ ] Source code artifacts have correct names matching the current release.
+  [ ] LICENSE and NOTICE files are correct for each OpenWhisk repository.
+  [ ] All files have license headers if necessary.
+  [ ] No compiled archives bundled in source archive.
+
+This majority vote is open for at least 72 hours.
+```
+
 - **TBD** We can create JIRA issue for this release and close it when the requirement is met and ready for release. **TODO** further document discrete steps/requirements community agrees upon.
 
+#### Wait for the Results
+
+From [Votes on Package Releases](http://www.apache.org/foundation/voting.html):
+```
+Votes on whether a package is ready to be released follow a format
+similar to majority approval -- except that the decision is officially
+determined solely by whether at least three +1 votes were
+registered. Releases may not be vetoed. Generally the community will
+table the vote to release if anyone identifies serious problems, but
+in most cases the ultimate decision, once three or more positive votes
+have been garnered, lies with the individual serving as release
+manager. The specifics of the process may vary from project to
+project, but the 'minimum of three +1 votes' rule is universal.
+```
+
+The list of binding voters is available on the Project Team page.
+
+If the vote is successful, post the result to the dev list - for example:
+```
+To: "OpenWhisk Developers List" <dev@openwhisk.apache.org>
+Subject: [RESULT] [VOTE] Release Apache OpenWhisk {ABC} version {X.Y.Z}
+
+Hi,
+
+The vote has passed with the following result:
+
++1 (binding): <<list of names>>
++1 (non binding): <<list of names>>
+```
+
+Be sure to include all votes in the list and indicate which votes were binding. Consider -1 votes very carefully. While there is technically no veto on release votes, there may be reasons for people to vote -1. So sometimes it may be better to cancel a release when someone, especially a member of the PMC, votes -1.
+
+If the vote is unsuccessful, you need to fix the issues and restart the process. Note that any changes to the artifacts under vote require a restart of the process, no matter how trivial. When restarting a vote version numbers must not be reused, since binaries might have already been copied around.
+
+#### Release verification tool
+
+The script [rcverify.sh](../tools/rcverify.sh) is available to automate the process of verifying a release.
+The script will download the release candidate, verify signatures, discalaimer, notice, and license. The tool assumes that are no executable files in the release and will flag any executable that it finds. If the tool discovers an issue during verification, it will try to emit useful information for you to further inspect the findings. The release is left on your disk for you to further inspect and you must delete the scratch space when finished.
+
+Example of how to use `rcverify.sh`:
+```
+rcverify.sh openwhisk-client-js 'OpenWhisk JavaScript Client Library' 3.19.0-incubating
+```
+
+Example output from `rcverify.sh`:
+```
+working in the following directory:
+/tmp/tmp.6t9xcMV8
+fetching openwhisk-client-js-3.19.0-incubating-sources.tar.gz
+fetching openwhisk-client-js-3.19.0-incubating-sources.tar.gz.asc
+fetching openwhisk-client-js-3.19.0-incubating-sources.tar.gz.sha512
+fetching release keys
+import keys
+gpg: key ABCXYZ: "Some Name <some@email>" ...
+gpg: key FOOBAR: "Another Name <another@email>" ...
+gpg: Total number processed: 2
+gpg:              unchanged: 2
+unpacking tar ball
+cloning scancode
+Cloning into 'incubator-openwhisk-utilities'...
+remote: Enumerating objects: 52, done.
+remote: Counting objects: 100% (52/52), done.
+remote: Compressing objects: 100% (35/35), done.
+remote: Total 52 (delta 23), reused 34 (delta 15), pack-reused 0
+Unpacking objects: 100% (52/52), done.
+computing sha512 and validating... passed
+verifying asc... passed (signed-by: Some Name <some@email>)
+verifying disclaimer... passed
+verifing notice... passed
+verifying license... failed (diff '/tmp/tmp.6t9xcMV8/incubator-openwhisk-client-js-3.19.0-incubating/LICENSE.txt' '/tmp/tmp.6t9xcMV8/LICENSE-2.0')
+verifying sources have proper headers... passed
+scanning for binaries... passed
+
+run the following command to remove the scratch space:
+  rm -rf '/tmp/tmp.6t9xcMV8'
+
+
 ### Create Release notes
 
 An example of the release note can be found at the following link: [example of release note](https://github.com/apache/cordova-coho/blob/master/docs/coho-release-process.md).
diff --git a/tools/rcverify.sh b/tools/rcverify.sh
new file mode 100755
index 0000000..db818da
--- /dev/null
+++ b/tools/rcverify.sh
@@ -0,0 +1,163 @@
+#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+
+# This script will download the release candidate artifacts and verify
+# they are properly signed and authentic. The script assumes you have
+# curl, git, python and gpg already installed and that your gpg is trusted.
+
+# the location providing the distribution
+DIST=https://dist.apache.org/repos/dist/dev/incubator/openwhisk
+
+# the artifact being released
+NAME=${1?"missing artifact name e.g., openwhisk-client-js"}
+
+# the name of the podling (to match what is in the disclaimer file)
+DESCRIPTION=${2?"missing podling description e.g., 'OpenWhisk JavaScript Client Library'"}
+
+# the version of the release artifact
+V=${3?"missing version e.g., '3.19.0-incubating'"}
+
+# the release candidate, usualy 'rc1'
+RC=${4:-rc1}
+
+# set to non-zero to download the artifacts to verify, this is the default
+DL=${DL:-1}
+
+# set to non-zero to import the release keys, this is the default
+IMPORT=${IMPORT:-1}
+
+# this is the construct name of the artifact
+BASE=incubator-$NAME-$V
+TGZ=$NAME-$V-sources.tar.gz
+
+# this is a constructed name for the keys file
+KEYS=$RC-$V-KEYS
+
+DISCLAIMER="Apache $DESCRIPTION is an effort undergoing incubation at The Apache Software Foundation (ASF), sponsored by the Apache Incubator. Incubation is required of all newly accepted projects until a further review indicates that the infrastructure, communications, and decision making process have stabilized in a manner consistent with other successful ASF projects. While incubation status is not necessarily a reflection of the completeness or stability of the code, it does indicate that the project has yet to be fully endorsed by the ASF."
+
+NOTICE=$(cat << END
+Apache $DESCRIPTION
+Copyright 2016-2019 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+END
+)
+
+DIR=$(mktemp -d)
+
+echo working in the following directory:
+echo "$(tput setaf 6)$DIR$(tput sgr0)"
+
+if [ $DL -ne 0 ]; then
+  echo fetching $TGZ
+  curl $DIST/apache-openwhisk-$V-$RC/$TGZ -s -o "$DIR/$TGZ"
+
+  echo fetching $TGZ.asc
+  curl $DIST/apache-openwhisk-$V-$RC/$TGZ.asc -s -o "$DIR/$TGZ.asc"
+
+  echo fetching $TGZ.sha512
+  curl $DIST/apache-openwhisk-$V-$RC/$TGZ.sha512 -s -o "$DIR/$TGZ.sha512"
+fi
+
+if [ $IMPORT -ne 0 ]; then
+  echo fetching release keys
+  curl $DIST/KEYS -s -o "$DIR/$KEYS"
+
+  echo import keys
+  gpg --import "$DIR/$KEYS"
+fi
+
+function validate() {
+  if [[ $1 == $2 ]]; then
+    printf " $(tput setaf 2)passed$(tput sgr0)"
+    if [[ $4 != "" ]]; then
+      echo " ($4)"
+    else
+      printf "\n"
+    fi
+  else
+    printf " $(tput setaf 1)failed$(tput sgr0)"
+    if [[ $3 != "" ]]; then
+      echo " ($3)"
+    else
+      printf "\n"
+    fi
+  fi
+}
+
+echo "unpacking tar ball"
+tar zxf "$DIR/$TGZ" -C "$DIR"
+
+echo "cloning scancode"
+cd "$DIR" && git clone https://github.com/apache/incubator-openwhisk-utilities.git --depth 1
+
+printf "computing sha512 and validating..."
+EXPECTED=$(cat "$DIR/$TGZ.sha512")
+CMD="cd $DIR && gpg --print-md SHA512 '$TGZ'"
+SHA=$(eval $CMD)
+validate "$EXPECTED" "$SHA" "$CMD"
+
+printf "verifying asc..."  
+CMD="gpg --verify '$DIR/$TGZ.asc' '$DIR/$TGZ'"
+ASC=$(eval $CMD 2>&1)
+RES=$?
+if [[ $ASC =~ ^.*\"(.*)\".*$ ]]; then
+  SIGNER=${BASH_REMATCH[1]}
+else
+  SIGNER="$(tput setaf 1)???$(tput sgr0)"
+fi
+validate $RES 0 "$CMD" "signed-by: $SIGNER"
+
+printf "verifying disclaimer..."
+DTXT=$(cat "$DIR/$BASE/DISCLAIMER.txt")
+validate "$DISCLAIMER" "$DTXT" "cat '$DIR/$BASE/DISCLAIMER.txt'"
+
+printf "verifing notice..."
+NTXT=$(cat "$DIR/$BASE/NOTICE.txt")
+validate "$NOTICE" "$NTXT" "cat '$DIR/$BASE/NOTICE.txt'"
+
+printf "verifying license..."
+curl http://www.apache.org/licenses/LICENSE-2.0 -s -o "$DIR/LICENSE-2.0"
+## this is a more forgiving license check that allows for the copyright line to be filled out
+#CMD="diff '$DIR/$BASE/LICENSE.txt' '$DIR/LICENSE-2.0' -I '^   Copyright'"
+CMD="diff '$DIR/$BASE/LICENSE.txt' '$DIR/LICENSE-2.0'"
+DIF=$(eval "$CMD")
+validate $? 0 "$CMD"
+
+printf "verifying sources have proper headers..."
+CMD="'$DIR/incubator-openwhisk-utilities/scancode/scanCode.py' --config '$DIR/incubator-openwhisk-utilities/scancode/ASF-Release.cfg' '$DIR/$BASE'"
+SC=$(eval $CMD >& /dev/null)
+validate $? 0 "$CMD"
+
+printf "scanning for binaries..."
+EXE=$(find "$DIR/$BASE" -type f ! -name "*.sh" ! -name "*.sh" ! -name "*.py" ! -name "*.php" ! -name "gradlew" ! -name "gradlew.bat" -perm -001)
+validate "$EXE" "" "$EXE"
+
+printf "scanning for archives..."
+EXE=$(find "$DIR/$BASE" -type f -name "*.tar" -name "*.tgz" -o -name "*.gz" -o -name ".zip" -o -name "*.jar")
+validate "$EXE" "" "$EXE"
+
+printf "scanning for packages..."
+EXE=$(find "$DIR/$BASE" -type d -name "node_modules" -o -name ".gradle")
+validate "$EXE" "" "$EXE"
+
+echo $(tput setaf 6)
+echo run the following command to remove the scratch space:
+echo "  rm -rf '$DIR'"
+echo $(tput sgr0)