Skip to content

Commit

Permalink
Move Components interface to common package
Browse files Browse the repository at this point in the history
This patch moves the components interface to the common package
Also, it get rids of the GetAndApply function that passes a callback
This patch does not unexport all the functions because the workspace
interface has not been created yet. Will come in another PR
  • Loading branch information
James C. Scott committed Aug 19, 2016
1 parent a0746d3 commit c1ba001
Show file tree
Hide file tree
Showing 15 changed files with 280 additions and 208 deletions.
6 changes: 3 additions & 3 deletions commands/diff/inventory.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ package diff
import (
"github.com/opencontrol/compliance-masonry/lib"
"github.com/opencontrol/compliance-masonry/tools/certifications"
"github.com/opencontrol/compliance-masonry/lib/components/versions/base"
"fmt"
"github.com/opencontrol/compliance-masonry/lib/common"
)

// Inventory maintains the inventory of all the controls within a given workspace.
type Inventory struct {
*lib.LocalWorkspace
masterControlList map[string]lib.Control
actualSatisfiedControls map[string]base.Satisfies
actualSatisfiedControls map[string]common.Satisfies
MissingControlList map[string]lib.Control
}

Expand Down Expand Up @@ -74,7 +74,7 @@ func ComputeGapAnalysis(config Config) (Inventory, []error) {
i := Inventory{
LocalWorkspace: workspace,
masterControlList: make(map[string]lib.Control),
actualSatisfiedControls: make(map[string]base.Satisfies),
actualSatisfiedControls: make(map[string]common.Satisfies),
MissingControlList: make(map[string]lib.Control),
}
if i.Certification == nil || i.Components == nil {
Expand Down
4 changes: 2 additions & 2 deletions commands/docs/gitbook/gitbook.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (

"github.com/opencontrol/compliance-masonry/lib"
"github.com/opencontrol/compliance-masonry/tools/fs"
"github.com/opencontrol/compliance-masonry/lib/components/versions/base"
"github.com/opencontrol/compliance-masonry/lib/common"
)

// Config contains data for gitbook export configurations
Expand All @@ -30,7 +30,7 @@ type OpenControlGitBook struct {
// ComponentGitbook struct is an extension of models.Component that adds
// an exportPath
type ComponentGitbook struct {
base.Component
common.Component
exportPath string
}

Expand Down
31 changes: 14 additions & 17 deletions commands/docs/gitbook/gitbookCertification.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,17 @@ import (
"path/filepath"

"github.com/opencontrol/compliance-masonry/lib"
"github.com/opencontrol/compliance-masonry/lib/components/versions/base"
"github.com/opencontrol/compliance-masonry/lib/common"
)

func (openControl *OpenControlGitBook) getResponsibleRole(text string, component base.Component) string {
func (openControl *OpenControlGitBook) getResponsibleRole(text string, component common.Component) string {
if component.GetResponsibleRole() != "" {
text = fmt.Sprintf("%s\n##### Responsible Role: %s\n", text, component.GetResponsibleRole())
}
return text
}

func (openControl *OpenControlGitBook) getNarratives(narratives []base.Section, text string, control *ControlGitbook) string {
func (openControl *OpenControlGitBook) getNarratives(narratives []common.Section, text string, control *ControlGitbook) string {
if len(narratives) == 0 {
return fmt.Sprintf("%s\nNo narrative found for the combination of standard %s and control %s\n", text, control.standardKey, control.controlKey)
}
Expand All @@ -28,15 +27,15 @@ func (openControl *OpenControlGitBook) getNarratives(narratives []base.Section,
return text
}

func (openControl *OpenControlGitBook) getNarrative(narrative base.Section, text string) string {
func (openControl *OpenControlGitBook) getNarrative(narrative common.Section, text string) string {
if narrative.GetKey() != "" {
text = fmt.Sprintf("%s\n##### %s\n", text, narrative.GetKey())
}
text = fmt.Sprintf("%s%s\n", text, narrative.GetText())
return text
}

func (openControl *OpenControlGitBook) getParameters(text string, parameters []base.Section) string {
func (openControl *OpenControlGitBook) getParameters(text string, parameters []common.Section) string {
if len(parameters) > 0 {
text = fmt.Sprintf("%s\n##### Parameters:\n", text)
}
Expand All @@ -46,7 +45,7 @@ func (openControl *OpenControlGitBook) getParameters(text string, parameters []b
return text
}

func (openControl *OpenControlGitBook) getParameter(text string, parameter base.Section) string{
func (openControl *OpenControlGitBook) getParameter(text string, parameter common.Section) string{
text = fmt.Sprintf("%s\n###### %s\n", text, parameter.GetKey())
text = fmt.Sprintf("%s%s\n", text, parameter.GetText())
return text
Expand All @@ -62,14 +61,13 @@ func (openControl *OpenControlGitBook) getCoveredBy(text string, justification l
if componentKey == "" {
componentKey = justification.ComponentKey
}
openControl.Components.GetAndApply(componentKey, func(component base.Component) {
text = openControl.getCoveredByVerification(text, component, coveredBy)
})
component := openControl.Components.Get(componentKey)
text = openControl.getCoveredByVerification(text, component, coveredBy)
}
return text
}

func (openControl *OpenControlGitBook) getCoveredByVerification(text string, component base.Component, coveredBy common.CoveredBy) string {
func (openControl *OpenControlGitBook) getCoveredByVerification(text string, component common.Component, coveredBy common.CoveredBy) string {
if component != nil {
verification := component.GetVerifications().Get(coveredBy.VerificationKey)
text += exportLink(
Expand Down Expand Up @@ -99,17 +97,16 @@ func (openControl *OpenControlGitBook) exportControl(control *ControlGitbook) (s
return
}
for _, justification := range selectJustifications {
openControl.Components.GetAndApply(justification.ComponentKey, func(component base.Component) {
text = fmt.Sprintf("%s\n#### %s\n", text, component.GetName())
component := openControl.Components.Get(justification.ComponentKey)
text = fmt.Sprintf("%s\n#### %s\n", text, component.GetName())

text = openControl.getResponsibleRole(text, component)
text = openControl.getResponsibleRole(text, component)

text = openControl.getParameters(text, justification.SatisfiesData.GetParameters())
text = openControl.getParameters(text, justification.SatisfiesData.GetParameters())

text = openControl.getControlOrigin(text, justification.SatisfiesData.GetControlOrigin())
text = openControl.getControlOrigin(text, justification.SatisfiesData.GetControlOrigin())

text = openControl.getNarratives(justification.SatisfiesData.GetNarratives(), text, control)
})
text = openControl.getNarratives(justification.SatisfiesData.GetNarratives(), text, control)
text = openControl.getCoveredBy(text, justification)
}
})
Expand Down
76 changes: 76 additions & 0 deletions lib/common/component.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package common

import "github.com/blang/semver"

// Component is the basic building block for all systems.
// Schema info: https://github.com/opencontrol/schemas#component-yaml
//
// GetName returns the name of the component
//
// GetKey returns the key for the component (may not be unique). Useful for creating directories.
//
// SetKey sets the key for the component. Useful for overriding.
//
// GetAllSatisfies gets all the Satisfies objects for the component.
//
// GetVerifications get all the verifications.
//
// GetReferences get all the references.
//
// GetVersion returns the version
//
// SetVersion sets the version for the component.
//
// GetResponsibleRole gets the responsible party / role for the component.
type Component interface {
GetName() string
GetKey() string
SetKey(string)
GetAllSatisfies() []Satisfies
GetVerifications() *VerificationReferences
GetReferences() *GeneralReferences
GetVersion() semver.Version
SetVersion(semver.Version)
GetResponsibleRole() string
}

// Satisfies contains information regarding how the component satisfies a given standard and control
//
// GetStandardKey returns the standard
//
// GetControlKey returns the control
//
// GetNarratives gets all the general documentation for this particular standard and control
//
// GetParameters gets all the parameters for this particular standard and control
//
// GetCoveredBy gets the list of all the CoveredBy
//
// GetControlOrigin returns the control origin (only the first one if multiple)
//
// GetControlOrigins returns all the control origins
//
// GetImplementationStatus returns the implementation status (only the first one if multiple)
//
// GetImplementationStatuses returns all implementation statuses
type Satisfies interface {
GetStandardKey() string
GetControlKey() string
GetNarratives() []Section
GetParameters() []Section
GetCoveredBy() CoveredByList
GetControlOrigin() string
GetControlOrigins() []string
GetImplementationStatus() string
GetImplementationStatuses() []string
}

// Section is a general holder that allows it to be used in something like a map
//
// GetKey returns a unique key
//
// GetText returns the text for the section
type Section interface {
GetKey() string
GetText() string
}
76 changes: 76 additions & 0 deletions lib/components.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package lib

import (
"sync"

"github.com/opencontrol/compliance-masonry/lib/components"
"github.com/opencontrol/compliance-masonry/lib/common"
"fmt"
)

// componentsMap struct is a thread-safe structure mapping for components
type componentsMap struct {
mapping map[string]common.Component
sync.RWMutex
}

// newComponents creates an instance of Components struct
func newComponents() *componentsMap {
return &componentsMap{mapping: make(map[string]common.Component)}
}

// add adds a new component to the component map
func (components *componentsMap) add(component common.Component) {
components.Lock()
components.mapping[component.GetKey()] = component
components.Unlock()
}

// Get retrieves a new component from the component map
func (components *componentsMap) Get(key string) common.Component {
components.RLock()
defer components.RUnlock()
return components.mapping[key]
}

// CompareAndAdd compares to see if the component exists in the map. If not, it adds the component.
// This function is thread-safe.
func (components *componentsMap) CompareAndAdd(component common.Component) bool {
components.Lock()
defer components.Unlock()
added := false
if _, exists := components.mapping[component.GetKey()]; !exists {
components.mapping[component.GetKey()] = component
added = true
}
return added
}

// GetAll retrieves all the components without giving directly to the map.
func (components *componentsMap) GetAll() []common.Component {
components.RLock()
defer components.RUnlock()
c := make([]common.Component, len(components.mapping))
idx := 0
for _, value := range components.mapping {
c[idx] = value
idx++
}
return c
}

// LoadComponent imports components into a Component struct and adds it to the
// Components map.
func (ws *LocalWorkspace) LoadComponent(componentDir string) error {
component, err := components.Load(componentDir)
if err != nil {
return err
}
// If the component is new, make sure we load the justifications as well.
if ws.Components.CompareAndAdd(component) {
ws.Justifications.LoadMappings(component)
} else {
return fmt.Errorf("Component: %s exists!\n", component.GetKey())
}
return nil
}
Original file line number Diff line number Diff line change
@@ -1,45 +1,44 @@
package base
package components

import (
"fmt"

"github.com/blang/semver"
"github.com/opencontrol/compliance-masonry/lib/common"
"errors"
"fmt"
"github.com/opencontrol/compliance-masonry/tools/constants"
"github.com/opencontrol/compliance-masonry/lib/common"
"github.com/opencontrol/compliance-masonry/tools/fs"
"path/filepath"
)

type Component interface {
GetName() string
GetKey() string
SetKey(string)
GetAllSatisfies() []Satisfies
GetVerifications() *common.VerificationReferences
GetReferences() *common.GeneralReferences
GetVersion() semver.Version
SetVersion(semver.Version)
GetResponsibleRole() string
// NewComponentParseError is a constructor for creating errors of type BaseComponentParseError
func NewComponentParseError(message string) BaseComponentParseError {
return BaseComponentParseError{message}
}

type Satisfies interface {
GetStandardKey() string
GetControlKey() string
GetNarratives() []Section
GetParameters() []Section
GetCoveredBy() common.CoveredByList
GetControlOrigin() string
GetControlOrigins() []string
GetImplementationStatus() string
GetImplementationStatuses() []string
// Load will read the file at the given path and attempt to return a component object.
func Load(path string) (common.Component, error) {
// Get file system assistance.
fs := fs.OSUtil{}
// Read the component file.
fileName := filepath.Join(path, "component.yaml")
componentData, err := fs.OpenAndReadFile(fileName)
if err != nil {
return nil, errors.New(constants.ErrComponentFileDNE)
}
// Parse the component.
var component common.Component
component, err = parseComponent(componentData,fileName)
if err != nil {
return nil, err
}
// Ensure we have a key for the component.
if component.GetKey() == "" {
component.SetKey(getKey(path))
}
return component, nil
}

type Section interface {
GetKey() string
GetText() string
}

func NewBaseComponentParseError(message string) BaseComponentParseError {
return BaseComponentParseError{message}
}

// BaseComponentParseError is the type of error that will be returned if the parsing failed for ONLY the `Base` struct.
type BaseComponentParseError struct {
Expand Down Expand Up @@ -123,3 +122,9 @@ func (b *Base) UnmarshalYAML(unmarshal func(v interface{}) error) error {
b.SchemaVersion = ver
return err
}

// getKey extracts a component key from the filepath
func getKey(filePath string) string {
_, key := filepath.Split(filePath)
return key
}

0 comments on commit c1ba001

Please sign in to comment.