Skip to content
This repository has been archived by the owner on Aug 20, 2021. It is now read-only.

Commit

Permalink
add subcontrol details (#24)
Browse files Browse the repository at this point in the history
* add subcontrol details

* Refactor race condition

* Remove comment

* Rename catalog channel
  • Loading branch information
minhaj10p authored and anweiss committed Dec 19, 2018
1 parent 8ce8313 commit 512b59a
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 116 deletions.
5 changes: 4 additions & 1 deletion cli/cmd/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,10 @@ var Generate = cli.Command{
}
defer newFile.Close()

catalogs := generator.CreateCatalogsFromProfile(profile)
catalogs, err := generator.CreateCatalogsFromProfile(profile)
if err != nil {
return cli.NewExitError(fmt.Sprintf("cannot create catalogs from profile, err: %v", err), 1)
}
t, err := templates.GetCatalogTemplate()
if err != nil {
return cli.NewExitError("cannot fetch template", 1)
Expand Down
15 changes: 12 additions & 3 deletions generator/generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,10 @@ func TestCreateCatalogsFromProfile(t *testing.T) {
},
},
}
x := CreateCatalogsFromProfile(&p)
x, err := CreateCatalogsFromProfile(&p)
if err != nil {
t.Errorf("error should be null")
}
if len(x) != 1 {
t.Error("there must be one catalog")
}
Expand Down Expand Up @@ -150,7 +153,10 @@ func TestCreateCatalogsFromProfileWithBadHref(t *testing.T) {
},
},
}
catalogs := CreateCatalogsFromProfile(&p)
catalogs, err := CreateCatalogsFromProfile(&p)
if err != nil {
t.Error("error should be nil")
}
if len(catalogs) > 0 {
t.Error("nothing should be parsed due to bad url")
}
Expand Down Expand Up @@ -187,7 +193,10 @@ func TestSubControlsMapping(t *testing.T) {
},
}

c := CreateCatalogsFromProfile(&profile)
c, err := CreateCatalogsFromProfile(&profile)
if err != nil {
t.Error("error should be nil")
}
if c[0].Groups[0].Controls[1].Subcontrols[0].Id != "ac-2.1" {
t.Errorf("does not contain ac-2.1 in subcontrols")
}
Expand Down
112 changes: 0 additions & 112 deletions generator/intersection.go

This file was deleted.

126 changes: 126 additions & 0 deletions generator/mapper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package generator

import (
"os"
"strings"

"github.com/Sirupsen/logrus"

"github.com/opencontrol/oscalkit/types/oscal/catalog"
"github.com/opencontrol/oscalkit/types/oscal/profile"
)

//CreateCatalogsFromProfile maps profile controls to multiple catalogs
func CreateCatalogsFromProfile(profileArg *profile.Profile) ([]*catalog.Catalog, error) {

done := 0
errChan := make(chan error)
catalogChan := make(chan *catalog.Catalog)
var outputCatalogs []*catalog.Catalog
//Get first import of the profile (which is a catalog)
for _, profileImport := range profileArg.Imports {
go func(profileImport profile.Import) {
//ForEach Import's Href, Fetch the Catalog JSON file
catalogReference, err := GetCatalogFilePath(profileImport.Href.String())
if err != nil {
logrus.Errorf("invalid file path: %v", err)
catalogChan <- nil
return
}

f, err := os.Open(catalogReference)
if err != nil {
logrus.Errorf("cannot read file: %v", err)
catalogChan <- nil
return
}

//Once fetched, Read the catalog JSON and Marshall it to Go struct.
importedCatalog, err := ReadCatalog(f)
if err != nil {
logrus.Errorf("cannot parse catalog listed in import.href %v", err)
errChan <- err
return

}
//Prepare a new catalog object to merge into the final List of OutputCatalogs
newCatalog, err := getMappedCatalogControlsFromImport(importedCatalog, profileImport)
if err != nil {
errChan <- err
return
}

catalogChan <- &newCatalog
}(profileImport)

}
for {
select {
case err := <-errChan:
return nil, err
case newCatalog := <-catalogChan:
done++
if newCatalog != nil {
outputCatalogs = append(outputCatalogs, newCatalog)
}
if done == len(profileArg.Imports) {
return outputCatalogs, nil
}
}
}
}

func getMappedCatalogControlsFromImport(importedCatalog *catalog.Catalog, profileImport profile.Import) (catalog.Catalog, error) {
newCatalog := catalog.Catalog{
Title: importedCatalog.Title,
Groups: []catalog.Group{},
}
for _, group := range importedCatalog.Groups {
//Prepare a new group to append matching controls into.
newGroup := catalog.Group{
Title: group.Title,
Controls: []catalog.Control{},
}
//Append controls to the new group if matches
for _, catalogControl := range group.Controls {
/**
wrapped it around a function to achieve immutability
profile.Include is a pointer hence, dereferencing
*/
func(include profile.Include) {
for controlIndex, call := range include.IdSelectors {
if strings.ToLower(catalogControl.Id) == strings.ToLower(call.ControlId) {
newControl := catalog.Control{
Id: catalogControl.Id,
Class: catalogControl.Class,
Title: catalogControl.Title,
Subcontrols: []catalog.Subcontrol{},
}
//For subcontrols, find again in entire profile
for _, catalogSubControl := range catalogControl.Subcontrols {
for subcontrolIndex, subcontrol := range include.IdSelectors {
//if found append the subcontrol into the control attribute
if strings.ToLower(catalogSubControl.Id) == strings.ToLower(subcontrol.SubcontrolId) {
newControl.Subcontrols = append(newControl.Subcontrols, catalogSubControl)
//remove that subcontrol from profile. (for less computation)
include.IdSelectors = append(include.IdSelectors[:subcontrolIndex], include.IdSelectors[subcontrolIndex+1:]...)
break
}
}
}
//finally append the control in the group.
newGroup.Controls = append(newGroup.Controls, newControl)
//remove controlId from profile as well. (for less computation)
include.IdSelectors = append(include.IdSelectors[:controlIndex], profileImport.Include.IdSelectors[controlIndex+1:]...)
break
}
}

}(*profileImport.Include)
}
if len(newGroup.Controls) > 0 {
newCatalog.Groups = append(newCatalog.Groups, newGroup)
}
}
return newCatalog, nil
}

0 comments on commit 512b59a

Please sign in to comment.