...

Text file src/github.com/sigstore/rekor/tests/sharding-e2e-test.sh

Documentation: github.com/sigstore/rekor/tests

     1#!/bin/bash
     2#
     3# Copyright 2021 The Sigstore Authors.
     4#
     5# Licensed under the Apache License, Version 2.0 (the "License");
     6# you may not use this file except in compliance with the License.
     7# You may obtain a copy of the License at
     8#
     9#     http://www.apache.org/licenses/LICENSE-2.0
    10#
    11# Unless required by applicable law or agreed to in writing, software
    12# distributed under the License is distributed on an "AS IS" BASIS,
    13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14# See the License for the specific language governing permissions and
    15# limitations under the License.
    16
    17set -ex
    18
    19# Things to install first:
    20# - jq, createtree
    21
    22# Spin up services as usual
    23
    24echo "Installing createtree..."
    25go install github.com/google/trillian/cmd/createtree@latest
    26
    27echo "starting services"
    28docker-compose up -d
    29rm ~/.rekor/state.json || true
    30
    31echo "building CLI and server"
    32go build -o rekor-cli ./cmd/rekor-cli
    33REKOR_CLI=$(pwd)/rekor-cli
    34go build -o rekor-server ./cmd/rekor-server
    35
    36
    37function check_log_index () {
    38  logIndex=$1
    39  # make sure we can get this log index from rekor
    40  $REKOR_CLI get --log-index $logIndex --rekor_server http://localhost:3000
    41  # make sure the entry index matches the log index
    42  gotIndex=$($REKOR_CLI get --log-index $logIndex --rekor_server http://localhost:3000 --format json | jq -r .LogIndex)
    43  if [[ "$gotIndex" == $logIndex ]]; then
    44    echo "New entry has expected virtual log index $gotIndex"
    45  else
    46    echo "FAIL: expected virtual log index $logIndex, got $gotIndex"
    47    exit 1
    48  fi
    49}
    50
    51function stringsMatch () {
    52  one=$1
    53  two=$2
    54
    55  if [[ "$one" == "$two" ]]; then
    56    echo "Strings match"
    57  else
    58    echo "$one and $two don't match but should"
    59    exit 1
    60  fi
    61}
    62
    63function waitForRekorServer () {
    64  count=0
    65
    66  echo -n "waiting up to 60 sec for system to start"
    67  until [ $(docker-compose ps | grep -c "(healthy)") == 3 ];
    68  do
    69      if [ $count -eq 6 ]; then
    70        echo "! timeout reached"
    71        REKOR_CONTAINER_ID=$(docker ps --filter name=rekor-server --format {{.ID}})
    72        docker logs $REKOR_CONTAINER_ID
    73        exit 1
    74      else
    75        echo -n "."
    76        sleep 10
    77        let 'count+=1'
    78      fi
    79  done
    80
    81  echo
    82}
    83
    84function collectLogsOnFailure () {
    85    if [[ "$1" -ne "0" ]]; then
    86        echo "failure detected, collecting docker-compose logs"
    87        docker-compose logs --no-color > /tmp/docker-compose.log
    88        exit $1
    89    elif docker-compose logs --no-color | grep -q "panic: runtime error:" ; then
    90        # if we're here, we found a panic
    91        echo "failing due to panics detected in logs"
    92        docker-compose logs --no-color > /tmp/docker-compose.log
    93        exit 1
    94    fi
    95    exit 0
    96}
    97trap "collectLogsOnFailure $?" EXIT
    98
    99echo "Waiting for rekor server to come up..."
   100waitForRekorServer
   101
   102# Add some things to the tlog :)
   103pushd tests
   104$REKOR_CLI upload --artifact test_file.txt --signature test_file.sig --public-key test_public_key.key --rekor_server http://localhost:3000
   105popd
   106
   107# Make sure we can prove consistency
   108$REKOR_CLI loginfo --rekor_server http://localhost:3000 
   109
   110# Add 2 more entries to the log
   111pushd tests/sharding-testdata
   112$REKOR_CLI upload --artifact file1 --signature file1.sig --pki-format=x509 --public-key=ec_public.pem --rekor_server http://localhost:3000
   113$REKOR_CLI upload --artifact file2 --signature file2.sig --pki-format=x509 --public-key=ec_public.pem --rekor_server http://localhost:3000
   114popd
   115
   116
   117INITIAL_TREE_ID=$($REKOR_CLI loginfo --rekor_server http://localhost:3000  --format json  | jq -r .TreeID)
   118echo "Initial Tree ID is $INITIAL_TREE_ID"
   119
   120# Make sure we have three entries in the log
   121check_log_index 2
   122$REKOR_CLI logproof --rekor_server http://localhost:3000 --last-size 2
   123
   124# Now, we want to shard the log.
   125# Create a new tree
   126echo "creating a new Tree ID...."
   127SHARD_TREE_ID=$(createtree --admin_server localhost:8090)
   128echo "the new shard ID is $SHARD_TREE_ID"
   129
   130# Once more
   131$REKOR_CLI loginfo --rekor_server http://localhost:3000
   132
   133# Get the public key for the active tree for later
   134ENCODED_PUBLIC_KEY=$(curl http://localhost:3000/api/v1/log/publicKey | base64 -w 0)
   135
   136# Spin down the rekor server
   137echo "stopping the rekor server..."
   138REKOR_CONTAINER_ID=$(docker ps --filter name=rekor-server --format {{.ID}})
   139docker stop $REKOR_CONTAINER_ID
   140
   141# Now we want to spin up the Rekor server again, but this time point
   142# to the new tree
   143SHARDING_CONFIG=sharding-config.yaml
   144cat << EOF > $SHARDING_CONFIG
   145- treeID: $INITIAL_TREE_ID
   146  encodedPublicKey: $ENCODED_PUBLIC_KEY
   147EOF
   148
   149cat $SHARDING_CONFIG
   150
   151COMPOSE_FILE=docker-compose-sharding.yaml
   152cat << EOF > $COMPOSE_FILE
   153version: '3.4'
   154services:
   155  rekor-server:
   156    build:
   157      context: .
   158      target: "deploy"
   159    command: [
   160      "rekor-server",
   161      "serve",
   162      "--trillian_log_server.address=trillian-log-server",
   163      "--trillian_log_server.port=8090",
   164      "--redis_server.address=redis-server",
   165      "--redis_server.port=6379",
   166      "--rekor_server.address=0.0.0.0",
   167      "--rekor_server.signer=memory",
   168      "--enable_attestation_storage",
   169      "--attestation_storage_bucket=file:///var/run/attestations",
   170      "--trillian_log_server.tlog_id=$SHARD_TREE_ID",
   171      "--trillian_log_server.sharding_config=/$SHARDING_CONFIG"
   172      # Uncomment this for production logging
   173      # "--log_type=prod",
   174      ]
   175    volumes:
   176    - "/var/run/attestations:/var/run/attestations:z"
   177    - "./$SHARDING_CONFIG:/$SHARDING_CONFIG:z"
   178    restart: always # keep the server running
   179    ports:
   180      - "3000:3000"
   181      - "2112:2112"
   182    healthcheck:
   183      test: ["CMD", "curl", "-f", "http://localhost:3000/ping"]
   184      interval: 10s
   185      timeout: 3s
   186      retries: 3
   187      start_period: 5s
   188EOF
   189
   190# Spin up the new Rekor
   191
   192docker-compose -f $COMPOSE_FILE up  -d
   193waitForRekorServer
   194$REKOR_CLI loginfo --rekor_server http://localhost:3000 
   195
   196# Make sure we are pointing to the new tree now
   197TREE_ID=$($REKOR_CLI loginfo --rekor_server http://localhost:3000  --format json | jq -r .TreeID)
   198# Check that the SHARD_TREE_ID is a substring of the `$REKOR_CLI loginfo` output
   199stringsMatch $TREE_ID $SHARD_TREE_ID
   200
   201# Now, if we run $REKOR_CLI get --log_index 2 again, it should grab the log index
   202# from Shard 0
   203check_log_index 2
   204
   205# Add in a new entry to this shard
   206pushd tests/sharding-testdata
   207$REKOR_CLI upload --artifact file2 --signature file2.sig --pki-format=x509 --public-key=ec_public.pem --rekor_server http://localhost:3000
   208popd
   209# Pass in the universal log_index & make sure it resolves 
   210check_log_index 3
   211
   212# Make sure the shard tree size is 1 and the total tree size is 4
   213rm $HOME/.rekor/state.json # We have to remove this since we can't prove consistency between entry 0 and entry 1
   214TREE_SIZE=$($REKOR_CLI loginfo --rekor_server http://localhost:3000 --format json | jq -r .ActiveTreeSize)
   215stringsMatch $TREE_SIZE "1"
   216
   217TOTAL_TREE_SIZE=$($REKOR_CLI loginfo --rekor_server http://localhost:3000 --format json | jq -r .TotalTreeSize)
   218stringsMatch $TOTAL_TREE_SIZE "4"
   219
   220
   221# Make sure we can still get logproof for the now-inactive shard
   222$REKOR_CLI logproof --last-size 2 --tree-id $INITIAL_TREE_ID --rekor_server http://localhost:3000
   223# And the logproof for the now active shard
   224$REKOR_CLI logproof --last-size 1 --rekor_server http://localhost:3000
   225
   226echo "Getting public key for inactive shard..."
   227GOT_PUB_KEY=$(curl "http://localhost:3000/api/v1/log/publicKey?treeID=$INITIAL_TREE_ID" | base64 -w 0)
   228echo "Got encoded public key $GOT_PUB_KEY, making sure this matches the public key we got earlier..."
   229stringsMatch $ENCODED_PUBLIC_KEY $GOT_PUB_KEY
   230
   231echo "Getting the public key for the active tree..."
   232NEW_PUB_KEY=$(curl "http://localhost:3000/api/v1/log/publicKey" | base64 -w 0)
   233echo "Making sure the public key for the active shard is different from the inactive shard..."
   234if [[ "$ENCODED_PUBLIC_KEY" == "$NEW_PUB_KEY" ]]; then
   235    echo
   236    echo "Active tree public key should be different from inactive shard public key but isn't..."
   237    echo "Inactive Shard Public Key: $ENCODED_PUBLIC_KEY"
   238    echo "Active Shard Public Key: $NEW_PUB_KEY"
   239    exit 1
   240fi
   241
   242# TODO: Try to get the entry via Entry ID (Tree ID in hex + UUID)
   243echo
   244echo "Testing /api/v1/log/entries/retrieve endpoint..."
   245
   246ENTRY_ID_1=$($REKOR_CLI get --log-index 1 --rekor_server http://localhost:3000 --format json | jq -r .UUID)
   247ENTRY_ID_2=$($REKOR_CLI get --log-index 3 --rekor_server http://localhost:3000 --format json | jq -r .UUID)
   248
   249
   250# Make sure retrieve by UUID in the inactive shard works
   251NUM_ELEMENTS=$(curl -f http://localhost:3000/api/v1/log/entries/retrieve -H "Content-Type: application/json" -H "Accept: application/json" -d "{ \"entryUUIDs\": [\"$ENTRY_ID_1\"]}" | jq '. | length')
   252stringsMatch $NUM_ELEMENTS "1"
   253
   254# Make sure we can verify the entry we entered into the now-inactive shard
   255pushd tests
   256$REKOR_CLI verify --artifact test_file.txt --signature test_file.sig --public-key test_public_key.key --rekor_server http://localhost:3000
   257popd
   258
   259# -f makes sure we exit on failure
   260NUM_ELEMENTS=$(curl -f http://localhost:3000/api/v1/log/entries/retrieve -H "Content-Type: application/json" -H "Accept: application/json" -d "{ \"entryUUIDs\": [\"$ENTRY_ID_1\", \"$ENTRY_ID_2\"]}" | jq '. | length')
   261stringsMatch $NUM_ELEMENTS "2"
   262
   263# Make sure the /api/v1/log/entries/retrieve endpoint is resolving virtual indexes correctly
   264NUM_ELEMENTS=$(curl -f -H "Content-Type: application/json" --data '{"logIndexes": [0,3]}'  "http://localhost:3000/api/v1/log/entries/retrieve" | jq '. | length')
   265stringsMatch $NUM_ELEMENTS "2"
   266
   267# Make sure we get the expected LogIndex in the response when calling /retrieve endpoint
   268RETRIEVE_LOGINDEX1=$(curl -f http://localhost:3000/api/v1/log/entries/retrieve -H "Content-Type: application/json" -H "Accept: application/json" -d "{ \"logIndexes\": [1]}" | jq '.[0]' | jq  -r .$UUID1.logIndex)
   269stringsMatch $RETRIEVE_LOGINDEX1 "1"
   270
   271# Make sure that verification succeeds via UUID
   272echo
   273echo "Testing rekor-cli verification via UUID..."
   274$REKOR_CLI verify --uuid $UUID1 --rekor_server http://localhost:3000
   275
   276# Make sure that verification succeeds via Entry ID (Tree ID in hex + UUID)
   277echo
   278echo "Testing rekor-cli verification via Entry ID..."
   279DEBUG=1 $REKOR_CLI verify --uuid $ENTRY_ID_1 --rekor_server http://localhost:3000
   280
   281echo "Test passed successfully :)"

View as plain text