1
0
mirror of https://github.com/strongdm/comply synced 2025-12-06 06:14:09 +00:00

Merge pull request #109 from camposer/fix/serve-handle-file-error

Fix/serve handle file error
This commit is contained in:
Rodolfo Campos
2021-10-14 16:08:27 +02:00
committed by GitHub
9 changed files with 725 additions and 20 deletions

View File

@@ -82,7 +82,7 @@ func Exists() bool {
}
// Config is the parsed contents of ProjectRoot()/config.yml.
func Config() *Project {
var Config = func() *Project {
p := Project{}
cfgBytes, err := ioutil.ReadFile(filepath.Join(ProjectRoot(), "comply.yml"))
if err != nil {

View File

@@ -83,7 +83,10 @@ func ReadStandards() ([]*Standard, error) {
return nil, errors.Wrap(err, "unable to read "+f.FullPath)
}
yaml.Unmarshal(sBytes, &s)
err = yaml.Unmarshal(sBytes, &s)
if err != nil {
return nil, errors.Wrap(err, "unable to parse "+f.FullPath)
}
standards = append(standards, s)
}
@@ -101,7 +104,10 @@ func ReadNarratives() ([]*Document, error) {
for _, f := range files {
n := &Document{}
mdmd := loadMDMD(f.FullPath)
mdmd, err := loadMDMD(f.FullPath)
if err != nil {
return nil, err
}
err = yaml.Unmarshal([]byte(mdmd.yaml), &n)
if err != nil {
return nil, errors.Wrap(err, "unable to parse "+f.FullPath)
@@ -120,13 +126,17 @@ func ReadNarratives() ([]*Document, error) {
func ReadProcedures() ([]*Procedure, error) {
var procedures []*Procedure
files, err := path.Procedures()
if err != nil {
return nil, errors.Wrap(err, "unable to enumerate paths")
}
for _, f := range files {
p := &Procedure{}
mdmd := loadMDMD(f.FullPath)
mdmd, err := loadMDMD(f.FullPath)
if err != nil {
return nil, err
}
err = yaml.Unmarshal([]byte(mdmd.yaml), &p)
if err != nil {
return nil, errors.Wrap(err, "unable to parse "+f.FullPath)
@@ -151,7 +161,10 @@ func ReadPolicies() ([]*Document, error) {
for _, f := range files {
p := &Document{}
mdmd := loadMDMD(f.FullPath)
mdmd, err := loadMDMD(f.FullPath)
if err != nil {
return nil, err
}
err = yaml.Unmarshal([]byte(mdmd.yaml), &p)
if err != nil {
return nil, errors.Wrap(err, "unable to parse "+f.FullPath)
@@ -171,7 +184,7 @@ type metadataMarkdown struct {
body string
}
func loadMDMD(path string) metadataMarkdown {
func loadMDMD(path string) (*metadataMarkdown, error) {
bytes, err := ioutil.ReadFile(path)
if err != nil {
panic(err)
@@ -183,9 +196,9 @@ func loadMDMD(path string) metadataMarkdown {
components = components[1:]
}
if len(components) == 1 {
panic(fmt.Sprintf("Malformed metadata markdown in %s, must be of the form: YAML\\n---\\nmarkdown content", path))
return nil, errors.New(fmt.Sprintf("Malformed metadata markdown in %s, must be of the form: YAML\\n---\\nmarkdown content", path))
}
yaml := components[0]
item := components[0]
body := strings.Join(components[1:], "---")
return metadataMarkdown{yaml, body}
return &metadataMarkdown{item, body}, nil
}

258
internal/model/fs_test.go Normal file
View File

@@ -0,0 +1,258 @@
package model
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"testing"
"github.com/strongdm/comply/internal/config"
"github.com/strongdm/comply/internal/path"
"gopkg.in/yaml.v2"
)
// TestReadNarratives calls model.ReadNarratives checking for a valid return value.
func TestReadNarratives(t *testing.T) {
mockConfig()
filePath := fmt.Sprintf("%s/narratives/control.md", getRootPath())
fileInfo, _ := os.Lstat(filePath)
path.Narratives = func() ([]path.File, error) {
return []path.File{
{FullPath: filePath, Info: fileInfo},
}, nil
}
documents, err := ReadNarratives()
if err != nil {
t.Fatalf(`ReadNarratives() returned an error %v`, err)
}
if len(documents) != 1 {
t.Fatal(`Invalid number of documents`)
}
if documents[0].FullPath != filePath {
t.Fatalf(`Invalid document path %s`, documents[0].FullPath)
}
}
// TestReadNarrativesWhenThereAreNoNarratives calls model.ReadNarratives checking for a valid return when
// there are no narratives to process
func TestReadNarrativesWhenThereAreNoNarratives(t *testing.T) {
mockConfig()
path.Narratives = func() ([]path.File, error) {
return []path.File{}, nil
}
documents, err := ReadNarratives()
if err != nil {
t.Fatalf(`ReadNarratives() returned an error %v`, err)
}
if len(documents) != 0 {
t.Fatal(`Invalid number of documents`)
}
}
// TestReadNarrativesFailsWhenInvalidNarrative calls model.ReadNarratives checking for an error return when
// there is an invalid narrative
func TestReadNarrativesFailsWhenInvalidNarrative(t *testing.T) {
mockConfig()
path.Narratives = func() ([]path.File, error) {
filePath := fmt.Sprintf("%s/../fixtures/narratives/invalid-control.md", getRootPath())
fileInfo, _ := os.Lstat(filePath)
return []path.File{
{FullPath: filePath, Info: fileInfo},
}, nil
}
_, err := ReadNarratives()
if err == nil {
t.Fatal(`ReadNarratives() was expected to fail`)
}
}
// TestReadProcedures calls model.ReadProcedures checking for a valid return value.
func TestReadProcedures(t *testing.T) {
mockConfig()
filePath := fmt.Sprintf("%s/procedures/workstation.md", getRootPath())
fileInfo, _ := os.Lstat(filePath)
path.Procedures = func() ([]path.File, error) {
return []path.File{
{FullPath: filePath, Info: fileInfo},
}, nil
}
documents, err := ReadProcedures()
if err != nil {
t.Fatalf(`ReadProcedures() returned an error %v`, err)
}
if len(documents) != 1 {
t.Fatal(`Invalid number of documents`)
}
if documents[0].FullPath != filePath {
t.Fatalf(`Invalid document path %s`, documents[0].FullPath)
}
}
// TestReadProceduresWhenThereAreNoProcedures calls model.ReadProcedures checking for a valid return when
// there are no procedures to process
func TestReadProceduresWhenThereAreNoProcedures(t *testing.T) {
mockConfig()
path.Procedures = func() ([]path.File, error) {
return []path.File{}, nil
}
documents, err := ReadProcedures()
if err != nil {
t.Fatalf(`ReadProcedures() returned an error %v`, err)
}
if len(documents) != 0 {
t.Fatal(`Invalid number of documents`)
}
}
// TestReadProceduresFailsWhenInvalidProcedure calls model.ReadProcedures checking for an error return when
// there is an invalid procedure
func TestReadProceduresFailsWhenInvalidProcedure(t *testing.T) {
mockConfig()
path.Procedures = func() ([]path.File, error) {
filePath := fmt.Sprintf("%s/../fixtures/procedures/invalid-workstation.md", getRootPath())
fileInfo, _ := os.Lstat(filePath)
return []path.File{
{FullPath: filePath, Info: fileInfo},
}, nil
}
_, err := ReadProcedures()
if err == nil {
t.Fatal(`ReadProcedures() was expected to fail`, err)
}
}
// TestReadPolicies calls model.ReadPolicies checking for a valid return value.
func TestReadPolicies(t *testing.T) {
mockConfig()
filePath := fmt.Sprintf("%s/policies/access.md", getRootPath())
fileInfo, _ := os.Lstat(filePath)
path.Policies = func() ([]path.File, error) {
return []path.File{
{FullPath: filePath, Info: fileInfo},
}, nil
}
documents, err := ReadPolicies()
if err != nil {
t.Fatalf(`ReadPolicies() returned an error %v`, err)
}
if len(documents) != 1 {
t.Fatal(`Invalid number of documents`)
}
if documents[0].FullPath != filePath {
t.Fatalf(`Invalid document path %s`, documents[0].FullPath)
}
}
// TestReadPoliciesWhenThereAreNoPolicies calls model.ReadPolicies checking for a valid return when
// there are no policies to process
func TestReadPoliciesWhenThereAreNoPolicies(t *testing.T) {
mockConfig()
path.Policies = func() ([]path.File, error) {
return []path.File{}, nil
}
documents, err := ReadPolicies()
if err != nil {
t.Fatalf(`ReadPolicies() returned an error %v`, err)
}
if len(documents) != 0 {
t.Fatal(`Invalid number of documents`)
}
}
// TestReadPoliciesFailsWhenInvalidPolicy calls model.ReadPolicies checking for an error return when
// there is an invalid policy
func TestReadPoliciesFailsWhenInvalidPolicy(t *testing.T) {
mockConfig()
path.Policies = func() ([]path.File, error) {
filePath := fmt.Sprintf("%s/../fixtures/policies/invalid-access.md", getRootPath())
fileInfo, _ := os.Lstat(filePath)
return []path.File{
{FullPath: filePath, Info: fileInfo},
}, nil
}
_, err := ReadPolicies()
if err == nil {
t.Fatal(`ReadPolicies() was expected to fail`, err)
}
}
// TestReadStandards calls model.ReadStandards checking for a valid return value.
func TestReadStandards(t *testing.T) {
mockConfig()
filePath := fmt.Sprintf("%s/standards/TSC-2017.yml", getRootPath())
fileInfo, _ := os.Lstat(filePath)
path.Standards = func() ([]path.File, error) {
return []path.File{
{FullPath: filePath, Info: fileInfo},
}, nil
}
documents, err := ReadStandards()
if err != nil {
t.Fatalf(`ReadStandards() returned an error %v`, err)
}
if len(documents) != 1 {
t.Fatal(`Invalid number of documents`)
}
}
// TestReadStandardsWhenThereAreNoStandards calls model.ReadStandards checking for a valid return when
// there are no standards to process
func TestReadStandardsWhenThereAreNoStandards(t *testing.T) {
mockConfig()
path.Standards = func() ([]path.File, error) {
return []path.File{}, nil
}
documents, err := ReadStandards()
if err != nil {
t.Fatalf(`ReadStandards() returned an error %v`, err)
}
if len(documents) != 0 {
t.Fatal(`Invalid number of documents`)
}
}
// TestReadStandardsFailsWhenInvalidStandard calls model.ReadStandards checking for an error return when
// there is an invalid standard
func TestReadStandardsFailsWhenInvalidStandard(t *testing.T) {
mockConfig()
path.Standards = func() ([]path.File, error) {
filePath := fmt.Sprintf("%s/../fixtures/standards/invalid-standard.yml", getRootPath())
fileInfo, _ := os.Lstat(filePath)
return []path.File{
{FullPath: filePath, Info: fileInfo},
}, nil
}
_, err := ReadStandards()
if err == nil {
t.Fatal(`ReadStandards() was expected to fail`, err)
}
}
func mockConfig() {
config.Config = func() *config.Project {
p := config.Project{}
cfgBytes, _ := ioutil.ReadFile(filepath.Join(getRootPath(), "comply.yml.example"))
yaml.Unmarshal(cfgBytes, &p)
return &p
}
}
func getRootPath() string {
_, fileName, _, _ := runtime.Caller(0)
fileDir := filepath.Dir(fileName)
return fmt.Sprintf("%s/../../example", fileDir)
}

View File

@@ -9,22 +9,22 @@ import (
func TestMarshal(t *testing.T) {
d := Data{
Tickets: []*Ticket{
&Ticket{
{
ID: "t1",
},
},
Audits: []*Audit{
&Audit{
{
ID: "a1",
},
},
Procedures: []*Procedure{
&Procedure{
Code: "pro1",
{
ID: "pro1",
},
},
Policies: []*Policy{
&Policy{
Policies: []*Document{
{
Name: "pol1",
},
},
@@ -40,5 +40,4 @@ func TestMarshal(t *testing.T) {
!strings.Contains(encoded, "pol1") {
t.Error("identifier not found in marshalled string")
}
}

View File

@@ -16,22 +16,22 @@ type File struct {
}
// Standards lists all standard files.
func Standards() ([]File, error) {
var Standards = func() ([]File, error) {
return filesFor("standards", "yml")
}
// Narratives lists all narrative files.
func Narratives() ([]File, error) {
var Narratives = func() ([]File, error) {
return filesFor("narratives", "md")
}
// Policies lists all policy files.
func Policies() ([]File, error) {
var Policies = func() ([]File, error) {
return filesFor("policies", "md")
}
// Procedures lists all procedure files.
func Procedures() ([]File, error) {
var Procedures = func() ([]File, error) {
return filesFor("procedures", "md")
}