-
Notifications
You must be signed in to change notification settings - Fork 187
Developer Knowledge Base
This page is a collection of assorted tasks and topics developers from the NIST OSCAL Team will need or want as part of development activities. Documentation items, when specifically relevant to OSCAL, could and should make their way into official documentation with commits to the git repository's Markdown files. For official documentation, bug reports for error corrections and feature request issues identify and track work items. Changes to information here are not tracked that way. See the note on the bottom of this page. Information this page and children pages are for supporting activities underlying OSCAL development: code snippets for testing data format snippets (JSON, XML, YAML), software configuration, and common queries in different querying languages (JMESPath for JSON, XPath for XML, etc.).
- Open the OSCAL repository on your workstation.
- Checkout your new branch from the target branch (
develop
ormain
):
$ git remote -v # confirm origin is usnistgov/OSCAL
me git@github.com:youruser/OSCAL.git (fetch)
me git@github.com:youruser/OSCAL.git (push)
origin git@github.com:usnistgov/OSCAL.git (fetch)
origin git@github.com:usnistgov/OSCAL.git (push)
$ git fetch --all
$ git checkout --track origin/develop
$ git checkout -b new-pr-to-develop # create PR branch
$ git push me HEAD # push to your fork
$ git submodule update --init --recursive
$ cd build/metaschema/
$ git fetch --all
$ git remote -v # confirm origin is usnistgov/metaschema
me git@github.com:youruser/metaschema.git (fetch)
me git@github.com:youruser/metaschema.git (push)
origin git@github.com:usnistgov/metaschema.git (fetch)
origin git@github.com:usnistgov/metaschema.git (push)
$ git checkout --track me/metaschema-fork-updated
$ cd ..
$ git submodule set-url build/metaschema git@github.com:youruser/metaschema.git
$ git add .gitmodules build/metaschema
$ git commit -m "[WIP] Test metaschema sub-module change to test tooling to fix model issue."
- Make sure that submodules are initialized
git submodule update --init --recursive
- (Optional) Update submodules recursively
git pull --recurse-submodules
-
cd
into thebuild/
directorycd ./build
-
Start the development stack:
docker-compose up -d
-
Exec into the
cli
containerdocker-compose exec cli /bin/bash
-
Generate the model documentation
In the
cli
container:cd ./build/ci-cd ./generate-model-documentation.sh -v
or combine the full path
./build/ci-cd/generate-model-documentation.sh -v
-
Preview the changes
In another window, with Hugo installed:
cd docs hugo serve
-
View the updated documentation
Visit http://localhost:1313/OSCAL/reference/. The "release" will depend on the branch you are in.
Developers of the OSCAL project are encouraged to rely on a shared Docker image to ensure their environment is consistent with the rest of the team and CI/CD. Currently developers can choose to build the image themselves, or use the private Docker registry.
Note: currently the Docker registry is only accessible to members of the csd773 Docker Hub organization for administrative reasons, though we hope to make the registry public at some point.
If you are a OSCAL team member that does not have an account with Docker Hub that has access to the csd773 organization, ask on the team Gitter for instructions.
Otherwise, logging in is simple.
If you are using Docker desktop, simply sign in via the button the top right corner.
Run the following command and follow the instructions:
docker login
Once you have logged in, simply pull the image as follows:
docker pull csd773/oscal-common-env:develop
Building the image locally is simple:
# From the root of the OSCAL project
# Force uninitialize submodules (optional)
# git submodule deinit -f .
# Ensure your submodules are up to date with the current commit
git submodule update --init --recursive
# Build the image
./build/build-oscal-env-dockerfile.sh
The script build-oscal-env-dockerfile.sh
will tell you the built image's tag. E.g.
# Script output from build-oscal-env-dockerfile.sh
Built and tagged csd773/oscal-common-env:fixed-a-thing, to push run:
docker push csd773/oscal-common-env:fixed-a-thing
Note that the tag of the built image is derived from your current branch name. For more details see "Controlling the Docker image in CI".
To run a single command within the container run the following, replacing csd773/oscal-common-env:fixed-a-thing
with the desired tag:
docker run \
-v $(pwd):/oscal \
csd773/oscal-common-env:fixed-a-thing \
your-command-here
To run an interactive session, prepend the -it
flags and do not put a command:
docker run -it \
-v $(pwd):/oscal \
csd773/oscal-common-env:fixed-a-thing
In both of these scenarios, the Docker image is passed the current working directory (e.g. the root of the repository) and maps it to /oscal
in the container.
For more options like port mapping (required to access the Hugo serve web server), consult the Docker documentation
In the future we plan to rely on Docker images for CI/CD more. GitHub actions workflows that depend on the Docker images use the csd773 registry (building locally each run would take forever). Because of this, GitHub workflows relying on CI will attempt to:
- Pull the image with a tag corresponding to the current branch of the PR
- Pull the image with the
develop
tag
This is done to provide users with an "escape hatch" for modifying the environment within a PR.
Users that have logged in to the Docker registry can build and push new images as follows:
-
Build the image as instructed in the "Building the image manually" section
-
Push the resulting tagged image to the registry as instructed by the script output:
docker push csd773/oscal-common-env:$TAG # where $TAG is the tag of your built image
- Java Classes Generator
- JSON Schema Documentation Generator
- OpenAPI Tester
- Oxygen Emmet Plugin
- Oxygen Emmet Plugin
- XSD to JSON Schema converter
- XSpec Framework
- XSpec Helper Viewer
Note: Plugins in Oxygen can be installed automatically or manually
This is an opinionated view, but Oxygen has a variety of configuration options for setting up a scenario for applying one or more XSLT transformations against a source document, a scenario for executing a XProc pipeline, and many more.
Below is how some of us use Editor Variables and other configuration elements. As a rule, some of us will use a variable for the source document and hard-code the path to the transform or XProc pipeline when running the scenarios interactively.
- Open the XSLT stylesheet you will use for the transform, for example
nist-metaschema-COMPOSE.xsl
. - Open an input file for transforms in a XSLT stylesheet, like the
oscal_ssp_metaschema.xml
Metaschema module. - Open the scenario menu or click the Ctrl+Shift+C keyboard shortcut.
- In the scenario menu, provide an appropriate name like
nist-metaschema-COMPOSE
. - For the XML URL for the input file, use the variable
${currentFileURL}
. - For the XSL URL for the stylesheet, do not use a variable, but hard-code the path toe transform on the workstation like
/path/to/code/repos/oscal/branches/origin/develop/build/metaschema/toolchains/xslt-M4/nist-metaschema-COMPOSE.xsl
This configuration will allow you to switch different inputs for testing while using the same stylesheet.
In several places across our stack we make use of Java-based tooling such as Saxon and Calabash.
The version of these tools can be pinned using POM files, such as the one present in the build/
directory.
Below is a simple template script that can be used to invoke a Java dependency directly from a POM file.
#!/usr/bin/env bash
# Fail early if an error occurs
set -Eeuo pipefail
if ! [ -x "$(command -v mvn)" ]; then
echo 'Error: Maven (mvn) is not in the PATH, is it installed?' >&2
exit 1
fi
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)"
OSCAL_DIR="${SCRIPT_DIR}/../../../.." # Edit this to resolve to the OSCAL root from the script's directory
POM_FILE="${OSCAL_DIR}/build/pom.xml"
# Grab any additional files relative to the root OSCAL directory (like stylesheets)
MAIN_CLASS="net.sf.saxon.Transform" #edit this to target your application's main class. below are a few examples:
# XML Calabash: "com.xmlcalabash.drivers.Main"
# Saxon: "net.sf.saxon.Transform"
# Perform any argument processing here, such as preselecting stylesheets in Saxon, etc.
# Note here "${*// /\\ }" is a shell expansion that escapes spaces within arguments.
# For more information, see https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
ARGS=${*// /\\ }
mvn \
-f "$POM_FILE" \
exec:java \
-Dexec.mainClass="$MAIN_CLASS" \
-Dexec.args="$ARGS"
Note that this template is often extended to parse arguments directly. See an example of this in the profile resolution Saxon wrapper.
This approach has several key advantages:
- The script can refer to resources invariably to the user's current working directory, making it more portable.
- The user does not have to worry about downloading, copying, or otherwise managing any of the Java dependencies.
- A lot of the complexity of consuming stylesheets and other operations can be hidden from the user, making our stack more approachable.
Let's say we want to look for the following OSCAL syntax elements in XML at the same time:
- any definition of a field with the name "with-id" in one or more target documents
- any definition of a flag with the name "pattern" in one or more target documents
- any definition of an assembly with the name "matching" in one or more target documents
Apply the following query against the target document(s) (for this example any Metaschema definition in src/metaschema/*.xml
), observing use of the |
("union") operator:
//(
define-flag[@name='pattern']
| define-assembly[@name='matching']
| define-field[@name='with-id']
)
Here is a sneakier way to do something similar:
//@name[.=('pattern','matching','with-id')]/parent::*
parent::*
can also be shortened to ..
for those who prefer.
Mathematically, this path returns a superset of the nodes returned by the first path given, although in a particular metaschema they are likely to be the same.
This takes advantage of a feature of general comparison operators in XPath (=
, <
, >
, <=
, >=
) namely that they support comparing sequences, i.e. many values on either side of the operand, hence .=('a','b','c')
.
lychee
or markdown-link-check
will run an automated scan of the destination of almost every link (there is an exclude list) for every Markdown file in the repo and in the generated HTML that runs the website. Infrequently, GitHub's websites and external websites as well will rate-limit the runner's attempt open the link target or there is an internal failure on the runner. The resulting HTTP status is 0 (and that is not a normal one in the 200, 400, or 500 range). The build failure will indicate the link or an issue will be automatically opened that looks like the report below.
FILE: build/ci-cd/README.md
[✓] https://github.com/jessedc/ajv-cli
2 links checked.
If you can open the full URL reliably in your web browser on a developer workstation, you can safely presume this is a the infrequent hiccup on a GitHub Actions runner and close the issue as a false positive.
NOTE: This information exists for the benefit of NIST staff. Although the community may reference or inquire about content, this material is not explicitly intended for community support. The community may create issues to report bugs or request enhancements related to this documentation, but there is no support guarantees for this material. All issues will be considered on a case by case basis.
- Contributing to OSCAL Development
- Issue Completeness Review
- OSCAL Patch (Hot Fix) Release Checklist
- OSCAL Release Branching
- Public Events Calendar Management
- Link Check Report Procedure
- Dependency Pull Request Procedure
- Issue Triage and Backlog Refinement
- NIST SP 800-53 OSCAL Content Data Governance
- Workflow for Prototyping a New OSCAL Model
- Backlog Review Process for OSCAL-related Repositories