From d326d80b42232f43758d889c74240667928e7667 Mon Sep 17 00:00:00 2001 From: Jennifer Power Date: Tue, 1 Oct 2024 18:37:32 -0400 Subject: [PATCH 1/2] chore: adds gitignore file Signed-off-by: Jennifer Power --- .gitignore | 164 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..66d61b2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,164 @@ +# 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/ +*reports/ + +# 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/ + +# Local VSCode +.vscode/ \ No newline at end of file From 92c0b77867d2f55a493a1b79900b715844ac2295 Mon Sep 17 00:00:00 2001 From: Jennifer Power Date: Thu, 3 Oct 2024 19:13:21 -0400 Subject: [PATCH 2/2] chore: WIP commit for conformance testing Signed-off-by: Jennifer Power --- .github/workflows/conformance-test.yml | 26 ++++++++++ .pre-commit-config.yaml | 5 ++ actions/conformance/SPEC.md | 0 actions/conformance/action.yml | 46 ++++++++++++++++ actions/conformance/conformance/__main__.py | 40 ++++++++++++++ .../conformance/conformance/tests/conftest.py | 28 ++++++++++ .../conformance/conformance/tests/data/.keep | 0 .../conformance/conformance/tests/test_1.py | 22 ++++++++ .../conformance/tests/test_runner.py | 52 +++++++++++++++++++ actions/conformance/pyproject.toml | 18 +++++++ 10 files changed, 237 insertions(+) create mode 100644 .github/workflows/conformance-test.yml create mode 100644 .pre-commit-config.yaml create mode 100644 actions/conformance/SPEC.md create mode 100644 actions/conformance/action.yml create mode 100644 actions/conformance/conformance/__main__.py create mode 100644 actions/conformance/conformance/tests/conftest.py create mode 100644 actions/conformance/conformance/tests/data/.keep create mode 100644 actions/conformance/conformance/tests/test_1.py create mode 100644 actions/conformance/conformance/tests/test_runner.py create mode 100644 actions/conformance/pyproject.toml diff --git a/.github/workflows/conformance-test.yml b/.github/workflows/conformance-test.yml new file mode 100644 index 0000000..7a4028c --- /dev/null +++ b/.github/workflows/conformance-test.yml @@ -0,0 +1,26 @@ +name: Test integration + +on: + pull_request: + branches: + - main + workflow_dispatch: + +jobs: + test-integration: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + + - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 + with: + python-version: "3.11" + cache: "pip" + + - name: install compliance-trestle + run: pip install compliance-trestle==3.4.0 + + - name: SDK Conformance Test + uses: ./actions/conformance + with: + entrypoint: trestle \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..89f18ce --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,5 @@ +repos: + - repo: https://github.com/gitleaks/gitleaks + rev: v8.20.0 + hooks: + - id: gitleaks \ No newline at end of file diff --git a/actions/conformance/SPEC.md b/actions/conformance/SPEC.md new file mode 100644 index 0000000..e69de29 diff --git a/actions/conformance/action.yml b/actions/conformance/action.yml new file mode 100644 index 0000000..b41a6db --- /dev/null +++ b/actions/conformance/action.yml @@ -0,0 +1,46 @@ +# Copyright (c) 2024 The OSCAL Compass Authors. All rights reserved. +# +# 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 +# +# https://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. + +name: "conformance" +description: "Conformance testing for the OSCAL Compass SDK specification." + +inputs: + entrypoint: + description: "The root command to invoke the OSCAL SDK client for testing." + required: true + default: "" + +runs: + using: "composite" + steps: + - name: Clone repo + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + with: + fetch-depth: 0 + + - name: Setup Python + uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 + with: + python-version: "3.12" + + - name: Automation setup + run: pip install ${GITHUB_ACTION_PATH} + shell: bash + + - name: Run conformance testing + id: conformance + run: run-conformance-tests + env: + CONFORMANCE_ENTRYPOINT: "${{ inputs.entrypoint }}" + shell: bash \ No newline at end of file diff --git a/actions/conformance/conformance/__main__.py b/actions/conformance/conformance/__main__.py new file mode 100644 index 0000000..da4b050 --- /dev/null +++ b/actions/conformance/conformance/__main__.py @@ -0,0 +1,40 @@ +# Copyright (c) 2024 The OSCAL Compass Authors. All rights reserved. +# +# 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 +# +# https://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. + +import os +import sys +from pathlib import Path + +import pytest # type: ignore + + +def main() -> None: + """Run tests""" + workspace = os.getenv("GITHUB_ACTION_PATH") + if not workspace: + raise RuntimeError("GITHUB_ACTION_PATH environment variable is not set.") + + test_dir = Path(workspace).joinpath("conformance/tests") + exit_code = pytest.main([str(test_dir)]) + + if exit_code == 0: + print("All tests passed!") + else: + print("One or more failures were found.") + + sys.exit(exit_code) + + +if __name__ == "__main__": + main() diff --git a/actions/conformance/conformance/tests/conftest.py b/actions/conformance/conformance/tests/conftest.py new file mode 100644 index 0000000..0803130 --- /dev/null +++ b/actions/conformance/conformance/tests/conftest.py @@ -0,0 +1,28 @@ +# Copyright (c) 2024 The OSCAL Compass Authors. All rights reserved. +# +# 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 +# +# https://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. +"""Test fixtures.""" + +import os +import pytest # type: ignore + +from conformance.tests.test_runner import ConformanceTestRunner # type: ignore + + +@pytest.fixture(scope="module") +def runner() -> ConformanceTestRunner: + """Create a test runner.""" + root_cmd = os.getenv("CONFORMANCE_ENTRYPOINT") + if not root_cmd: + raise RuntimeError("CONFORMANCE_ENTRYPOINT environment variable is not set.") + return ConformanceTestRunner(root_cmd) diff --git a/actions/conformance/conformance/tests/data/.keep b/actions/conformance/conformance/tests/data/.keep new file mode 100644 index 0000000..e69de29 diff --git a/actions/conformance/conformance/tests/test_1.py b/actions/conformance/conformance/tests/test_1.py new file mode 100644 index 0000000..317ce98 --- /dev/null +++ b/actions/conformance/conformance/tests/test_1.py @@ -0,0 +1,22 @@ +# Copyright (c) 2024 The OSCAL Compass Authors. All rights reserved. +# +# 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 +# +# https://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. + +"""Example test.""" + +from conformance.tests.test_runner import ConformanceTestRunner # type: ignore + + +def test_example(runner: ConformanceTestRunner) -> None: + """This is an testing example.""" + runner.invoke_command([], None) diff --git a/actions/conformance/conformance/tests/test_runner.py b/actions/conformance/conformance/tests/test_runner.py new file mode 100644 index 0000000..b9d0168 --- /dev/null +++ b/actions/conformance/conformance/tests/test_runner.py @@ -0,0 +1,52 @@ +# Copyright (c) 2024 The OSCAL Compass Authors. All rights reserved. +# +# 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 +# +# https://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. + +"""Test runners for test suite""" + +import pathlib +import subprocess +from typing import List, Optional, Tuple + + +class ConformanceTestRunner: + """Class to run test suite.""" + + def __init__(self, root_cmd: str) -> None: + """Initialize the class.""" + self.root_cmd = root_cmd + + def invoke_command( + self, args: List[str], working_dir: Optional[pathlib.Path] = None + ) -> Tuple[int, str, str]: + """ + Invoke a command for test + + Args: + args List(str): Arguments to run with root command in the shell + + Returns: + Tuple[int, str]: Return code, stdout, stderr of the command + """ + command: List[str] = [self.root_cmd] + command.extend(args) + result = subprocess.run( + command, + cwd=working_dir, + capture_output=True + ) + return ( + result.returncode, + result.stdout.decode("utf-8"), + result.stderr.decode("utf-8"), + ) diff --git a/actions/conformance/pyproject.toml b/actions/conformance/pyproject.toml new file mode 100644 index 0000000..3422f34 --- /dev/null +++ b/actions/conformance/pyproject.toml @@ -0,0 +1,18 @@ +[build-system] +requires = ["setuptools", "setuptools-scm"] +build-backend = "setuptools.build_meta" + +[project] +name = "conformance" +version = "0.1.0" +description = "Test SDK conformance with defined specification." +authors = [ + {name = "Jenn Power"}, +] +license = {file = "LICENSE"} +readme = "README.md" +requires-python = ">=3.12" +dependencies = ["pytest"] + +[project.scripts] +run-conformance-tests = "conformance.__main__:main" \ No newline at end of file