Skip to content

Commit

Permalink
comid create
Browse files Browse the repository at this point in the history
  • Loading branch information
thomas-fossati committed Sep 29, 2021
1 parent 16fee00 commit 62da24f
Show file tree
Hide file tree
Showing 10 changed files with 1,174 additions and 3 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ GO111MODULE := on

GOPKG := github.com/veraison/corim/corim
GOPKG += github.com/veraison/corim/comid
GOPKG += github.com/veraison/corim/cli/cmd

GOLINT ?= golangci-lint

Expand Down
33 changes: 33 additions & 0 deletions cli/cmd/comid.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright 2021 Contributors to the Veraison project.
// SPDX-License-Identifier: Apache-2.0

package cmd

import (
"os"

"github.com/spf13/cobra"
)

var comidCmd = &cobra.Command{
Use: "comid",
Short: "CoMID specific manipulation",
Long: `CoMID specific manipulation
Create CoMID from template t1.json and save the result in the current working directory.
cli comid create --file=t1.json
`,

Run: func(cmd *cobra.Command, args []string) {
if len(args) == 0 {
cmd.Help() // nolint: errcheck
os.Exit(0)
}
},
}

func init() {
rootCmd.AddCommand(comidCmd)
}
147 changes: 147 additions & 0 deletions cli/cmd/comidCreate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// Copyright 2021 Contributors to the Veraison project.
// SPDX-License-Identifier: Apache-2.0

package cmd

import (
"errors"
"fmt"
"path/filepath"

"github.com/spf13/afero"
"github.com/spf13/cobra"
"github.com/veraison/corim/comid"
)

var (
comidCreateFiles []string
comidCreateDirs []string
comidCreateOutputDir string
)

var comidCreateCmd = NewComidCreateCmd()

func NewComidCreateCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create",
Short: "create one or more CBOR-encoded CoMID(s) from the supplied JSON template(s)",
Long: `create one or more CBOR-encoded CoMID(s) from the supplied JSON template(s)
Create CoMIDs from templates t1.json and t2.json, plus any template found in the
templates/ directory. Save them to the current working directory.
cli comid create --tmpl-file=t1.json --tmpl-file=t2.json --tmpl-dir=templates
Create one CoMID from template t3.json and save it to the comids/ directory.
Note that the output directory must exist.
cli comid create --tmpl-file=t3.json --output-dir=comids
`,

RunE: func(cmd *cobra.Command, args []string) error {
if err := checkComidCreateArgs(); err != nil {
return err
}

filesList := filesList(comidCreateFiles, comidCreateDirs)
if len(filesList) == 0 {
return errors.New("no files found")
}

for _, tmplFile := range filesList {
cborFile, err := templateToCBOR(tmplFile, comidCreateOutputDir)
if err != nil {
return err
}
fmt.Printf("created %q from %q\n", cborFile, tmplFile)
}
return nil
},
}

cmd.Flags().StringArrayVarP(
&comidCreateFiles, "tmpl-file", "f", []string{}, "a CoMID template file (in JSON format)",
)

cmd.Flags().StringArrayVarP(
&comidCreateDirs, "tmpl-dir", "d", []string{}, "a directory containing CoMID template files",
)

cmd.Flags().StringVarP(
&comidCreateOutputDir, "output-dir", "o", ".", "directory where the created files are stored",
)

return cmd
}

func checkComidCreateArgs() error {
if len(comidCreateFiles) == 0 && len(comidCreateDirs) == 0 {
return errors.New("no templates supplied")
}
return nil
}

func filesList(files, dirs []string) []string {
var l []string

for _, file := range files {
if _, err := fs.Stat(file); err == nil {
l = append(l, file)
}
}

for _, dir := range dirs {
filesInfo, err := afero.ReadDir(fs, dir)
if err != nil {
continue
}

for _, fileInfo := range filesInfo {
if !fileInfo.IsDir() && filepath.Ext(fileInfo.Name()) == ".json" {
l = append(l, filepath.Join(dir, fileInfo.Name()))
}
}
}

return l
}

func templateToCBOR(tmplFile, outputDir string) (string, error) {
var (
tmplData, cborData []byte
cborFile string
c comid.Comid
err error
)

if tmplData, err = afero.ReadFile(fs, tmplFile); err != nil {
return "", fmt.Errorf("error loading template from %s: %w", tmplFile, err)
}

if err = c.FromJSON(tmplData); err != nil {
return "", fmt.Errorf("error decoding template from %s: %w", tmplFile, err)
}

if err = c.Valid(); err != nil {
return "", fmt.Errorf("error validating template %s: %w", tmplFile, err)
}

cborData, err = c.ToCBOR()
if err != nil {
return "", fmt.Errorf("error encoding template %s to CBOR: %w", tmplFile, err)
}

// we can use tag-id as the basename, since it is supposedly unique
cborFile = filepath.Join(outputDir, c.TagIdentity.TagID.String()+".cbor")

err = afero.WriteFile(fs, cborFile, cborData, 0400)
if err != nil {
return "", fmt.Errorf("error saving CBOR file %s: %w", cborFile, err)
}

return cborFile, nil
}

func init() {
comidCmd.AddCommand(comidCreateCmd)
}
117 changes: 117 additions & 0 deletions cli/cmd/comidCreate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Copyright 2021 Contributors to the Veraison project.
// SPDX-License-Identifier: Apache-2.0

package cmd

import (
"testing"

"github.com/spf13/afero"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/veraison/corim/comid"
)

func Test_ComidCreateCmd_unknown_argument(t *testing.T) {
cmd := NewComidCreateCmd()

args := []string{"--unknown-argument=val"}
cmd.SetArgs(args)

err := cmd.Execute()
assert.EqualError(t, err, "unknown flag: --unknown-argument")
}

func Test_ComidCreateCmd_no_templates(t *testing.T) {
cmd := NewComidCreateCmd()

// no args

err := cmd.Execute()
assert.EqualError(t, err, "no templates supplied")
}

func Test_ComidCreateCmd_no_files_found(t *testing.T) {
cmd := NewComidCreateCmd()

args := []string{
"--tmpl-file=unknown",
"--tmpl-dir=unsure",
}
cmd.SetArgs(args)

err := cmd.Execute()
assert.EqualError(t, err, "no files found")
}

func Test_ComidCreateCmd_template_with_invalid_json(t *testing.T) {
var err error

cmd := NewComidCreateCmd()

fs = afero.NewMemMapFs()
err = afero.WriteFile(fs, "invalid.json", []byte("..."), 0400)
require.NoError(t, err)

args := []string{
"--tmpl-file=invalid.json",
}
cmd.SetArgs(args)

err = cmd.Execute()
assert.EqualError(t, err, "error decoding template from invalid.json: invalid character '.' looking for beginning of value")
}

func Test_ComidCreateCmd_template_with_invalid_comid(t *testing.T) {
var err error

cmd := NewComidCreateCmd()

fs = afero.NewMemMapFs()
err = afero.WriteFile(fs, "bad-comid.json", []byte("{}"), 0400)
require.NoError(t, err)

args := []string{
"--tmpl-file=bad-comid.json",
}
cmd.SetArgs(args)

err = cmd.Execute()
assert.EqualError(t, err, "error validating template bad-comid.json: tag-identity validation failed: empty tag-id")
}

func Test_ComidCreateCmd_template_from_file_ok(t *testing.T) {
var err error

cmd := NewComidCreateCmd()

fs = afero.NewMemMapFs()
err = afero.WriteFile(fs, "ok.json", []byte(comid.PSARefValJSONTemplate), 0400)
require.NoError(t, err)

args := []string{
"--tmpl-file=ok.json",
}
cmd.SetArgs(args)

err = cmd.Execute()
assert.NoError(t, err)
}

func Test_ComidCreateCmd_template_from_dir_ok(t *testing.T) {
var err error

cmd := NewComidCreateCmd()

fs = afero.NewMemMapFs()
err = afero.WriteFile(fs, "testdir/ok.json", []byte(comid.PSARefValJSONTemplate), 0400)
require.NoError(t, err)

args := []string{
"--tmpl-dir=testdir",
}
cmd.SetArgs(args)

err = cmd.Execute()
assert.NoError(t, err)
}
60 changes: 60 additions & 0 deletions cli/cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2021 Contributors to the Veraison project.
// SPDX-License-Identifier: Apache-2.0

package cmd

import (
"fmt"
"os"

"github.com/spf13/afero"
"github.com/spf13/cobra"

"github.com/spf13/viper"
)

var (
cfgFile string
fs = afero.NewOsFs()
)

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "cli",
Short: "CoRIM & CoMID swiss-army knife",
Version: "0.0.1",
SilenceUsage: true,
SilenceErrors: true,
}

func Execute() {
cobra.CheckErr(rootCmd.Execute())
}

func init() {
cobra.OnInitialize(initConfig)

rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cli.yaml)")
}

// initConfig reads in config file and ENV variables if set
func initConfig() {
if cfgFile != "" {
viper.SetConfigFile(cfgFile)
} else {
home, err := os.UserHomeDir()
cobra.CheckErr(err)

// search config in home directory with name ".cli" (without extension)
viper.AddConfigPath(home)
viper.SetConfigType("yaml")
viper.SetConfigName(".cli")
}

viper.AutomaticEnv() // read in environment variables that match

// if a config file is found, read it in
if err := viper.ReadInConfig(); err == nil {
fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed())
}
}
Loading

0 comments on commit 62da24f

Please sign in to comment.