Skip to content

Commit

Permalink
fix: updates ssp add-props to replace existing properties (#1801)
Browse files Browse the repository at this point in the history
* fix: updates ssp add-props to replace existing properties

Signed-off-by: Jennifer Power <[email protected]>

* docs: fixes broken links

Signed-off-by: Jennifer Power <[email protected]>

---------

Signed-off-by: Jennifer Power <[email protected]>
  • Loading branch information
jpower432 authored Jan 22, 2025
1 parent bdb6444 commit b261ead
Show file tree
Hide file tree
Showing 9 changed files with 39 additions and 22 deletions.
8 changes: 4 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ To contribute code or documentation, please submit a [pull request](https://gith

A good way to familiarize yourself with the codebase and contribution process is
to look for and tackle low-hanging fruit in the [issue tracker](https://github.com/oscal-compass/compliance-trestle/issues).
Before embarking on a more ambitious contribution, please quickly [get in touch](https://oscal-compass.github.io/compliance-trestle/maintainers/) with us.
Before embarking on a more ambitious contribution, please quickly [get in touch](https://oscal-compass.github.io/compliance-trestle/latest/contributing/maintainers/) with us.

**Note: We appreciate your effort, and want to avoid a situation where a contribution
requires extensive rework (by you or by us), sits in backlog for a long time, or
Expand All @@ -32,7 +32,7 @@ review to indicate acceptance.

A change requires LGTMs from at least two reviewers. One of the reviewers must be a [`CODEOWNER`](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners).

For a list of the maintainers (also codeowners), see the [maintainers](https://oscal-compass.github.io/compliance-trestle/maintainers/) page.
For a list of the maintainers (also codeowners), see the [maintainers](https://oscal-compass.github.io/compliance-trestle/latest/contributing/maintainers/)

### Trestle updating, testing and release logistics

Expand Down Expand Up @@ -88,7 +88,7 @@ The devops process does not _strictly_ enforce typing, however, the expectation
commits with a focus on quality over quantity (e.g. don't add `Any` everywhere just to meet coverage requirements).
Python typing of functions is an active work in progress.

`mkbuild` is used to generate the [trestle documenation site](https://oscal-compass.github.io/compliance-trestle). The `mkbuild`
`mkbuild` is used to generate the [trestle documenation site](https://oscal-compass.github.io/compliance-trestle/latest). The `mkbuild`
website includes an API reference section generated from the code. Docstrings within the code are expected to follow
[google style docstrings](https://www.sphinx-doc.org/en/master/usage/extensions/example_google.html).

Expand Down Expand Up @@ -116,7 +116,7 @@ e.g.

We have tried to make it as easy as possible to make contributions. This
applies to how we handle the legal aspects of contribution. We use the
same approach - the [Developer's Certificate of Origin 1.1 (DCO)](https://oscal-compass.github.io/compliance-trestle/contributing/DCO/) - that the Linux® Kernel [community](https://developercertificate.org/)
same approach - the [Developer's Certificate of Origin 1.1 (DCO)](https://oscal-compass.github.io/compliance-trestle/latest/contributing/DCO/) - that the Linux® Kernel [community](https://developercertificate.org/)
uses to manage code contributions.

We simply ask that when submitting a patch for review, the developer
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,11 @@ Users needing to import XML OSCAL artifacts are recommended to look at NIST's XM

Trestle runs on almost all Python platforms (e.g. Linux, Mac, Windows), is available on PyPi and can be easily installed via pip. It is under active development and new releases are made available regularly.\
To install run: `pip install compliance-trestle`\
See [Install trestle in a python virtual environment](https://oscal-compass.github.io/compliance-trestle/python_trestle_setup/) for the full installation guide.
See [Install trestle in a python virtual environment](https://oscal-compass.github.io/compliance-trestle/latest/installation/) for the full installation guide.

## Complete documentation and tutorials

Complete documentation, tutorials, and background on compliance can be found [here](https://oscal-compass.github.io/compliance-trestle).
Complete documentation, tutorials, and background on compliance can be found [here](https://oscal-compass.github.io/compliance-trestle/latest).

## Agile Authoring

Expand Down Expand Up @@ -101,7 +101,7 @@ Please refer to the community [README](https://github.com/oscal-compass/communit

## Contributing to Trestle

Our project welcomes external contributions. Please consult [contributing](https://oscal-compass.github.io/compliance-trestle/contributing/mkdocs_contributing/) to get started.
Our project welcomes external contributions. Please consult [contributing](https://oscal-compass.github.io/compliance-trestle/latest/contributing/mkdocs_contributing/) to get started.

## Code of Conduct

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ The second is a one-command transformation from `.profile` to `OSCAL.json`.

## Step 1: Install trestle in a Python virtual environment

Follow the instructions [here](https://oscal-compass.github.io/compliance-trestle/python_trestle_setup/) to install trestle in a virtual environment.
Follow the instructions [here](https://oscal-compass.github.io/compliance-trestle/latest/installation/) to install trestle in a virtual environment.

## Step 2: Transform profile data (CIS benchmarks)

Expand Down
2 changes: 1 addition & 1 deletion docs/tutorials/Transformers_and_Tasks/csv_to_oscal_cd.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ The below table represents the expectations of trestle task `csv-to-oscal-cd` fo

## *Step 1: Install trestle in a Python virtual environment*

Follow the instructions [here](https://oscal-compass.github.io/compliance-trestle/python_trestle_setup/) to install trestle in a virtual environment.
Follow the instructions [here](https://oscal-compass.github.io/compliance-trestle/latest/installation/) to install trestle in a virtual environment.

## *Step 2: Transform profile data (CIS benchmarks)*

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ Access control policy and procedures address the controls in the AC family that
<!-- "## Part" parts are new subparts added into the existing top-level statement part with that label. -->
<!-- Subparts may be added with nested hash levels of the form ### My Subpart Name -->
<!-- underneath the parent ## Control or ## Part being added -->
<!-- See https://oscal-compass.github.io/compliance-trestle/tutorials/ssp_profile_catalog_authoring/ssp_profile_catalog_authoring for guidance. -->
<!-- See https://oscal-compass.github.io/compliance-trestle/latest/tutorials/Trestle_authoring/ssp_profile_catalog_authoring/ for guidance. -->

## Control Implementation Guidance

Expand Down
10 changes: 5 additions & 5 deletions docs/tutorials/Trestle_authoring/trestle_author.md
Original file line number Diff line number Diff line change
Expand Up @@ -690,7 +690,7 @@ CLI evocation:

> trestle author catalog-assemble
The `catalog` author commands allow you to convert a control catalog to markdown and edit its control statement, then assemble markdown back into an OSCAL catalog with the modifications to the statement. Items in the statement may be edited or added. For more details on its usage please see [the catalog authoring tutorial](https://oscal-compass.github.io/compliance-trestle/tutorials/ssp_profile_catalog_authoring/ssp_profile_catalog_authoring).
The `catalog` author commands allow you to convert a control catalog to markdown and edit its control statement, then assemble markdown back into an OSCAL catalog with the modifications to the statement. Items in the statement may be edited or added. For more details on its usage please see [the catalog authoring tutorial](https://oscal-compass.github.io/compliance-trestle/latest/tutorials/Trestle_authoring/ssp_profile_catalog_authoring/).

### Profile authoring

Expand All @@ -704,7 +704,7 @@ CLI evocation:

> trestle author profile-assemble
The `profile` author commands allow you to edit additions made by a profile to its imported controls that end up in the final resolved profile catalog. Only the additions may be edited or added to the generated markdown control files - and those additions can then be assembled into a new version of the original profile, with those additions. For more details on its usage please see [the profile authoring tutorial](https://oscal-compass.github.io/compliance-trestle/tutorials/ssp_profile_catalog_authoring/ssp_profile_catalog_authoring).
The `profile` author commands allow you to edit additions made by a profile to its imported controls that end up in the final resolved profile catalog. Only the additions may be edited or added to the generated markdown control files - and those additions can then be assembled into a new version of the original profile, with those additions. For more details on its usage please see [the profile authoring tutorial](https://oscal-compass.github.io/compliance-trestle/latest/tutorials/Trestle_authoring/ssp_profile_catalog_authoring/).

### Profile generation with inheritance

Expand All @@ -719,7 +719,7 @@ All components must have exported provided statements, no exported responsibilit

As with the other related author commands, if an existing destination file already exists, it is not updated if no changes would be made.

For more details on its usage please see [the ssp-filter tutorial](https://oscal-compass.github.io/compliance-trestle/tutorials/ssp_profile_catalog_authoring/ssp_profile_catalog_authoring).
For more details on its usage please see [the ssp-filter tutorial](https://oscal-compass.github.io/compliance-trestle/latest/tutorials/Trestle_authoring/ssp_profile_catalog_authoring/).

### SSP authoring

Expand All @@ -735,7 +735,7 @@ CLI evocation:
The `ssp-generate` sub-command creates a partial SSP (System Security Plan) from a profile and optional yaml header file. `ssp-assemble` can then assemble the markdown files into a single json SSP file.

For more details on its usage please see [the ssp authoring tutorial](https://oscal-compass.github.io/compliance-trestle/tutorials/ssp_profile_catalog_authoring/ssp_profile_catalog_authoring).
For more details on its usage please see [the ssp authoring tutorial](https://oscal-compass.github.io/compliance-trestle/latest/tutorials/Trestle_authoring/ssp_profile_catalog_authoring/).

### SSP Content Filtering

Expand All @@ -757,6 +757,6 @@ You may filter by a combination of a profile, list of component names, implement

As with the other related author commands, if an existing destination file already exists, it is not updated if no changes would be made.

For more details on its usage please see [the ssp-filter tutorial](https://oscal-compass.github.io/compliance-trestle/tutorials/ssp_profile_catalog_authoring/ssp_profile_catalog_authoring).
For more details on its usage please see [the ssp-filter tutorial](https://oscal-compass.github.io/compliance-trestle/latest/tutorials/Trestle_authoring/ssp_profile_catalog_authoring/).

</details>
15 changes: 10 additions & 5 deletions tests/trestle/core/commands/author/ssp_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1160,14 +1160,19 @@ def test_ssp_gen_and_assemble_add_props(tmp_trestle_dir: pathlib.Path) -> None:
impl_reqs = assem_ssp.control_implementation.implemented_requirements
impl_req = next((i_req for i_req in impl_reqs if i_req.control_id == 'ac-1'), None)
assert len(impl_req.props) == 1
assert impl_req.props[0].name == 'prop_with_ns'
assert impl_req.props[0].value == 'prop with ns'
assert impl_req.props[0].ns == 'https://my_new_namespace'
assert impl_req.props[0].name == 'prop_with_ns' # type: ignore
assert impl_req.props[0].value == 'prop with ns' # type: ignore
assert impl_req.props[0].ns == 'https://my_new_namespace' # type: ignore

smt_a = next((smt for smt in impl_req.statements if smt.statement_id == 'ac-1_smt.a'), None)
assert len(smt_a.props) == 1
assert smt_a.props[0].name == 'smt_prop'
assert smt_a.props[0].value == 'smt prop'
assert smt_a.props[0].name == 'smt_prop' # type: ignore
assert smt_a.props[0].value == 'smt prop' # type: ignore

# Run again and check that there is no change
assert ssp_assemble._run(args) == 0
assem_ssp_2, _ = ModelUtils.load_model_for_class(tmp_trestle_dir, ssp_name, ossp.SystemSecurityPlan)
assert assem_ssp_2.metadata.last_modified == assem_ssp.metadata.last_modified


def test_ssp_gen_and_assemble_implementation_parts(tmp_trestle_dir: pathlib.Path, monkeypatch: MonkeyPatch) -> None:
Expand Down
4 changes: 2 additions & 2 deletions trestle/core/catalog/catalog_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ def _add_props_to_imp_req(
# add the props at control level
if props:
imp_req.props = as_list(imp_req.props)
imp_req.props.extend(props)
ControlInterface.reconcile_props(imp_req, props)

# add the props at the part level
for label, part_id in control_part_id_map.items():
Expand All @@ -359,7 +359,7 @@ def _add_props_to_imp_req(
for statement in as_list(imp_req.statements):
if statement.statement_id == part_id:
statement.props = as_list(statement.props)
statement.props.extend(props)
ControlInterface.reconcile_props(statement, props)

@staticmethod
def _update_ssp_with_md_header(
Expand Down
12 changes: 12 additions & 0 deletions trestle/core/control_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -1121,6 +1121,18 @@ def insert_status_in_props(item: TypeWithProps, status: common.ImplementationSta
prop = ControlInterface._status_as_prop(status)
ControlInterface._replace_prop(item, prop)

@staticmethod
def reconcile_props(item: TypeWithProps, props: List[common.Property]) -> None:
"""Add properties to an item with properties while replacing existing."""
names = [prop.name for prop in as_list(item.props)]
item.props = as_list(item.props)
for prop in props:
if prop.name in names:
index = names.index(prop.name)
item.props[index] = prop
else:
item.props.append(prop)

@staticmethod
def _copy_status_in_props(dest: TypeWithProps, src: TypeWithProps) -> None:
"""Copy status in props from one object to another."""
Expand Down

0 comments on commit b261ead

Please sign in to comment.