diff --git a/impl/impl_test.go b/impl/impl_test.go index 939b4646..a38d8ffd 100644 --- a/impl/impl_test.go +++ b/impl/impl_test.go @@ -15,23 +15,60 @@ const ( ) func TestGenerateImplementation(t *testing.T) { - + ucpCompID := "(component ID: cpe:2.3:a:docker:ucp:3.2.0:*:*:*:*:*:*:*)" + dtrCompID := "(component ID: cpe:2.3:a:docker:dtr:2.7.0:*:*:*:*:*:*:*)" + engineCompID := "(component ID: cpe:2.3:a:docker:engine-enterprise:18.09:*:*:*:*:*:*:*)" components := []string{"CompA", "CompB", "CompC"} - controls := []string{"ac-2", "ac-2.2", "ac-4"} + comps := []component{ + { + id: getComponentID(ucpCompID), + name: "UCP", + compNameIndex: 17, + uuidIndex: 18, + narrativeIndex: 19, + definition: make(cdMap), + }, + { + id: getComponentID(dtrCompID), + name: "DTR", + compNameIndex: 20, + uuidIndex: 21, + narrativeIndex: 22, + definition: make(cdMap), + }, + { + id: getComponentID(engineCompID), + name: "Engine", + compNameIndex: 14, + uuidIndex: 15, + narrativeIndex: 16, + definition: make(cdMap), + }, + } + controls := []string{"ac-2", "ac-2.2", "ac-4", "bc-1.1", "hk-1.2", "as-3.2", "af-1.23", "ar-5.2", "fp-8.5"} ComponentDetails := [][]string{ []string{controls[0], fmt.Sprintf("%s|%s", components[0], components[1]), "2-Narrative", "123|321"}, []string{controls[1], fmt.Sprintf("%s|%s", components[0], components[1]), "2.2-Narrative", "456|654"}, []string{controls[2], "CompC", "4-Narrative", "789|987"}, + []string{controls[0], fmt.Sprintf("%s|%s", components[0], components[1]), "3-Narrative", "123|321"}, + []string{controls[1], fmt.Sprintf("%s|%s", components[0], components[1]), "3.4-Narrative", "567|1231"}, + []string{controls[2], "CompC", "5-Narrative", "789|987"}, + []string{controls[0], fmt.Sprintf("%s|%s", components[0], components[1]), "4-Narrative", "123|321"}, + []string{controls[1], fmt.Sprintf("%s|%s", components[0], components[1]), "4.1-Narrative", "111|222"}, + []string{controls[2], "CompC", "6-Narrative", "789|987"}, } csvs := make([][]string, totalControlsInExcel) for i := range csvs { - csvs[i] = make([]string, 20) + csvs[i] = make([]string, 25) } - for i, x := range ComponentDetails { - csvs[i+rowIndex][controlIndex] = x[0] - csvs[i+rowIndex][componentConfigIndex] = x[1] - csvs[i+rowIndex][narrativeIndex] = x[2] - csvs[i+rowIndex][uuidIndex] = x[3] + + for _, comp := range comps { + for i, x := range ComponentDetails { + csvs[i+rowIndex][controlIndex] = x[0] + csvs[i+rowIndex][comp.compNameIndex] = x[1] + csvs[i+rowIndex][comp.narrativeIndex] = x[2] + csvs[i+rowIndex][comp.uuidIndex] = x[3] + } } p := profile.Profile{ @@ -81,6 +118,10 @@ func TestGenerateImplementation(t *testing.T) { }, } i := GenerateImplementation(csvs, &p, &NISTCatalog{"NISTSP80053"}) + + if len(i.ComponentDefinitions) != len(comps) { + t.Error("mismatch number of component definitions") + } if len(i.ComponentDefinitions[0].ComponentConfigurations) != len(components) { t.Error("mismatch number of components") } diff --git a/impl/implementation.go b/impl/implementation.go index 9cfa6929..8ae0123e 100644 --- a/impl/implementation.go +++ b/impl/implementation.go @@ -12,29 +12,69 @@ import ( const ( // totalControlsInExcel the total number of controls in the excel sheet totalControlsInExcel = 264 - // componentConfigIndex The Column at which name of the component configuration is present - componentConfigIndex = 17 - //uuidIndex The Column at which guid of component exist - uuidIndex = 18 - // narrativeIndex The Column at which narrative of the component configuration is present - narrativeIndex = 19 // controlIndex Column at which control is present in the excel sheet controlIndex = 2 - //rowIndex Starting point for valid rows (neglects titles) - rowIndex = 3 + // rowIndex Starting point for valid rows (neglects titles) + rowIndex = 3 + delimiter = "|" + componentIDRegex = `cpe:[0-9].[0-9]:[a-z]:docker:[a-z-]*:(\d+\.)?(\d+\.)?(\*|\d+)` // componentNameRow is the index for getting component name componentNameRow = 1 - delimiter = "|" - componentIDRegex = "cpe:[0-9].[0-9]:[a-z]:docker:[a-z]*:[0-9].[0-9].[0-9]" ) type guidMap map[string]uuid.UUID type cdMap map[string]implementation.ComponentDefinition -//GenerateImplementation generates implementation from component excel sheet +type component struct { + id string + compNameIndex int + name string + uuidIndex int + narrativeIndex int + definition cdMap +} + +// GenerateImplementation generates implementation from component excel sheet func GenerateImplementation(CSVS [][]string, p *profile.Profile, c Catalog) implementation.Implementation { - componentDefinitionMap := make(map[string]implementation.ComponentDefinition) + var cdMapList = make([]cdMap, 0) + + components := []component{ + { + id: getComponentID(CSVS[componentNameRow][17]), + name: "UCP", + compNameIndex: 17, + uuidIndex: 18, + narrativeIndex: 19, + definition: make(cdMap), + }, + { + id: getComponentID(CSVS[componentNameRow][20]), + name: "DTR", + compNameIndex: 20, + uuidIndex: 21, + narrativeIndex: 22, + definition: make(cdMap), + }, + { + id: getComponentID(CSVS[componentNameRow][14]), + name: "Engine", + compNameIndex: 14, + uuidIndex: 15, + narrativeIndex: 16, + definition: make(cdMap), + }, + } + + for _, comp := range components { + cdMapList = append(cdMapList, fillCDMap(CSVS, comp.compNameIndex, comp.definition, comp.uuidIndex, comp.narrativeIndex, comp.id, p, c)) + } + + return CompileImplementation(cdMapList, CSVS, c, p, components) + +} + +func fillCDMap(CSVS [][]string, compNameIndex int, compDef cdMap, uuidIndex int, narrativeIndex int, compID string, p *profile.Profile, c Catalog) cdMap { checkAgainstGUID := make(map[string]uuid.UUID) for i := rowIndex; i < totalControlsInExcel; i++ { applicableControl := CSVS[i][controlIndex] @@ -42,31 +82,31 @@ func GenerateImplementation(CSVS [][]string, p *profile.Profile, c Catalog) impl continue } applicableNarrative := CSVS[i][narrativeIndex] - ListOfComponentConfigName := strings.Split(CSVS[i][componentConfigIndex], delimiter) + ListOfComponentConfigName := strings.Split(CSVS[i][compNameIndex], delimiter) for compIndex, componentConfigName := range ListOfComponentConfigName { componentConfigName = strings.TrimSpace(componentConfigName) if componentConfigName == "" { continue } - if _, ok := componentDefinitionMap[componentConfigName]; !ok { + if _, ok := compDef[componentConfigName]; !ok { + guid := strings.Split(CSVS[i][uuidIndex], delimiter)[compIndex] guid = strings.TrimSpace(guid) - CreateComponentDefinition(checkAgainstGUID, componentDefinitionMap, componentConfigName, p, c, applicableControl, applicableNarrative, guid) + CreateComponentDefinition(checkAgainstGUID, compDef, componentConfigName, p, c, applicableControl, applicableNarrative, guid, compID) } else { - securityCheck := componentDefinitionMap[componentConfigName] + securityCheck := compDef[componentConfigName] guid := checkAgainstGUID[componentConfigName] temp := AppendParameterInImplementation(securityCheck, guid, p, c, applicableControl) temp = AppendControlInImplementation(securityCheck, guid, c, applicableControl) - componentDefinitionMap[componentConfigName] = temp + compDef[componentConfigName] = temp } } } - return CompileImplementation(componentDefinitionMap, CSVS, c, p) - + return compDef } -//CreateComponentDefinition creates a component definition -func CreateComponentDefinition(gm guidMap, cdm cdMap, componentConfName string, p *profile.Profile, c Catalog, control, narrative, guid string) { +// CreateComponentDefinition creates a component definition +func CreateComponentDefinition(gm guidMap, cdm cdMap, componentConfName string, p *profile.Profile, c Catalog, control, narrative, guid string, cdID string) { componentConfGUID, _ := uuid.FromString(guid) gm[componentConfName] = componentConfGUID @@ -88,9 +128,20 @@ func CreateComponentDefinition(gm guidMap, cdm cdMap, componentConfName string, } } } - + controlConfiguration.ProvisioningMechanisms = []implementation.ProvisioningMechanism{ + implementation.ProvisioningMechanism{ + ProvisionedControls: []implementation.ControlId{ + implementation.ControlId{ + ControlID: c.GetControl(control), + CatalogIDRef: c.GetID(), + ItemID: "", + }, + }, + }, + } controlConfiguration.Parameters = parameters cdm[componentConfName] = implementation.ComponentDefinition{ + ID: cdID, ComponentConfigurations: []*implementation.ComponentConfiguration{ CreateComponentConfiguration(componentConfGUID, componentConfName, narrative), }, @@ -105,19 +156,7 @@ func CreateComponentDefinition(gm guidMap, cdm cdMap, componentConfName string, ControlImplementations: []*implementation.ControlImplementation{ &implementation.ControlImplementation{ ControlConfigurations: []implementation.ControlConfiguration{ - implementation.ControlConfiguration{ - ConfigurationIDRef: componentConfGUID.String(), - ProvisioningMechanisms: []implementation.ProvisioningMechanism{ - implementation.ProvisioningMechanism{ - ProvisionedControls: []implementation.ControlId{ - implementation.ControlId{ - ControlID: c.GetControl(control), - CatalogIDRef: c.GetID(), - }, - }, - }, - }, - }, + controlConfiguration, }, }, }, @@ -125,7 +164,7 @@ func CreateComponentDefinition(gm guidMap, cdm cdMap, componentConfName string, } -//CreateComponentConfiguration creates component configuration +// CreateComponentConfiguration creates component configuration func CreateComponentConfiguration(guid uuid.UUID, componentConfName, narrative string) *implementation.ComponentConfiguration { return &implementation.ComponentConfiguration{ @@ -187,83 +226,104 @@ func AppendControlInImplementation(cd implementation.ComponentDefinition, guid u } // CompileImplementation compiles all checks from maps to implementation json -func CompileImplementation(cd cdMap, CSVS [][]string, cat Catalog, p *profile.Profile) implementation.Implementation { +func CompileImplementation(cdList []cdMap, CSVS [][]string, cat Catalog, p *profile.Profile, components []component) implementation.Implementation { + return implementation.Implementation{ - ComponentDefinitions: []implementation.ComponentDefinition{ - { - ID: getComponentID(CSVS[componentNameRow][componentConfigIndex]), - ComponentConfigurations: func() []*implementation.ComponentConfiguration { - var arr []*implementation.ComponentConfiguration - for _, v := range cd { - for _, x := range v.ComponentConfigurations { - arr = append(arr, x) + ComponentDefinitions: func() []implementation.ComponentDefinition { + + var cds []implementation.ComponentDefinition + for _, cd := range cdList { + compD := implementation.ComponentDefinition{ + ID: func() string { + for _, c := range cd { + for _, comp := range components { + if c.ID == comp.id { + return c.ID + } + } } - } - return arr - }(), - ControlImplementations: func() []*implementation.ControlImplementation { - arr := []*implementation.ControlImplementation{ - &implementation.ControlImplementation{ - ControlIds: []implementation.ControlId{}, - }, - } - for i := 3; i < totalControlsInExcel; i++ { - if CSVS[i][controlIndex] == "" { - continue + return "" + }(), + + ComponentConfigurations: func() []*implementation.ComponentConfiguration { + var arr []*implementation.ComponentConfiguration + for _, v := range cd { + for _, x := range v.ComponentConfigurations { + arr = append(arr, x) + } + } + + return arr + }(), + ControlImplementations: func() []*implementation.ControlImplementation { + arr := []*implementation.ControlImplementation{ + &implementation.ControlImplementation{ + ControlIds: []implementation.ControlId{}, + }, } - c := strings.ToLower(CSVS[i][controlIndex]) - if cat.isSubControl(c) { + for i := 3; i < totalControlsInExcel; i++ { + if CSVS[i][controlIndex] == "" { + continue + } + c := strings.ToLower(CSVS[i][controlIndex]) + if cat.isSubControl(c) { + arr[0].ControlIds = append(arr[0].ControlIds, implementation.ControlId{ + ControlID: cat.GetControl(c), + ItemID: c, + CatalogIDRef: cat.GetID(), + }) + continue + } arr[0].ControlIds = append(arr[0].ControlIds, implementation.ControlId{ - ControlID: cat.GetControl(c), - ItemID: c, + ControlID: cat.GetControl(CSVS[i][controlIndex]), + ItemID: "", CatalogIDRef: cat.GetID(), }) - continue } - arr[0].ControlIds = append(arr[0].ControlIds, implementation.ControlId{ - ControlID: cat.GetControl(CSVS[i][controlIndex]), - ItemID: "", - CatalogIDRef: cat.GetID(), - }) - } - for _, def := range cd { - for _, ci := range def.ImplementsProfiles { - for _, cc := range ci.ControlConfigurations { - arr[0].ControlConfigurations = append(arr[0].ControlConfigurations, cc) + for _, def := range cd { + for _, ci := range def.ImplementsProfiles { + for _, cc := range ci.ControlConfigurations { + arr[0].ControlConfigurations = append(arr[0].ControlConfigurations, cc) + } } } - for _, ci := range def.ControlImplementations { - for _, cc := range ci.ControlConfigurations { - arr[0].ControlConfigurations = append(arr[0].ControlConfigurations, cc) + + for j, x := range arr[0].ControlConfigurations { + for _, def := range cd { + for _, ci := range def.ControlImplementations { + for _, cc := range ci.ControlConfigurations { + if cc.ConfigurationIDRef == x.ConfigurationIDRef { + arr[0].ControlConfigurations[j].ProvisioningMechanisms = cc.ProvisioningMechanisms + } + } + } } } - } - return arr - }(), - ImplementsProfiles: []*implementation.ImplementsProfile{ - &implementation.ImplementsProfile{ - ProfileID: p.ID, - ControlConfigurations: func() []implementation.ControlConfiguration { - var arr []implementation.ControlConfiguration - for _, v := range cd { - for _, x := range v.ImplementsProfiles { - for _, y := range x.ControlConfigurations { - arr = append(arr, y) + return arr + }(), + ImplementsProfiles: []*implementation.ImplementsProfile{ + &implementation.ImplementsProfile{ + ProfileID: p.ID, + ControlConfigurations: func() []implementation.ControlConfiguration { + var arr []implementation.ControlConfiguration + for _, v := range cd { + for _, x := range v.ImplementsProfiles { + for _, y := range x.ControlConfigurations { + arr = append(arr, y) + } } } - } - return arr - }(), + return arr + }(), + }, }, - }, - }, - }, - } -} + } -func getComponentID(componentName string) string { - re := regexp.MustCompile(componentIDRegex) - return re.FindString(componentName) + cds = append(cds, compD) + } + return cds + }(), + } } //Catalog catalog interface to determine control id pattern @@ -345,3 +405,8 @@ func existsInControls(cID string, controls []implementation.ControlId) bool { } return false } + +func getComponentID(componentName string) string { + re := regexp.MustCompile(componentIDRegex) + return re.FindString(componentName) +}