Skip to content

Commit

Permalink
Added new export command relates to #84
Browse files Browse the repository at this point in the history
  • Loading branch information
xntrik committed Feb 29, 2024
1 parent 698e4cc commit 1b958c2
Show file tree
Hide file tree
Showing 11 changed files with 856 additions and 144 deletions.
16 changes: 2 additions & 14 deletions cmd/hcltm/dfd.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,18 +118,6 @@ func (c *DfdCommand) fetchDfd(allFiles []string, index int) (string, error) {
return dot, nil
}

func (c *DfdCommand) fileExistenceCheck(outfiles []string, overwrite bool) error {
if !overwrite {
for _, outfile := range outfiles {
_, err := os.Stat(outfile)
if !os.IsNotExist(err) {
return fmt.Errorf("'%s' already exists", outfile)
}
}
}
return nil
}

func (c *DfdCommand) Run(args []string) int {

flagSet := c.GetFlagset("dfd")
Expand Down Expand Up @@ -265,7 +253,7 @@ func (c *DfdCommand) Run(args []string) int {

// We're going to output a single file
case c.flagOutFile != "" && c.flagOutDir == "":
err := c.fileExistenceCheck([]string{c.flagOutFile}, c.flagOverwrite)
err := fileExistenceCheck([]string{c.flagOutFile}, c.flagOverwrite)
if err != nil {
fmt.Printf("%s\n", err)
return 1
Expand Down Expand Up @@ -387,7 +375,7 @@ func (c *DfdCommand) Run(args []string) int {

// Check if there are any files, and whether we're handling
// overwriting correctly
err := c.fileExistenceCheck(outfiles, c.flagOverwrite)
err := fileExistenceCheck(outfiles, c.flagOverwrite)
if err != nil {
fmt.Printf("%s\n", err)
return 1
Expand Down
166 changes: 166 additions & 0 deletions cmd/hcltm/export.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
package main

import (
"encoding/json"
"fmt"
"os"
"strings"

"github.com/xntrik/go-otm/pkg/otm"
"github.com/xntrik/hcltm/pkg/spec"
)

// ExportCommand struct defines the "hcltm export" commands
type ExportCommand struct {
*GlobalCmdOptions
specCfg *spec.ThreatmodelSpecConfig
flagFormat string
flagOutput string
flagOverwrite bool
}

// Help is the help output for the "hcltm export" command
func (e *ExportCommand) Help() string {
helpText := `
Usage: hcltm export [options] <files>
Export provided HCL threat models into other formats
Options:
-config=<file>
Optional config file
-format=<json|otm>
-output=<file>
Optional filename to output to.
-overwrite
`
return strings.TrimSpace(helpText)
}

// Run executes the "hcltm export" logic
func (e *ExportCommand) Run(args []string) int {
flagSet := e.GetFlagset("export")
flagSet.StringVar(&e.flagFormat, "format", "json", "Format of output. json, or otm. Defaults to json")
flagSet.StringVar(&e.flagOutput, "output", "", "Name of output file. If not set, will output to STDOUT")
flagSet.BoolVar(&e.flagOverwrite, "overwrite", false, "Overwrite existing file. Defaults to false")
flagSet.Parse(args)

if e.flagConfig != "" {
err := e.specCfg.LoadSpecConfigFile(e.flagConfig)

if err != nil {
fmt.Printf("Error: %s\n", err)
return 1
}
}

if len(flagSet.Args()) == 0 {
fmt.Printf("Please provide a filename\n")
return 1
} else {
// Find all the .hcl files we're going to parse
AllFiles := findAllFiles(flagSet.Args())
var AllTms []spec.Threatmodel

// Parse all the identified .hcl files
for _, file := range AllFiles {
tmParser := spec.NewThreatmodelParser(e.specCfg)
err := tmParser.ParseFile(file, false)
if err != nil {
fmt.Printf("Error parsing %s: %s\n", file, err)
return 1
}

for _, tm := range tmParser.GetWrapped().Threatmodels {
AllTms = append(AllTms, tm)
}

}

var outputString string

switch e.flagFormat {
case "json":

tmJson, err := json.Marshal(AllTms)
if err != nil {
fmt.Printf("Error parsing into json: %s\n", err)
return 1
}

outputString = string(tmJson)

case "otm":
allOtms := []otm.OtmSchemaJson{}
for _, tm := range AllTms {
tmOtm, err := tm.RenderOtm()
if err != nil {
fmt.Printf("Error parsing into otm: %s\n", err)
return 1
}

allOtms = append(allOtms, tmOtm)
}

var otmJson []byte
var err error

if len(AllTms) > 1 {
otmJson, err = json.Marshal(allOtms)
if err != nil {
fmt.Printf("Error parsing into otm: %s\n", err)
return 1
}
} else if len(AllTms) == 1 {
otmJson, err = json.Marshal(allOtms[0])
if err != nil {
fmt.Printf("Error parsing into otm: %s\n", err)
return 1
}
}

outputString = string(otmJson)

default:

fmt.Printf("Incorrect -format option\n")
return 1

}

if e.flagOutput == "" {
fmt.Printf("%s\n", outputString)
} else {
err := fileExistenceCheck([]string{e.flagOutput}, e.flagOverwrite)
if err != nil {
fmt.Printf("%s\n", err)
return 1
}

f, err := os.Create(e.flagOutput)
if err != nil {
fmt.Printf("Error creating file: %s: %s\n", e.flagOutput, err)
return 1
}
defer f.Close()

_, err = f.WriteString(outputString)
if err != nil {
fmt.Printf("Error writing output to %s: %s\n", e.flagOutput, err)
return 1
}
fmt.Printf("Successfully wrote '%s'\n", e.flagOutput)
}
}
return 0
}

// Synopsis returns the synopsis for the "hcltm export" command
func (e *ExportCommand) Synopsis() string {
return "Export threat models into other formats"
}
Loading

0 comments on commit 1b958c2

Please sign in to comment.