Skip to content

Commit

Permalink
Merge pull request #1593 from oscal-compass/develop
Browse files Browse the repository at this point in the history
chore: Trestle release
  • Loading branch information
AleJo2995 authored Jun 18, 2024
2 parents ef26073 + a44312c commit 8e7c490
Show file tree
Hide file tree
Showing 10 changed files with 306 additions and 49 deletions.
23 changes: 1 addition & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,28 +96,7 @@ Compliance trestle is currently stable and is based on NIST OSCAL version 1.1.2,

## Community meetings and communications

##### Scheduled meetings

Please attend! All are invited.

**When**:

Every other Tuesday starting on April 23, 2024 · 11:00 – 11:30am ET
[convert to your local time](https://mytime.io/11am/ET)

**Where**: [Google Meet Link](https://meet.google.com/mwp-affd-tvu)

Dial in:
(US) +1 402-627-0247 PIN: 535 362 764#\
[More phone numbers](https://tel.meet/mwp-affd-tvu?pin=9717189704231)

**What**: Meeting agenda and notes [Google Docs](https://docs.google.com/document/d/1XTYM7xnWlIqd-8Nn5-qtgvgk8kH3NSmYle5yZvaS7qs/edit?usp=sharing)

##### Chat anytime

Slack: [#oscal-compliance-trestle-agileauthoring-c2p](https://cloud-native.slack.com/archives/C06F3PEPNBW)

- **Note**: You can login to Slack using another account like Google, Apple
Please refer to the community [README](https://github.com/oscal-compass/community/blob/main/README.md) for communication details.

## Contributing to Trestle

Expand Down
4 changes: 2 additions & 2 deletions docs/python_trestle_setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ There are a few things you need to to start using trestle:

## *Confirm you have python installed*

- Ensure you have a modern [Python](https://www.python.org/downloads/) (3.7, 3.8, 3.9).
- Ensure you have a modern [Python](https://www.python.org/downloads/) (3.9, 3.10, 3.11).

```bash
$ python -V
Python 3.8.3
Python 3.9.2
```

## *Setup a virtual environment*
Expand Down
8 changes: 7 additions & 1 deletion scripts/oscal_normalize.py
Original file line number Diff line number Diff line change
Expand Up @@ -1033,7 +1033,13 @@ def kill_roots(file_classes):
for ii in range(1, len(c.lines)):
line = c.lines[ii]
for name, body in new_root_classes.items():
# handle special case
# handle special cases
if 'NonNegativeIntegerDatatype' in line:
line = line.replace('NonNegativeIntegerDatatype', 'conint(ge=0, multiple_of=1)', 1)
if 'PositiveIntegerDatatype' in line:
line = line.replace('PositiveIntegerDatatype', 'conint(ge=1, multiple_of=1)', 1)
if 'IntegerDatatype' in line:
line = line.replace('IntegerDatatype', 'conint(multiple_of=1)', 1)
if c.name == 'OscalVersion':
if any(token in line for token in [' __root__: StringDatatype']):
line = line.replace(name, body, 1)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"component-definition": {
"uuid": "e7ba3d37-2ba0-4db9-9cf8-f5ec1214ffd5",
"metadata": {
"title": "Generic component-definition created by trestle named replication.",
"last-modified": "2024-06-11T21:16:49.175968+00:00",
"version": "0.0.0",
"oscal-version": "1.0.4"
},
"components": [
{
"uuid": "4cef9684-578e-460e-a2d1-6eb78b8a76ca",
"type": "REPLACE_ME",
"title": "REPLACE_ME",
"description": "REPLACE_ME",
"control-implementations": []
}
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"component-definition": {
"uuid": "e7ba3d37-2ba0-4db9-9cf8-f5ec1214ffd5",
"metadata": {
"title": "Generic component-definition created by trestle named replication.",
"last-modified": "2024-06-11T21:16:49.175968+00:00",
"version": "0.0.0",
"oscal-version": "1.0.4"
},
"components": [
{
"uuid": "4cef9684-578e-460e-a2d1-6eb78b8a76ca",
"type": "REPLACE_ME",
"title": "REPLACE_ME",
"description": "REPLACE_ME",
"protocols": [
{
"uuid": "0130b4ef-4561-4363-bab5-1e20b9888e49",
"name": "https",
"title": "Transport Layer Security",
"port-ranges": [
{
"start": 443,
"end": 443,
"transport": "TCP"
}
]
}
],
"control-implementations": []
}
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"component-definition": {
"uuid": "e7ba3d37-2ba0-4db9-9cf8-f5ec1214ffd5",
"metadata": {
"title": "Generic component-definition created by trestle named replication.",
"last-modified": "2024-06-11T21:16:49.175968+00:00",
"version": "0.0.0",
"oscal-version": "1.0.4"
},
"components": [
{
"uuid": "4cef9684-578e-460e-a2d1-6eb78b8a76ca",
"type": "REPLACE_ME",
"title": "REPLACE_ME",
"description": "REPLACE_ME",
"protocols": [
{
"uuid": "0130b4ef-4561-4363-bab5-1e20b9888e49",
"name": "https",
"title": "Transport Layer Security",
"port-ranges": [
{
"start": -443,
"end": 443,
"transport": "TCP"
}
]
}
],
"control-implementations": []
}
]
}
}
63 changes: 63 additions & 0 deletions tests/trestle/core/commands/validate_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import trestle.common.const as const
import trestle.core.generators as gens
import trestle.oscal.assessment_plan as ap
import trestle.oscal.common as common
import trestle.oscal.profile as prof
import trestle.oscal.ssp as ossp
from trestle import cli
Expand Down Expand Up @@ -407,3 +408,65 @@ def test_validate_ssp_with_no_profile(tmp_trestle_dir: pathlib.Path, monkeypatch

new_ssp.import_profile.href = original_href
ModelUtils.save_top_level_model(new_ssp, tmp_trestle_dir, ssp_name, FileContentType.JSON)


def test_period(tmp_trestle_dir: pathlib.Path, monkeypatch: MonkeyPatch) -> None:
"""Test period."""
unit = common.TimeUnitValidValues.seconds
_ = common.AtFrequency(period=1, unit=unit)
try:
_ = common.AtFrequency(period=0, unit=unit)
raise RuntimeError('must be positive integer')
except Exception:
pass


def test_validate_component_definition(tmp_trestle_dir: pathlib.Path, monkeypatch: MonkeyPatch) -> None:
"""Test validation of Component Definition."""
jfile = 'component-definition.json'

sdir = test_data_dir / 'validate' / 'component-definitions' / 'x1'
spth = sdir / f'{jfile}'

tdir = tmp_trestle_dir / test_utils.COMPONENT_DEF_DIR / 'my_test_model'
tpth = tdir / f'{jfile}'

(tdir).mkdir(exist_ok=True, parents=True)

shutil.copyfile(spth, tpth)
validate_command = f'trestle validate -f {tpth}'
test_utils.execute_command_and_assert(validate_command, 0, monkeypatch)


def test_validate_component_definition_ports(tmp_trestle_dir: pathlib.Path, monkeypatch: MonkeyPatch) -> None:
"""Test validation of ports in Component Definition."""
jfile = 'component-definition.json'

sdir = test_data_dir / 'validate' / 'component-definitions' / 'x2'
spth = sdir / f'{jfile}'

tdir = tmp_trestle_dir / test_utils.COMPONENT_DEF_DIR / 'my_test_model'
tpth = tdir / f'{jfile}'

(tdir).mkdir(exist_ok=True, parents=True)

shutil.copyfile(spth, tpth)
validate_command = f'trestle validate -f {tpth}'
test_utils.execute_command_and_assert(validate_command, 0, monkeypatch)


def test_validate_component_definition_ports_invalid(tmp_trestle_dir: pathlib.Path, monkeypatch: MonkeyPatch) -> None:
"""Test validation of ports in Component Definition."""
jfile = 'component-definition.json'

sdir = test_data_dir / 'validate' / 'component-definitions' / 'x3'
spth = sdir / f'{jfile}'

tdir = tmp_trestle_dir / test_utils.COMPONENT_DEF_DIR / 'my_test_model'
tpth = tdir / f'{jfile}'

(tdir).mkdir(exist_ok=True, parents=True)

shutil.copyfile(spth, tpth)
validate_command = f'trestle validate -f {tpth}'
test_utils.execute_command_and_assert(validate_command, 1, monkeypatch)
109 changes: 109 additions & 0 deletions tests/trestle/tasks/csv_to_oscal_cd_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,34 @@ def test_execute_param_duplicate_value(tmp_path: pathlib.Path) -> None:
assert retval == TaskOutcome.FAILURE


def test_execute_correct_rule_key(tmp_path: pathlib.Path) -> None:
"""Test execute missing value."""
_, section = _get_config_section_init(tmp_path, 'test-csv-to-oscal-cd.config')
rows = _get_rows('tests/data/csv/ocp4-user.v2.csv')
row = rows[2]
# ensure component_title and component_description are different
assert row[7] == 'OSCO'
assert row[8] == 'OSCO'
row[8] = 'IAM'
assert row[8] == 'IAM'
component_title = row[7]
component_description = row[8]
component_type = row[5]
rule_id = row[1]
with mock.patch('trestle.tasks.csv_to_oscal_cd.csv.reader') as mock_csv_reader:
mock_csv_reader.return_value = rows
# perform transformation
tgt = csv_to_oscal_cd.CsvToOscalComponentDefinition(section)
retval = tgt.execute()
assert retval == TaskOutcome.SUCCESS
# insure expected key exists
expected_key = (component_title, component_type, rule_id)
assert expected_key in tgt._csv_mgr.get_rule_keys()
# insure unexpected key does not exist
unexpected_key = (component_description, component_type, rule_id)
assert unexpected_key not in tgt._csv_mgr.get_rule_keys()


def test_execute_missing_param_default_value(tmp_path: pathlib.Path) -> None:
"""Test execute missing param default_value."""
_, section = _get_config_section_init(tmp_path, 'test-csv-to-oscal-cd-bp.config')
Expand Down Expand Up @@ -1234,6 +1262,87 @@ def test_execute_add_property(tmp_path: pathlib.Path) -> None:
assert component.props[6].value == 'add-fetcher-description'


def test_execute_with_risk_properties(tmp_path: pathlib.Path) -> None:
"""Test execute with risk properties."""
_, section = _get_config_section_init(tmp_path, 'test-csv-to-oscal-cd-bp.config')
# add risk properties
rows = _get_rows('tests/data/csv/bp.sample.v2.csv')
rows[0].append('Original_Risk_Rating')
rows[0].append('Adjusted_Risk_Rating')
rows[0].append('Risk_Adjustment')
# row 3 will be tested
rows[2].append('add-original-risk-rating')
rows[2].append('add-adjusted-risk-rating')
rows[2].append('add-risk-adjustment')
# ensure all rows have a value for the risk columns to execute task successfully
for row in rows[3:]:
row.append('')
row.append('')
row.append('')
with mock.patch('trestle.tasks.csv_to_oscal_cd.csv.reader') as mock_csv_reader:
mock_csv_reader.return_value = rows
tgt = csv_to_oscal_cd.CsvToOscalComponentDefinition(section)
retval = tgt.execute()
assert retval == TaskOutcome.SUCCESS
# read component-definition
fp = pathlib.Path(tmp_path) / 'component-definition.json'
cd = ComponentDefinition.oscal_read(fp)
# spot check
component = cd.components[0]
# the bp.sample.v2.csv before mock has 62 properties
assert len(component.props) == 65
assert component.props[0].name == 'Rule_Id'
assert component.props[1].name == 'Rule_Description'
assert component.props[2].name == 'Check_Id'
assert component.props[3].name == 'Check_Description'
assert component.props[4].name == 'Original_Risk_Rating'
assert component.props[4].value == 'add-original-risk-rating'
assert component.props[5].name == 'Adjusted_Risk_Rating'
assert component.props[5].value == 'add-adjusted-risk-rating'
assert component.props[6].name == 'Risk_Adjustment'
assert component.props[6].value == 'add-risk-adjustment'


def test_execute_with_ignored_risk_properties(tmp_path: pathlib.Path) -> None:
"""Test execute with ignored risk properties when component type is validation."""
_, section = _get_config_section_init(tmp_path, 'test-csv-to-oscal-cd-bp.config')
# add risk properties
rows = _get_rows('tests/data/csv/bp.sample.v2.csv')
rows[0].append('Original_Risk_Rating')
rows[0].append('Adjusted_Risk_Rating')
rows[0].append('Risk_Adjustment')
# row 3 will be tested
rows[2].append('add-original-risk-rating')
rows[2].append('add-adjusted-risk-rating')
rows[2].append('add-risk-adjustment')
# ensure all rows have a value for the risk columns to execute task successfully
for row in rows[3:]:
row.append('')
row.append('')
row.append('')
# set validation component type
assert rows[0][9] == 'Component_Type'
assert rows[2][9] == 'Service'
rows[2][9] = 'Validation'
with mock.patch('trestle.tasks.csv_to_oscal_cd.csv.reader') as mock_csv_reader:
mock_csv_reader.return_value = rows
tgt = csv_to_oscal_cd.CsvToOscalComponentDefinition(section)
retval = tgt.execute()
assert retval == TaskOutcome.SUCCESS
# read component-definition
fp = pathlib.Path(tmp_path) / 'component-definition.json'
cd = ComponentDefinition.oscal_read(fp)
# spot check
component = cd.components[0]
assert component.type == 'Validation'
# there are 4 component validation props: Rule_Id, Check_Id, Check_Description, Reference_Id
assert len(component.props) == 4
for prop in component.props:
assert prop.name != 'Original_Risk_Rating'
assert prop.name != 'Adjusted_Risk_Rating'
assert prop.name != 'Risk_Adjustment'


def test_execute_add_user_property(tmp_path: pathlib.Path) -> None:
"""Test execute add user property."""
_, section = _get_config_section_init(tmp_path, 'test-csv-to-oscal-cd-bp.config')
Expand Down
Loading

0 comments on commit 8e7c490

Please sign in to comment.