Skip to content

Commit

Permalink
refactor loop into main
Browse files Browse the repository at this point in the history
Signed-off-by: linus-sun <linussun@google.com>
  • Loading branch information
linus-sun committed Oct 18, 2024
1 parent 70f13d7 commit f38008f
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 51 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/reusable_monitoring.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ jobs:
run: cat ${{ env.LOG_FILE }}
# Skip on first run
continue-on-error: true
- run: go run ./cmd/verifier --file ${{ env.LOG_FILE }} --once --monitored-values "${{ inputs.identities }}" --user-agent "${{ format('{0}/{1}/{2}', needs.detect-workflow.outputs.repository, needs.detect-workflow.outputs.ref, github.run_id) }}"
- run: go run ./cmd/verifier --config-file ${{ env.REUSABLE_MONITORING_CONFIG_FILE }} --once
- name: Upload checkpoint
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
with:
Expand Down
27 changes: 27 additions & 0 deletions cmd/verifier/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// Copyright 2024 The Sigstore Authors.
//
// 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.

package main

import (
"time"
)

type ConsistencyCheckConfiguration struct {
ServerURL string `yaml:"serverURL"`
UserAgentString string `yaml:"userAgentString"`
LogInfoFile string `yaml:"logInfoFile"`
Interval *time.Duration `yaml:"interval"`
}
59 changes: 50 additions & 9 deletions cmd/verifier/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ import (
"flag"
"fmt"
"log"
"os"
"runtime"
"strings"
"time"

"github.com/sigstore/rekor-monitor/pkg/rekor"
"github.com/sigstore/rekor/pkg/client"
"gopkg.in/yaml.v2"

"sigs.k8s.io/release-utils/version"
)
Expand All @@ -42,14 +44,37 @@ const (
// indefinitely to perform consistency check for every time interval that was specified.
func main() {
// Command-line flags that are parameters to the verifier job
serverURL := flag.String("url", publicRekorServerURL, "URL to the rekor server that is to be monitored")
interval := flag.Duration("interval", 5*time.Minute, "Length of interval between each periodical consistency check")
logInfoFile := flag.String("file", logInfoFileName, "Name of the file containing initial merkle tree information")
configFilePath := flag.String("config-file", "", "Name of the file containing the consistency check workflow configuration settings")
once := flag.Bool("once", false, "Perform consistency check once and exit")
userAgentString := flag.String("user-agent", "", "details to include in the user agent string")
flag.Parse()

rekorClient, err := client.GetRekorClient(*serverURL, client.WithUserAgent(strings.TrimSpace(fmt.Sprintf("rekor-monitor/%s (%s; %s) %s", version.GetVersionInfo().GitVersion, runtime.GOOS, runtime.GOARCH, *userAgentString))))
if configFilePath == nil {
log.Fatalf("empty configuration file path")
}

readConfig, err := os.ReadFile(*configFilePath)
if err != nil {
log.Fatalf("error reading from identity monitor configuration file: %v", err)
}

configString := string(readConfig)
var config ConsistencyCheckConfiguration
if err := yaml.Unmarshal([]byte(configString), &config); err != nil {
log.Fatalf("error parsing identities: %v", err)
}

if config.ServerURL == "" {
config.ServerURL = publicRekorServerURL
}
if config.Interval == nil {
defaultInterval := time.Hour
config.Interval = &defaultInterval
}
if config.LogInfoFile == "" {
config.LogInfoFile = logInfoFileName
}

rekorClient, err := client.GetRekorClient(config.ServerURL, client.WithUserAgent(strings.TrimSpace(fmt.Sprintf("rekor-monitor/%s (%s; %s) %s", version.GetVersionInfo().GitVersion, runtime.GOOS, runtime.GOARCH, config.UserAgentString))))
if err != nil {
log.Fatalf("getting Rekor client: %v", err)
}
Expand All @@ -59,13 +84,29 @@ func main() {
log.Fatal(err)
}

err = rekor.VerifyConsistencyCheckInputs(interval, logInfoFile, once)
err = rekor.VerifyConsistencyCheckInputs(config.Interval, &config.LogInfoFile, once)
if err != nil {
log.Fatal(err)
}

err = rekor.RunConsistencyCheck(*interval, rekorClient, verifier, *logInfoFile, *once)
if err != nil {
log.Fatalf("%v", err)
ticker := time.NewTicker(*config.Interval)
defer ticker.Stop()

// Loop will:
// 1. Fetch latest checkpoint and verify
// 2. If old checkpoint is present, verify consistency proof
// 3. Write latest checkpoint to file

// To get an immediate first tick
for ; ; <-ticker.C {
err = rekor.RunConsistencyCheck(rekorClient, verifier, config.LogInfoFile)
if err != nil {
fmt.Fprintf(os.Stderr, "error running consistency check: %v", err)
return
}

if *once {
return
}
}
}
68 changes: 27 additions & 41 deletions pkg/rekor/verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,53 +107,39 @@ func VerifyConsistencyCheckInputs(interval *time.Duration, logInfoFile *string,
}

// RunConsistencyCheck periodically verifies the root hash consistency of a Rekor log.
func RunConsistencyCheck(interval time.Duration, rekorClient *client.Rekor, verifier signature.Verifier, logInfoFile string, once bool) error {
ticker := time.NewTicker(interval)
defer ticker.Stop()

// Loop will:
// 1. Fetch latest checkpoint and verify
// 2. If old checkpoint is present, verify consistency proof
// 3. Write latest checkpoint to file
func RunConsistencyCheck(rekorClient *client.Rekor, verifier signature.Verifier, logInfoFile string) error {
logInfo, err := GetLogInfo(context.Background(), rekorClient)
if err != nil {
return fmt.Errorf("failed to get log info: %v", err)
}
checkpoint, err := verifyLatestCheckpointSignature(logInfo, verifier)
if err != nil {
return fmt.Errorf("failed to verify signature of latest checkpoint: %v", err)
}

// To get an immediate first tick
for ; ; <-ticker.C {
logInfo, err := GetLogInfo(context.Background(), rekorClient)
if err != nil {
return fmt.Errorf("failed to get log info: %v", err)
}
checkpoint, err := verifyLatestCheckpointSignature(logInfo, verifier)
fi, err := os.Stat(logInfoFile)
// File containing previous checkpoints exists
var prevCheckpoint *util.SignedCheckpoint
if err == nil && fi.Size() != 0 {
prevCheckpoint, err = verifyCheckpointConsistency(logInfoFile, checkpoint, *logInfo.TreeID, rekorClient, verifier)
if err != nil {
return fmt.Errorf("failed to verify signature of latest checkpoint: %v", err)
return fmt.Errorf("failed to verify previous checkpoint: %v", err)
}

fi, err := os.Stat(logInfoFile)
// File containing previous checkpoints exists
var prevCheckpoint *util.SignedCheckpoint
if err == nil && fi.Size() != 0 {
prevCheckpoint, err = verifyCheckpointConsistency(logInfoFile, checkpoint, *logInfo.TreeID, rekorClient, verifier)
if err != nil {
return fmt.Errorf("failed to verify previous checkpoint: %v", err)
}

}

// Write if there was no stored checkpoint or the sizes differ
if prevCheckpoint == nil || prevCheckpoint.Size != checkpoint.Size {
if err := file.WriteCheckpoint(checkpoint, logInfoFile); err != nil {
return fmt.Errorf("failed to write checkpoint: %v", err)
}
}
}

// TODO: Switch to writing checkpoints to GitHub so that the history is preserved. Then we only need
// to persist the last checkpoint.
// Delete old checkpoints to avoid the log growing indefinitely
if err := file.DeleteOldCheckpoints(logInfoFile); err != nil {
return fmt.Errorf("failed to delete old checkpoints: %v", err)
// Write if there was no stored checkpoint or the sizes differ
if prevCheckpoint == nil || prevCheckpoint.Size != checkpoint.Size {
if err := file.WriteCheckpoint(checkpoint, logInfoFile); err != nil {
return fmt.Errorf("failed to write checkpoint: %v", err)
}
}

if once {
return nil
}
// TODO: Switch to writing checkpoints to GitHub so that the history is preserved. Then we only need
// to persist the last checkpoint.
// Delete old checkpoints to avoid the log growing indefinitely
if err := file.DeleteOldCheckpoints(logInfoFile); err != nil {
return fmt.Errorf("failed to delete old checkpoints: %v", err)
}
return nil
}

0 comments on commit f38008f

Please sign in to comment.