-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: expand metadata returned by search call, allow filter on collec…
…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
1 parent
1055f0e
commit bdf90f2
Showing
13 changed files
with
329 additions
and
124 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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())) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(), ", ")) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.