diff --git a/.github/workflows/regenerate-cd.yml b/.github/workflows/regenerate-cd.yml index 6604983..839134c 100644 --- a/.github/workflows/regenerate-cd.yml +++ b/.github/workflows/regenerate-cd.yml @@ -12,9 +12,6 @@ jobs: update: name: Regenerate content runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write steps: - name: Generate app token uses: tibdex/github-app-token@v2.1.0 diff --git a/.github/workflows/update-profiles.yml b/.github/workflows/update-profiles.yml index ad2d8d2..c787511 100644 --- a/.github/workflows/update-profiles.yml +++ b/.github/workflows/update-profiles.yml @@ -7,18 +7,33 @@ jobs: update: name: Run update runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write steps: + - name: Generate app token + uses: tibdex/github-app-token@v2.1.0 + id: get_installation_token + with: + app_id: ${{ secrets.APP_ID }} + private_key: ${{ secrets.PRIVATE_KEY }} + permissions: >- + {"contents": "write", "pull_requests": "write"} - name: Clone uses: actions/checkout@v4 - - name: Set up Python 3.8 - uses: actions/setup-python@v4 with: - python-version: 3.8 + token: ${{ steps.get_installation_token.outputs.token }} - name: Update from upstream repo - run: bash ./vendor/scripts/update-from-upstream.sh -b "main" -r "https://github.com/RedHatProductSecurity/oscal-profiles" -a "$ACTOR" -p "*.json" -i catalogs -i profiles - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - ACTOR: "${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>" \ No newline at end of file + run: bash ./scripts/update-from-upstream.sh -b "main" -r "https://github.com/RedHatProductSecurity/oscal-profiles" -p "*.json" -i catalogs -i profiles + - uses: peter-evans/create-pull-request@v5.0.2 + with: + base: main + branch: autoupdate-${{ github.run_id }} + delete-branch: true + commit-message: "Update vendored OSCAL content" + title: "Update vendored OSCAL content" + body: | + This PR updates content from https://github.com/RedHatProductSecurity/oscal-profiles. + "Automatically generated by the [update-profiles](.github/workflows/update-profiles.yml) workflow." + add-paths: | + catalogs/ + profiles/ + token: ${{ steps.get_installation_token.outputs.token }} + committer: trestle-bot[bot] <136850459+trestle-bot[bot]@users.noreply.github.com> \ No newline at end of file diff --git a/.mega-linter.yml b/.mega-linter.yml index 9a2e96a..05810d2 100644 --- a/.mega-linter.yml +++ b/.mega-linter.yml @@ -3,10 +3,7 @@ ENABLE_LINTERS: - REPOSITORY_GITLEAKS - ACTION_ACTIONLINT - MARKDOWN_MARKDOWNLINT - -DISABLE_ERRORS_LINTERS: - - MAKEFILE_CHECKMAKE - - REPOSITORY_KICS - BASH_SHELLCHECK + - REPOSITORY_KICS -FILTER_REGEX_EXCLUDE: (vendor/) \ No newline at end of file +REPOSITORY_KICS_ARGUMENTS: "--fail-on high" diff --git a/Makefile b/Makefile deleted file mode 100644 index bb0bba5..0000000 --- a/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -include ./vendor/mk/*.mk - -REPO := https://github.com/RedHatProductSecurity/oscal-automation-libs.git -BRANCH := main -SHELL := /bin/bash -SCRIPTS_DIR := "./vendor/scripts" -CONFIGS :=$(shell bash scripts/get_config_updates.sh) - -############################################################################ -## Environment setup -############################################################################ - -update-subtree: - @git subtree pull --prefix vendor/ "$(REPO)" "$(BRANCH)" --squash -.PHONY: update-subtree \ No newline at end of file diff --git a/docs/faqs.md b/docs/faqs.md index 7c2ee51..c6e6eab 100644 --- a/docs/faqs.md +++ b/docs/faqs.md @@ -2,12 +2,8 @@ Q: How do I update the catalogs in this workspace? -A: This is managed through GitHub Actions. The workflow file is located [here](../.github/workflows/update-nist.yml). It can be run [manually](https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow). +A: This is managed through GitHub Actions. The workflow file is located [here](../.github/workflows/update-profiles.yml). It can be run [manually](https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow). Q: How do I update profiles in this workspace? -A: This is managed through GitHub Actions. The workflow file is located [here](../.github/workflows/update-fedramp.yml). It can be run [manually](https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow). - -Q: How do I update the vendor directory? - -A: The vendor directory is managed as a git subtree. To pull the latest commit from main on the [`oscal-automation-libs`](https://github.com/RedHatProductSecurity/oscal-automation-libs.git) repository, run `make update-subtree`. \ No newline at end of file +A: This is managed through GitHub Actions. The workflow file is located [here](../.github/workflows/update-profile.yml). It can be run [manually](https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow). \ No newline at end of file diff --git a/vendor/scripts/update-from-upstream.sh b/scripts/update-from-upstream.sh similarity index 66% rename from vendor/scripts/update-from-upstream.sh rename to scripts/update-from-upstream.sh index 0088c52..8b92322 100644 --- a/vendor/scripts/update-from-upstream.sh +++ b/scripts/update-from-upstream.sh @@ -6,34 +6,53 @@ set -eu # Script: update-from-upstream.sh # Description: Clones a git repository at a specific branch based on an argument input. # It copies if any files matching a pattern to the current directory -# If the files have been updated and creates a branch and GitHub pull request. # Usage: ./update-from-upstream.sh -b -r -p ...[-i include_dir1] # Note: Useful for keeping upstream profiles and catalogs up to date #################################################### -# shellcheck disable=SC2128 -SCRIPT_DIR="$(realpath "$(dirname "$BASH_SOURCE")")" +function run_log () { + if [[ $1 == 0 ]]; then + echo ">> INFO: $2" + elif [[ $1 != 0 ]]; then + echo ">> ERROR: $2" + exit 1 + fi +} + +# Function to clone a git repository +function clone_repo() { + local BRANCH="${1:?branch is required}" + local REPO="${2:?repository is required}" + local DIR="${3:-"."}" + echo "git clone --branch $BRANCH $REPO $DIR" + git clone --branch "$BRANCH" "$REPO" "$DIR" +} + +# Function to generate the destination path based on the source path while removing specified parent directories +function generate_destination_path() { + local SOURCE_PATH="${1:?"source directory is required"}" + local remove_dirs=("${@:2}") -# shellcheck disable=SC1091 -source "$SCRIPT_DIR/logging.sh" -# shellcheck disable=SC1091 -source "$SCRIPT_DIR/auto-commit-push.sh" + # Iterate over the remove_dirs array and remove each specified parent directory from the source path + for dir in "${remove_dirs[@]}"; do + SOURCE_PATH=${SOURCE_PATH#"$dir/"} + done + echo "$SOURCE_PATH" +} function main() { # Default include directories DEFAULT_INCLUDE_DIRS=() BRANCH="" REPO_URL="" - AUTHOR="" patterns=() # Parse command line options - while getopts ":b:r:a:p:i:" opt; do + while getopts ":b:r:p:i:" opt; do case $opt in b) BRANCH="$OPTARG";; r) REPO_URL="$OPTARG";; - a) AUTHOR="$OPTARG";; p) patterns+=("$OPTARG");; i) include_dirs+=("$OPTARG");; \?) echo "Invalid option -$OPTARG" >&2; exit 1;; @@ -42,17 +61,13 @@ function main() { # Check if required arguments are provided if [ -z "$BRANCH" ] || [ -z "$REPO_URL" ] || [ ${#patterns[@]} -eq 0 ]; then - echo "Usage: update-from-upstream.sh -b branch -r repo_url -a author -p pattern1 -p pattern2 ... [-i include_dir1] [-i include_dir2] ..." + echo "Usage: update-from-upstream.sh -b branch -r repo_url -p pattern1 -p pattern2 ... [-i include_dir1] [-i include_dir2] ..." exit 1 fi # Set default value for include_dirs if not provided include_dirs=("${include_dirs[@]:-${DEFAULT_INCLUDE_DIRS[@]}}") - local COMMIT_TITLE="Sync OSCAL Content" - local COMMIT_BODY="chore: updates from upstream $REPO_URL" - git checkout -b "autoupdate_$GITHUB_RUN_ID" - tmpdir=$(mktemp -d) run_log 0 "Created $tmpdir" clone_repo "$BRANCH" "$REPO_URL" "$tmpdir" @@ -79,20 +94,6 @@ function main() { done done done - - if [ -n "$(git status --porcelain)" ]; then - - add_files "${patterns[@]}" - - if [ -n "$(git status --untracked-files=no --porcelain)" ]; then - local_commit "$COMMIT_BODY" "$AUTHOR" - create_branch_pull_request "autoupdate_$GITHUB_RUN_ID" "$COMMIT_TITLE" "$COMMIT_BODY" - else - run_log 0 "Nothing to commit." - fi - else - run_log 0 "Nothing to commit." - fi } main "$@" \ No newline at end of file diff --git a/vendor/.flake8 b/vendor/.flake8 deleted file mode 100644 index 79a16af..0000000 --- a/vendor/.flake8 +++ /dev/null @@ -1,2 +0,0 @@ -[flake8] -max-line-length = 120 \ No newline at end of file diff --git a/vendor/.github/workflows/linters.yml b/vendor/.github/workflows/linters.yml deleted file mode 100644 index b50f9c1..0000000 --- a/vendor/.github/workflows/linters.yml +++ /dev/null @@ -1,29 +0,0 @@ ---- -name: MegaLinter - -on: - push: - pull_request: - branches: main - -concurrency: - group: ${{ github.ref }}-${{ github.workflow }} - cancel-in-progress: true - -jobs: - lint: - name: MegaLinter - runs-on: ubuntu-latest - permissions: - issues: write - pull-requests: write - steps: - - name: Checkout Code - uses: actions/checkout@v3 - - - name: MegaLinter - id: ml - uses: oxsecurity/megalinter@v7 - env: - VALIDATE_ALL_CODEBASE: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/vendor/.gitignore b/vendor/.gitignore deleted file mode 100644 index c12ed07..0000000 --- a/vendor/.gitignore +++ /dev/null @@ -1,162 +0,0 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py,cover -.hypothesis/ -.pytest_cache/ -cover/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 -db.sqlite3-journal - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -.pybuilder/ -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock - -# pdm -# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. -#pdm.lock -# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it -# in version control. -# https://pdm.fming.dev/#use-with-ide -.pdm.toml - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# pytype static type analyzer -.pytype/ - -# Cython debug symbols -cython_debug/ - -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -.idea/ - -megalinter-reports/ diff --git a/vendor/.mega-linter.yml b/vendor/.mega-linter.yml deleted file mode 100644 index 1a0ee0d..0000000 --- a/vendor/.mega-linter.yml +++ /dev/null @@ -1,13 +0,0 @@ - -ENABLE_LINTERS: - - REPOSITORY_GITLEAKS - - REPOSITORY_KICS - - BASH_SHELLCHECK - - PYTHON_BLACK - - PYTHON_FLAKE8 - - PYTHON_ISORT - - ACTION_ACTIONLINT - - MARKDOWN_MARKDOWNLINT - - MAKEFILE_CHECKMAKE - -REPOSITORY_KICS_DISABLE_ERRORS_IF_LESS_THAN: 4 \ No newline at end of file diff --git a/vendor/CODEOWNERS b/vendor/CODEOWNERS deleted file mode 100644 index d05f246..0000000 --- a/vendor/CODEOWNERS +++ /dev/null @@ -1 +0,0 @@ -* @RedHatProductSecurity/project-trestle-dev \ No newline at end of file diff --git a/vendor/Containerfile b/vendor/Containerfile deleted file mode 100644 index d324160..0000000 --- a/vendor/Containerfile +++ /dev/null @@ -1,28 +0,0 @@ -FROM registry.access.redhat.com/ubi8/ubi AS build - -WORKDIR /demo - -COPY ./scripts/ /demo/scripts/ - -# Install dependencies -ENV BIN_DIR=/demo/bin/ PATH=$PATH:BIN_DIR - -RUN ./scripts/install.sh build - -FROM registry.access.redhat.com/ubi8/python-38 AS demo - -COPY requirements.txt requirements.txt - -# Install dependencies -RUN python3.8 -m pip install --no-cache-dir --upgrade pip setuptools \ - && python3.8 -m pip install --no-cache-dir -r requirements.txt - -COPY --from=build /demo /demo - -WORKDIR /demo - -USER root - -RUN ./scripts/install.sh install_demo_utils - -USER 1001 \ No newline at end of file diff --git a/vendor/LICENSE b/vendor/LICENSE deleted file mode 100644 index 775fc83..0000000 --- a/vendor/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2023 Red Hat, Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/README.md b/vendor/README.md deleted file mode 100644 index 5444f43..0000000 --- a/vendor/README.md +++ /dev/null @@ -1,35 +0,0 @@ -# oscal-automation-libs - -A common repository to share code for Makefiles, helper scripts, and IaC to support repositories with OSCAL content. - -## Makefiles -`mk/` directory contains several predefined makefiles `(*.mk)`. They are imported into the top-level Makefiles. - -## Scripts -`scripts` contain more complicated logic that is used in some make targets and in CI. - -## IAC - -`iac` contains code for automating deployments for assessments. - -## How to consume - -These shared automation resources are able to be consumed locally and through CI. This repository can be pulled in as a git submodule or subtree. - -Create a Makefile to consume: -```bash -git subtree add --prefix automation/ https://github.com/RedHatProductSecurity/oscal-automation-libs.git main --squash - -cat << EOF >> ./Makefile -include ./automation/mk/*.mk - -SHELL := /bin/bash -EOF - -make help -``` - -We plan to publish the container image for the environment, but it can be built locally using the following command: -```bash -podman build -t localhost:5000/trestle-demo:latest -f Containerfile -``` \ No newline at end of file diff --git a/vendor/iac/.keep b/vendor/iac/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/vendor/mk/assemble.mk b/vendor/mk/assemble.mk deleted file mode 100644 index a96efb2..0000000 --- a/vendor/mk/assemble.mk +++ /dev/null @@ -1,20 +0,0 @@ -############################################################################ -## Assemble OSCAL content -############################################################################ - -scripts_dir :=$(shell realpath $(dir $(lastword $(MAKEFILE_LIST)))../scripts) - -assemble: assemble-catalogs assemble-profiles assemble-cd -.PHONY: assemble - -assemble-catalogs: - @source $(scripts_dir)/assemble.sh && assemble_catalogs -.PHONY: assemble-catalogs - -assemble-profiles: - @source $(scripts_dir)/assemble.sh && assemble_profiles -.PHONY: assemble-profiles - -assemble-cd: - @source $(scripts_dir)/assemble.sh && assemble_components -.PHONY: assemble-cd \ No newline at end of file diff --git a/vendor/mk/create.mk b/vendor/mk/create.mk deleted file mode 100644 index 21c3c9c..0000000 --- a/vendor/mk/create.mk +++ /dev/null @@ -1,7 +0,0 @@ -############################################################################ -## Assemble OSCAL content -############################################################################ - -create-ssp: - @source $(scripts_dir)/create.sh && create_ssp -.PHONY: create-ssp \ No newline at end of file diff --git a/vendor/mk/help.mk b/vendor/mk/help.mk deleted file mode 100644 index fb8784a..0000000 --- a/vendor/mk/help.mk +++ /dev/null @@ -1,10 +0,0 @@ -############################################################################ -## Help Menu -############################################################################ - -help: - $(info The following make targets are available:) - @$(MAKE) -f $(firstword $(MAKEFILE_LIST)) --print-data-base --question no-such-target 2>&1 | grep -v 'no-such-target' | \ - grep -v -e '^no-such-target' -e '^makefile' | \ - awk '/^[^.%][-A-Za-z0-9_]*:/ { print substr($$1, 1, length($$1)-1) }' | sort -u -.PHONY: help \ No newline at end of file diff --git a/vendor/mk/regenerate.mk b/vendor/mk/regenerate.mk deleted file mode 100644 index fd988d4..0000000 --- a/vendor/mk/regenerate.mk +++ /dev/null @@ -1,24 +0,0 @@ -############################################################################ -## Generate markdown from OSCAL content -############################################################################ - -scripts_dir :=$(shell realpath $(dir $(lastword $(MAKEFILE_LIST)))../scripts) - -SKIP_COMPONENTS ?= "hello world" -SKIP_PROFILES ?= "" -SKIP_CATALOGS ?= "" - -regenerate: regenerate-catalogs regenerate-profiles regenerate-cd -.PHONY: regenerate - -regenerate-catalogs: - @source $(scripts_dir)/regenerate.sh && regenerate_catalogs ${SKIP_CATALOGS} -.PHONY: regenerate-catalogs - -regenerate-profiles: - @source $(scripts_dir)/regenerate.sh && regenerate_profiles ${SKIP_PROFILES} -.PHONY: regenerate-profiles - -regenerate-cd: - @source $(scripts_dir)/regenerate.sh && regenerate_components ${SKIP_COMPONENTS} -.PHONY: regenerate-cd diff --git a/vendor/mk/regenerate.mk.example.txt b/vendor/mk/regenerate.mk.example.txt deleted file mode 100644 index d2591aa..0000000 --- a/vendor/mk/regenerate.mk.example.txt +++ /dev/null @@ -1,8 +0,0 @@ -# Include the library makefile -include ./regenerate.mk -# All the available targets can be listed using `make help` - - -SKIP_COMPONENTS := "comp_a" "comp_b" -SKIP_CATALOG := "my_catalog" -SKIP_PROFILES := "my_profile" \ No newline at end of file diff --git a/vendor/mk/reports.mk b/vendor/mk/reports.mk deleted file mode 100644 index fea5129..0000000 --- a/vendor/mk/reports.mk +++ /dev/null @@ -1,38 +0,0 @@ -############################################################################ -## Generate reports for gap analysis activities -############################################################################ - -scripts_dir :=$(shell realpath $(dir $(lastword $(MAKEFILE_LIST)))../scripts) - - -# $1 - input ssp -# $2 - profile name -# $3 - template -define gap-report - @source $(scripts_dir)/trestle.sh && trestle author ssp-filter --name $(1) -o filtered_ssp -co "system-specific" -is "planned" \ - && trestle author jinja -i $(3) -ssp filtered_ssp -p $(2) -o gap-report.md -endef - -# $1 - input ssp -# $2 - profile name -# $3 - template -define auditing-report - @source $(scripts_dir)/trestle.sh && trestle author ssp-filter --name $(1) -o auditing_ssp -is "alternative,not-applicable" \ - && trestle author jinja -i $(3) -ssp auditing_ssp -p $(2) -o auditing-report.md -endef - -# $1 - input ssp -# $2 - profile name -# $3 - template -define customer-report - @source $(scripts_dir)/trestle.sh && trestle author ssp-filter --name $(1) -o crm_ssp -co "customer-configured,customer-provided" -is "planned,partial" \ - && trestle author jinja -i $(3) -ssp crm_ssp -p $(2) -o customer-report.md -endef - -# $1 - input ssp -# $2 - profile name -# $3 - template -define export-report - @source $(scripts_dir)/trestle.sh && trestle author ssp-filter --name $(1) -o exports_ssp -co "customer-configured,customer-provided,system-specific" \ - && trestle author jinja -i $(3) -ssp exports_ssp -p $(2) -o exports-report.md -endef diff --git a/vendor/mk/reports.mk.example.txt b/vendor/mk/reports.mk.example.txt deleted file mode 100644 index d026ef0..0000000 --- a/vendor/mk/reports.mk.example.txt +++ /dev/null @@ -1,22 +0,0 @@ -all: build -.PHONY: all - - -# Include the library makefile -include ./reports.mk -# All the available targets can be listed using `make help` - - -TEMPLATE := "my-template.jinja" - -generate-gap-report: - $(call gap-report,my_ssp,my_prof,$(TEMPLATE)) -.PHONY: generate-gap-report - -generate-customer-report: - $(call customer-report,my_ssp,my_prof,$(TEMPLATE)) -.PHONY: generate-customer-report - -generate-auditing-report: - $(call auditing-report,my_ssp,my_prof,$(TEMPLATE)) -.PHONY: generate-auditing-report \ No newline at end of file diff --git a/vendor/mk/sandbox.mk b/vendor/mk/sandbox.mk deleted file mode 100644 index ed1f807..0000000 --- a/vendor/mk/sandbox.mk +++ /dev/null @@ -1,9 +0,0 @@ -############################################################################ -## Environment setup -############################################################################ - -requirements :=$(shell realpath $(dir $(lastword $(MAKEFILE_LIST)))../requirements.txt) - -trestle-install: - @python3 -m pip install --upgrade pip setuptools && python3 -m pip install -r "$(requirements)" -.PHONY: trestle-install \ No newline at end of file diff --git a/vendor/mk/sanity.mk b/vendor/mk/sanity.mk deleted file mode 100644 index 52f97b5..0000000 --- a/vendor/mk/sanity.mk +++ /dev/null @@ -1,24 +0,0 @@ -############################################################################ -## Sanity checks -############################################################################ - -scripts_dir :=$(shell realpath $(dir $(lastword $(MAKEFILE_LIST)))../scripts) - -sanity: sanity-catalogs sanity-profiles sanity-cd sanity-ssps -.PHONY: sanity - -validate: - @source $(scripts_dir)/trestle.sh && trestle validate -a -.PHONY: validate - -sanity-catalogs: assemble-catalogs regenerate-catalogs - @git diff --exit-code -.PHONY: sanity-catalog - -sanity-profiles: assemble-profiles regenerate-profiles - @git diff --exit-code -.PHONY: sanity-profiles - -sanity-cd: assemble-cd regenerate-cd - @git diff --exit-code -.PHONY: sanity-cd \ No newline at end of file diff --git a/vendor/requirements.in b/vendor/requirements.in deleted file mode 100644 index 1003121..0000000 --- a/vendor/requirements.in +++ /dev/null @@ -1,66 +0,0 @@ -anyio==3.6.2 -argcomplete==2.0.0 -attrs==22.2.0 -bcrypt==4.0.1 -black==23.1.0 -certifi==2023.7.22 -cffi==1.15.1 -chardet==5.1.0 -charset-normalizer==3.0.1 -click==8.1.3 -cmarkgfm==0.6.0 -compliance-trestle==2.2.0 -cryptography==41.0.3 -datamodel-code-generator==0.17.1 -defusedxml==0.7.1 -dnspython==2.3.0 -email-validator==1.3.1 -et-xmlfile==1.1.0 -furl==2.1.3 -genson==1.2.2 -h11==0.14.0 -httpcore==0.16.3 -httpx==0.23.3 -idna==3.4 -ilcli==0.3.2 -importlib-resources==5.12.0 -inflect==5.6.2 -isort==5.12.0 -Jinja2==3.1.2 -jsonschema==4.17.3 -jsonschema-spec==0.1.3 -lazy-object-proxy==1.9.0 -MarkupSafe==2.1.2 -mypy-extensions==1.0.0 -openapi-schema-validator==0.3.4 -openapi-spec-validator==0.5.1 -openpyxl==3.1.1 -orderedmultidict==1.0.1 -orjson==3.8.7 -packaging==23.0 -paramiko==3.0.0 -pathable==0.4.3 -pathspec==0.11.0 -pkgutil_resolve_name==1.3.10 -platformdirs==3.0.0 -prance==0.22.2.22.0 -pycparser==2.21 -pydantic==1.10.5 -PyNaCl==1.5.0 -pyrsistent==0.19.3 -PySnooper==1.1.1 -python-dotenv==1.0.0 -python-frontmatter==1.0.0 -PyYAML==6.0 -requests==2.31.0 -rfc3986==1.5.0 -ruamel.yaml==0.17.21 -ruamel.yaml.clib==0.2.7 -six==1.16.0 -sniffio==1.3.0 -toml==0.10.2 -tomli==2.0.1 -typed-ast==1.5.4 -typing_extensions==4.5.0 -urllib3==1.26.14 -zipp==3.15.0 diff --git a/vendor/requirements.txt b/vendor/requirements.txt deleted file mode 100644 index accb50a..0000000 --- a/vendor/requirements.txt +++ /dev/null @@ -1,284 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.9 -# by the following command: -# -# pip-compile --output-file=requirements.txt requirements.in -# -anyio==3.6.2 - # via - # -r requirements.in - # httpcore -argcomplete==2.0.0 - # via - # -r requirements.in - # datamodel-code-generator -attrs==22.2.0 - # via - # -r requirements.in - # compliance-trestle - # jsonschema - # openapi-schema-validator -bcrypt==4.0.1 - # via - # -r requirements.in - # paramiko -black==23.1.0 - # via - # -r requirements.in - # datamodel-code-generator -certifi==2023.7.22 - # via - # -r requirements.in - # httpcore - # httpx - # requests -cffi==1.15.1 - # via - # -r requirements.in - # cmarkgfm - # cryptography - # pynacl -chardet==5.1.0 - # via - # -r requirements.in - # prance -charset-normalizer==3.0.1 - # via - # -r requirements.in - # requests -click==8.1.3 - # via - # -r requirements.in - # black -cmarkgfm==0.6.0 - # via - # -r requirements.in - # compliance-trestle -compliance-trestle==2.2.0 - # via -r requirements.in -cryptography==41.0.3 - # via - # -r requirements.in - # compliance-trestle - # paramiko -datamodel-code-generator[http]==0.17.1 - # via - # -r requirements.in - # compliance-trestle -defusedxml==0.7.1 - # via - # -r requirements.in - # compliance-trestle -dnspython==2.3.0 - # via - # -r requirements.in - # email-validator -email-validator==1.3.1 - # via - # -r requirements.in - # pydantic -et-xmlfile==1.1.0 - # via - # -r requirements.in - # openpyxl -furl==2.1.3 - # via - # -r requirements.in - # compliance-trestle -genson==1.2.2 - # via - # -r requirements.in - # datamodel-code-generator -h11==0.14.0 - # via - # -r requirements.in - # httpcore -httpcore==0.16.3 - # via - # -r requirements.in - # httpx -httpx==0.23.3 - # via - # -r requirements.in - # datamodel-code-generator -idna==3.4 - # via - # -r requirements.in - # anyio - # email-validator - # requests - # rfc3986 -ilcli==0.3.2 - # via - # -r requirements.in - # compliance-trestle -importlib-resources==5.12.0 - # via - # -r requirements.in - # openapi-spec-validator -inflect==5.6.2 - # via - # -r requirements.in - # datamodel-code-generator -isort==5.12.0 - # via - # -r requirements.in - # datamodel-code-generator -jinja2==3.1.2 - # via - # -r requirements.in - # compliance-trestle - # datamodel-code-generator -jsonschema==4.17.3 - # via - # -r requirements.in - # jsonschema-spec - # openapi-schema-validator - # openapi-spec-validator -jsonschema-spec==0.1.3 - # via - # -r requirements.in - # openapi-spec-validator -lazy-object-proxy==1.9.0 - # via - # -r requirements.in - # openapi-spec-validator -markupsafe==2.1.2 - # via - # -r requirements.in - # jinja2 -mypy-extensions==1.0.0 - # via - # -r requirements.in - # black -openapi-schema-validator==0.3.4 - # via - # -r requirements.in - # openapi-spec-validator -openapi-spec-validator==0.5.1 - # via - # -r requirements.in - # datamodel-code-generator -openpyxl==3.1.1 - # via - # -r requirements.in - # compliance-trestle -orderedmultidict==1.0.1 - # via - # -r requirements.in - # furl -orjson==3.8.7 - # via - # -r requirements.in - # compliance-trestle -packaging==23.0 - # via - # -r requirements.in - # black - # datamodel-code-generator - # prance -paramiko==3.0.0 - # via - # -r requirements.in - # compliance-trestle -pathable==0.4.3 - # via - # -r requirements.in - # jsonschema-spec -pathspec==0.11.0 - # via - # -r requirements.in - # black -pkgutil-resolve-name==1.3.10 - # via -r requirements.in -platformdirs==3.0.0 - # via - # -r requirements.in - # black -prance==0.22.2.22.0 - # via - # -r requirements.in - # datamodel-code-generator -pycparser==2.21 - # via - # -r requirements.in - # cffi -pydantic[email]==1.10.5 - # via - # -r requirements.in - # compliance-trestle - # datamodel-code-generator -pynacl==1.5.0 - # via - # -r requirements.in - # paramiko -pyrsistent==0.19.3 - # via - # -r requirements.in - # jsonschema -pysnooper==1.1.1 - # via - # -r requirements.in - # datamodel-code-generator -python-dotenv==1.0.0 - # via - # -r requirements.in - # compliance-trestle -python-frontmatter==1.0.0 - # via - # -r requirements.in - # compliance-trestle -pyyaml==6.0 - # via - # -r requirements.in - # jsonschema-spec - # openapi-spec-validator - # python-frontmatter -requests==2.31.0 - # via - # -r requirements.in - # prance -rfc3986[idna2008]==1.5.0 - # via - # -r requirements.in - # httpx -ruamel-yaml==0.17.21 - # via - # -r requirements.in - # compliance-trestle - # prance -ruamel-yaml-clib==0.2.7 - # via -r requirements.in -six==1.16.0 - # via - # -r requirements.in - # furl - # orderedmultidict - # prance -sniffio==1.3.0 - # via - # -r requirements.in - # anyio - # httpcore - # httpx -toml==0.10.2 - # via - # -r requirements.in - # datamodel-code-generator -tomli==2.0.1 - # via -r requirements.in -typed-ast==1.5.4 - # via - # -r requirements.in - # datamodel-code-generator -typing-extensions==4.5.0 - # via - # -r requirements.in - # jsonschema-spec - # pydantic -urllib3==1.26.14 - # via - # -r requirements.in - # requests -zipp==3.15.0 - # via -r requirements.in diff --git a/vendor/scripts/assemble.sh b/vendor/scripts/assemble.sh deleted file mode 100644 index 3551ad6..0000000 --- a/vendor/scripts/assemble.sh +++ /dev/null @@ -1,85 +0,0 @@ -#!/bin/bash - -# shellcheck disable=SC2128 -SCRIPT_DIR="$(realpath "$(dirname "$BASH_SOURCE")")" - -# shellcheck disable=SC1091 -source "$SCRIPT_DIR/logging.sh" -# shellcheck disable=SC1091 -source "$SCRIPT_DIR/trestle.sh" - -function assemble_catalogs() { -version_tag=$1 -catalogs=$(find ./markdown/catalogs -type d | wc -l) -if [ "$catalogs" -gt 0 ]; then - for d in ./markdown/catalogs/* ; do - catalog=$(basename "$d") - if [ "$1" != "" ]; then - run_log 0 "Assembling ${catalog} with version ${version_tag}" - trestle author catalog-assemble --markdown markdown/catalogs/"$catalog" --output "$catalog" --version "$version_tag" - else - run_log 0 "Assembling ${catalog}" - trestle author catalog-assemble --markdown markdown/catalogs/"$catalog" --output "$catalog" - fi - done -else - run_log 0 "No catalogs found" -fi -} - -function assemble_components() { -version_tag=$1 -components=$(find ./markdown/components -mindepth 1 -type d | wc -l) -if [ "$components" -gt 0 ]; then - for d in ./markdown/components/* ; do - component=$(basename "$d") - if [ "$1" != "" ]; then - run_log 0 "Assembling ${component} with version ${version_tag}" - trestle author component-assemble --name "$component" --markdown markdown/components/"$component"--output "$component" --version "$version_tag" - else - run_log 0 "Assembling ${component}" - trestle author component-assemble --name "$component" --markdown markdown/components/"$component" --output "$component" - fi - done -else - run_log 0 "No components found" -fi -} - -function assemble_profiles() { -version_tag=$1 -profiles=$(find ./markdown/profiles -mindepth 1 -type d | wc -l) -if [ "$profiles" -gt 0 ]; then - for d in ./markdown/profiles/* ; do - profile=$(basename "$d") - if [ "$1" != "" ]; then - run_log 0 "Assembling ${profile} with version ${version_tag}" - trestle author profile-assemble --markdown markdown/profiles/"$profile" --output "$profile" --set-parameters --version "$version_tag" - else - run_log 0 "Assembling ${profile}" - trestle author profile-assemble --markdown markdown/profiles/"$profile" --output "$profile" --set-parameters - fi - done -else - run_log 0 "No profiles found" -fi -} - -function assemble_ssps() { -version_tag=$1 -ssps=$(find ./markdown/system-security-plans -mindepth 1 -type d | wc -l) -if [ "$ssps" -gt 0 ]; then - for d in ./markdown/system-security-plans/* ; do - ssp=$(basename "$d") - if [ "$1" != "" ]; then - run_log 0 "Assembling ${ssp} with version ${version_tag}" - trestle author ssp-assemble --name "$ssp" --markdown markdown/system-security-plans/"$ssp"--output "$ssp" --version "$version_tag" - else - run_log 0 "Assembling ${ssp}" - trestle author ssp-assemble --name "$ssp" --markdown markdown/system-security-plans/"$ssp" --output "$ssp" - fi - done -else - run_log 0 "No ssps found" -fi -} \ No newline at end of file diff --git a/vendor/scripts/auth.sh b/vendor/scripts/auth.sh deleted file mode 100755 index e247bde..0000000 --- a/vendor/scripts/auth.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash - -while getopts "e:t:" opt; do - case $opt in - e) - arg_e="$OPTARG" - ;; - t) - arg_t="$OPTARG" - ;; - \?) - echo "Invalid option: -$OPTARG" >&2 - exit 1 - ;; - :) - echo "Option -$OPTARG requires an argument." >&2 - exit 1 - ;; - esac -done - -if [ -z "$arg_e" ] || [ -z "$arg_t" ]; then - echo "The \"email\" (-e) and \"token\" (-t) flags are required with their respective arguments." - exit 1 -fi - -function authenticate () { - echo "$arg_t" | gh auth login --with-token - gh auth setup-git -} - -function config-git () { - git config user.name "$(gh api user -q ".login")" - git config user.email "$arg_e" - echo "Logged into GitHub as: $(gh api user -q ".login")" - echo "Email set as: $(git config --get user.email)" -} - -authenticate -config-git diff --git a/vendor/scripts/auto-commit-push.sh b/vendor/scripts/auto-commit-push.sh deleted file mode 100644 index d1e13b2..0000000 --- a/vendor/scripts/auto-commit-push.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/bash - -# Function to clone a git repository -function clone_repo() { - local BRANCH="${1:?branch is required}" - local REPO="${2:?repository is required}" - local DIR="${3:-"."}" - echo "git clone --branch $BRANCH $REPO $DIR" - git clone --branch "$BRANCH" "$REPO" "$DIR" -} - -# Function to commit changes locally in git -function local_commit () { - local COMMIT_MESSAGE="${1:-"chore: automatic content update"}" - local COMMIT_AUTHOR="${2:-"github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>"}" - local COMMIT_USER="${3:-"github-actions[bot]"}" - local COMMIT_EMAIL="${4:-"41898282+github-actions[bot]@users.noreply.github.com"}" - - git -c user.name="$COMMIT_USER" -c user.email="$COMMIT_EMAIL" \ - commit -m "$COMMIT_MESSAGE" --author "$COMMIT_AUTHOR" -} - -# Function to stage changes files -function add_files(){ - local FILE_PATTERN="${1:?file pattern is required}" - read -r -a FILE_PATTERN_EXPANDED <<< "$FILE_PATTERN"; - git add ${FILE_PATTERN:+"${FILE_PATTERN_EXPANDED[@]}"} -} - -# Function to push to remote repository -function push_to_remote() { - local BRANCH="$1" - if [ -z "$BRANCH" ]; then - git push origin - else - git push --set-upstream origin "HEAD:$BRANCH" - fi -} - -# Function to create a new branch and GitHub pull request -function create_branch_pull_request() { - local BRANCH="${1:?"branch is required"}" - local PR_TITLE="${2:-"chore: sync OSCAL content"}" - local PR_BODY="${3:-"chore: automatic content update"}" - push_to_remote "$BRANCH" - gh pr create -t "$PR_TITLE" -b "$PR_BODY" -B "main" -H "$BRANCH" --draft -} - -# Function to generate the destination path based on the source path while removing specified parent directories -function generate_destination_path() { - local SOURCE_PATH="${1:?"source directory is required"}" - local remove_dirs=("${@:2}") - - # Iterate over the remove_dirs array and remove each specified parent directory from the source path - for dir in "${remove_dirs[@]}"; do - SOURCE_PATH=${SOURCE_PATH#"$dir/"} - done - - echo "$SOURCE_PATH" -} \ No newline at end of file diff --git a/vendor/scripts/create.sh b/vendor/scripts/create.sh deleted file mode 100644 index a0f9c25..0000000 --- a/vendor/scripts/create.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash - -# shellcheck disable=SC2128 -SCRIPT_DIR="$(realpath "$(dirname "$BASH_SOURCE")")" - -# shellcheck disable=SC1091 -source "$SCRIPT_DIR/logging.sh" -# shellcheck disable=SC1091 -source "$SCRIPT_DIR/trestle.sh" - -function generate_ssp() { - # Function requires the following variables - vars=("comps" "output" "profile") - var_check "${vars[@]}" - - # shellcheck disable=SC2154 - run_log 0 "Generating Markdown for ${output}" - # shellcheck disable=SC2154 - trestle author ssp-generate --compdefs "$comps" --profile "$profile" --output markdown/system-security-plans/"$output" -} - - -function assemble_ssp() { - # Function requires the following variables - vars=("comps" "output") - var_check "${vars[@]}" - - run_log 0 "Assembling to JSON for ${output}" - trestle author ssp-assemble --name "$output" --compdefs "$comps" --markdown markdown/system-security-plans/"$output" --output "$output" -} - - -function create_ssp() { - # Function requires the following variables - vars=("comps" "output" "profile") - var_check "${vars[@]}" - - run_log 0 "Creating new SSP ${output}" - generate_ssp - assemble_ssp -} - -function var_check() { - checkvars=("$@") - for i in "${checkvars[@]}"; do - if [ -z "${!i}" ]; then - run_log 1 "Required variable $i not set" - fi - done -} \ No newline at end of file diff --git a/vendor/scripts/dependencies.sh b/vendor/scripts/dependencies.sh deleted file mode 100644 index 7e9e4d3..0000000 --- a/vendor/scripts/dependencies.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash - -# shellcheck disable=SC2128 -SCRIPT_DIR="$(realpath "$(dirname "$BASH_SOURCE")")" - -# shellcheck disable=SC1091 -source "$SCRIPT_DIR/logging.sh" - -function install_epel () { - run_log 0 "Starting base dependency install" - subscription-manager repos --enable codeready-builder-for-rhel-8-"$(arch)"-rpms - dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm -} - -function install_go () { - run_log 0 "Starting base dependency install" - dnf install -y go -} - -function install_utils () { - run_log 0 "Starting base dependency install" - dnf install -y which pv asciinema make jq wget -} - -function install_gh_cli () { - run_log 0 "Starting GitHub CLI install" - dnf install 'dnf-command(config-manager)' - dnf config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo - dnf install -y gh -} - -function install_gcr () { - run_log 0 "Starting go-containerregistry install" - GOBIN=$BIN_DIR go install github.com/google/go-containerregistry/cmd/registry@latest - -} - -function install_oras () { - run_log 0 "Starting oras install" - GOBIN=$BIN_DIR go install oras.land/oras/cmd/oras@latest -} - -function install_cosign () { - run_log 0 "Starting cosign install" - GOBIN=$BIN_DIR go install github.com/sigstore/cosign/cmd/cosign@latest -} \ No newline at end of file diff --git a/vendor/scripts/export-cd.sh b/vendor/scripts/export-cd.sh deleted file mode 100644 index f85042b..0000000 --- a/vendor/scripts/export-cd.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -# shellcheck disable=SC2128 -SCRIPT_DIR="$(realpath "$(dirname "$BASH_SOURCE")")" - -# shellcheck disable=SC1091 -source "$SCRIPT_DIR/logging.sh" - -NSDATE=$(date --rfc-3339=ns | sed 's/ /T/; s/\(\....\).*\([+-]\)/\1\2/g') -export NSDATE -export CDDIR="component-definitions/hello-world-$GITHUB_REF_NAME" - -function export-cd () { - mkdir -p "$CDDIR" - local JSON_CD="${1:?JSON_CD required}" - envsubst < "$JSON_CD" > "$CDDIR"/component-definition.json -} \ No newline at end of file diff --git a/vendor/scripts/import.sh b/vendor/scripts/import.sh deleted file mode 100755 index 6392224..0000000 --- a/vendor/scripts/import.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -# shellcheck disable=SC2128 -SCRIPT_DIR="$(realpath "$(dirname "$BASH_SOURCE")")" - -# shellcheck disable=SC1091 -source "$SCRIPT_DIR/logging.sh" -# shellcheck disable=SC1091 -source "$SCRIPT_DIR/trestle.sh" - -function import_nist_rev5_catalog () { - 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 nist_rev5_800_53 -} - -function import_nist_rev4_catalog () { - trestle import -f https://raw.githubusercontent.com/usnistgov/oscal-content/master/nist.gov/SP800-53/rev4/json/NIST_SP-800-53_rev4_catalog.json -o nist_rev4_800_53 -} - -function import_fedramp_rev4_moderate_profiles () { - trestle import -f https://raw.githubusercontent.com/GSA/fedramp-automation/master/dist/content/rev4/baselines/json/FedRAMP_rev4_MODERATE-baseline_profile.json -o fedramp_rev4_moderate - trestle href --name fedramp_rev4_moderate -hr trestle://catalogs/nist_rev4_800_53/catalog.json -} \ No newline at end of file diff --git a/vendor/scripts/install.sh b/vendor/scripts/install.sh deleted file mode 100755 index 44fbe2b..0000000 --- a/vendor/scripts/install.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -# shellcheck disable=SC2128 -SCRIPT_DIR="$(realpath "$(dirname "$BASH_SOURCE")")" - -# shellcheck disable=SC1091 -source "$SCRIPT_DIR/dependencies.sh" - -function build () { - install_go -} - -function install_demo_utils () { - install_gh_cli - install_epel - install_utils - -} - - -"$@" diff --git a/vendor/scripts/logging.sh b/vendor/scripts/logging.sh deleted file mode 100644 index be91be1..0000000 --- a/vendor/scripts/logging.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -function run_log () { - if [[ $1 == 0 ]]; then - echo ">> INFO: $2" - elif [[ $1 != 0 ]]; then - echo ">> ERROR: $2" - exit 1 - fi -} \ No newline at end of file diff --git a/vendor/scripts/pandoc.sh b/vendor/scripts/pandoc.sh deleted file mode 100644 index fc399a2..0000000 --- a/vendor/scripts/pandoc.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -PANDOC_IMAGE="docker.io/pandoc/core" -PANDOC_IMAGE_TAG="3.1" -CONTAINER_CMD=$(command -pv podman || command -pv docker) - -if [ ! "$(command -v pandoc >/dev/null)" ]; -then - function pandoc { - ARGS=$* - CMD="$CONTAINER_CMD run -it --rm -w /demo/trestle-workspace -v $(pwd):/demo/trestle-workspace $PANDOC_IMAGE:$PANDOC_IMAGE_TAG $ARGS" - bash -c "$CMD" - } -fi \ No newline at end of file diff --git a/vendor/scripts/regenerate.sh b/vendor/scripts/regenerate.sh deleted file mode 100644 index ebc2e9e..0000000 --- a/vendor/scripts/regenerate.sh +++ /dev/null @@ -1,78 +0,0 @@ -#!/bin/bash - -# shellcheck disable=2128 -SCRIPT_DIR="$(realpath "$(dirname "$BASH_SOURCE")")" - -# shellcheck disable=SC1091 -source "$SCRIPT_DIR/logging.sh" -# shellcheck disable=SC1091 -source "$SCRIPT_DIR/trestle.sh" - -function containsElement() { - local value="$1" - shift - local array=("$@") - local element - - for element in "${array[@]}"; do - if [[ "$element" == "$value" ]]; then - return 0 # Value found, return success - fi - done - - return 1 # Value not found, return failure -} - -function regenerate_catalogs() { -local skip=("$@") -catalogs=$(find ./catalogs -mindepth 1 -type d | wc -l) -if [ "$catalogs" -gt 0 ]; then - for d in ./catalogs/* ; do - catalog=$(basename "$d") - if containsElement "$catalog" "${skip[@]}"; then - run_log 0 "Skipping $catalog" - continue - fi - run_log 0 "Regenerating $catalog" - trestle author catalog-generate --name "$catalog" --output markdown/catalogs/"$catalog" - done -else - run_log 0 "No catalogs found" -fi -} - -function regenerate_profiles() { -local skip=("$@") -profiles=$(find ./profiles -mindepth 1 -type d | wc -l) -if [ "$profiles" -gt 0 ]; then - for d in ./profiles/* ; do - profile=$(basename "$d") - if containsElement "$profile" "${skip[@]}"; then - run_log 0 "Skipping $profile" - continue - fi - run_log 0 "Regenerating $profile" - trestle author profile-generate --output markdown/profiles/"$profile" --name "$profile" - done - else - run_log 0 "No profiles found" - fi -} - -function regenerate_components() { -local skip=("$@") -components=$(find ./component-definitions -mindepth 1 -type d | wc -l) -if [ "$components" -gt 0 ]; then - for d in ./component-definitions/* ; do - component=$(basename "$d") - if containsElement "$component" "${skip[@]}"; then - run_log 0 "Skipping $component" - continue - fi - run_log 0 "Regenerating $component" - trestle author component-generate --output markdown/components/"$component" --name "$component" - done -else - run_log 0 "No components found" - fi -} \ No newline at end of file diff --git a/vendor/scripts/sandbox-entrypoint.sh b/vendor/scripts/sandbox-entrypoint.sh deleted file mode 100755 index fc9380f..0000000 --- a/vendor/scripts/sandbox-entrypoint.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -export PATH=$PATH:/demo/bin/ -bash \ No newline at end of file diff --git a/vendor/scripts/ssp-to-markdown/ssp_to_markdown.py b/vendor/scripts/ssp-to-markdown/ssp_to_markdown.py deleted file mode 100755 index fe22d19..0000000 --- a/vendor/scripts/ssp-to-markdown/ssp_to_markdown.py +++ /dev/null @@ -1,159 +0,0 @@ -#!/usr/bin/env python3 -# ssp_to_markdown.py - -""" -Create an SSP representation in Markdown with only high-level information -using the compliance-trestle libraries. - -Author: Jenn Power -""" - -import logging -import pathlib -import argparse - -from typing import List - -from trestle.common.load_validate import load_validate_model_name -from trestle.oscal.ssp import SystemSecurityPlan -from trestle.oscal.ssp import Diagram -from trestle.oscal.common import Link -from trestle.core.markdown.docs_markdown_node import DocsMarkdownNode -from trestle.core.markdown.md_writer import MDWriter - - -logging.basicConfig(format="%(levelname)s: %(message)s", level=logging.INFO) - - -def traverse_diagrams(diagrams: List[Diagram], md_writer: MDWriter, level: int): - """ - - :param diagrams: a list of ssp.Diagram types - :param md_writer: MDWriter type - :param level: heading level for the keys in Markdown - :return: None - """ - if diagrams is None: - return None - - md_writer.new_header(level=level, title="Diagrams") - md_writer.new_table( - [[diagram.caption, diagram.description] for diagram in diagrams], - ["Caption", "Description"], - ) - for diagram in diagrams: - traverse_links(diagram.links, md_writer, level + 1) - - -def get_link_text_if_exits(link: Link) -> str: - if link.text is str: - return link.text - else: - return "" - - -def traverse_links(links: List[Link], md_writer: MDWriter, level: int): - """ - - :param links: a list of common.Link types - :param md_writer: MDWriter type - :param level: heading level for the keys in Markdown - :return: - """ - if links is None: - return None - - md_writer.new_header(level=level, title="Links") - - md_writer.new_table( - [[link.href, get_link_text_if_exits(link)] for link in links], - ["Reference", "Text"], - ) - - -def main(): - p = argparse.ArgumentParser( - description="Generates a markdown from high-level SSP data" - ) - p.add_argument("--ssp_name", required=True) - p.add_argument("--trestle_root", required=True) - args = p.parse_args() - - # Read the applicable ssp name stored in trestle workspace - # into the OSCAL SSP type - ssp_data, _ = load_validate_model_name( - pathlib.Path(args.trestle_root), args.ssp_name, SystemSecurityPlan - ) - - md_writer = MDWriter(None) - md_writer.new_header(level=2, title="System Characteristics") - md_writer.new_paragraph - md_writer.new_table( - [ - [ - ssp_data.system_characteristics.system_name, - ssp_data.system_characteristics.description, - ] - ], - ["Name", "Description"], - ) - - md_writer.new_paragraph - - md_writer.new_header(level=3, title="System State") - md_writer.new_line(ssp_data.system_characteristics.status.state.value) - - md_writer.new_header(level=3, title="Security Impact Level") - md_writer.new_table( - [ - [ - "Confidentiality", - ssp_data.system_characteristics.security_impact_level.security_objective_confidentiality, - ], - [ - "Integrity", - ssp_data.system_characteristics.security_impact_level.security_objective_integrity, - ], - [ - "Availability", - ssp_data.system_characteristics.security_impact_level.security_objective_availability, - ], - ], - ["Security Objective", "Low, Moderate, High"], - ) - - # Get Authorization Boundary information, diagrams, and links - md_writer.new_header(level=3, title="Authorization Boundary") - auth_boundary = ssp_data.system_characteristics.authorization_boundary - md_writer.new_line(auth_boundary.description) - - traverse_links(auth_boundary.links, md_writer, 3) - traverse_diagrams(auth_boundary.diagrams, md_writer, 3) - - # Get Network Architecture information, diagrams, and links - md_writer.new_header(level=3, title="Network Architecture") - net_architecture = ssp_data.system_characteristics.network_architecture - md_writer.new_line(net_architecture.description) - - traverse_links(net_architecture.links, md_writer, 4) - - traverse_diagrams(net_architecture.diagrams, md_writer, 4) - - # Get Data Flow information, diagrams, and links - md_writer.new_header(level=3, title="Data Flow") - data_flow = ssp_data.system_characteristics.data_flow - md_writer.new_line(data_flow.description) - - traverse_links(data_flow.links, md_writer, 4) - - traverse_diagrams(data_flow.diagrams, md_writer, 4) - - lines = md_writer.get_lines() - tree = DocsMarkdownNode.build_tree_from_markdown(lines) - - # Print Markdown text - print(tree.content.raw_text) - - -if __name__ == "__main__": - main() diff --git a/vendor/scripts/trestle.sh b/vendor/scripts/trestle.sh deleted file mode 100755 index dc21c2e..0000000 --- a/vendor/scripts/trestle.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash - -TRESTLE_IMAGE="localhost:5000/trestle-demo" -TRESTLE_IMAGE_TAG="latest" - -TRESTLE_CMD_IMAGE="trestle" -PYTHON_CMD_IMAGE="python" - -CONTAINER_CMD=$(command -pv podman || command -pv docker) -TRESTLE_IMAGE_EXISTS=$($CONTAINER_CMD image inspect $TRESTLE_IMAGE 2>/dev/null > /dev/null; echo $?) - -if [ "$TRESTLE_IMAGE_EXISTS" == "0" ]; -then - # the trestle image exists, use it by creating wrapper functions - function trestle { - ARGS=$* - CMD="$CONTAINER_CMD run -it --rm -w /demo/trestle-workspace -v $(pwd):/demo/trestle-workspace $TRESTLE_IMAGE:$TRESTLE_IMAGE_TAG $TRESTLE_CMD_IMAGE $ARGS" - bash -c "$CMD" - } - - function python { - ARGS=$* - CMD="$CONTAINER_CMD run -it --rm -w /demo/trestle-workspace -v $(pwd):/demo/trestle-workspace $TRESTLE_IMAGE:$TRESTLE_IMAGE_TAG $PYTHON_CMD_IMAGE $ARGS" - bash -c "$CMD" - } -fi diff --git a/vendor/scripts/update-fedramp.sh b/vendor/scripts/update-fedramp.sh deleted file mode 100644 index 7e248ed..0000000 --- a/vendor/scripts/update-fedramp.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -set -eu - -# shellcheck disable=SC2128 -SCRIPT_DIR="$(realpath "$(dirname "$BASH_SOURCE")")" - -# shellcheck disable=SC1091 -source "$SCRIPT_DIR/logging.sh" -# shellcheck disable=SC1091 -source "$SCRIPT_DIR/import.sh" - -function update_fedramp () { - run_log 0 "Removing existing FedRAMP content from workspace" - rm -rf "profiles/fedramp_rev4_moderate" - import_fedramp_rev4_moderate_profiles - # shellcheck disable=SC1091 - source "$SCRIPT_DIR/update.sh" -c "Sync FedRAMP" "profiles/*" -} - -update_fedramp "$@" \ No newline at end of file diff --git a/vendor/scripts/update-nist.sh b/vendor/scripts/update-nist.sh deleted file mode 100644 index 2ae3728..0000000 --- a/vendor/scripts/update-nist.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -set -eu - -# shellcheck disable=SC2128 -SCRIPT_DIR="$(realpath "$(dirname "$BASH_SOURCE")")" - -# shellcheck disable=SC1091 -source "$SCRIPT_DIR/logging.sh" -# shellcheck disable=SC1091 -source "$SCRIPT_DIR/import.sh" - -function update_nist () { - run_log 0 "Removing existing NIST rev5 catalog from workspace" - rm -rf "catalogs/nist_rev5_800_53" - rm -rf "catalogs/nist_rev4_800_53" - import_nist_rev5_catalog - import_nist_rev4_catalog - # shellcheck disable=SC1091 - source "$SCRIPT_DIR/update.sh" -c "Sync NIST OSCAL content" "catalogs/*" -} - -update_nist "$@" \ No newline at end of file diff --git a/vendor/scripts/update-push.sh b/vendor/scripts/update-push.sh deleted file mode 100644 index c9c9696..0000000 --- a/vendor/scripts/update-push.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/bin/bash - -set -eu - -#################################################### -# Script: update-push.sh -# Description: It checks if there are any uncommited changes in a repo -# with a specific pattern. It commit the changes to the specified -# branch. -# Note: Useful for assembling Markdown into OSCAL JSON -#################################################### - -# shellcheck disable=2128 -SCRIPT_DIR="$(realpath "$(dirname "$BASH_SOURCE")")" - -# shellcheck disable=SC1091 -source "$SCRIPT_DIR/logging.sh" -# shellcheck disable=SC1091 -source "$SCRIPT_DIR/auto-commit-push.sh" - -USAGE="Usage: update-push.sh [-b branch] [-c commit_msg] [-a author] " - -function main() { - - DEFAULT_COMMIT_MSG="chore: automatic content update" - BRANCH="" - AUTHOR="" - - # Parse command line options - while getopts ":b:c:a:" opt; do - case $opt in - b) BRANCH="$OPTARG";; - c) commit_msg="$OPTARG";; - a) AUTHOR="$OPTARG";; - \?) echo "Invalid option -$OPTARG" >&2; exit 1;; - esac - done - - # Shift the option parameters - shift $((OPTIND - 1)) - - # Get the required argument - patterns=$1 - - # Check if patterns are provided - if [ -z "$patterns" ]; then - echo "$USAGE" - exit 1 - fi - - # Set default value for commit_msg if not provided - local COMMIT_BODY=${commit_msg:-$DEFAULT_COMMIT_MSG} - - if [ -n "$(git status --porcelain)" ]; then - add_files "${patterns[@]}" - - if [ -n "$(git status --untracked-files=no --porcelain)" ]; then - local_commit "$COMMIT_BODY" "$AUTHOR" - push_to_remote "$BRANCH" - else - run_log 0 "Nothing to commit." - fi - else - run_log 0 "Nothing to commit." - fi -} - -if [[ $# -lt 1 ]]; then - echo "$USAGE" - exit 1 -fi - -main "$@" \ No newline at end of file diff --git a/vendor/scripts/update.sh b/vendor/scripts/update.sh deleted file mode 100644 index a1d4471..0000000 --- a/vendor/scripts/update.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/bin/bash - -set -eu - -#################################################### -# Script: update.sh -# Description: It checks if there are any uncommited changes in a repo -# with a specific pattern. It create a new branch and pull -# request if there are changes. -# Note: Useful for regenerating downstream OSCAL content -#################################################### - -# shellcheck disable=2128 -SCRIPT_DIR="$(realpath "$(dirname "$BASH_SOURCE")")" - -# shellcheck disable=SC1091 -source "$SCRIPT_DIR/logging.sh" -# shellcheck disable=SC1091 -source "$SCRIPT_DIR/auto-commit-push.sh" - -USAGE="Usage: update.sh [-c commit_msg] [-a author] " - -function main() { - - DEFAULT_COMMIT_MSG="chore: automatic content update" - AUTHOR="" - - # Parse command line options - while getopts ":c:a:" opt; do - case $opt in - c) commit_msg="$OPTARG";; - a) AUTHOR="$OPTARG";; - \?) echo "Invalid option -$OPTARG" >&2; exit 1;; - esac - done - - # Shift the option parameters - shift $((OPTIND - 1)) - - # Get the required argument - patterns=$1 - - # Check if patterns are provided - if [ -z "$patterns" ]; then - echo "$USAGE" - exit 1 - fi - - # Set default value for commit_msg if not provided - local COMMIT_BODY=${commit_msg:-$DEFAULT_COMMIT_MSG} - local COMMIT_TITLE="Sync OSCAL content" - - git checkout -b "autoupdate_$GITHUB_RUN_ID" - - if [ -z "$(git status --porcelain)" ]; then - run_log 0 "Nothing to commit" - else - add_files "${patterns[@]}" - if [ -z "$(git status --untracked-files=no --porcelain)" ]; then - run_log 0 "Nothing to commit" - else - local_commit "$COMMIT_BODY" "$AUTHOR" - create_branch_pull_request "autoupdate_$GITHUB_RUN_ID" "$COMMIT_TITLE" "$COMMIT_BODY" - fi - fi -} - -if [[ $# -lt 1 ]]; then - echo "$USAGE" - exit 1 -fi - -main "$@" diff --git a/vendor/templates/ssp_exports_template.md.jinja b/vendor/templates/ssp_exports_template.md.jinja deleted file mode 100644 index d5caa26..0000000 --- a/vendor/templates/ssp_exports_template.md.jinja +++ /dev/null @@ -1,37 +0,0 @@ -# SSP Export Report - -{% for group in catalog_interface.get_all_groups_from_catalog() +%} -## {{ group.title }} {{ group.class }} \({{ group.id|upper }}\) -{% for control in catalog_interface.get_sorted_controls_in_group(group.id) %} -{% set control_orig = ssp_md_writer.get_fedramp_control_origination(control.id,4) %} -{% if control_orig is defined and control_orig != '' %} -{{ ssp_md_writer.get_control_statement(control.id, 2) }} - -#### {{ control_interface.get_label(control) }} Summary information -{{ ssp_md_writer.get_fedramp_control_tables(control.id, 4, true) }} -{% if 'customer-configured' in control_orig %} - -##### Exports - -In the context of the application component in satisfaction of {{control.id}}. - -- Provided Statement: *Consumer-appropriate description of what may be inherited.* -- Responsibilities Statement: *Leveraging system's responsibilities with respect to inheriting this capability.* -{% elif 'customer-provided' in control_orig %} - -##### Exports - -In the context of the application component in satisfaction of {{control.id}}. - -- Responsibilities Statement: *Leveraging system's responsibilities with respect to inheriting this capability.* -{% elif 'system-specific' in control_orig %} - -##### Exports - -In the context of the application component in satisfaction of {{control.id}}. - -- Provided Statement: *Consumer-appropriate description of what may be inherited.* -{% endif %} -{% endif %} -{% endfor %} -{% endfor %} \ No newline at end of file diff --git a/vendor/templates/ssp_gap_analysis_template.md.jinja b/vendor/templates/ssp_gap_analysis_template.md.jinja deleted file mode 100644 index 212dfe5..0000000 --- a/vendor/templates/ssp_gap_analysis_template.md.jinja +++ /dev/null @@ -1,15 +0,0 @@ -# SSP Analysis Report - -{% for group in catalog_interface.get_all_groups_from_catalog() +%} -## {{ group.title }} {{ group.class }} \({{ group.id|upper }}\) -{% for control in catalog_interface.get_sorted_controls_in_group(group.id) %} -{% set control_orig = ssp_md_writer.get_fedramp_control_origination(control.id,4) %} -{% if control_orig is defined and control_orig != '' %} -{{ ssp_md_writer.get_control_statement(control.id, 2) }} - -#### {{ control_interface.get_label(control) }} Summary information -{{ ssp_md_writer.get_fedramp_control_tables(control.id, 4, true) }} - -{% endif %} -{% endfor %} -{% endfor %} \ No newline at end of file