Skip to content

Tutorial: Introduction to trestle workflow¤

Here are step-by-step instructions to manipulate a NIST standard OSCAL catalog using the compliance-trestle ("trestle") tool.

Objective¤

Learn how to split and merge an OSCAL catalog json file using trestle commands and its command line interface (CLI). Trestle simplifies the manipulation and management of large OSCAL documents by allowing controlled deconstruction into smaller components, and later reconstruction after editing those components. And all operations guarantee that the individual files conform to the corresponding OSCAL schema to maintain integrity of the document in the process.

This tutorial assumes you have installed Python and installed trestle in a virtual environment per the directions found here.

The examples shown will work for linux and mac, but Windows will require the following modifications:

  • use backslashes `\` for file paths (this is optional in most cases)
  • use copy instead of cp (unless you have cp installed)
  • use md instead of mkdir (unless you have mkdir installed)
  • quotes (') are often not needed unless the text includes spaces, but if quotes are needed they should be double quotes (")

Commands are shown without prompts so they are easy to cut and paste, and responses by trestle are shown with >>> at the start of the line. In actual usage the >>> would not appear.

Be sure to include the quotes (' ') as shown in the examples, e.g. merge -e 'catalog.*' [On windows you should probably use double quotes (") as needed.]

In this tutorial you will see sections that contain dropdown that is revealed when you click on them. Below is an example ("Like this"). Be sure to click on those sections to see their contents - and then close them if you like.


Like this
more
information
in
here


Step 1: Create a trestle workspace if you don't have one already¤

mkdir my_workspace
cd my_workspace
trestle init
>>> Initialized trestle project successfully in [user_path]/my_workspace

Step 2: Import a catalog from the trestle sample data directory into your trestle workspace¤

For this tutorial we will use a catalog file from NIST, but we first must import it into the trestle workspace. This can be done either by first downloading the file locally and then importing it, or you can download it directly using its url address.

We will import the file directly from the NIST OSCAL github site. The specific catalog is NIST_SP-800-53_rev5_catalog.json

Import the file from the url with the following command:

trestle import -f https://raw.githubusercontent.com/usnistgov/oscal-content/master/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_catalog.json -o mycatalog

As a reminder, you could also have imported the file from a local directory on your file system, or an sftp:// address. But the file must first be imported to the trestle workspace in order for it to be directly manipulated by trestle as in this tutorial.

The import command will also check the validity of the file including the presence of any duplicate uuid's. If the file is manually created please be sure it conforms with the current OSCAL schema (OSCAL version 1.0.4) and has no defined uuid's that are duplicates. If there are any errors the Import will fail and the file must be corrected.


Your initial workspace will look like this
my_workspace
 ┣ .trestle
 ┃ ┣ .keep
 ┃ ┗ config.ini
 ┣ assessment-plans
 ┃ ┗ .keep
 ┣ assessment-results
 ┃ ┗ .keep
 ┣ catalogs
 ┃ ┣ mycatalog
 ┃ ┃ ┗ catalog.json
 ┃ ┗ .keep
 ┣ component-definitions
 ┃ ┗ .keep
 ┣ dist
 ┃ ┣ assessment-plans
 ┃ ┃ ┗ .keep
 ┃ ┣ assessment-results
 ┃ ┃ ┗ .keep
 ┃ ┣ catalogs
 ┃ ┃ ┗ .keep
 ┃ ┣ component-definitions
 ┃ ┃ ┗ .keep
 ┃ ┣ plan-of-action-and-milestones
 ┃ ┃ ┗ .keep
 ┃ ┣ profiles
 ┃ ┃ ┗ .keep
 ┃ ┣ system-security-plans
 ┃ ┃ ┗ .keep
 ┃ ┗ target-definitions
 ┃ ┃ ┗ .keep
 ┣ plan-of-action-and-milestones
 ┃ ┗ .keep
 ┣ profiles
 ┃ ┗ .keep
 ┣ system-security-plans
 ┃ ┗ .keep
 ┗ target-definitions
 ┃ ┗ .keep


You will see that the directory now shows your catalog file in my_workspace/catalogs/mycatalog/catalog.json. Note that the .keep files are simply to make sure git does not remove the directories - and can be ignored. Also note that the json file itself is singular (catalog) while the directory above is plural (catalogs). This convention is used throughout trestle because a given model directory like catalogs may contain several individual models - each of which is singular. The imported catalog file size may be larger than the original due to a change in formatting, but the contents should be the same.

From here on in this tutorial we will just focus on the catalogs directory since the others are not directly involved.

You have now populated your trestle workspace with an OSCAL catalog that you can manipulate. Let's start.

Step 3: Split the file into smaller parts¤

The OSCAL schema specifies that a catalog must contain metadata, groups, and back-matter - so this command will pull them out of the original file and place them in separate json files for additional manipulations.

To begin splitting the file, first cd to the directory where catalog.json has been placed.

cd catalogs/mycatalog
trestle split -f ./catalog.json -e 'catalog.metadata,catalog.groups,catalog.back-matter'

Here the -f refers to the filename of the json catalog file, and -e refers to the comma-separated list of elements you would like to split from the file. This list does not represent the full file contents of the source catalog.json file, so some contents will be left behind in a much smaller catalog.json file after the split. The elements that were split off will be placed in separate json files next to the new and smaller catalog.json file.


Your new catalogs directory with json files split out
catalogs
 ┗ mycatalog
 ┃ ┣ catalog
 ┃ ┃ ┣ back-matter.json
 ┃ ┃ ┣ groups.json
 ┃ ┃ ┗ metadata.json
 ┃ ┗ catalog.json


Note there still remains a catalog.json file, but it is much smaller since the bulk of its contents have been split off.

Any split step can be reversed by a corresponding merge operation. In this case we can go backwards with:

trestle merge -e 'catalog.metadata,catalog.groups,catalog.back-matter'

or simply

trestle merge -e 'catalog.*'

You can go back and forth splitting and merging, but for the next step please start with the above files split so that metadata.json can be further split.

Step 4: Split the metadata into constituent files¤

cd catalog
trestle split -f ./metadata.json -e 'metadata.roles,metadata.parties,metadata.responsible-parties'


The directory will now look like this, with metadata split into files
catalogs
 ┗ mycatalog
 ┃ ┣ catalog
 ┃ ┃ ┣ metadata
 ┃ ┃ ┃ ┣ parties.json
 ┃ ┃ ┃ ┣ responsible-parties.json
 ┃ ┃ ┃ ┗ roles.json
 ┃ ┃ ┣ back-matter.json
 ┃ ┃ ┣ groups.json
 ┃ ┃ ┗ metadata.json
 ┃ ┗ catalog.json


Again there remains a metadata.json file but it is smaller than the original.

And this step can be reversed with the following:

trestle merge -e 'metadata.roles,metadata.parties,metadata.responsible-parties'

or simply

trestle merge -e 'metadata.*'

Step 5: Split metadata further using wildcards¤

cd metadata
trestle split -f ./roles.json -e 'roles.*'
trestle split -f ./responsible-parties.json -e 'responsible-parties.*'


The directory now looks like this, with new subdirectories containing multiple roles and responsible-parties
catalogs
 ┗ mycatalog
 ┃ ┣ catalog
 ┃ ┃ ┣ metadata
 ┃ ┃ ┃ ┣ responsible-parties
 ┃ ┃ ┃ ┃ ┣ contact__responsible-party.json
 ┃ ┃ ┃ ┃ ┗ creator__responsible-party.json
 ┃ ┃ ┃ ┣ roles
 ┃ ┃ ┃ ┃ ┣ 00000__role.json
 ┃ ┃ ┃ ┃ ┗ 00001__role.json
 ┃ ┃ ┃ ┗ parties.json
 ┃ ┃ ┣ back-matter.json
 ┃ ┃ ┣ groups.json
 ┃ ┃ ┗ metadata.json
 ┃ ┗ catalog.json


Note that the presence of wildcards caused new directories to be created containing the full lists of roles and responsible parties. You can read the wildcard as split off all roles from roles.json.

This split can be reversed with

trestle merge -e 'roles.*,responsible-parties.*'

Step 6: Split groups and controls with two wildcards¤

This single command will split off all controls in all groups. To do it you need to go back up into the catalog directory where the groups.json file is found:

cd ..
trestle split -f ./groups.json -e 'groups.*.controls.*'


Your directory is now very large with that one command!
catalogs
 ┗ mycatalog
 ┃ ┣ catalog
 ┃ ┃ ┣ groups
 ┃ ┃ ┃ ┣ 00000__group
 ┃ ┃ ┃ ┃ ┗ controls
 ┃ ┃ ┃ ┃ ┃ ┣ 00000__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00001__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00002__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00003__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00004__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00005__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00006__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00007__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00008__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00009__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00010__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00011__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00012__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00013__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00014__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00015__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00016__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00017__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00018__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00019__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00020__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00021__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00022__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00023__control.json
 ┃ ┃ ┃ ┃ ┃ ┗ 00024__control.json
 ┃ ┃ ┃ ┣ 00001__group
 ┃ ┃ ┃ ┃ ┗ controls
 ┃ ┃ ┃ ┃ ┃ ┣ 00000__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00001__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00002__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00003__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00004__control.json
 ┃ ┃ ┃ ┃ ┃ ┗ 00005__control.json
 ┃ ┃ ┃ ┣ 00002__group
 ┃ ┃ ┃ ┃ ┗ controls
 ┃ ┃ ┃ ┃ ┃ ┣ 00000__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00001__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00002__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00003__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00004__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00005__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00006__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00007__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00008__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00009__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00010__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00011__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00012__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00013__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00014__control.json
 ┃ ┃ ┃ ┃ ┃ ┗ 00015__control.json
 ┃ ┃ ┃ ┣ 00003__group
 ┃ ┃ ┃ ┃ ┗ controls
 ┃ ┃ ┃ ┃ ┃ ┣ 00000__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00001__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00002__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00003__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00004__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00005__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00006__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00007__control.json
 ┃ ┃ ┃ ┃ ┃ ┗ 00008__control.json
 ┃ ┃ ┃ ┣ 00004__group
 ┃ ┃ ┃ ┃ ┗ controls
 ┃ ┃ ┃ ┃ ┃ ┣ 00000__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00001__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00002__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00003__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00004__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00005__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00006__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00007__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00008__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00009__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00010__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00011__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00012__control.json
 ┃ ┃ ┃ ┃ ┃ ┗ 00013__control.json
 ┃ ┃ ┃ ┣ 00005__group
 ┃ ┃ ┃ ┃ ┗ controls
 ┃ ┃ ┃ ┃ ┃ ┣ 00000__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00001__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00002__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00003__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00004__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00005__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00006__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00007__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00008__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00009__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00010__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00011__control.json
 ┃ ┃ ┃ ┃ ┃ ┗ 00012__control.json
 ┃ ┃ ┃ ┣ 00006__group
 ┃ ┃ ┃ ┃ ┗ controls
 ┃ ┃ ┃ ┃ ┃ ┣ 00000__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00001__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00002__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00003__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00004__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00005__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00006__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00007__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00008__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00009__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00010__control.json
 ┃ ┃ ┃ ┃ ┃ ┗ 00011__control.json
 ┃ ┃ ┃ ┣ 00007__group
 ┃ ┃ ┃ ┃ ┗ controls
 ┃ ┃ ┃ ┃ ┃ ┣ 00000__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00001__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00002__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00003__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00004__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00005__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00006__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00007__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00008__control.json
 ┃ ┃ ┃ ┃ ┃ ┗ 00009__control.json
 ┃ ┃ ┃ ┣ 00008__group
 ┃ ┃ ┃ ┃ ┗ controls
 ┃ ┃ ┃ ┃ ┃ ┣ 00000__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00001__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00002__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00003__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00004__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00005__control.json
 ┃ ┃ ┃ ┃ ┃ ┗ 00006__control.json
 ┃ ┃ ┃ ┣ 00009__group
 ┃ ┃ ┃ ┃ ┗ controls
 ┃ ┃ ┃ ┃ ┃ ┣ 00000__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00001__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00002__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00003__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00004__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00005__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00006__control.json
 ┃ ┃ ┃ ┃ ┃ ┗ 00007__control.json
 ┃ ┃ ┃ ┣ 00010__group
 ┃ ┃ ┃ ┃ ┗ controls
 ┃ ┃ ┃ ┃ ┃ ┣ 00000__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00001__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00002__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00003__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00004__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00005__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00006__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00007__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00008__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00009__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00010__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00011__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00012__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00013__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00014__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00015__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00016__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00017__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00018__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00019__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00020__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00021__control.json
 ┃ ┃ ┃ ┃ ┃ ┗ 00022__control.json
 ┃ ┃ ┃ ┣ 00011__group
 ┃ ┃ ┃ ┃ ┗ controls
 ┃ ┃ ┃ ┃ ┃ ┣ 00000__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00001__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00002__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00003__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00004__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00005__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00006__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00007__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00008__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00009__control.json
 ┃ ┃ ┃ ┃ ┃ ┗ 00010__control.json
 ┃ ┃ ┃ ┣ 00012__group
 ┃ ┃ ┃ ┃ ┗ controls
 ┃ ┃ ┃ ┃ ┃ ┣ 00000__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00001__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00002__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00003__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00004__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00005__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00006__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00007__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00008__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00009__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00010__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00011__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00012__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00013__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00014__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00015__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00016__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00017__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00018__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00019__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00020__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00021__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00022__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00023__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00024__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00025__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00026__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00027__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00028__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00029__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00030__control.json
 ┃ ┃ ┃ ┃ ┃ ┗ 00031__control.json
 ┃ ┃ ┃ ┣ 00013__group
 ┃ ┃ ┃ ┃ ┗ controls
 ┃ ┃ ┃ ┃ ┃ ┣ 00000__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00001__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00002__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00003__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00004__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00005__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00006__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00007__control.json
 ┃ ┃ ┃ ┃ ┃ ┗ 00008__control.json
 ┃ ┃ ┃ ┣ 00014__group
 ┃ ┃ ┃ ┃ ┗ controls
 ┃ ┃ ┃ ┃ ┃ ┣ 00000__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00001__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00002__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00003__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00004__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00005__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00006__control.json
 ┃ ┃ ┃ ┃ ┃ ┗ 00007__control.json
 ┃ ┃ ┃ ┣ 00015__group
 ┃ ┃ ┃ ┃ ┗ controls
 ┃ ┃ ┃ ┃ ┃ ┣ 00000__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00001__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00002__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00003__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00004__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00005__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00006__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00007__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00008__control.json
 ┃ ┃ ┃ ┃ ┃ ┗ 00009__control.json
 ┃ ┃ ┃ ┣ 00016__group
 ┃ ┃ ┃ ┃ ┗ controls
 ┃ ┃ ┃ ┃ ┃ ┣ 00000__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00001__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00002__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00003__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00004__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00005__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00006__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00007__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00008__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00009__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00010__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00011__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00012__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00013__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00014__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00015__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00016__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00017__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00018__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00019__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00020__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00021__control.json
 ┃ ┃ ┃ ┃ ┃ ┗ 00022__control.json
 ┃ ┃ ┃ ┣ 00017__group
 ┃ ┃ ┃ ┃ ┗ controls
 ┃ ┃ ┃ ┃ ┃ ┣ 00000__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00001__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00002__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00003__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00004__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00005__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00006__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00007__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00008__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00009__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00010__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00011__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00012__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00013__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00014__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00015__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00016__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00017__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00018__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00019__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00020__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00021__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00022__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00023__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00024__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00025__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00026__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00027__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00028__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00029__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00030__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00031__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00032__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00033__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00034__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00035__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00036__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00037__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00038__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00039__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00040__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00041__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00042__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00043__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00044__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00045__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00046__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00047__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00048__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00049__control.json
 ┃ ┃ ┃ ┃ ┃ ┗ 00050__control.json
 ┃ ┃ ┃ ┣ 00018__group
 ┃ ┃ ┃ ┃ ┗ controls
 ┃ ┃ ┃ ┃ ┃ ┣ 00000__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00001__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00002__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00003__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00004__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00005__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00006__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00007__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00008__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00009__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00010__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00011__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00012__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00013__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00014__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00015__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00016__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00017__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00018__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00019__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00020__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00021__control.json
 ┃ ┃ ┃ ┃ ┃ ┗ 00022__control.json
 ┃ ┃ ┃ ┣ 00019__group
 ┃ ┃ ┃ ┃ ┗ controls
 ┃ ┃ ┃ ┃ ┃ ┣ 00000__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00001__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00002__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00003__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00004__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00005__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00006__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00007__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00008__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00009__control.json
 ┃ ┃ ┃ ┃ ┃ ┣ 00010__control.json
 ┃ ┃ ┃ ┃ ┃ ┗ 00011__control.json
 ┃ ┃ ┃ ┣ 00000__group.json
 ┃ ┃ ┃ ┣ 00001__group.json
 ┃ ┃ ┃ ┣ 00002__group.json
 ┃ ┃ ┃ ┣ 00003__group.json
 ┃ ┃ ┃ ┣ 00004__group.json
 ┃ ┃ ┃ ┣ 00005__group.json
 ┃ ┃ ┃ ┣ 00006__group.json
 ┃ ┃ ┃ ┣ 00007__group.json
 ┃ ┃ ┃ ┣ 00008__group.json
 ┃ ┃ ┃ ┣ 00009__group.json
 ┃ ┃ ┃ ┣ 00010__group.json
 ┃ ┃ ┃ ┣ 00011__group.json
 ┃ ┃ ┃ ┣ 00012__group.json
 ┃ ┃ ┃ ┣ 00013__group.json
 ┃ ┃ ┃ ┣ 00014__group.json
 ┃ ┃ ┃ ┣ 00015__group.json
 ┃ ┃ ┃ ┣ 00016__group.json
 ┃ ┃ ┃ ┣ 00017__group.json
 ┃ ┃ ┃ ┣ 00018__group.json
 ┃ ┃ ┃ ┗ 00019__group.json
 ┃ ┃ ┣ metadata
 ┃ ┃ ┃ ┣ responsible-parties
 ┃ ┃ ┃ ┃ ┣ contact__responsible-party.json
 ┃ ┃ ┃ ┃ ┗ creator__responsible-party.json
 ┃ ┃ ┃ ┣ roles
 ┃ ┃ ┃ ┃ ┣ 00000__role.json
 ┃ ┃ ┃ ┃ ┗ 00001__role.json
 ┃ ┃ ┃ ┗ parties.json
 ┃ ┃ ┣ back-matter.json
 ┃ ┃ ┗ metadata.json
 ┃ ┗ catalog.json


All 20 groups of controls have been split off, and each one has a corresponding directory with its full list of controls in it.

You can then reverse the split with

trestle merge -e 'groups.*'

Step 7: Collapse the entire directory structure back into a single catalog.json file - possibly after modifying individual files¤

You can collapse everything back to a single catalog.json file after first going up one directory to the mycatalog directory

cd ..
trestle merge -e 'catalog.*'


After all that splitting and merging you are back to this directory structure
catalogs
 ┗ mycatalog
 ┃ ┗ catalog.json


Conclusion¤

This completes the tutorial on using trestle to split and merge an OSCAL catalog file. Not shown here are modifications of the individual files that would be done in an actual use case, but note that if any changes are made that violate the OSCAL schema, trestle will notice them and flag them in the merge. This way not only does trestle allow user-driven decomposition and aggregation of these large, complex files; it also does constant checks on the contents against the required schema to make sure no errors are introduced in the process.