From c5df8154c7ef1547e4d0f68a994656c1c25ea2ab Mon Sep 17 00:00:00 2001
From: Jennifer Power <barnabei.jennifer@gmail.com>
Date: Fri, 14 Feb 2025 17:58:14 -0500
Subject: [PATCH 1/6] chore: add test data with example SSP

Signed-off-by: Jennifer Power <barnabei.jennifer@gmail.com>
---
 testdata/component-definition-test.json |   7 +
 testdata/test-ssp.json                  | 246 ++++++++++++++++++++++++
 2 files changed, 253 insertions(+)
 create mode 100644 testdata/test-ssp.json

diff --git a/testdata/component-definition-test.json b/testdata/component-definition-test.json
index 03138ce..4c51c9b 100644
--- a/testdata/component-definition-test.json
+++ b/testdata/component-definition-test.json
@@ -80,6 +80,13 @@
                     "ns": "https://oscal-compass.github.io/compliance-trestle/schemas/oscal/cd",
                     "value": "etcd_key_file"
                   }
+                ],
+                "statements": [
+                  {
+                    "statement-id": "CIS-2.1_smt",
+                    "uuid": "cb9219b1-e51c-4680-abb0-616a43bbfbb2",
+                    "description": ""
+                  }
                 ]
               }
             ]
diff --git a/testdata/test-ssp.json b/testdata/test-ssp.json
new file mode 100644
index 0000000..2676da5
--- /dev/null
+++ b/testdata/test-ssp.json
@@ -0,0 +1,246 @@
+{
+  "system-security-plan": {
+    "uuid": "05bc8eb4-4a8a-4b54-8c10-ee3eba2c401f",
+    "metadata": {
+      "title": "Test SSP",
+      "last-modified": "2023-04-27T15:44:08.070614+10:00",
+      "version": "0.1.0",
+      "oscal-version": "1.1.2"
+    },
+    "import-profile": {
+      "href": "profiles/example/profile.json"
+    },
+    "system-characteristics": {
+      "system-ids": [
+        {
+          "id": "REPLACE_ME"
+        }
+      ],
+      "system-name": "REPLACE_ME",
+      "description": "REPLACE_ME",
+      "security-sensitivity-level": "REPLACE_ME",
+      "system-information": {
+        "information-types": [
+          {
+            "title": "REPLACE_ME",
+            "description": "REPLACE_ME",
+            "confidentiality-impact": {
+              "base": "REPLACE_ME"
+            },
+            "integrity-impact": {
+              "base": "REPLACE_ME"
+            },
+            "availability-impact": {
+              "base": "REPLACE_ME"
+            }
+          }
+        ]
+      },
+      "security-impact-level": {
+        "security-objective-confidentiality": "REPLACE_ME",
+        "security-objective-integrity": "REPLACE_ME",
+        "security-objective-availability": "REPLACE_ME"
+      },
+      "status": {
+        "state": "operational"
+      },
+      "authorization-boundary": {
+        "description": "REPLACE_ME"
+      }
+    },
+    "system-implementation": {
+      "users": [
+        {
+          "uuid": "fce50e22-a3c4-4ee6-b397-f4b94e0d5e2d"
+        }
+      ],
+      "components": [
+        {
+          "uuid": "4e19131e-b361-4f0e-8262-02bf4456202e",
+          "type": "service",
+          "title": "Example Service",
+          "description": "An example service for SSP testing",
+          "props": [
+            {
+              "name": "Rule_Id",
+              "ns": "https://oscal-compass.github.io/compliance-trestle/schemas/oscal/cd",
+              "value": "rule-1",
+              "remarks": "rule_set_00"
+            },
+            {
+              "name": "Rule_Description",
+              "ns": "https://oscal-compass.github.io/compliance-trestle/schemas/oscal/cd",
+              "value": "Rule 1 description",
+              "remarks": "rule_set_00"
+            },
+            {
+              "name": "Parameter_Id",
+              "ns": "https://oscal-compass.github.io/compliance-trestle/schemas/oscal/cd",
+              "value": "param-1",
+              "remarks": "rule_set_00"
+            },
+            {
+              "name": "Parameter_Description",
+              "ns": "https://oscal-compass.github.io/compliance-trestle/schemas/oscal/cd",
+              "value": "Param 1 description",
+              "remarks": "rule_set_00"
+            },
+            {
+              "name": "Parameter_Value_Alternatives",
+              "ns": "https://oscal-compass.github.io/compliance-trestle/schemas/oscal/cd",
+              "value": "1, 2, 3",
+              "remarks": "rule_set_00"
+            },
+            {
+              "name": "Rule_Id",
+              "ns": "https://oscal-compass.github.io/compliance-trestle/schemas/oscal/cd",
+              "value": "rule-2",
+              "remarks": "rule_set_01"
+            },
+            {
+              "name": "Rule_Description",
+              "ns": "https://oscal-compass.github.io/compliance-trestle/schemas/oscal/cd",
+              "value": "Rule 2 description",
+              "remarks": "rule_set_01"
+            }
+          ],
+          "status": {
+            "state": "REPLACE_ME"
+          }
+        },
+        {
+          "uuid": "ceb0b4b0-8b3c-4e71-8874-57d42c0f36e3",
+          "type": "this-system",
+          "title": "This System",
+          "description": "",
+          "status": {
+            "state": "REPLACE_ME"
+          }
+        },
+        {
+          "uuid": "701c70f1-482b-42b0-a419-9870158cd9e2",
+          "type": "validation",
+          "title": "Validator",
+          "description": "An example validation component",
+          "props": [
+            {
+              "name": "Rule_Id",
+              "ns": "https://oscal-compass.github.io/compliance-trestle/schemas/oscal/cd",
+              "value": "rule-1",
+              "remarks": "rule_set_00"
+            },
+            {
+              "name": "Rule_Description",
+              "ns": "https://oscal-compass.github.io/compliance-trestle/schemas/oscal/cd",
+              "value": "Rule 1 description",
+              "remarks": "rule_set_00"
+            },
+            {
+              "name": "Check_Id",
+              "ns": "https://oscal-compass.github.io/compliance-trestle/schemas/oscal/cd",
+              "value": "check-1",
+              "remarks": "rule_set_00"
+            },
+            {
+              "name": "Check_Description",
+              "ns": "https://oscal-compass.github.io/compliance-trestle/schemas/oscal/cd",
+              "value": "Check 1 Description",
+              "remarks": "rule_set_00"
+            }
+          ]
+        }
+      ]
+    },
+    "control-implementation": {
+      "description": "This is an example control implementation for the system.",
+      "implemented-requirements": [
+        {
+          "uuid": "db7b97db-dadc-4afd-850a-245ca09cb811",
+          "control-id": "ex-1",
+          "statements": [
+            {
+              "statement-id": "ex-1_smt",
+              "uuid": "7ad47329-dc55-4196-a19d-178a8fe7438e",
+              "by-components": [
+                {
+                  "component-uuid": "a95533ab-9427-4abe-820f-0b571bacfe6d",
+                  "uuid": "a64681b2-fbcb-46eb-90fd-0d55aa74ac7c",
+                  "description": "Example 1 Statement Implementation",
+                  "props": [
+                    {
+                      "name": "Rule_Id",
+                      "ns": "https://oscal-compass.github.io/compliance-trestle/schemas/oscal/cd",
+                      "value": "rule-1"
+                    }
+                  ]
+                }
+                ]
+            }
+          ],
+          "by-components": [
+            {
+              "component-uuid": "4e19131e-b361-4f0e-8262-02bf4456202e",
+              "uuid": "126b5dcd-30cc-4521-9aa8-5f9f6781a6c4",
+              "description": "Example 1 implementation",
+              "props": [
+                {
+                  "name": "Rule_Id",
+                  "ns": "https://oscal-compass.github.io/compliance-trestle/schemas/oscal/cd",
+                  "value": "rule-2"
+                }
+              ],
+              "implementation-status": {
+                "state": "planned"
+              }
+            },
+            {
+              "component-uuid": "ceb0b4b0-8b3c-4e71-8874-57d42c0f36e3",
+              "uuid": "04deed1d-87c2-4ec6-8a6c-5973511d8758",
+              "description": "",
+              "implementation-status": {
+                "state": "planned"
+              }
+            }
+          ]
+        },
+        {
+          "uuid": "08e93a77-16e3-4881-9694-e77f114a164b",
+          "control-id": "ex-2",
+          "by-components": [
+            {
+              "component-uuid": "4e19131e-b361-4f0e-8262-02bf4456202e",
+              "uuid": "d93f7198-5ea9-4add-a279-7428098e9b48",
+              "description": "Example 2 implementation",
+              "props": [
+                {
+                  "name": "Rule_Id",
+                  "ns": "https://oscal-compass.github.io/compliance-trestle/schemas/oscal/cd",
+                  "value": "rule-1"
+                }
+              ],
+              "set-parameters": [
+                {
+                  "param-id": "param-1",
+                  "values": [
+                    "2"
+                  ]
+                }
+              ],
+              "implementation-status": {
+                "state": "planned"
+              }
+            },
+            {
+              "component-uuid": "ceb0b4b0-8b3c-4e71-8874-57d42c0f36e3",
+              "uuid": "7c045a8d-74c6-4047-a17f-b6661660b332",
+              "description": "",
+              "implementation-status": {
+                "state": "planned"
+              }
+            }
+          ]
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file

From 20e8e26980224d2d00be577388c5f5470cd766de Mon Sep 17 00:00:00 2001
From: Jennifer Power <barnabei.jennifer@gmail.com>
Date: Fri, 14 Feb 2025 18:00:27 -0500
Subject: [PATCH 2/6] feat: add generic implementation of ControlImplementation
 types

To reuse existing Implementation parsing logic implemented for Component Definitions,
generic implementation of ControlImplementation, ImplementedRequirement, and
Statements are added.

Signed-off-by: Jennifer Power <barnabei.jennifer@gmail.com>
---
 models/components/component_definition.go     | 188 ++++++++++++++++
 .../components/component_definition_test.go   |  75 +++++++
 models/components/defined.go                  |  69 ------
 models/components/defined_test.go             |  41 ----
 models/components/doc.go                      |   2 +-
 models/components/implementation.go           |  50 +++++
 models/components/ssp.go                      | 204 ++++++++++++++++++
 models/components/ssp_test.go                 |  67 ++++++
 8 files changed, 585 insertions(+), 111 deletions(-)
 create mode 100644 models/components/component_definition.go
 create mode 100644 models/components/component_definition_test.go
 delete mode 100644 models/components/defined.go
 delete mode 100644 models/components/defined_test.go
 create mode 100644 models/components/implementation.go
 create mode 100644 models/components/ssp.go
 create mode 100644 models/components/ssp_test.go

diff --git a/models/components/component_definition.go b/models/components/component_definition.go
new file mode 100644
index 0000000..6dda888
--- /dev/null
+++ b/models/components/component_definition.go
@@ -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
+}
diff --git a/models/components/component_definition_test.go b/models/components/component_definition_test.go
new file mode 100644
index 0000000..137c070
--- /dev/null
+++ b/models/components/component_definition_test.go
@@ -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())
+}
diff --git a/models/components/defined.go b/models/components/defined.go
deleted file mode 100644
index 5c5b681..0000000
--- a/models/components/defined.go
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- 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"
-
-	"github.com/oscal-compass/oscal-sdk-go/models"
-)
-
-var _ Component = (*DefinedComponentAdapter)(nil)
-
-// 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: models.SampleRequiredString,
-		},
-		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
-}
diff --git a/models/components/defined_test.go b/models/components/defined_test.go
deleted file mode 100644
index f140f02..0000000
--- a/models/components/defined_test.go
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- 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)
-}
diff --git a/models/components/doc.go b/models/components/doc.go
index 866601c..637c69d 100644
--- a/models/components/doc.go
+++ b/models/components/doc.go
@@ -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
diff --git a/models/components/implementation.go b/models/components/implementation.go
new file mode 100644
index 0000000..ee73985
--- /dev/null
+++ b/models/components/implementation.go
@@ -0,0 +1,50 @@
+/*
+ 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"
+
+// Implementation is an interface representing a generic control implementation for
+// a component that is present in an OSCAL Component Definition and an OSCAL SSP in
+// different forms.
+type Implementation interface {
+	// Requirements returns a slice of implemented requirements associated to
+	// the implementation.
+	Requirements() []Requirement
+	// SetParameters returns a list of OSCAL set-parameters associated with the implementation.
+	SetParameters() []oscalTypes.SetParameter
+	// Props returns a list of OSCAL properties associated with the implementation.
+	Props() []oscalTypes.Property
+}
+
+// Requirement is an interface representing a generic implemented requirement
+// for a component that is present in an OSCAL Component Definition and an OSCAL SSP in
+// different forms.
+type Requirement interface {
+	// ControlID  returns the associated human-readable identifier for the requirement.
+	ControlID() string
+	// UUID returns the requirement assembly UUID
+	UUID() string
+	// SetParameters returns a list of OSCAL set-parameters associated with the requirement.
+	SetParameters() []oscalTypes.SetParameter
+	// Props returns a list of OSCAL properties associated with the requirement.
+	Props() []oscalTypes.Property
+	// Statements returns a slice of statements or implemented requirement parts associated
+	// with an implemented requirement.
+	Statements() []Statement
+}
+
+// Statement is an interface representing an implemented statement or
+// sub-requirement for a component that is present in an OSCAL Component Definition and an OSCAL SSP in
+// different forms.
+type Statement interface {
+	// StatementID returns the associated human-readable identifier for the statement.
+	StatementID() string
+	// UUID returns the statement assembly UUID
+	UUID() string
+	// Props returns a list of OSCAL properties associated with the statement.
+	Props() []oscalTypes.Property
+}
diff --git a/models/components/ssp.go b/models/components/ssp.go
new file mode 100644
index 0000000..9f9987d
--- /dev/null
+++ b/models/components/ssp.go
@@ -0,0 +1,204 @@
+/*
+ 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 implementations for SSP structures
+var (
+	_ Component      = (*SystemComponentAdapter)(nil)
+	_ Implementation = (*ControlImplementationAdapter)(nil)
+	_ Requirement    = (*ImplementedRequirementAdapter)(nil)
+	_ Statement      = (*StatementAdapter)(nil)
+)
+
+// SystemComponentAdapter wraps an OSCAL SystemComponent to
+// provide methods for compatibility with Component.
+type SystemComponentAdapter struct {
+	systemComp oscalTypes.SystemComponent
+}
+
+// NewSystemComponentAdapter returns an initialized SystemComponentAdapter from a given
+// SystemComponent.
+func NewSystemComponentAdapter(systemComponent oscalTypes.SystemComponent) *SystemComponentAdapter {
+	return &SystemComponentAdapter{
+		systemComp: systemComponent,
+	}
+}
+
+func (s *SystemComponentAdapter) UUID() string {
+	return s.systemComp.UUID
+}
+
+func (s *SystemComponentAdapter) Title() string {
+	return s.systemComp.Title
+}
+
+func (s *SystemComponentAdapter) Type() ComponentType {
+	return ComponentType(s.systemComp.Type)
+}
+
+func (s *SystemComponentAdapter) AsDefinedComponent() (oscalTypes.DefinedComponent, bool) {
+	return oscalTypes.DefinedComponent{
+		Description:      s.systemComp.Description,
+		Links:            s.systemComp.Links,
+		Props:            s.systemComp.Props,
+		Protocols:        s.systemComp.Protocols,
+		Purpose:          s.systemComp.Purpose,
+		Remarks:          s.systemComp.Remarks,
+		ResponsibleRoles: s.systemComp.ResponsibleRoles,
+		Title:            s.systemComp.Title,
+		Type:             s.systemComp.Type,
+		UUID:             s.systemComp.UUID,
+	}, true
+}
+
+func (s *SystemComponentAdapter) AsSystemComponent() (oscalTypes.SystemComponent, bool) {
+	return s.systemComp, true
+}
+
+func (s *SystemComponentAdapter) Props() []oscalTypes.Property {
+	if s.systemComp.Props == nil {
+		return []oscalTypes.Property{}
+	}
+	return *s.systemComp.Props
+}
+
+// ControlImplementationAdapter wraps an OSCAL ControlImplementation to provide
+// methods for compatibility with Implementation.
+type ControlImplementationAdapter struct {
+	controlImp oscalTypes.ControlImplementation
+}
+
+// NewControlImplementationAdapter returns an initialized ControlImplementationAdapter from a given
+// ControlImplementation from an OSCAL SSP.
+func NewControlImplementationAdapter(controlImp oscalTypes.ControlImplementation) *ControlImplementationAdapter {
+	return &ControlImplementationAdapter{
+		controlImp: controlImp,
+	}
+}
+
+func (c *ControlImplementationAdapter) Requirements() []Requirement {
+	var requirements []Requirement
+	for _, requirement := range c.controlImp.ImplementedRequirements {
+		requirementAdapter := NewImplementedRequirementAdapter(requirement)
+		requirements = append(requirements, requirementAdapter)
+	}
+	return requirements
+}
+
+func (c *ControlImplementationAdapter) SetParameters() []oscalTypes.SetParameter {
+	if c.controlImp.SetParameters == nil {
+		return []oscalTypes.SetParameter{}
+	}
+	return *c.controlImp.SetParameters
+}
+
+func (c *ControlImplementationAdapter) Props() []oscalTypes.Property {
+	// TODO: Where does this go in the SSP?
+	return []oscalTypes.Property{}
+}
+
+// ImplementedRequirementAdapter wraps an OSCAL ImplementedRequirement to provide
+// methods for compatibility with Requirement.
+type ImplementedRequirementAdapter struct {
+	impReq oscalTypes.ImplementedRequirement
+}
+
+// NewImplementedRequirementAdapter returns an initialized ImplementedRequirementAdapter from a given
+// ImplementedRequirement from an OSCAL SSP.
+func NewImplementedRequirementAdapter(impReq oscalTypes.ImplementedRequirement) *ImplementedRequirementAdapter {
+	return &ImplementedRequirementAdapter{
+		impReq: impReq,
+	}
+}
+
+func (i *ImplementedRequirementAdapter) ControlID() string {
+	return i.impReq.ControlId
+}
+
+func (i *ImplementedRequirementAdapter) UUID() string {
+	return i.impReq.UUID
+}
+
+func (i *ImplementedRequirementAdapter) SetParameters() []oscalTypes.SetParameter {
+	if i.impReq.SetParameters == nil {
+		return []oscalTypes.SetParameter{}
+	}
+	return *i.impReq.SetParameters
+}
+
+func (i *ImplementedRequirementAdapter) Props() []oscalTypes.Property {
+	var oscalProps []oscalTypes.Property
+	if i.impReq.Props != nil {
+		oscalProps = append(oscalProps, *i.impReq.Props...)
+	}
+
+	if i.impReq.ByComponents == nil {
+
+		return oscalProps
+	}
+
+	for _, byComp := range *i.impReq.ByComponents {
+		if byComp.Props != nil {
+			oscalProps = append(oscalProps, *byComp.Props...)
+		}
+	}
+	return oscalProps
+}
+
+func (i *ImplementedRequirementAdapter) Statements() []Statement {
+	var statements []Statement
+	if i.impReq.Statements == nil {
+		return statements
+	}
+	for _, stm := range *i.impReq.Statements {
+		stmAdapter := NewStatementAdapter(stm)
+		statements = append(statements, stmAdapter)
+	}
+
+	return statements
+}
+
+// StatementAdapter wraps an OSCAL Statement to provide
+// methods for compatibility with Statement.
+type StatementAdapter struct {
+	stm oscalTypes.Statement
+}
+
+// NewStatementAdapter returns an initialized StatementAdapter from a given
+// Statement from an OSCAL SSP.
+func NewStatementAdapter(statement oscalTypes.Statement) *StatementAdapter {
+	return &StatementAdapter{
+		stm: statement,
+	}
+}
+
+func (s *StatementAdapter) StatementID() string {
+	return s.stm.StatementId
+}
+
+func (s *StatementAdapter) UUID() string {
+	return s.stm.UUID
+}
+
+func (s *StatementAdapter) Props() []oscalTypes.Property {
+	var oscalProps []oscalTypes.Property
+	if s.stm.Props != nil {
+		oscalProps = append(oscalProps, *s.stm.Props...)
+	}
+
+	if s.stm.ByComponents == nil {
+		return oscalProps
+	}
+
+	for _, byComp := range *s.stm.ByComponents {
+		if byComp.Props != nil {
+			oscalProps = append(oscalProps, *byComp.Props...)
+		}
+	}
+	return oscalProps
+}
diff --git a/models/components/ssp_test.go b/models/components/ssp_test.go
new file mode 100644
index 0000000..3a345d3
--- /dev/null
+++ b/models/components/ssp_test.go
@@ -0,0 +1,67 @@
+/*
+ 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 TestSystemComponentAdapter(t *testing.T) {
+	testDataPath := filepath.Join("../../testdata", "test-ssp.json")
+
+	file, err := os.Open(testDataPath)
+	require.NoError(t, err)
+	ssp, err := models.NewSystemSecurityPlan(file, validation.NoopValidator{})
+	require.NoError(t, err)
+	require.NotNil(t, ssp)
+
+	require.Len(t, ssp.SystemImplementation.Components, 3)
+	adapter := NewSystemComponentAdapter(ssp.SystemImplementation.Components[0])
+	require.Equal(t, "Example Service", adapter.Title())
+	require.Equal(t, Service, adapter.Type())
+	require.Equal(t, "4e19131e-b361-4f0e-8262-02bf4456202e", adapter.UUID())
+	require.Len(t, adapter.Props(), 7)
+	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 TestControlImplementationAdapter(t *testing.T) {
+	testDataPath := filepath.Join("../../testdata", "test-ssp.json")
+
+	file, err := os.Open(testDataPath)
+	require.NoError(t, err)
+	ssp, err := models.NewSystemSecurityPlan(file, validation.NoopValidator{})
+	require.NoError(t, err)
+	require.NotNil(t, ssp)
+
+	adapter := NewControlImplementationAdapter(ssp.ControlImplementation)
+	require.Len(t, adapter.Requirements(), 2)
+	require.Len(t, adapter.SetParameters(), 0)
+	require.Len(t, adapter.Props(), 0)
+
+	impReq := adapter.Requirements()[0]
+	require.Len(t, impReq.SetParameters(), 0)
+	require.Len(t, impReq.Props(), 1)
+	require.Equal(t, "db7b97db-dadc-4afd-850a-245ca09cb811", impReq.UUID())
+	require.Equal(t, "ex-1", impReq.ControlID())
+	require.Len(t, impReq.Statements(), 1)
+
+	statement := impReq.Statements()[0]
+	require.Len(t, statement.Props(), 1)
+	require.Equal(t, "7ad47329-dc55-4196-a19d-178a8fe7438e", statement.UUID())
+	require.Equal(t, "ex-1_smt", statement.StatementID())
+}

From 95a302744b5f65e8263503a7505606e7e09ccadc Mon Sep 17 00:00:00 2001
From: Jennifer Power <barnabei.jennifer@gmail.com>
Date: Fri, 14 Feb 2025 18:04:30 -0500
Subject: [PATCH 3/6] feat: add generic implementation as inputs for Settings
 creation

Signed-off-by: Jennifer Power <barnabei.jennifer@gmail.com>
---
 settings/doc.go                 |  5 +--
 settings/factory.go             | 61 ++++++++++++++-------------------
 settings/factory_test.go        |  4 ++-
 settings/framework.go           |  6 ++--
 settings/implementation.go      | 23 ++++++-------
 settings/implementation_test.go |  4 ++-
 settings/settings.go            |  7 +++-
 settings/settings_test.go       |  2 +-
 8 files changed, 57 insertions(+), 55 deletions(-)

diff --git a/settings/doc.go b/settings/doc.go
index c5b7041..9339e99 100644
--- a/settings/doc.go
+++ b/settings/doc.go
@@ -3,6 +3,7 @@
  SPDX-License-Identifier: Apache-2.0
 */
 
-// Package settings defines logic relating to processing implementation and
-// implemented requirements for framework or requirement specific settings for the usage of RuleSets.
+// Package settings defines logic relating to compliance framework specific
+// settings for tailoring available component RuleSets for specific implementation or
+// assessment.
 package settings
diff --git a/settings/factory.go b/settings/factory.go
index 0a358a3..521896e 100644
--- a/settings/factory.go
+++ b/settings/factory.go
@@ -10,6 +10,7 @@ import (
 
 	"github.com/oscal-compass/oscal-sdk-go/extensions"
 	"github.com/oscal-compass/oscal-sdk-go/internal/set"
+	"github.com/oscal-compass/oscal-sdk-go/models/components"
 )
 
 // NewSettings returns a new Settings instance with given rules and associated rule parameters.
@@ -22,26 +23,23 @@ func NewSettings(rules map[string]struct{}, parameters map[string]string) Settin
 
 // NewImplementationSettings returns ImplementationSettings populated with data from an OSCAL Control Implementation
 // Set and the nested Implemented Requirements.
-func NewImplementationSettings(controlImplementation oscalTypes.ControlImplementationSet) *ImplementationSettings {
+func NewImplementationSettings(controlImplementation components.Implementation) *ImplementationSettings {
 	implementation := &ImplementationSettings{
 		implementedReqSettings: make(map[string]Settings),
 		settings:               NewSettings(set.New[string](), make(map[string]string)),
 		controlsByRules:        make(map[string]set.Set[string]),
 		controlsById:           make(map[string]oscalTypes.AssessedControlsSelectControlById),
 	}
-	if controlImplementation.SetParameters != nil {
-		setParameters(*controlImplementation.SetParameters, implementation.settings.selectedParameters)
-	}
+	setParameters(controlImplementation.SetParameters(), implementation.settings.selectedParameters)
 
-	for _, implementedReq := range controlImplementation.ImplementedRequirements {
-		newRequirementForImplementation(implementedReq, implementation)
+	for _, requirement := range controlImplementation.Requirements() {
+		newRequirementForImplementation(requirement, implementation)
 	}
 
 	return implementation
 }
 
-// NewAssessmentActivitiesSettings returns a new Setting populated based on data from OSCAL Assessment Plan
-// Activities.
+// NewAssessmentActivitiesSettings returns a new Setting populate based on data from OSCAL Activities
 //
 // The mapping between a RuleSet and Activity is as follows:
 // Activity -> Rule
@@ -71,10 +69,12 @@ func NewAssessmentActivitiesSettings(assessmentActivities []oscalTypes.Activity)
 	}
 }
 
-// newRequirementForImplementation adds a new Setting to an existing ImplementationSettings and updates all related fields.
-func newRequirementForImplementation(implementedReq oscalTypes.ImplementedRequirementControlImplementation, implementation *ImplementationSettings) {
+//	newRequirementForImplementation adds a new Setting to an existing ImplementationSettings and updates all related
+//
+// fields.
+func newRequirementForImplementation(implementedReq components.Requirement, implementation *ImplementationSettings) {
 	implementedControl := oscalTypes.AssessedControlsSelectControlById{
-		ControlId: implementedReq.ControlId,
+		ControlId: implementedReq.ControlID(),
 	}
 	requirement := settingsFromImplementedRequirement(implementedReq)
 
@@ -85,44 +85,35 @@ func newRequirementForImplementation(implementedReq oscalTypes.ImplementedRequir
 			if !ok {
 				controlSet = set.New[string]()
 			}
-			controlSet.Add(implementedReq.ControlId)
+			controlSet.Add(implementedReq.ControlID())
 			implementation.controlsByRules[mappedRule] = controlSet
-			implementation.controlsById[implementedReq.ControlId] = implementedControl
+			implementation.controlsById[implementedReq.ControlID()] = implementedControl
 			implementation.settings.mappedRules.Add(mappedRule)
 		}
 
-		implementation.implementedReqSettings[implementedReq.ControlId] = requirement
+		implementation.implementedReqSettings[implementedReq.ControlID()] = requirement
 	}
 }
 
 // settingsFromImplementedRequirement returns Settings populated with data from an
 // OSCAL Implemented Requirement.
-func settingsFromImplementedRequirement(implementedReq oscalTypes.ImplementedRequirementControlImplementation) Settings {
+func settingsFromImplementedRequirement(implementedReq components.Requirement) Settings {
 	requirement := NewSettings(set.New[string](), make(map[string]string))
 
-	if implementedReq.Props != nil {
-		mappedRulesProps := extensions.FindAllProps(*implementedReq.Props, extensions.WithName(extensions.RuleIdProp))
-		for _, mappedRule := range mappedRulesProps {
-			requirement.mappedRules.Add(mappedRule.Value)
-		}
-	}
-
-	if implementedReq.SetParameters != nil {
-		setParameters(*implementedReq.SetParameters, requirement.selectedParameters)
+	mappedRulesProps := extensions.FindAllProps(implementedReq.Props(), extensions.WithName(extensions.RuleIdProp))
+	for _, mappedRule := range mappedRulesProps {
+		requirement.mappedRules.Add(mappedRule.Value)
 	}
 
-	if implementedReq.Statements != nil {
-		for _, stm := range *implementedReq.Statements {
-			if stm.Props != nil {
-				mappedRulesProps := extensions.FindAllProps(*stm.Props, extensions.WithName(extensions.RuleIdProp))
-				if len(mappedRulesProps) == 0 {
-					continue
-				}
-				for _, mappedRule := range mappedRulesProps {
-					requirement.mappedRules.Add(mappedRule.Value)
-				}
-			}
+	setParameters(implementedReq.SetParameters(), requirement.selectedParameters)
 
+	for _, stm := range implementedReq.Statements() {
+		mappedRulesStmProps := extensions.FindAllProps(stm.Props(), extensions.WithName(extensions.RuleIdProp))
+		if len(mappedRulesStmProps) == 0 {
+			continue
+		}
+		for _, mappedRule := range mappedRulesStmProps {
+			requirement.mappedRules.Add(mappedRule.Value)
 		}
 	}
 
diff --git a/settings/factory_test.go b/settings/factory_test.go
index 7bf7612..f309f91 100644
--- a/settings/factory_test.go
+++ b/settings/factory_test.go
@@ -13,6 +13,7 @@ import (
 
 	"github.com/oscal-compass/oscal-sdk-go/extensions"
 	"github.com/oscal-compass/oscal-sdk-go/internal/set"
+	"github.com/oscal-compass/oscal-sdk-go/models/components"
 )
 
 func TestSettingsFromImplementedRequirements(t *testing.T) {
@@ -109,7 +110,8 @@ func TestSettingsFromImplementedRequirements(t *testing.T) {
 
 	for _, c := range tests {
 		t.Run(c.name, func(t *testing.T) {
-			gotSettings := settingsFromImplementedRequirement(c.inputRequirement)
+			adapter := components.NewImplementedRequirementImplementationAdapter(c.inputRequirement)
+			gotSettings := settingsFromImplementedRequirement(adapter)
 			require.Equal(t, c.wantSettings, gotSettings)
 		})
 	}
diff --git a/settings/framework.go b/settings/framework.go
index 0dda6ba..8bb53eb 100644
--- a/settings/framework.go
+++ b/settings/framework.go
@@ -13,6 +13,7 @@ import (
 	oscalTypes "github.com/defenseunicorns/go-oscal/src/types/oscal-1-1-2"
 
 	"github.com/oscal-compass/oscal-sdk-go/extensions"
+	"github.com/oscal-compass/oscal-sdk-go/models/components"
 )
 
 // GetFrameworkShortName returns the human-readable short name for the control source in a
@@ -52,11 +53,12 @@ func Framework(framework string, controlImplementations []oscalTypes.ControlImpl
 
 	for _, controlImplementation := range controlImplementations {
 		frameworkShortName, found := GetFrameworkShortName(controlImplementation)
+		implementationAdapter := components.NewControlImplementationSetAdapter(controlImplementation)
 		if found && frameworkShortName == framework {
 			if implementationSettings == nil {
-				implementationSettings = NewImplementationSettings(controlImplementation)
+				implementationSettings = NewImplementationSettings(implementationAdapter)
 			} else {
-				implementationSettings.merge(controlImplementation)
+				implementationSettings.merge(implementationAdapter)
 			}
 		}
 	}
diff --git a/settings/implementation.go b/settings/implementation.go
index f7ab8e7..310eac1 100644
--- a/settings/implementation.go
+++ b/settings/implementation.go
@@ -11,6 +11,7 @@ import (
 	oscalTypes "github.com/defenseunicorns/go-oscal/src/types/oscal-1-1-2"
 
 	"github.com/oscal-compass/oscal-sdk-go/internal/set"
+	"github.com/oscal-compass/oscal-sdk-go/models/components"
 )
 
 // ImplementationSettings defines settings for RuleSets defined at the control
@@ -79,18 +80,16 @@ func (i *ImplementationSettings) ApplicableControls(ruleId string) ([]oscalTypes
 
 // merge another ImplementationSettings into the ImplementationSettings. Existing settings at the
 // requirements level are also merged.
-func (i *ImplementationSettings) merge(inputImplementation oscalTypes.ControlImplementationSet) {
-	if inputImplementation.SetParameters != nil {
-		setParameters(*inputImplementation.SetParameters, i.settings.selectedParameters)
-	}
+func (i *ImplementationSettings) merge(inputImplementation components.Implementation) {
+	setParameters(inputImplementation.SetParameters(), i.settings.selectedParameters)
 
-	for _, implementedReq := range inputImplementation.ImplementedRequirements {
-		requirement, ok := i.implementedReqSettings[implementedReq.ControlId]
+	for _, requirement := range inputImplementation.Requirements() {
+		reqSettings, ok := i.implementedReqSettings[requirement.ControlID()]
 		if !ok {
-			newRequirementForImplementation(implementedReq, i)
+			newRequirementForImplementation(requirement, i)
 		} else {
 
-			inputRequirement := settingsFromImplementedRequirement(implementedReq)
+			inputRequirement := settingsFromImplementedRequirement(requirement)
 			if len(inputRequirement.mappedRules) == 0 {
 				continue
 			}
@@ -100,15 +99,15 @@ func (i *ImplementationSettings) merge(inputImplementation oscalTypes.ControlImp
 				if !ok {
 					controlSet = set.New[string]()
 				}
-				controlSet.Add(implementedReq.ControlId)
+				controlSet.Add(requirement.ControlID())
 				i.controlsByRules[mappedRule] = controlSet
 				i.settings.mappedRules.Add(mappedRule)
-				requirement.mappedRules.Add(mappedRule)
+				reqSettings.mappedRules.Add(mappedRule)
 			}
 			for name, value := range inputRequirement.selectedParameters {
-				requirement.selectedParameters[name] = value
+				reqSettings.selectedParameters[name] = value
 			}
-			i.implementedReqSettings[implementedReq.ControlId] = requirement
+			i.implementedReqSettings[requirement.ControlID()] = reqSettings
 		}
 	}
 }
diff --git a/settings/implementation_test.go b/settings/implementation_test.go
index dad280e..934a795 100644
--- a/settings/implementation_test.go
+++ b/settings/implementation_test.go
@@ -16,6 +16,7 @@ import (
 	"github.com/oscal-compass/oscal-sdk-go/extensions"
 	"github.com/oscal-compass/oscal-sdk-go/internal/set"
 	"github.com/oscal-compass/oscal-sdk-go/models"
+	"github.com/oscal-compass/oscal-sdk-go/models/components"
 	"github.com/oscal-compass/oscal-sdk-go/validation"
 )
 
@@ -234,7 +235,8 @@ func TestMerge(t *testing.T) {
 	for _, c := range tests {
 		t.Run(c.name, func(t *testing.T) {
 			testSettings := prepSettings(t)
-			testSettings.merge(c.inputImplementation)
+			adapter := components.NewControlImplementationSetAdapter(c.inputImplementation)
+			testSettings.merge(adapter)
 			require.Equal(t, c.wantSettings, *testSettings)
 		})
 	}
diff --git a/settings/settings.go b/settings/settings.go
index 5dfd595..6f068b9 100644
--- a/settings/settings.go
+++ b/settings/settings.go
@@ -7,6 +7,7 @@ package settings
 
 import (
 	"context"
+	"errors"
 	"fmt"
 
 	"github.com/oscal-compass/oscal-sdk-go/extensions"
@@ -14,6 +15,10 @@ import (
 	"github.com/oscal-compass/oscal-sdk-go/rules"
 )
 
+// ErrRulesNotFound defines an error returned when there are not intersecting ruleSet store
+// for a component and in the given Settings.
+var ErrRulesNotFound = errors.New("no rules found with criteria")
+
 // Settings defines settings for RuleSets to tune options based in the
 // target baseline or compliance goals.
 type Settings struct {
@@ -64,7 +69,7 @@ func ApplyToComponent(ctx context.Context, componentId string, store rules.Store
 		resolvedRules = append(resolvedRules, ruleSet)
 	}
 	if len(resolvedRules) == 0 {
-		return []extensions.RuleSet{}, fmt.Errorf("no rules found with criteria for component %s", componentId)
+		return []extensions.RuleSet{}, fmt.Errorf("component %s: %w", componentId, ErrRulesNotFound)
 	}
 	return resolvedRules, nil
 }
diff --git a/settings/settings_test.go b/settings/settings_test.go
index f2e39e6..1ebeebe 100644
--- a/settings/settings_test.go
+++ b/settings/settings_test.go
@@ -84,7 +84,7 @@ func TestApplyToComponents(t *testing.T) {
 					"doesnotexists": struct{}{},
 				},
 			},
-			expError: "no rules found with criteria for component testComponent1",
+			expError: "component testComponent1: no rules found with criteria",
 		},
 	}
 

From 6285eeb5ec274617c6b8472ebccf0f448fb34206 Mon Sep 17 00:00:00 2001
From: Jennifer Power <barnabei.jennifer@gmail.com>
Date: Fri, 14 Feb 2025 18:04:54 -0500
Subject: [PATCH 4/6] feat: add top-level transformer for OSCAL SSP to OSCAL AP

Signed-off-by: Jennifer Power <barnabei.jennifer@gmail.com>
---
 transformers/transformer_test.go | 29 ++++++++++++++++++++++++++++-
 transformers/transformers.go     | 22 ++++++++++++++++++++++
 2 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/transformers/transformer_test.go b/transformers/transformer_test.go
index 4d69a14..7118184 100644
--- a/transformers/transformer_test.go
+++ b/transformers/transformer_test.go
@@ -34,7 +34,6 @@ func TestComponentDefinitionsToAssessmentPlan(t *testing.T) {
 	require.Len(t, *plan.LocalDefinitions.Activities, 2)
 	require.Len(t, *plan.AssessmentAssets.Components, 2)
 	require.Len(t, *plan.AssessmentSubjects, 1)
-	require.Len(t, *plan.AssessmentAssets.Components, 2)
 	require.Len(t, plan.ReviewedControls.ControlSelections, 1)
 	require.Len(t, *plan.Tasks, 1)
 	tasks := *plan.Tasks
@@ -47,3 +46,31 @@ func TestComponentDefinitionsToAssessmentPlan(t *testing.T) {
 	require.Contains(t, activities, "etcd_cert_file")
 	require.Contains(t, activities, "etcd_key_file")
 }
+
+func TestSSPToAssessmentPlan(t *testing.T) {
+	testDataPath := filepath.Join("../testdata", "test-ssp.json")
+
+	file, err := os.Open(testDataPath)
+	require.NoError(t, err)
+	ssp, err := models.NewSystemSecurityPlan(file, validation.NoopValidator{})
+	require.NoError(t, err)
+	require.NotNil(t, ssp)
+
+	plan, err := SSPToAssessmentPlan(context.TODO(), *ssp, "importPath")
+	require.NoError(t, err)
+
+	require.Len(t, *plan.LocalDefinitions.Activities, 2)
+	require.Len(t, *plan.AssessmentAssets.Components, 1)
+	require.Len(t, *plan.AssessmentSubjects, 1)
+	require.Len(t, plan.ReviewedControls.ControlSelections, 1)
+	require.Len(t, *plan.Tasks, 1)
+	tasks := *plan.Tasks
+	require.Len(t, *tasks[0].AssociatedActivities, 2)
+
+	var activities []string
+	for _, act := range *plan.LocalDefinitions.Activities {
+		activities = append(activities, act.Title)
+	}
+	require.Contains(t, activities, "rule-1")
+	require.Contains(t, activities, "rule-2")
+}
diff --git a/transformers/transformers.go b/transformers/transformers.go
index 181698d..7f20daa 100644
--- a/transformers/transformers.go
+++ b/transformers/transformers.go
@@ -41,3 +41,25 @@ func ComponentDefinitionsToAssessmentPlan(ctx context.Context, definitions []osc
 	}
 	return plans.GenerateAssessmentPlan(ctx, allComponents, *implementationSettings)
 }
+
+// SSPToAssessmentPlan transforms the data from a System Security Plan at a given import location to a single OSCAL Assessment Plan.
+func SSPToAssessmentPlan(ctx context.Context, ssp oscalTypes.SystemSecurityPlan, sspImportPath string) (*oscalTypes.AssessmentPlan, error) {
+	var allComponents []components.Component
+	for _, sysComp := range ssp.SystemImplementation.Components {
+		componentAdapter := components.NewSystemComponentAdapter(sysComp)
+		// Skip any components that don't have attached rules
+		// For an SSP, this is likely the "This System" component
+		if len(componentAdapter.Props()) == 0 || componentAdapter.Title() == "This System" {
+			continue
+		}
+		allComponents = append(allComponents, componentAdapter)
+	}
+	implementationAdapter := components.NewControlImplementationAdapter(ssp.ControlImplementation)
+	implementationSettings := settings.NewImplementationSettings(implementationAdapter)
+
+	if implementationSettings == nil {
+		return nil, fmt.Errorf("cannot transform ssp for at path %s", sspImportPath)
+	}
+
+	return plans.GenerateAssessmentPlan(ctx, allComponents, *implementationSettings, plans.WithImport(sspImportPath))
+}

From 2b7f2d0b39310f82621c70897f24f2fef5b4ba6d Mon Sep 17 00:00:00 2001
From: Jennifer Power <barnabei.jennifer@gmail.com>
Date: Fri, 14 Feb 2025 18:05:19 -0500
Subject: [PATCH 5/6] fix: updates Assessment Platform to remove empty
 component array

Assessment Platform is a required field under Assessment Assests
but component are not. This updated that field to ensure there are
no empty component lists.

Signed-off-by: Jennifer Power <barnabei.jennifer@gmail.com>
---
 models/plans/plan.go | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/models/plans/plan.go b/models/plans/plan.go
index 1c1308b..6a650a6 100644
--- a/models/plans/plan.go
+++ b/models/plans/plan.go
@@ -115,11 +115,7 @@ func GenerateAssessmentPlan(ctx context.Context, comps []components.Component, i
 	}
 
 	assessmentAssets := AssessmentAssets(comps)
-	taskAssessmentSubject := oscalTypes.AssessmentSubject{
-		IncludeSubjects: &subjectSelectors,
-		Type:            defaultSubjectType,
-	}
-	*ruleBasedTask.Subjects = append(*ruleBasedTask.Subjects, taskAssessmentSubject)
+	*ruleBasedTask.Subjects = append(*ruleBasedTask.Subjects, oscalTypes.AssessmentSubject{IncludeSubjects: &subjectSelectors})
 
 	metadata := models.NewSampleMetadata()
 	metadata.Title = options.title
@@ -151,7 +147,7 @@ func newTask() oscalTypes.Task {
 		UUID:                 uuid.NewUUID(),
 		Title:                "Automated Assessment",
 		Type:                 defaultTaskType,
-		Description:          "Evaluation of defined rules for components.",
+		Description:          "Evaluation of defined rules for applicable comps.",
 		Subjects:             &[]oscalTypes.AssessmentSubject{},
 		AssociatedActivities: &[]oscalTypes.AssociatedActivity{},
 	}
@@ -296,12 +292,20 @@ func AssessmentAssets(comps []components.Component) oscalTypes.AssessmentAssets
 
 		}
 	}
+
 	// AssessmentPlatforms is a required field under AssessmentAssets
 	assessmentPlatform := oscalTypes.AssessmentPlatform{
-		UUID:           uuid.NewUUID(),
-		Title:          models.SampleRequiredString,
-		UsesComponents: &usedComponents,
+		UUID:  uuid.NewUUID(),
+		Title: models.SampleRequiredString,
+	}
+
+	if len(usedComponents) == 0 {
+		return oscalTypes.AssessmentAssets{
+			AssessmentPlatforms: []oscalTypes.AssessmentPlatform{assessmentPlatform},
+		}
 	}
+
+	assessmentPlatform.UsesComponents = &usedComponents
 	assessmentAssets := oscalTypes.AssessmentAssets{
 		Components:          &systemComponents,
 		AssessmentPlatforms: []oscalTypes.AssessmentPlatform{assessmentPlatform},

From c7ab3b95cf172c655e49838617b83be970590881 Mon Sep 17 00:00:00 2001
From: Jennifer Power <barnabei.jennifer@gmail.com>
Date: Thu, 6 Mar 2025 20:36:03 -0500
Subject: [PATCH 6/6] fix: updates testdata and logic to fix validation error

Creates a NilOrEmpty function to ensure any optional and
empty slices are not set.

Signed-off-by: Jennifer Power <barnabei.jennifer@gmail.com>
---
 models/components/ssp_test.go    |  2 +-
 models/plans/plan.go             | 22 ++++++++--------
 models/utils.go                  | 14 +++++++++++
 models/utils_test.go             | 43 ++++++++++++++++++++++++++++++++
 testdata/test-ssp.json           | 17 ++++++++++---
 transformers/transformer_test.go | 14 +++++++++++
 6 files changed, 96 insertions(+), 16 deletions(-)
 create mode 100644 models/utils.go
 create mode 100644 models/utils_test.go

diff --git a/models/components/ssp_test.go b/models/components/ssp_test.go
index 3a345d3..2adfb3b 100644
--- a/models/components/ssp_test.go
+++ b/models/components/ssp_test.go
@@ -50,7 +50,7 @@ func TestControlImplementationAdapter(t *testing.T) {
 
 	adapter := NewControlImplementationAdapter(ssp.ControlImplementation)
 	require.Len(t, adapter.Requirements(), 2)
-	require.Len(t, adapter.SetParameters(), 0)
+	require.Len(t, adapter.SetParameters(), 1)
 	require.Len(t, adapter.Props(), 0)
 
 	impReq := adapter.Requirements()[0]
diff --git a/models/plans/plan.go b/models/plans/plan.go
index 6a650a6..4645b17 100644
--- a/models/plans/plan.go
+++ b/models/plans/plan.go
@@ -115,7 +115,11 @@ func GenerateAssessmentPlan(ctx context.Context, comps []components.Component, i
 	}
 
 	assessmentAssets := AssessmentAssets(comps)
-	*ruleBasedTask.Subjects = append(*ruleBasedTask.Subjects, oscalTypes.AssessmentSubject{IncludeSubjects: &subjectSelectors})
+	taskSubjects := oscalTypes.AssessmentSubject{
+		IncludeSubjects: &subjectSelectors,
+		Type:            defaultSubjectType,
+	}
+	*ruleBasedTask.Subjects = append(*ruleBasedTask.Subjects, taskSubjects)
 
 	metadata := models.NewSampleMetadata()
 	metadata.Title = options.title
@@ -147,7 +151,7 @@ func newTask() oscalTypes.Task {
 		UUID:                 uuid.NewUUID(),
 		Title:                "Automated Assessment",
 		Type:                 defaultTaskType,
-		Description:          "Evaluation of defined rules for applicable comps.",
+		Description:          "Evaluation of defined rules for components.",
 		Subjects:             &[]oscalTypes.AssessmentSubject{},
 		AssociatedActivities: &[]oscalTypes.AssociatedActivity{},
 	}
@@ -194,7 +198,7 @@ func ActivitiesForComponent(ctx context.Context, targetComponentID string, store
 			Props:           &[]oscalTypes.Property{methodProp},
 			RelatedControls: &relatedControls,
 			Title:           rule.Rule.ID,
-			Steps:           &steps,
+			Steps:           models.NilIfEmpty(&steps),
 		}
 
 		if rule.Rule.Parameter != nil {
@@ -295,17 +299,11 @@ func AssessmentAssets(comps []components.Component) oscalTypes.AssessmentAssets
 
 	// AssessmentPlatforms is a required field under AssessmentAssets
 	assessmentPlatform := oscalTypes.AssessmentPlatform{
-		UUID:  uuid.NewUUID(),
-		Title: models.SampleRequiredString,
-	}
-
-	if len(usedComponents) == 0 {
-		return oscalTypes.AssessmentAssets{
-			AssessmentPlatforms: []oscalTypes.AssessmentPlatform{assessmentPlatform},
-		}
+		UUID:           uuid.NewUUID(),
+		Title:          models.SampleRequiredString,
+		UsesComponents: models.NilIfEmpty(&usedComponents),
 	}
 
-	assessmentPlatform.UsesComponents = &usedComponents
 	assessmentAssets := oscalTypes.AssessmentAssets{
 		Components:          &systemComponents,
 		AssessmentPlatforms: []oscalTypes.AssessmentPlatform{assessmentPlatform},
diff --git a/models/utils.go b/models/utils.go
new file mode 100644
index 0000000..53a71b7
--- /dev/null
+++ b/models/utils.go
@@ -0,0 +1,14 @@
+/*
+ Copyright 2024 The OSCAL Compass Authors
+ SPDX-License-Identifier: Apache-2.0
+*/
+
+package models
+
+// NilIfEmpty returns nil if the slice is empty, otherwise returns the original slice.
+func NilIfEmpty[T any](slice *[]T) *[]T {
+	if slice == nil || len(*slice) == 0 {
+		return nil
+	}
+	return slice
+}
diff --git a/models/utils_test.go b/models/utils_test.go
new file mode 100644
index 0000000..407a7a3
--- /dev/null
+++ b/models/utils_test.go
@@ -0,0 +1,43 @@
+/*
+ Copyright 2024 The OSCAL Compass Authors
+ SPDX-License-Identifier: Apache-2.0
+*/
+
+package models
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/require"
+)
+
+func TestNilIfEmpty(t *testing.T) {
+	tests := []struct {
+		name      string
+		slice     *[]string
+		wantSlice *[]string
+	}{
+		{
+			name:      "Valid/NilSlice",
+			slice:     nil,
+			wantSlice: nil,
+		},
+		{
+			name:      "Valid/EmptySlice",
+			slice:     &[]string{},
+			wantSlice: nil,
+		},
+		{
+			name:      "Valid/NonEmptySlice",
+			slice:     &[]string{"test"},
+			wantSlice: &[]string{"test"},
+		},
+	}
+
+	for _, c := range tests {
+		t.Run(c.name, func(t *testing.T) {
+			gotSlice := NilIfEmpty(c.slice)
+			require.Equal(t, c.wantSlice, gotSlice)
+		})
+	}
+}
diff --git a/testdata/test-ssp.json b/testdata/test-ssp.json
index 2676da5..0c61fe7 100644
--- a/testdata/test-ssp.json
+++ b/testdata/test-ssp.json
@@ -105,7 +105,7 @@
             }
           ],
           "status": {
-            "state": "REPLACE_ME"
+            "state": "operational"
           }
         },
         {
@@ -114,7 +114,7 @@
           "title": "This System",
           "description": "",
           "status": {
-            "state": "REPLACE_ME"
+            "state": "operational"
           }
         },
         {
@@ -147,12 +147,23 @@
               "value": "Check 1 Description",
               "remarks": "rule_set_00"
             }
-          ]
+          ],
+          "status": {
+            "state": "operational"
+          }
         }
       ]
     },
     "control-implementation": {
       "description": "This is an example control implementation for the system.",
+      "set-parameters": [
+        {
+          "param-id": "param-1",
+          "values": [
+            "2"
+          ]
+        }
+      ],
       "implemented-requirements": [
         {
           "uuid": "db7b97db-dadc-4afd-850a-245ca09cb811",
diff --git a/transformers/transformer_test.go b/transformers/transformer_test.go
index 7118184..83f78f4 100644
--- a/transformers/transformer_test.go
+++ b/transformers/transformer_test.go
@@ -45,6 +45,13 @@ func TestComponentDefinitionsToAssessmentPlan(t *testing.T) {
 	}
 	require.Contains(t, activities, "etcd_cert_file")
 	require.Contains(t, activities, "etcd_key_file")
+
+	// Validate against the schema
+	validator := validation.NewSchemaValidator()
+	oscalModels := oscalTypes.OscalModels{
+		AssessmentPlan: plan,
+	}
+	require.NoError(t, validator.Validate(oscalModels))
 }
 
 func TestSSPToAssessmentPlan(t *testing.T) {
@@ -73,4 +80,11 @@ func TestSSPToAssessmentPlan(t *testing.T) {
 	}
 	require.Contains(t, activities, "rule-1")
 	require.Contains(t, activities, "rule-2")
+
+	// Validate against the schema
+	validator := validation.NewSchemaValidator()
+	oscalModels := oscalTypes.OscalModels{
+		AssessmentPlan: plan,
+	}
+	require.NoError(t, validator.Validate(oscalModels))
 }