diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..7c974cc14 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +# Ignore everything +* +!/src/validations/constraints \ No newline at end of file diff --git a/.github/workflows/content-artifacts.yml b/.github/workflows/content-artifacts.yml index e423225ab..6dd0f0b30 100644 --- a/.github/workflows/content-artifacts.yml +++ b/.github/workflows/content-artifacts.yml @@ -15,10 +15,19 @@ on: name: Process Content env: HOME_REPO: GSA/fedramp-automation + IMAGE_NAME: GSA/fedramp-automation/validation-tools + REGISTRY: ghcr.io + # Docs: github.com/docker/metadata-action/?tab=readme-ov-file#typesha + DOCKER_METADATA_PR_HEAD_SHA: true jobs: validate-and-publish-content: name: Content Validation Checking, Conversion and Validation runs-on: ubuntu-20.04 + permissions: + contents: read + packages: write + attestations: write + id-token: write steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 with: @@ -53,3 +62,59 @@ jobs: commit_user_name: OSCAL GitHub Actions Bot commit_user_email: oscal@nist.gov commit_author: OSCAL GitHub Actions Bot + - name: Container image QEMU setup for cross-arch builds + id: image_setup_qemu + uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf + - name: Container image buildx setup for cross-arch builds + id: image_setup_buildx + with: + platforms: linux/amd64,linux/arm64 + uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db + - name: Container image login + id: image_login + uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Container image metadata and tag generation + id: image_metadata + uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 + with: + images: + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=sha,prefix=,suffix=,format=long + type=ref,event=branch + type=ref,event=tag + type=ref,event=pr + # For now, do not auto-tag latest, maintainers will decided what is + # release-worthy. + flavor: | + latest=false + annotations: + maintainers="FedRAMP Automation Team " + org.opencontainers.image.authors="FedRAMP Automation Team " + org.opencontainers.image.documentation="https://automate.fedramp.gov" + org.opencontainers.image.source="https://github.com/GSA/fedramp-automation" + org.opencontainers.image.vendor="GSA Technology Transformation Services" + org.opencontainers.image.title="FedRAMP Validation Tools" + org.opencontainers.image.description="FedRAMP's tools for validating OSCAL data" + org.opencontainers.image.licenses="CC0-1.0" + - name: Container image registry push + id: image_registry_push + uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 + with: + context: git-content + push: true + tags: ${{ steps.image_metadata.outputs.tags }} + labels: ${{ steps.image_metadata.outputs.annotations }} + platforms: linux/amd64,linux/arm64 + cache-from: type=gha + cache-to: type=gha,mode=max + - name: Container image push attestations + uses: actions/attest-build-provenance@1c608d11d69870c2092266b3f9a6f3abbf17002c + with: + subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}} + subject-digest: ${{ steps.image_registry_push.outputs.digest }} + push-to-registry: false diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..67d8e1b49 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,67 @@ +ARG MAVEN_IMAGE=maven:3.9.9-eclipse-temurin-22-alpine +ARG NODE_IMAGE=node:22-alpine3.20 +ARG APK_EXTRA_ARGS +ARG WGET_EXTRA_ARGS +# Static analysis from docker build and push warns this is a secret, it is not. +# Per official developer instructions, it is necessary to verify the APK packages +# for Alpine or properly signed. This information is inherently public. +# https://adoptium.net/installation/linux/#_alpine_linux_instructions +ARG TEMURIN_APK_KEY_URL=https://packages.adoptium.net/artifactory/api/security/keypair/public/repositories/apk +ARG TEMURIN_APK_REPO_URL=https://packages.adoptium.net/artifactory/apk/alpine/main +ARG TEMURIN_APK_VERSION=temurin-22-jdk +ARG MAVEN_DEP_PLUGIN_VERSION=3.8.0 +ARG OSCAL_CLI_VERSION=2.0.2 +# Current public key ID for maintainers@metaschema.dev releases of oscal-cli +# Static analysis from docker build and push warns this is a secret, it is not +# and is necessary to cross-ref the Maven GPG key for checking build signatures. +# https://keyserver.ubuntu.com/pks/lookup?search=0127D75951997E00&fingerprint=on&op=index +ARG OSCAL_CLI_GPG_KEY=0127D75951997E00 +ARG OSCAL_JS_VERSION=1.4.4 +ARG FEDRAMP_AUTO_GIT_URL=https://github.com/GSA/fedramp-automation.git +ARG FEDRAMP_AUTO_GIT_REF=feature/external-constraints +ARG FEDRAMP_AUTO_GIT_COMMIT + +FROM ${MAVEN_IMAGE} as oscal_cli_downloader +ARG MAVEN_DEP_PLUGIN_VERSION +ARG OSCAL_CLI_VERSION +ARG OSCAL_CLI_GPG_KEY +ARG APK_EXTRA_ARGS +ARG WGET_EXTRA_ARGS +RUN apk add --no-cache gpg gpg-agent unzip && \ + mkdir -p /opt/oscal-cli && \ + mvn \ + org.apache.maven.plugins:maven-dependency-plugin:${MAVEN_DEP_PLUGIN_VERSION}:copy \ + -DoutputDirectory=/opt/oscal-cli \ + -DremoteRepositories=https://repo1.maven.org/maven2 \ + -Dartifact=dev.metaschema.oscal:oscal-cli-enhanced:${OSCAL_CLI_VERSION}:zip:oscal-cli && \ + mvn \ + org.apache.maven.plugins:maven-dependency-plugin:${MAVEN_DEP_PLUGIN_VERSION}:copy \ + -DoutputDirectory=/opt/oscal-cli \ + -DremoteRepositories=https://repo1.maven.org/maven2 \ + -Dartifact=dev.metaschema.oscal:oscal-cli-enhanced:${OSCAL_CLI_VERSION}:zip.asc:oscal-cli && \ + gpg --recv-keys ${OSCAL_CLI_GPG_KEY} && \ + gpg -k ${OSCAL_CLI_GPG_KEY} && \ + cd /opt/oscal-cli && \ + gpg --verify *.zip.asc && \ + unzip *.zip && \ + rm -f *.zip && \ + rm -f *.zip.asc + +FROM ${NODE_IMAGE} as final +ARG OSCAL_JS_VERSION +ARG TEMURIN_APK_KEY_URL +ARG TEMURIN_APK_REPO_URL +ARG TEMURIN_APK_VERSION +ARG APK_EXTRA_ARGS +ARG WGET_EXTRA_ARGS +COPY --from=oscal_cli_downloader /opt/oscal-cli /opt/oscal-cli +RUN wget ${WGET_EXTRA_ARGS} -O /etc/apk/keys/adoptium.rsa.pub "${TEMURIN_APK_KEY_URL}" && \ + echo "${TEMURIN_APK_REPO_URL}" >> /etc/apk/repositories && \ + apk add ${APK_EXTRA_ARGS} --no-cache ${TEMURIN_APK_VERSION} && \ + mkdir -p /opt/fedramp/oscaljs && \ + mkdir -p /opt/fedramp/constraints && \ + (cd /opt/fedramp/oscaljs && npm install oscal@${OSCAL_JS_VERSION}) +COPY ./src/validations/constraints/*.xml /opt/fedramp/constraints/ +ENV PATH="$PATH:/opt/oscal-cli/bin:/opt/fedramp/oscaljs/node_modules/.bin" +WORKDIR /opt/fedramp/constraints +ENTRYPOINT [ "/opt/oscal-cli/bin/oscal-cli" ] diff --git a/Makefile b/Makefile index 77fe3c8a2..7b8f5de32 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ export BASE_DIR=$(shell pwd) +OCI_REV_TAG=$(shell git rev-parse HEAD) help: @grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' @@ -26,6 +27,12 @@ clean-dist: ## Clean non-RCS-tracked dist files @echo "Cleaning dist..." git clean -xfd dist +clean-oci-image: + docker rmi -f \ + validation-tools:$(OCI_REV_TAG) \ + ghcr.io/gsa/fedramp-automation/validation-tools:$(OCI_REV_TAG) \ + gsatts/validation-tools:$(OCI_REV_TAG) \ + test: build-validations ## Test all build: build-validations build-web dist ## Build all artifacts and copy into dist directory @@ -39,3 +46,27 @@ build: build-validations build-web dist ## Build all artifacts and copy into di @echo '#/bin/bash\necho "Serving FedRAMP ASAP documentation at http://localhost:8000/..."\npython3 -m http.server 8000 --directory web/' > ./dist/serve-documentation chmod +x ./dist/serve-documentation + +build-oci-image: + docker build \ + --build-arg APK_EXTRA_ARGS="--no-check-certificate" \ + --build-arg WGET_EXTRA_ARGS="--no-check-certificate" \ + -t validation-tools:$(OCI_REV_TAG) \ + -t ghcr.io/gsa/fedramp-automation/validation-tools:$(OCI_REV_TAG) \ + -t gsatts/validation-tools:$(OCI_REV_TAG) \ + . + +publish-oci-image: + docker tag \ + validation-tools:$(OCI_REV_TAG) validation-tools:latest + + docker tag \ + ghcr.io/gsa/fedramp-automation/validation-tools:$(OCI_REV_TAG) \ + ghcr.io/gsa/fedramp-automation/validation-tools:latest + + docker tag \ + gsatts/validation-tools:$(OCI_REV_TAG) \ + gsatts/validation-tools:latest + + docker push ghcr.io/gsa/fedramp-automation/validation-tools:$(OCI_REV_TAG) + docker push ghcr.io/gsa/fedramp-automation/validation-tools:latest