Skip to content

Commit

Permalink
feat: expand metadata returned by search call, allow filter on collec…
Browse files Browse the repository at this point in the history
…tion name

Adds the collection name and the identifiers of any attestations
contained within the collection to the response from GetBySubjectDigest.

Adds a parameter to limit results by a collection's name.

Adds more options to archivistctl to interact with archivist.

Some code re-org to split up metadata stores from object stores, and
moves the object store calls out of the mysqlstore.

Signed-off-by: Mikhail Swift <mikhail@testifysec.com>
  • Loading branch information
mikhailswift committed Jul 7, 2022
1 parent 1055f0e commit bdf90f2
Show file tree
Hide file tree
Showing 13 changed files with 329 additions and 124 deletions.
4 changes: 2 additions & 2 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ build-and-push-server:
KO_DOCKER_REPO: registry.gitlab.com/testifysec/judge-platform/archivist/archivist
stage: build
image:
name: registry.gitlab.com/testifysec/docker-images/ko:0.9.3
name: registry.gitlab.com/testifysec/docker-images/ko:0.11.2
entrypoint: [""]
script:
- ko auth login -u ${CI_REGISTRY_USER} -p ${CI_REGISTRY_PASSWORD} ${CI_REGISTRY}
Expand All @@ -17,7 +17,7 @@ build-and-push-client:
KO_DOCKER_REPO: registry.gitlab.com/testifysec/judge-platform/archivist/archivistctl
stage: build
image:
name: registry.gitlab.com/testifysec/docker-images/ko:0.9.3
name: registry.gitlab.com/testifysec/docker-images/ko:0.11.2
entrypoint: [""]
script:
- ko auth login -u ${CI_REGISTRY_USER} -p ${CI_REGISTRY_PASSWORD} ${CI_REGISTRY}
Expand Down
10 changes: 5 additions & 5 deletions cmd/archivist/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ import (

"github.com/testifysec/archivist-api/pkg/api/archivist"
"github.com/testifysec/archivist/internal/config"
"github.com/testifysec/archivist/internal/metadatastorage/mysqlstore"
"github.com/testifysec/archivist/internal/objectstorage/blobstore"
"github.com/testifysec/archivist/internal/objectstorage/filestore"
"github.com/testifysec/archivist/internal/server"
"github.com/testifysec/archivist/internal/storage/blob"
"github.com/testifysec/archivist/internal/storage/filestore"
"github.com/testifysec/archivist/internal/storage/mysqlstore"

nested "github.com/antonfisher/nested-logrus-formatter"
"github.com/networkservicemesh/sdk/pkg/tools/debug"
Expand Down Expand Up @@ -105,7 +105,7 @@ func main() {
logrus.Fatalf("error initializing storage clients: %+v", err)
}

mysqlStore, mysqlStoreCh, err := mysqlstore.NewServer(ctx, cfg.SQLStoreConnectionString, fileStore)
mysqlStore, mysqlStoreCh, err := mysqlstore.NewServer(ctx, cfg.SQLStoreConnectionString)

log.FromContext(ctx).WithField("duration", time.Since(now)).Infof("completed phase 3: initializing storage clients")
// ********************************************************************************
Expand All @@ -117,7 +117,7 @@ func main() {
archivistService := server.NewArchivistServer(mysqlStore)
archivist.RegisterArchivistServer(grpcServer, archivistService)

collectorService := server.NewCollectorServer(mysqlStore)
collectorService := server.NewCollectorServer(mysqlStore, fileStore)
archivist.RegisterCollectorServer(grpcServer, collectorService)

srvErrCh := grpcutils.ListenAndServe(ctx, &cfg.ListenOn, grpcServer)
Expand Down
59 changes: 59 additions & 0 deletions cmd/archivistctl/cmd/retrieve.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package cmd

import (
"context"
"io"
"os"
"strings"

"github.com/spf13/cobra"
"github.com/testifysec/archivist-api/pkg/api/archivist"
)

var (
outFile string

retrieveCmd = &cobra.Command{
Use: "retrieve",
Short: "Retrieves a dsse envelope by it's gitoid from archivist",
SilenceUsage: true,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
conn, err := newConn(archivistUrl)
if err != nil {
return err
}

var out io.Writer = os.Stdout
if len(outFile) > 0 {
file, err := os.Create(outFile)
defer file.Close()
if err != nil {
return err
}

out = file
}

return retrieveEnvelope(cmd.Context(), archivist.NewCollectorClient(conn), args[0], out)
},
}
)

func init() {
rootCmd.AddCommand(retrieveCmd)
retrieveCmd.Flags().StringVarP(&outFile, "out", "o", "", "File to write the envelope out to. Defaults to stdout")
}

func retrieveEnvelope(ctx context.Context, client archivist.CollectorClient, gitoid string, out io.Writer) error {
resp, err := client.Get(ctx, &archivist.GetRequest{Gitoid: gitoid})
if err != nil {
return err
}

if _, err := io.Copy(out, strings.NewReader(resp.Object)); err != nil {
return err
}

return nil
}
28 changes: 28 additions & 0 deletions cmd/archivistctl/cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package cmd

import (
"github.com/spf13/cobra"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)

var (
archivistUrl string

rootCmd = &cobra.Command{
Use: "archivistctl",
Short: "A utility to interact with an archivist server",
}
)

func init() {
rootCmd.PersistentFlags().StringVarP(&archivistUrl, "archivisturl", "u", "localhost:8080", "url of the archivist instance")
}

func Execute() error {
return rootCmd.Execute()
}

func newConn(url string) (*grpc.ClientConn, error) {
return grpc.Dial(url, grpc.WithTransportCredentials(insecure.NewCredentials()))
}
92 changes: 92 additions & 0 deletions cmd/archivistctl/cmd/search.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package cmd

import (
"context"
"errors"
"fmt"
"io"
"strings"

"github.com/spf13/cobra"
"github.com/testifysec/archivist-api/pkg/api/archivist"
)

var (
collectionName string

searchCmd = &cobra.Command{
Use: "search",
Short: "Searches the archivist instance for an attestation matching a query",
SilenceUsage: true,
Long: `Searches the archivist instance for an envelope with a specified subject digest.
Optionally a collection name can be provided to further constrain results.
Digests are expected to be in the form algorithm:digest, for instance: sha256:456c0c9a7c05e2a7f84c139bbacedbe3e8e88f9c`,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return errors.New("expected exactly 1 argument")
}

if _, _, err := validateDigestString(args[0]); err != nil {
return err
}

return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
conn, err := newConn(archivistUrl)
defer conn.Close()
if err != nil {
return nil
}

algo, digest, err := validateDigestString(args[0])
if err != nil {
return err
}

return searchArchivist(cmd.Context(), archivist.NewArchivistClient(conn), algo, digest, collectionName)
},
}
)

func init() {
rootCmd.AddCommand(searchCmd)
searchCmd.Flags().StringVarP(&collectionName, "collectionname", "n", "", "Only envelopes containing an attestation collection with the provided name will be returned.")
}

func validateDigestString(ds string) (algo, digest string, err error) {
algo, digest, found := strings.Cut(ds, ":")
if !found {
return "", "", errors.New("invalid digest string. expected algorithm:digest")
}

return algo, digest, nil
}

func searchArchivist(ctx context.Context, client archivist.ArchivistClient, algo, digest, collName string) error {
req := &archivist.GetBySubjectDigestRequest{Algorithm: algo, Value: digest, CollectionName: collName}
stream, err := client.GetBySubjectDigest(ctx, req)
if err != nil {
return err
}

for {
resp, err := stream.Recv()
if err == io.EOF {
break
}

if err != nil {
return err
}

printResponse(resp)
}

return nil
}

func printResponse(resp *archivist.GetBySubjectDigestResponse) {
fmt.Printf("Gitoid: %s\nCollection name: %s\nAttestations: %s\n\n", resp.GetGitoid(), resp.GetCollectionName(), strings.Join(resp.GetAttestations(), ", "))
}
63 changes: 63 additions & 0 deletions cmd/archivistctl/cmd/store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package cmd

import (
"context"
"encoding/json"
"fmt"
"io"
"os"

"github.com/spf13/cobra"
"github.com/testifysec/archivist-api/pkg/api/archivist"
"github.com/testifysec/go-witness/dsse"
)

var (
storeCmd = &cobra.Command{
Use: "store",
Short: "stores an attestation on the archivist server",
SilenceUsage: true,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
conn, err := newConn(archivistUrl)
defer conn.Close()
if err != nil {
return err
}

file, err := os.Open(args[0])
defer file.Close()
if err != nil {
return err
}

return storeAttestation(cmd.Context(), archivist.NewCollectorClient(conn), file)
},
}
)

func init() {
rootCmd.AddCommand(storeCmd)
}

func storeAttestation(ctx context.Context, client archivist.CollectorClient, envelope io.Reader) error {
objBytes, err := io.ReadAll(envelope)
if err != nil {
return err
}

obj := &dsse.Envelope{}
if err := json.Unmarshal(objBytes, &obj); err != nil {
return err
}

if len(obj.Payload) == 0 || obj.PayloadType == "" || len(obj.Signatures) == 0 {
return fmt.Errorf("obj is not DSSE %d %d %d", len(obj.Payload), len(obj.PayloadType), len(obj.Signatures))
}

if _, err := client.Store(ctx, &archivist.StoreRequest{Object: string(objBytes)}); err != nil {
return err
}

return nil
}
64 changes: 3 additions & 61 deletions cmd/archivistctl/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,71 +15,13 @@
package main

import (
"context"
"encoding/json"
"fmt"
"github.com/testifysec/go-witness/dsse"
"io/ioutil"
"os"

"github.com/testifysec/archivist-api/pkg/api/archivist"

"github.com/sirupsen/logrus"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"github.com/testifysec/archivist/cmd/archivistctl/cmd"
)

func main() {
if len(os.Args) != 2 {
logrus.Fatalln("error")
}

file, err := ioutil.ReadFile(os.Args[1])
if err != nil {
logrus.Fatalf("unable to read file %+v", err)
}

var opts []grpc.DialOption
opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
conn, err := grpc.Dial("127.0.0.1:8080", opts...)
if err != nil {
logrus.Fatalf("unable to grpc dial: %+v", err)
}
defer func() {
err := conn.Close()
if err != nil {
logrus.Errorf("unable to close connection: %+v", err)
}
}()

archivistClient := archivist.NewArchivistClient(conn)
collectorClient := archivist.NewCollectorClient(conn)

// check if valid

obj := &dsse.Envelope{}
err = json.Unmarshal(file, obj)
if err != nil {
logrus.Fatalln("could not unmarshal input: ", err)
}

if len(obj.Payload) == 0 || obj.PayloadType == "" || len(obj.Signatures) == 0 {
logrus.Fatalf("obj is not DSSE %d %d %d", len(obj.Payload), len(obj.PayloadType), len(obj.Signatures))
}

_, err = collectorClient.Store(context.Background(), &archivist.StoreRequest{
Object: string(file),
})
if err != nil {
logrus.Errorf("unable to store object: %+v", err)
}

resp, err := archivistClient.GetBySubjectDigest(context.Background(), &archivist.GetBySubjectDigestRequest{Algorithm: "sha256", Value: "3ff8d62302fe86d3f2d637843c696ab4d065f9e1cc873121806cf9467e546e4f"})
if err != nil {
logrus.Fatalf("unable to retrieve object: %+v", err)
}

for i, v := range resp.GetObject() {
fmt.Printf("%d: %s\n", i, v)
if err := cmd.Execute(); err != nil {
os.Exit(1)
}
}
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ require (
github.com/minio/minio-go v6.0.14+incompatible
github.com/networkservicemesh/sdk v1.3.0
github.com/sirupsen/logrus v1.8.1
github.com/spf13/cobra v1.4.0
github.com/spiffe/go-spiffe/v2 v2.0.0
github.com/testifysec/archivist-api v0.0.0-20220603060816-12e25ceccbf1
github.com/testifysec/archivist-api v0.0.0-20220707182002-b803369e93a4
github.com/testifysec/go-witness v0.1.11
google.golang.org/grpc v1.46.0
google.golang.org/protobuf v1.28.0
Expand All @@ -36,10 +37,12 @@ require (
github.com/google/uuid v1.3.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/hashicorp/hcl/v2 v2.10.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect
github.com/networkservicemesh/api v1.3.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/zclconf/go-cty v1.10.0 // indirect
github.com/zeebo/errs v1.2.2 // indirect
go.opencensus.io v0.23.0 // indirect
Expand Down
Loading

0 comments on commit bdf90f2

Please sign in to comment.