Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add transformation from OSCAL SSP to OSCAL Assessment Plan #45

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
188 changes: 188 additions & 0 deletions models/components/component_definition.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
/*
Copyright 2025 The OSCAL Compass Authors
SPDX-License-Identifier: Apache-2.0
*/

package components

import oscalTypes "github.com/defenseunicorns/go-oscal/src/types/oscal-1-1-2"

// Interface checks for the implementation for Component Definition structures
var (
_ Component = (*DefinedComponentAdapter)(nil)
_ Implementation = (*ControlImplementationSetAdapter)(nil)
_ Requirement = (*ImplementedRequirementImplementationAdapter)(nil)
_ Statement = (*ControlStatementAdapter)(nil)
)

const defaultState = "operational"

// DefinedComponentAdapter wrapped an OSCAL DefinedComponent to
// provide methods for compatibility with Component.
type DefinedComponentAdapter struct {
definedComp oscalTypes.DefinedComponent
}

// NewDefinedComponentAdapter returns an initialized DefinedComponentAdapter from a given
// DefinedComponent.
func NewDefinedComponentAdapter(definedComponent oscalTypes.DefinedComponent) *DefinedComponentAdapter {
return &DefinedComponentAdapter{
definedComp: definedComponent,
}
}

func (d *DefinedComponentAdapter) UUID() string {
return d.definedComp.UUID
}

func (d *DefinedComponentAdapter) Title() string {
return d.definedComp.Title
}

func (d *DefinedComponentAdapter) Type() ComponentType {
return ComponentType(d.definedComp.Type)
}

func (d *DefinedComponentAdapter) AsDefinedComponent() (oscalTypes.DefinedComponent, bool) {
return d.definedComp, true
}

func (d *DefinedComponentAdapter) AsSystemComponent() (oscalTypes.SystemComponent, bool) {
return oscalTypes.SystemComponent{
Description: d.definedComp.Description,
Links: d.definedComp.Links,
Props: d.definedComp.Props,
Protocols: d.definedComp.Protocols,
Purpose: d.definedComp.Purpose,
Remarks: d.definedComp.Remarks,
ResponsibleRoles: d.definedComp.ResponsibleRoles,
Status: oscalTypes.SystemComponentStatus{
State: defaultState,
},
Title: d.definedComp.Title,
Type: d.definedComp.Type,
UUID: d.definedComp.UUID,
}, true
}

func (d *DefinedComponentAdapter) Props() []oscalTypes.Property {
if d.definedComp.Props == nil {
return []oscalTypes.Property{}
}
return *d.definedComp.Props
}

// ControlImplementationSetAdapter wraps an OSCAL ControlImplementationSet to provide
// methods for compatibility with Implementation.
type ControlImplementationSetAdapter struct {
controlImp oscalTypes.ControlImplementationSet
}

// NewControlImplementationSetAdapter returns an initialized ControlImplementationAdapterSet from a given
// ControlImplementation from an OSCAL Component Definition.
func NewControlImplementationSetAdapter(controlImp oscalTypes.ControlImplementationSet) *ControlImplementationSetAdapter {
return &ControlImplementationSetAdapter{
controlImp: controlImp,
}
}

func (c *ControlImplementationSetAdapter) Requirements() []Requirement {
var requirements []Requirement
for _, requirement := range c.controlImp.ImplementedRequirements {
requirementAdapter := NewImplementedRequirementImplementationAdapter(requirement)
requirements = append(requirements, requirementAdapter)
}
return requirements
}

func (c *ControlImplementationSetAdapter) SetParameters() []oscalTypes.SetParameter {
if c.controlImp.SetParameters == nil {
return []oscalTypes.SetParameter{}
}
return *c.controlImp.SetParameters
}

func (c *ControlImplementationSetAdapter) Props() []oscalTypes.Property {
if c.controlImp.Props == nil {
return []oscalTypes.Property{}
}
return *c.controlImp.Props
}

// ImplementedRequirementImplementationAdapter wraps an OSCAL ImplementedRequirementImplementation to provide
// methods for compatibility with Requirement.
type ImplementedRequirementImplementationAdapter struct {
impReq oscalTypes.ImplementedRequirementControlImplementation
}

// NewImplementedRequirementImplementationAdapter returns an initialized ImplementedRequirementImplementationAdapter from a given
// ImplementedRequirementImplementation from an OSCAL Component Definition.
func NewImplementedRequirementImplementationAdapter(impReq oscalTypes.ImplementedRequirementControlImplementation) *ImplementedRequirementImplementationAdapter {
return &ImplementedRequirementImplementationAdapter{
impReq: impReq,
}
}

func (i *ImplementedRequirementImplementationAdapter) ControlID() string {
return i.impReq.ControlId
}

func (i *ImplementedRequirementImplementationAdapter) UUID() string {
return i.impReq.UUID
}

func (i *ImplementedRequirementImplementationAdapter) SetParameters() []oscalTypes.SetParameter {
if i.impReq.SetParameters == nil {
return []oscalTypes.SetParameter{}
}
return *i.impReq.SetParameters
}

func (i *ImplementedRequirementImplementationAdapter) Props() []oscalTypes.Property {
if i.impReq.Props == nil {
return []oscalTypes.Property{}
}
return *i.impReq.Props
}

func (i *ImplementedRequirementImplementationAdapter) Statements() []Statement {
var statements []Statement
if i.impReq.Statements == nil {
return statements
}
for _, stm := range *i.impReq.Statements {
stmAdapter := NewControlStatementAdapter(stm)
statements = append(statements, stmAdapter)
}

return statements
}

// ControlStatementAdapter wraps an OSCAL ControlStatement to provide
// methods for compatibility with Statement.
type ControlStatementAdapter struct {
stm oscalTypes.ControlStatementImplementation
}

// NewControlStatementAdapter returns an initialized ControlStatementAdapter from a given
// ControlStatement from an OSCAL Component Definition.
func NewControlStatementAdapter(statement oscalTypes.ControlStatementImplementation) *ControlStatementAdapter {
return &ControlStatementAdapter{
stm: statement,
}
}

func (c *ControlStatementAdapter) StatementID() string {
return c.stm.StatementId
}

func (c *ControlStatementAdapter) UUID() string {
return c.stm.UUID
}

func (c *ControlStatementAdapter) Props() []oscalTypes.Property {
if c.stm.Props == nil {
return []oscalTypes.Property{}
}
return *c.stm.Props
}
75 changes: 75 additions & 0 deletions models/components/component_definition_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
Copyright 2025 The OSCAL Compass Authors
SPDX-License-Identifier: Apache-2.0
*/

package components

import (
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/require"

"github.com/oscal-compass/oscal-sdk-go/models"
"github.com/oscal-compass/oscal-sdk-go/validation"
)

func TestDefinedComponentAdapter(t *testing.T) {
testDataPath := filepath.Join("../../testdata", "component-definition-test.json")

file, err := os.Open(testDataPath)
require.NoError(t, err)
definition, err := models.NewComponentDefinition(file, validation.NoopValidator{})
require.NoError(t, err)
require.NotNil(t, definition)
require.NotNil(t, definition.Components)
comps := *definition.Components
require.Len(t, comps, 3)
adapter := NewDefinedComponentAdapter(comps[0])
require.Equal(t, "TestKubernetes", adapter.Title())
require.Equal(t, Service, adapter.Type())
require.Equal(t, "c8106bc8-5174-4e86-91a4-52f2fe0ed027", adapter.UUID())
require.Len(t, adapter.Props(), 6)
systemComp, ok := adapter.AsSystemComponent()
require.True(t, ok)
require.Equal(t, adapter.UUID(), systemComp.UUID)
definedComp, ok := adapter.AsDefinedComponent()
require.True(t, ok)
require.Equal(t, adapter.UUID(), definedComp.UUID)
}

func TestControlImplementationSetAdapter(t *testing.T) {

testDataPath := filepath.Join("../../testdata", "component-definition-test.json")

file, err := os.Open(testDataPath)
require.NoError(t, err)
definition, err := models.NewComponentDefinition(file, validation.NoopValidator{})
require.NoError(t, err)
require.NotNil(t, definition)
require.NotNil(t, definition.Components)
comps := *definition.Components
require.Len(t, comps, 3)

comp := comps[0]
require.NotNil(t, comp.ControlImplementations)
implementations := *comp.ControlImplementations
adapter := NewControlImplementationSetAdapter(implementations[0])
require.Len(t, adapter.Props(), 0)
require.Len(t, adapter.SetParameters(), 1)
require.Len(t, adapter.Requirements(), 1)

impReq := adapter.Requirements()[0]
require.Len(t, impReq.SetParameters(), 0)
require.Len(t, impReq.Props(), 2)
require.Equal(t, "a1b5b713-52c7-46fb-ab57-ebac7f576b23", impReq.UUID())
require.Equal(t, "CIS-2.1", impReq.ControlID())
require.Len(t, impReq.Statements(), 1)

statement := impReq.Statements()[0]
require.Len(t, statement.Props(), 0)
require.Equal(t, "cb9219b1-e51c-4680-abb0-616a43bbfbb2", statement.UUID())
require.Equal(t, "CIS-2.1_smt", statement.StatementID())
}
69 changes: 0 additions & 69 deletions models/components/defined.go

This file was deleted.

41 changes: 0 additions & 41 deletions models/components/defined_test.go

This file was deleted.

2 changes: 1 addition & 1 deletion models/components/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
*/

// Package components defines logic for working with different defined OSCAL component types.
// Supported components type include DefinedComponent and will include SystemComponent.
// This provides a generic implementations of Components and associated Control Implementations.
package components
Loading
Loading