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

Adjust SSP Viewer for FedRAMP template #140

Merged
merged 16 commits into from
Aug 9, 2021
Merged

Adjust SSP Viewer for FedRAMP template #140

merged 16 commits into from
Aug 9, 2021

Conversation

Bronstrom
Copy link
Contributor

Adjustments have been made in the visual display of the FedRAMP SSP template, importing a profile, and displaying statements.

Visually, columns in System Characteristics and System Implementation have been adjusted in placement and size to lessen word wrap and fill more of the negative space. While making visual adjustments, the placement of other elements on screen were maintained.

After resolving the import-profile xml link in OSCALSspResolver, there was a need to rework how statements are fetched for the implementation controls to display correctly. This FedRAMP SSP template provided the set-parameters in the first/overarching statement, rather than each individual statement for the controls. For example, the set-parameters are listed purely in "ac-1_smt" versus being listed in something like "ac-1_smt.a" or "ac-1_smt.b.1" in NIST's SSPs. OSCALControl now tries to grab these statements (which are null if provided like NIST's statements), then passes them to underlying components. With this added feature, the SSP Viewer has no problem handling controls from both NIST and FedRAMP.

Testing

Use the FedRAMP SSP template when running the SSP Viewer.

To fill negative space and limit word wrap, stylistic adjustments
have been made to OSCALSystemCharacteristics and
OSCALSystemImplementation.
The FedRAMP SSP template provides a different format to how statement
set-parameters are provide than seen in NIST's SSPs. Instead of having
set-parameters provided on each statement of a control, they are
provided by only the initial statement of a control in this SSP
template. Control and underlying components have been reworked to fit
this description.
src/components/OSCALControl.js Outdated Show resolved Hide resolved
src/components/OSCALControlProse.js Outdated Show resolved Hide resolved
@@ -61,6 +61,21 @@ export default function OSCALControl(props) {
);
}

// When FedRAMP, retrieve the set-parameters from the initial implementation request statement
let firstImplReqStatement = null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we just pulling the first of each here?

Copy link
Contributor Author

@Bronstrom Bronstrom Jul 28, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this sample it contains the set-parameters only in the first (initial) implemented requirement statement

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, but we don't have guaranteed ordering here.

What I think we're really looking for are set-parameters at the 'top-level' of the control, so within ac-1_smt, which won't necessarily be the first statement in the array.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh okay, that makes more sense. Maybe instead here, we should find the 'top-level' of the control with an ends with "_smt" check?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like that, we may already be doing something similar elsewhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added an endsWith check when searching through the array of implReqStatements for now. I haven't found a place where we're doing something similar but will continue looking.

src/components/OSCALSystemCharacteristics.js Outdated Show resolved Hide resolved
src/components/OSCALSystemImplementation.js Outdated Show resolved Hide resolved
src/components/OSCALControl.js Outdated Show resolved Hide resolved
}
});
}
// NOTE: The top-level by-component is the first element in the by-components array
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this is an accurate statement.

Each component in the by-components array represents how each component address the control.

I believe OSCALContorlImplementationImplReq sends in a componentId that we should check for?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was a little hesitant to include that part as well. Grabbing the first array is definitely not the best practice here as this doesn't seem to be a consistent pattern. Also, thanks for clarifying on this. Your right about OSCALControlImplementationImplReq passing componentId as a prop. I can make a by-component id match check as well - I'm not seeing it elsewhere.

src/components/OSCALSystemImplementation.js Outdated Show resolved Hide resolved
src/components/OSCALSystemImplementation.js Outdated Show resolved Hide resolved
To help with readability and reusability of code, the
implemented requirements set-parameters fetch has been made into
a seperate method in OSCALControl.
@Bronstrom
Copy link
Contributor Author

I chose to make the set-parameter fetch into a separate function in OSCALControl. I was wondering if we would even want to split this up further or place it elsewhere - like in ./oscal-utils? At this point, the implReqStatements grab and by-component id checks aren't used outside the scope of OSCALControl, but could potentially be referenced by components in the future?

Copy link
Contributor

@tuckerzp tuckerzp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good so far! This does not have to prevent an approval. I just had a few potential things to look into.

Comment on lines 47 to 48
* @param {Object} implReqStatements
* @param {String} componentId
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would a brief description of these two parameters be useful here?

Comment on lines 54 to 67
if (implReqStatements) {
// NOTE: The top level statement ends with "_smt"
topLevelImplReqStatement = implReqStatements.find((statement) =>
statement["statement-id"].endsWith("_smt")
);
}
// NOTE: The top-level by-component has a matching uuid to the componentId
let topLevelByComp = null;
if (topLevelImplReqStatement?.["by-components"]) {
topLevelByComp = topLevelImplReqStatement["by-components"].find(
(byComp) => byComp["component-uuid"] === componentId
);
}
return topLevelByComp?.["set-parameters"] || null;
Copy link
Contributor

@tuckerzp tuckerzp Jul 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could be wrong here, but is it possible to make this into just a pipe of find().find() or something along those lines? It seems like there could be a cleaner way of doing this.

Copy link
Contributor

@hreineck hreineck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. Viewer looks as specified locally.
I would like to see @tuckerzp 's comments implemented, but other than that looks great.

* @param {String} componentId
* @returns An array of set-parameters
*/
function getImplReqSetParameters(implReqStatements, componentId) {
Copy link
Contributor

@rgauss rgauss Aug 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this entire function be pushed down to OSCALControlProse.js since that code is already responsible for finding the parameters and has the componentId?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will push the function to OSCALControlProse.js

@mikeisen1 mikeisen1 marked this pull request as draft August 3, 2021 13:11
Clean up code in getImplReqSetParameters by
creating a find.find pipe and removing the
extra lines no longer needed.

Add brief description to the parameters of
getImplReqSetParameters to improve
understanding of their purpose.
Move getImplReqSetParameters from OSCALControl to
OSCALControlProse, as OSCALControlProse already
finds the parameters and has the componentId.
@mikeisen1 mikeisen1 marked this pull request as ready for review August 3, 2021 16:29
@mikeisen1 mikeisen1 self-assigned this Aug 3, 2021
@@ -61,6 +62,12 @@ export default function OSCALControl(props) {
);
}

// Retrieve implemented requirements set-parameters
const setParams = getImplReqSetParameters(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I meant the function and the execution of that function could be moved to OSCALControlProse.

There shouldn't be any need to evaluate here and pass the results as implReqSetParameters all the way down to OSCALControlProse where it's actually used, I think we should be able to just call from within OSCALControlProse.

Move getImplReqSetParameters to OSCALControlProse
file, as the result is only used in that file.
Modified OSCALControl and OSCALControlPart to
no longer use implReqSetParameters, as it is
not used in those files. This improve readability
and understanding of the code and where results
of functions are used.
Move getImplReqSetParameters to top of file, as it
was previously being used before it was defined.
Copy link
Contributor

@kylelaker kylelaker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some thoughts but not really required.

// Get the top-level implemented requirement statement
const topLevelByComp = implReqStatements
?.find((statement) => statement["statement-id"].endsWith("_smt"))
?.["by-components"]?.find(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
?.["by-components"]?.find(
?.["by-components"]
?.find(

Would the linter allow this? Makes the chain a little more "obvious"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've tried locally but whenever I run npm run lint, the suggested change is fixed to what it originally looked like so I don't think so.

// Locate set-parameters when found in the by-component
if (statementByComponent?.["set-parameters"]) {
foundParameterSetting = statementByComponent["set-parameters"].find(
(parameterSetting) => parameterSetting["param-id"] === parameterId
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're using this twice (once per branch), we should move it to it's own function within getParameterValue.

// This assumes that `parameterId` from `getParameterValue` is in scope
function parameterHasGivenId(parameterSetting) {
  return parameterSetting["param-id"] === parameterId;
}

And then you can use it as:

if (statementByComponent?.["set-parameters"]) {
  foundParameterSetting = statementByComponent["set-parameters"].find(parameterHasGivenId);
} else if (implReqSetParameters) {
  foundParameterSetting = implReqSetParameters.find(parameterHasGivenId);
} else {
  return null;
}

But I'd also suggest that we've got quite a bit of repetition there still (between the if and the actual clause). And we may want to consider also doing something like:

const setParameters = () => statementByComponents?.["set-parameters"] || implReqSetParameters;
const foundParameterSetting = setParameters()?.find(parameterHasGivenId);

And since the next check is if (!foundParameterSetting?.values) { return null; } we shouldn't need to modify any code. But we could do a if (!foundParameterSetting) { return null; } if we really wanted to.

This has the benefits of not only reducing repetition but also keeping more things const. It's also one less null that we really need to worry about.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made all recommended changes except the change in the conditional because we do foundParameterSetting.values.toString() right after the check and if foundParameterSetting.values is null, we would get an error.

Comment on lines 127 to 132
const topLevelByComp = implReqStatements
?.find((statement) => statement["statement-id"].endsWith("_smt"))
?.["by-components"]?.find(
(byComp) => byComp["component-uuid"] === componentId
);
return topLevelByComp?.["set-parameters"] || null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const topLevelByComp = implReqStatements
?.find((statement) => statement["statement-id"].endsWith("_smt"))
?.["by-components"]?.find(
(byComp) => byComp["component-uuid"] === componentId
);
return topLevelByComp?.["set-parameters"] || null;
return implReqStatements
?.find((statement) => statement["statement-id"].endsWith("_smt"))
?.["by-components"]?.find(
(byComp) => byComp["component-uuid"] === componentId
)
?.["set-parameters"] || null;

Any reason to keep the temporary value variable there?

Clean up code in OSCALControlProse to remove
duplication, make code easier to read and
understand, and keep more variables const.
src/components/OSCALControlProse.js Outdated Show resolved Hide resolved
Clean up OSCALControlProse file to remove a
function definition and convert it to an
expression, as the function is only used once
and is no longer needed.
Copy link
Contributor

@kkennedy26 kkennedy26 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adjustments look good

@rgauss rgauss merged commit dcf0502 into develop Aug 9, 2021
@rgauss rgauss deleted the EGRC-474 branch August 9, 2021 13:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Minor Adjustments for FedRAMP SSP Templates
7 participants